From 18ad36f1dd6bbed621e7157aedadab20b0edfcb3 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:26:50 +0200 Subject: [PATCH 01/17] feature: add initial files --- .devcontainer/devcontainer.json | 13 + .gitattributes | 1 + .github/workflows/ci.yml | 80 + .github/workflows/pr.yml | 52 + .github/workflows/release.yml | 112 + .gitignore | 53 +- .nvmrc | 1 + LICENSE | 2 +- README.md | 13 +- eslint.config.js | 49 + lerna.json | 4 + package-lock.json | 14157 ++++++++++++++++ package.json | 33 + packages/build/package-lock.json | 3157 ++++ packages/build/package.json | 25 + packages/build/src/build-static.ts | 39 + packages/build/src/build.ts | 74 + packages/build/src/bundleJs.ts | 37 + .../build/src/computeNodeModulesCacheKey.ts | 67 + packages/build/src/dev.ts | 15 + packages/build/src/measureMemory.ts | 21 + packages/build/src/root.ts | 5 + packages/build/tsconfig.json | 24 + packages/e2e/extension/extension.json | 3 + .../extension.json | 10 + .../main.js | 31 + .../extension.json | 10 + .../main.js | 33 + .../extension.json | 10 + .../main.js | 32 + .../extension.json | 10 + .../main.js | 30 + .../extension.json | 3 + .../main.js | 36 + .../extension.json | 3 + .../main.js | 36 + .../extension.json | 10 + .../main.js | 29 + .../fixtures/sample.icon-theme/extension.json | 8 + .../sample.icon-theme/icon-theme.json | 6 + .../sample.icon-theme/icons/default_file.svg | 3 + .../icons/default_folder.svg | 3 + .../extension.json | 10 + .../main.js | 50 + .../extension.json | 10 + .../main.js | 50 + .../extension.json | 10 + .../sample.source-control-decoration/main.js | 57 + packages/e2e/package-lock.json | 116 + packages/e2e/package.json | 15 + ...t.explorer-accept-edit-when-not-editing.ts | 33 + .../e2e/src/viewlet.explorer-accessibility.ts | 69 + packages/e2e/src/viewlet.explorer-blur.ts | 24 + ...k-empty-space-clears-multiple-selection.ts | 27 + ...orer-click-empty-space-clears-selection.ts | 24 + .../e2e/src/viewlet.explorer-collapse-all.ts | 23 + ...orer-context-menu-compare-with-selected.ts | 21 + ...et.explorer-context-menu-copy-path-file.ts | 20 + ...et.explorer-context-menu-copy-path-root.ts | 19 + ...er-context-menu-copy-relative-path-file.ts | 20 + ...copy-relative-path-root-no-focused-item.ts | 20 + ...t-menu-create-file-error-already-exists.ts | 23 + ...menu-create-folder-error-already-exists.ts | 23 + ...rer-context-menu-delete-file-with-focus.ts | 24 + ...ewlet.explorer-context-menu-delete-file.ts | 24 + ...context-menu-paste-root-no-focused-item.ts | 27 + ...ntext-menu-remove-folder-from-workspace.ts | 17 + ...xplorer-context-menu-select-for-compare.ts | 20 + .../viewlet.explorer-copy-and-paste-file.ts | 31 + ...et.explorer-copy-and-paste-folder-error.ts | 22 + ...plorer-copy-and-paste-folder-with-items.ts | 34 + .../viewlet.explorer-copy-and-paste-folder.ts | 28 + ...let.explorer-copy-paste-error-scenarios.ts | 54 + .../src/viewlet.explorer-copy-path-empty.ts | 17 + .../src/viewlet.explorer-copy-path-file.ts | 20 + .../src/viewlet.explorer-copy-path-folder.ts | 18 + ...ewlet.explorer-create-file-blur-no-name.ts | 26 + .../src/viewlet.explorer-create-file-blur.ts | 26 + .../viewlet.explorer-create-file-cancel.ts | 27 + ...xplorer-create-file-different-languages.ts | 104 + ...er-create-file-double-click-empty-space.ts | 19 + ...plorer-create-file-error-already-exists.ts | 21 + ...r-file-name-cannot-start-with-backslash.ts | 29 + ...e-error-file-name-cannot-start-with-dot.ts | 29 + ...error-file-name-cannot-start-with-slash.ts | 29 + ...orer-create-file-error-no-name-provided.ts | 29 + ...mission-denied-escape-then-create-again.ts | 45 + ...-file-error-permission-denied-long-path.ts | 34 + ...rer-create-file-error-permission-denied.ts | 32 + ...explorer-create-file-explorer-collapses.ts | 23 + ...plorer-create-file-inside-closed-folder.ts | 27 + ...wlet.explorer-create-file-inside-folder.ts | 29 + .../viewlet.explorer-create-file-nested.ts | 35 + ...et.explorer-create-file-opens-in-editor.ts | 35 + ....explorer-create-file-starting-with-dot.ts | 27 + ...let.explorer-create-file-switch-folders.ts | 46 + ...plorer-create-file-when-file-is-focused.ts | 29 + ...plorer-create-file-with-emoji-extension.ts | 29 + ...viewlet.explorer-create-file-with-emoji.ts | 29 + ...lorer-create-file-with-greek-characters.ts | 29 + ...ewlet.explorer-create-file-with-newline.ts | 29 + ...rer-create-file-with-non-breaking-space.ts | 33 + ...iewlet.explorer-create-file-with-spaces.ts | 29 + .../e2e/src/viewlet.explorer-create-file.ts | 31 + ...explorer-create-folder-nested-150-times.ts | 53 + .../viewlet.explorer-create-folder-nested.ts | 33 + ...explorer-create-folder-with-backslashes.ts | 16 + .../e2e/src/viewlet.explorer-create-folder.ts | 29 + ...cut-and-paste-file-error-already-exists.ts | 33 + .../viewlet.explorer-cut-and-paste-file.ts | 36 + ...iewlet.explorer-cut-and-paste-two-files.ts | 39 + ...wlet.explorer-cut-and-paste-two-folders.ts | 39 + .../e2e/src/viewlet.explorer-cut-cancel.ts | 25 + .../viewlet.explorer-deeply-nested-folders.ts | 28 + ...et.explorer-delete-file-empty-workspace.ts | 16 + .../src/viewlet.explorer-delete-file-error.ts | 31 + ...et.explorer-delete-file-no-focused-item.ts | 21 + .../e2e/src/viewlet.explorer-delete-file.ts | 23 + ...ewlet.explorer-delete-folder-with-items.ts | 28 + .../e2e/src/viewlet.explorer-delete-folder.ts | 20 + .../src/viewlet.explorer-delete-last-file.ts | 18 + ....explorer-delete-multiple-files-at-once.ts | 28 + ...e-multiple-files-focuses-remaining-item.ts | 27 + .../viewlet.explorer-delete-multiple-files.ts | 58 + ...et.explorer-delete-nested-middle-folder.ts | 33 + ...wlet.explorer-drag-drop-error-scenarios.ts | 66 + .../viewlet.explorer-drag-file-into-folder.ts | 31 + ...orer-drop-empty-handles-empty-workspace.ts | 18 + ...er-drop-file-and-folder-empty-workspace.ts | 34 + ...wlet.explorer-drop-file-empty-workspace.ts | 23 + .../e2e/src/viewlet.explorer-drop-file.ts | 27 + ...et.explorer-drop-folder-empty-workspace.ts | 28 + ...viewlet.explorer-drop-folder-with-files.ts | 35 + .../e2e/src/viewlet.explorer-drop-folder.ts | 28 + ...plorer-drop-two-folders-empty-workspace.ts | 40 + .../src/viewlet.explorer-empty-workspace.ts | 23 + .../e2e/src/viewlet.explorer-expand-all.ts | 53 + ...viewlet.explorer-expand-folder-10-items.ts | 35 + ...iewlet.explorer-expand-folder-100-items.ts | 29 + ...ewlet.explorer-expand-folder-100k-items.ts | 38 + ...iewlet.explorer-expand-folder-10k-items.ts | 38 + ...iewlet.explorer-expand-folder-10m-items.ts | 25 + ...viewlet.explorer-expand-folder-1m-items.ts | 25 + .../viewlet.explorer-expand-recursively.ts | 30 + ...let.explorer-file-system-provider-error.ts | 31 + ...lorer-file-system-provider-invalid-data.ts | 37 + ...ewlet.explorer-handle-copy-no-selection.ts | 18 + ...iewlet.explorer-handle-cut-no-selection.ts | 18 + .../src/viewlet.explorer-handle-drag-leave.ts | 25 + .../viewlet.explorer-handle-drag-over-all.ts | 19 + ...viewlet.explorer-handle-drag-over-files.ts | 28 + ...iewlet.explorer-handle-drag-over-folder.ts | 18 + ...rer-handle-drag-over-index-out-of-range.ts | 17 + ...et.explorer-handle-drag-over-index-root.ts | 18 + .../src/viewlet.explorer-handle-drag-over.ts | 19 + .../e2e/src/viewlet.explorer-handle-drop.ts | 26 + ...ewlet.explorer-handle-icon-theme-change.ts | 23 + ...er-ignored-file-decoration-invalid-null.ts | 23 + ...-ignored-file-decoration-invalid-object.ts | 23 + ...iewlet.explorer-ignored-file-decoration.ts | 26 + .../viewlet.explorer-keyboard-navigation.ts | 118 + ...et.explorer-large-directory-performance.ts | 52 + ...ewlet.explorer-long-file-name-500-emoji.ts | 21 + .../src/viewlet.explorer-long-file-name.ts | 17 + .../src/viewlet.explorer-many-files-20000.ts | 47 + ...xplorer-many-files-repeated-focus-jumps.ts | 32 + .../viewlet.explorer-many-folders-20000.ts | 47 + .../src/viewlet.explorer-mouse-navigation.ts | 42 + .../viewlet.explorer-new-file-called-twice.ts | 20 + ...ewlet.explorer-open-folder-enoent-error.ts | 25 + .../src/viewlet.explorer-read-folder-error.ts | 23 + packages/e2e/src/viewlet.explorer-refresh.ts | 25 + .../viewlet.explorer-rename-file-150-times.ts | 46 + ...t.explorer-rename-file-cancel-150-times.ts | 32 + .../viewlet.explorer-rename-file-cancel.ts | 35 + ...orer-rename-file-error-no-name-provided.ts | 32 + ...rer-rename-file-error-permission-denied.ts | 28 + ...explorer-rename-file-special-characters.ts | 75 + .../src/viewlet.explorer-rename-file-twice.ts | 27 + ...viewlet.explorer-rename-file-whitespace.ts | 31 + .../e2e/src/viewlet.explorer-rename-file.ts | 37 + .../viewlet.explorer-rename-folder-nested.ts | 39 + ...orer-rename-root-folder-no-indent-shift.ts | 34 + ...t.explorer-reveal-from-tab-context-menu.ts | 36 + ...iewlet.explorer-reveal-non-existent-uri.ts | 34 + packages/e2e/src/viewlet.explorer-scroll.ts | 43 + ...t.explorer-select-all-then-delete-files.ts | 21 + .../e2e/src/viewlet.explorer-select-all.ts | 24 + .../e2e/src/viewlet.explorer-select-down.ts | 24 + ...orer-select-multiple-files-individually.ts | 25 + ...plorer-select-multiple-files-with-mouse.ts | 24 + .../viewlet.explorer-select-multiple-files.ts | 23 + .../e2e/src/viewlet.explorer-select-up.ts | 24 + ...wlet.explorer-set-delta-y-invalid-value.ts | 27 + ...iewlet.explorer-sort-numeric-file-names.ts | 24 + .../src/viewlet.explorer-sorting-emojis.ts | 45 + ...orer-sorting-mixed-alphanumeric-special.ts | 45 + ...let.explorer-sorting-special-characters.ts | 45 + ...let.explorer-sorting-unicode-characters.ts | 45 + packages/e2e/src/viewlet.explorer-sorting.ts | 44 + packages/e2e/src/viewlet.explorer.empty.ts | 16 + packages/e2e/src/viewlet.explorer.open.ts | 19 + packages/e2e/tsconfig.json | 22 + packages/explorer-view/package-lock.json | 4785 ++++++ packages/explorer-view/package.json | 61 + .../src/explorerViewWorkerMain.ts | 3 + .../src/parts/AcceptCreate/AcceptCreate.ts | 68 + .../AcceptCreateFile/AcceptCreateFile.ts | 7 + .../AcceptCreateFolder/AcceptCreateFolder.ts | 7 + .../src/parts/AcceptEdit/AcceptEdit.ts | 19 + .../src/parts/AcceptRename/AcceptRename.ts | 55 + .../src/parts/ActionType/ActionType.ts | 1 + .../AdjustScrollAfterPaste.ts | 17 + .../ApplyFileOperation/ApplyFileOperation.ts | 18 + .../ApplyFileOperations.ts | 16 + .../src/parts/ApplyRender/ApplyRender.ts | 14 + .../src/parts/AriaRoles/AriaRoles.ts | 4 + .../explorer-view/src/parts/Arrays/Arrays.ts | 11 + .../explorer-view/src/parts/Assert/Assert.ts | 1 + .../CanBeDroppedInto/CanBeDroppedInto.ts | 16 + .../src/parts/CancelEdit/CancelEdit.ts | 6 + .../CancelEditCreate/CancelEditCreate.ts | 22 + .../CancelEditInternal/CancelEditInternal.ts | 12 + .../CancelEditRename/CancelEditRename.ts | 24 + .../parts/CancelTypeAhead/CancelTypeAhead.ts | 8 + .../src/parts/Character/Character.ts | 4 + .../ChevronDownVirtualDom.ts | 10 + .../ChevronRightVirtualDom.ts | 10 + .../src/parts/ChevronType/ChevronType.ts | 3 + .../src/parts/ClassNames/ClassNames.ts | 40 + .../src/parts/ClickHandler/ClickHandler.ts | 6 + .../src/parts/ClipBoard/ClipBoard.ts | 14 + .../src/parts/CollapseAll/CollapseAll.ts | 13 + .../src/parts/CommandMap/CommandMap.ts | 176 + .../src/parts/Compare/Compare.ts | 8 + .../src/parts/CompareDirent/CompareDirent.ts | 24 + .../CompareWithSelected.ts | 18 + .../ComputeExplorerRenamedDirentUpdate.ts | 28 + .../src/parts/ConfirmDelete/ConfirmDelete.ts | 8 + .../src/parts/ConfirmPaste/ConfirmPaste.ts | 7 + .../src/parts/ContextMenu/ContextMenu.ts | 12 + .../ContextMenuHandler/ContextMenuHandler.ts | 5 + .../ContextMenuProps/ContextMenuProps.ts | 11 + .../CopyFilesElectron/CopyFilesElectron.ts | 11 + .../src/parts/CopyPath/CopyPath.ts | 12 + .../CopyRelativePath/CopyRelativePath.ts | 28 + .../src/parts/CountInRange/CountInRange.ts | 7 + .../explorer-view/src/parts/Create/Create.ts | 82 + .../src/parts/Create2/Create2.ts | 17 + .../CreateDecorationMap.ts | 10 + .../CreateDefaultState/CreateDefaultState.ts | 62 + .../CreateFileSystemWorkerRpc.ts | 15 + .../CreateIconThemeWorkerRpc.ts | 19 + .../CreateNestedPath/CreateNestedPath.ts | 18 + .../CreateSourceControlWorkerWorkerRpc.ts | 20 + .../src/parts/CreateTree/CreateTree.ts | 33 + .../CreateUploadTree/CreateUploadTree.ts | 22 + .../src/parts/DeltaEditing/DeltaEditing.ts | 1 + packages/explorer-view/src/parts/Diff/Diff.ts | 13 + .../explorer-view/src/parts/Diff2/Diff2.ts | 8 + .../src/parts/DiffCss/DiffCss.ts | 21 + .../src/parts/DiffDragData/DiffDragData.ts | 5 + .../DiffEditingSelection.ts | 10 + .../src/parts/DiffFocus/DiffFocus.ts | 5 + .../src/parts/DiffItems/DiffItems.ts | 23 + .../src/parts/DiffModules/DiffModules.ts | 27 + .../src/parts/DiffSelection/DiffSelection.ts | 5 + .../src/parts/DiffType/DiffType.ts | 9 + .../src/parts/DiffValue/DiffValue.ts | 9 + .../src/parts/DirentType/DirentType.ts | 21 + .../DomEventListener/DomEventListener.ts | 7 + .../DomEventListenerFunctions.ts | 18 + .../src/parts/DragDataItem/DragDataItem.ts | 4 + .../src/parts/DropHandler/DropHandler.ts | 6 + .../parts/DropTargetFull/DropTargetFull.ts | 1 + .../src/parts/EnsureUris/EnsureUris.ts | 10 + .../src/parts/ErrorCodes/ErrorCodes.ts | 1 + .../src/parts/ExpandAll/ExpandAll.ts | 38 + .../ExpandRecursively/ExpandRecursively.ts | 38 + .../src/parts/ExpandedType/ExpandedType.ts | 3 + .../ExplorerEditingType.ts | 7 + .../src/parts/ExplorerError/ExplorerError.ts | 6 + .../src/parts/ExplorerItem/ExplorerItem.ts | 10 + .../src/parts/ExplorerState/ExplorerState.ts | 65 + .../parts/ExplorerStates/ExplorerStates.ts | 81 + .../parts/ExplorerStrings/ExplorerStrings.ts | 140 + .../parts/FileDecoration/FileDecoration.ts | 4 + .../src/parts/FileIconCache/FileIconCache.ts | 3 + .../parts/FileIconsRequest/FileIconsResult.ts | 6 + .../src/parts/FileOperation/FileOperation.ts | 35 + .../FileOperationType/FileOperationType.ts | 5 + .../src/parts/FileSystem/FileSystem.ts | 41 + .../FileSystemWorker/FileSystemWorker.ts | 8 + .../FilterByFocusWord/FilterByFocusWord.ts | 25 + .../explorer-view/src/parts/Focus/Focus.ts | 12 + .../src/parts/FocusFirst/FocusFirst.ts | 10 + .../src/parts/FocusId/FocusId.ts | 3 + .../src/parts/FocusIndex/FocusIndex.ts | 45 + .../src/parts/FocusKey/FocusKey.ts | 3 + .../src/parts/FocusLast/FocusLast.ts | 12 + .../src/parts/FocusNext/FocusNext.ts | 11 + .../src/parts/FocusNone/FocusNone.ts | 10 + .../FocusParentFolder/FocusParentFolder.ts | 11 + .../src/parts/FocusPrevious/FocusPrevious.ts | 18 + .../GenerateUniqueName/GenerateUniqueName.ts | 42 + .../GetActionButtonVirtualDom.ts | 19 + .../GetActionVirtualDom.ts | 13 + .../src/parts/GetActions/GetActions.ts | 41 + .../GetActionsVirtualDom.ts | 20 + .../parts/GetChevronType/GetChevronType.ts | 17 + .../GetChevronVirtualDom.ts | 13 + .../parts/GetChildDirents/GetChildDirents.ts | 22 + .../GetChildDirentsRaw/GetChildDirentsRaw.ts | 14 + .../GetChildDirentsRecursively.ts | 24 + .../parts/GetChildHandles/GetChildHandles.ts | 8 + .../src/parts/GetClickFn/GetClickFn.ts | 49 + .../GetContainingFolder.ts | 10 + .../GetContextMenuHandler.ts | 13 + .../explorer-view/src/parts/GetCss/GetCss.ts | 27 + .../src/parts/GetDragData/GetDragData.ts | 36 + .../src/parts/GetDragLabel/GetDragLabel.ts | 8 + .../parts/GetDropHandler/GetDropHandler.ts | 12 + .../parts/GetEditingIcon/GetEditingIcon.ts | 21 + .../parts/GetEditingType/GetEditingType.ts | 8 + .../src/parts/GetErrorCode/GetErrorCode.ts | 6 + .../parts/GetErrorMessage/GetErrorMessage.ts | 9 + .../GetErrorMessageDom/GetErrorMessageDom.ts | 19 + .../GetErrorMessagePosition.ts | 25 + .../src/parts/GetExcluded/GetExcluded.ts | 10 + .../GetExpandedDirents/GetExpandedDirents.ts | 6 + .../parts/GetExpandedType/GetExpandedType.ts | 14 + .../GetExplorerItemVirtualDom.ts | 43 + .../GetExplorerVirtualDom.ts | 65 + .../GetExplorerWelcomeVirtualDom.ts | 52 + .../src/parts/GetFileArray/GetFileArray.ts | 5 + .../GetFileDecorations/GetFileDecorations.ts | 32 + .../GetFileHandleText/GetFileHandleText.ts | 5 + .../parts/GetFileHandles/GetFileHandles.ts | 10 + .../GetFileIconVirtualDom.ts | 14 + .../src/parts/GetFileIcons/GetFileIcons.ts | 20 + .../GetFileIconsCached/GetFileIconsCached.ts | 5 + .../GetFileOperations/GetFileOperations.ts | 22 + .../GetFileOperationsCopy.ts | 33 + .../GetFileOperationsCreate.ts | 47 + .../GetFileOperationsCut.ts | 20 + .../GetFileOperationsElectron.ts | 24 + .../GetFileOperationsRename.ts | 16 + .../GetFilePathElectron.ts | 5 + .../src/parts/GetFilePaths/GetFilePaths.ts | 15 + .../parts/GetFittingIndex/GetFittingIndex.ts | 16 + .../GetFocusedDirent/GetFocusedDirent.ts | 8 + .../parts/GetFocusedFile/GetFocusedFile.ts | 14 + .../GetFocusedIndexCancel.ts | 6 + .../src/parts/GetFolderIcon/GetFolderIcon.ts | 5 + .../GetFriendlyErrorMessage.ts | 15 + .../GetIconVirtualDom/GetIconVirtualDom.ts | 12 + .../src/parts/GetIndentRule/GetIndentRule.ts | 5 + .../src/parts/GetIndex/GetIndex.ts | 11 + .../GetIndexFromPosition.ts | 13 + .../GetInputClassName/GetInputClassName.ts | 9 + .../src/parts/GetInputDom/GetInputDom.ts | 30 + .../parts/GetKeyBindings/GetKeyBindings.ts | 123 + .../src/parts/GetLabelDom/GetLabelDom.ts | 28 + .../GetListItemsVirtualDom.ts | 58 + .../GetLoadErrorMessage.ts | 24 + .../GetLoadErrorVirtualDom.ts | 57 + .../src/parts/GetMaxLineY/GetMaxLineY.ts | 6 + .../parts/GetMenuEntries/GetMenuEntries.ts | 214 + .../parts/GetMenuEntries2/GetMenuEntries2.ts | 7 + .../GetMissingIconRequests.ts | 27 + .../parts/GetMouseAction/GetMouseAction.ts | 5 + .../parts/GetMouseActions/GetMouseActions.ts | 33 + .../GetNewChildDirentsForNewDirent.ts | 43 + .../GetNewDirentType/GetNewDirentType.ts | 13 + .../GetNewDirentsAccept.ts | 72 + .../GetNewDirentsForCancelRename.ts | 12 + .../GetNewDirentsForNewDirent.ts | 50 + .../GetNewDirentsForRename.ts | 15 + .../GetNewDropTargets/GetNewDropTargets.ts | 24 + .../GetNumberOfVisibleItems.ts | 9 + .../GetParentEndIndex/GetParentEndIndex.ts | 11 + .../parts/GetParentFolder/GetParentFolder.ts | 22 + .../GetParentStartIndex.ts | 10 + .../parts/GetPasteHandler/GetPasteHandler.ts | 18 + .../src/parts/GetPath/GetPath.ts | 5 + .../GetPathDirentsMap/GetPathDirentsMap.ts | 17 + .../src/parts/GetPathParts/GetPathParts.ts | 18 + .../GetPathPartsChildren.ts | 16 + .../GetPathPartsFromFileOperations.ts | 20 + .../GetPathPartsToReveal.ts | 15 + .../GetPathSeparator/GetPathSeparator.ts | 5 + .../src/parts/GetPaths/GetPaths.ts | 6 + .../src/parts/GetProtoMap/GetProtoMap.ts | 11 + .../GetProtoMapInternal.ts | 34 + .../GetRenameSelectionRange.ts | 15 + .../src/parts/GetRenderer/GetRenderer.ts | 33 + .../GetRestoredDeltaY/GetRestoredDeltaY.ts | 6 + .../GetSavedChildDirents.ts | 48 + .../src/parts/GetSavedRoot/GetSavedRoot.ts | 3 + .../src/parts/GetScheme/GetScheme.ts | 9 + .../GetScrollBarSize/GetScrollBarSize.ts | 6 + .../parts/GetScrollBarTop/GetScrollBarTop.ts | 10 + .../GetScrollBarVirtualDom.ts | 23 + .../GetSelectedItems/GetSelectedItems.ts | 7 + .../src/parts/GetSettings/GetSettings.ts | 21 + .../GetSiblingFileNames.ts | 20 + .../GetSimpleIconRequestType.ts | 13 + .../parts/GetSymlinkType/GetSymlinkType.ts | 12 + .../GetTopLevelDirents/GetTopLevelDirents.ts | 8 + .../GetTreeItemClassName.ts | 24 + .../GetTreeItemIndent/GetTreeItemIndent.ts | 5 + .../GetTreeItemIndentWithChevron.ts | 13 + .../src/parts/GetUnique/GetUnique.ts | 9 + .../GetUniqueIndents/GetUniqueIndents.ts | 10 + .../GetVisibleExplorerItems.ts | 84 + .../GetWorkspacePath/GetWorkspacePath.ts | 5 + .../parts/HandleArrowLeft/HandleArrowLeft.ts | 23 + .../HandleArrowRight/HandleArrowRight.ts | 28 + .../HandleArrowRightDirectoryExpanded.ts | 14 + .../src/parts/HandleBlur/HandleBlur.ts | 18 + .../HandleButtonClick/HandleButtonClick.ts | 21 + .../src/parts/HandleClick/HandleClick.ts | 49 + .../src/parts/HandleClickAt/HandleClickAt.ts | 32 + .../HandleClickAtRangeSelection.ts | 13 + .../HandleClickCurrent/HandleClickCurrent.ts | 6 + .../HandleClickCurrentButKeepFocus.ts | 6 + .../HandleClickDirectory.ts | 37 + .../HandleClickDirectoryExpanded.ts | 44 + .../HandleClickDirectoryExpanding.ts | 20 + .../parts/HandleClickFile/HandleClickFile.ts | 12 + .../HandleClickOpenFolder.ts | 7 + .../HandleClickSymlink/HandleClickSymlink.ts | 16 + .../HandleContextMenu/HandleContextMenu.ts | 8 + .../HandleContextMenuAtIndex.ts | 21 + .../HandleContextMenuKeyboard.ts | 9 + .../HandleContextMenuMouseAt.ts | 11 + .../HandleContextMenuWelcome.ts | 5 + .../src/parts/HandleCopy/HandleCopy.ts | 21 + .../src/parts/HandleCut/HandleCut.ts | 20 + .../HandleDoubleClick/HandleDoubleClick.ts | 11 + .../src/parts/HandleDragEnd/HandleDragEnd.ts | 8 + .../parts/HandleDragLeave/HandleDragLeave.ts | 5 + .../parts/HandleDragOver/HandleDragOver.ts | 11 + .../HandleDragOverIndex.ts | 15 + .../parts/HandleDragStart/HandleDragStart.ts | 5 + .../src/parts/HandleDrop/HandleDrop.ts | 28 + .../parts/HandleDropIndex/HandleDropIndex.ts | 90 + .../parts/HandleDropRoot/HandleDropRoot.ts | 27 + .../HandleDropRootDefault.ts | 79 + .../HandleDropRootElectron.ts | 67 + .../src/parts/HandleEscape/HandleEscape.ts | 8 + .../src/parts/HandleFocus/HandleFocus.ts | 12 + .../HandleIconThemeChange.ts | 6 + .../parts/HandleInputBlur/HandleInputBlur.ts | 14 + .../HandleInputClick/HandleInputClick.ts | 5 + .../HandleInputKeyDown/HandleInputKeyDown.ts | 5 + .../src/parts/HandleKeyDown/HandleKeyDown.ts | 42 + .../src/parts/HandlePaste/HandlePaste.ts | 35 + .../parts/HandlePasteCopy/HandlePasteCopy.ts | 53 + .../parts/HandlePasteCut/HandlePasteCut.ts | 63 + .../parts/HandlePasteNone/HandlePasteNone.ts | 7 + .../HandlePointerDown/HandlePointerDown.ts | 17 + .../HandleRangeSelection.ts | 24 + .../src/parts/HandleResize/HandleResize.ts | 43 + .../parts/HandleSelection/HandleSelection.ts | 13 + .../src/parts/HandleUpload/HandleUpload.ts | 18 + .../src/parts/HandleWheel/HandleWheel.ts | 6 + .../HandleWorkspaceChange.ts | 10 + .../HandleWorkspaceRefresh.ts | 6 + .../HasLeadingOrTrailingWhitespace.ts | 5 + .../src/parts/HasProperty/HasProperty.ts | 7 + .../parts/HasSymbolicLink/HasSymbolicLink.ts | 6 + .../explorer-view/src/parts/Height/Height.ts | 1 + .../src/parts/I18NString/I18NString.ts | 1 + .../src/parts/IconRequest/IconRequest.ts | 5 + .../src/parts/IconTheme/IconTheme.ts | 23 + .../src/parts/Initialize/Initialize.ts | 3 + .../InitializeFileSystemWorker.ts | 7 + .../InitializeIconThemeWorker.ts | 7 + .../initializeRendereWorker.ts | 10 + .../InitializeSourceControlWorker.ts | 12 + .../src/parts/InputName/InputName.ts | 6 + .../src/parts/InputSource/InputSource.ts | 2 + .../src/parts/IsAscii/IsAscii.ts | 5 + .../IsDirectoryHandle/IsDirectoryHandle.ts | 3 + .../src/parts/IsEqual/IsEqual.ts | 12 + .../src/parts/IsExpanded/IsExpanded.ts | 6 + .../IsExpandedDirectory.ts | 6 + .../src/parts/IsFileHandle/IsFileHandle.ts | 3 + .../src/parts/IsNormalItem/IsNormalItem.ts | 6 + .../parts/IsSymbolicLink/IsSymbolicLink.ts | 6 + .../src/parts/IsTopLevel/IsTopLevel.ts | 5 + .../parts/IsUriWithinRoot/IsUriWithinRoot.ts | 7 + .../parts/IsValidBaseName/IsValidBaseName.ts | 47 + .../src/parts/KeyBinding/KeyBinding.ts | 5 + .../src/parts/KeyCode/KeyCode.ts | 18 + .../src/parts/KeyModifier/KeyModifier.ts | 4 + .../explorer-view/src/parts/Listen/Listen.ts | 11 + .../src/parts/LoadContent/LoadContent.ts | 71 + packages/explorer-view/src/parts/Main/Main.ts | 5 + .../src/parts/MakeExpanded/MakeExpanded.ts | 12 + .../src/parts/MaskIcon/MaskIcon.ts | 4 + .../src/parts/MenuEntry/MenuEntry.ts | 6 + .../src/parts/MenuEntryId/MenuEntryId.ts | 1 + .../MenuEntrySeparator/MenuEntrySeparator.ts | 8 + .../src/parts/MenuItemFlags/MenuItemFlags.ts | 5 + .../parts/MergeClassNames/MergeClassNames.ts | 1 + .../src/parts/MergeDirents/MergeDirents.ts | 17 + .../src/parts/MergeTrees/MergeTrees.ts | 8 + .../MergeVisibleWithHiddenItems.ts | 15 + .../src/parts/MouseAction/MouseAction.ts | 12 + .../parts/MouseEventType/MouseEventType.ts | 3 + .../parts/NativeFileTypes/NativeFileTypes.ts | 3 + .../NativeFilesResult/NativeFilesResult.ts | 5 + .../src/parts/NewDirent/NewDirent.ts | 27 + .../NewDirentsAcceptResult.ts | 6 + .../src/parts/NewFile/NewFile.ts | 8 + .../src/parts/NewFolder/NewFolder.ts | 7 + .../NormalizeDecorations.ts | 12 + .../NormalizeDirentType.ts | 8 + .../OpenContainingFolder.ts | 10 + .../src/parts/OpenDiff/OpenDiff.ts | 5 + .../src/parts/OpenFolder/OpenFolder.ts | 5 + .../OpenNativeFolder/OpenNativeFolder.ts | 5 + .../src/parts/OpenUri/OpenUri.ts | 5 + .../src/parts/OrderDirents/OrderDirents.ts | 28 + .../src/parts/PasteHandler/PasteHandler.ts | 6 + packages/explorer-view/src/parts/Path/Path.ts | 26 + .../src/parts/PathPart/PathPart.ts | 7 + .../PathSeparatorType/PathSeparatorType.ts | 1 + .../src/parts/PlatformType/PlatformType.ts | 7 + .../src/parts/PromiseStatus/PromiseStatus.ts | 3 + packages/explorer-view/src/parts/Px/Px.ts | 1 + .../src/parts/RawDirent/RawDirent.ts | 4 + .../src/parts/Refresh/Refresh.ts | 25 + .../RefreshChildDirents.ts | 46 + .../RefreshWorkspace/RefreshWorkspace.ts | 10 + .../src/parts/RemoveDirent/RemoveDirent.ts | 44 + .../src/parts/RenameDirent/RenameDirent.ts | 28 + .../src/parts/Render2/Render2.ts | 9 + .../parts/RenderActions2/RenderActions2.ts | 11 + .../src/parts/RenderCss/RenderCss.ts | 33 + .../parts/RenderDragData/RenderDragData.ts | 10 + .../RenderEditingSelection.ts | 8 + .../RenderEventListeners.ts | 98 + .../src/parts/RenderFocus/RenderFocus.ts | 21 + .../RenderFocusContext/RenderFocusContext.ts | 14 + .../RenderIncremental/RenderIncremental.ts | 11 + .../src/parts/RenderItems/RenderItems.ts | 30 + .../src/parts/RenderValue/RenderValue.ts | 14 + .../src/parts/Renderer/Renderer.ts | 5 + .../RequestFileIcons/RequestFileIcons.ts | 12 + .../src/parts/ResetEditing/ResetEditing.ts | 13 + .../ResolveSymbolicLinks.ts | 44 + .../RestoreDirentType/RestoreDirentType.ts | 8 + .../RestoreExpandedState.ts | 53 + .../src/parts/RestoreState/RestoreState.ts | 41 + .../src/parts/RestoredState/RestoredState.ts | 5 + .../src/parts/RevealItem/RevealItem.ts | 20 + .../RevealItemHidden/RevealItemHidden.ts | 35 + .../RevealItemVisible/RevealItemVisible.ts | 14 + .../explorer-view/src/parts/RpcId/RpcId.ts | 1 + .../src/parts/RpcRegistry/RpcRegistry.ts | 1 + .../src/parts/SaveState/SaveState.ts | 16 + .../src/parts/SavedState/SavedState.ts | 7 + .../src/parts/ScrollInto/ScrollInto.ts | 23 + .../ScrollIntoResult/ScrollIntoResult.ts | 4 + .../src/parts/SelectAll/SelectAll.ts | 15 + .../src/parts/SelectDown/SelectDown.ts | 30 + .../SelectForCompare/SelectForCompare.ts | 13 + .../src/parts/SelectIndices/SelectIndices.ts | 13 + .../src/parts/SelectUp/SelectUp.ts | 18 + .../src/parts/Selection/Selection.ts | 4 + .../SendMessagePortToFileSystemWorker.ts | 5 + .../SendMessagePortToIconThemeWorker.ts | 5 + .../src/parts/SetDeltaY/SetDeltaY.ts | 24 + .../src/parts/SetFocus/SetFocus.ts | 5 + .../src/parts/Settings/Settings.ts | 6 + .../src/parts/Severity/Severity.ts | 4 + .../parts/ShowErrorAlert/ShowErrorAlert.ts | 5 + .../SortExplorerItems/SortExplorerItems.ts | 6 + .../SortPathDirentsMap/SortPathDirentsMap.ts | 11 + .../src/parts/Terminate/Terminate.ts | 3 + .../src/parts/Timeout/Timeout.ts | 5 + .../ToCollapsedDirent/ToCollapsedDirent.ts | 12 + .../parts/ToDisplayDirent/ToDisplayDirent.ts | 24 + .../ToDisplayDirents/ToDisplayDirents.ts | 23 + .../ToSimpleIconRequest.ts | 9 + .../ToggleIndividualSelection.ts | 20 + packages/explorer-view/src/parts/Tree/Tree.ts | 5 + .../src/parts/TreeItem/TreeItem.ts | 4 + .../src/parts/TreeToArray/TreeToArray.ts | 9 + .../TreeToArrayInternal.ts | 27 + .../src/parts/TreeUpdate/TreeUpdate.ts | 3 + .../src/parts/UiStrings/UiStrings.ts | 34 + .../UpdateDirentsAtPath.ts | 34 + .../UpdateEditingValue/UpdateEditingValue.ts | 25 + .../UpdateExplorerAfterFileOperations.ts | 57 + .../parts/UpdateIconCache/UpdateIconCache.ts | 15 + .../src/parts/UpdateIcons/UpdateIcons.ts | 13 + .../src/parts/UpdateRoot/UpdateRoot.ts | 24 + .../src/parts/UpdateTree/UpdateTree.ts | 13 + .../src/parts/UpdateTree2/UpdateTree2.ts | 12 + .../UploadFileSystemHandles.ts | 54 + .../explorer-view/src/parts/VError/VError.ts | 1 + .../ValidateFileName/ValidateFileName.ts | 150 + .../ValidateFileName2/ValidateFileName2.ts | 32 + .../ValidateFileNameResult.ts | 4 + .../ValidateFolderCopy/ValidateFolderCopy.ts | 17 + .../ValidateOperations/ValidateOperations.ts | 16 + .../src/parts/ViewletAction/ViewletAction.ts | 10 + .../VirtualDomElements/VirtualDomElements.ts | 5 + .../VirtualDomHelpers/VirtualDomHelpers.ts | 1 + .../parts/VirtualDomNode/VirtualDomNode.ts | 1 + .../VisibleExplorerItem.ts | 20 + .../parts/WhenExpression/WhenExpression.ts | 2 + .../explorer-view/test/AcceptCreate.test.ts | 274 + .../test/AcceptCreateFile.test.ts | 51 + .../explorer-view/test/AcceptEdit.test.ts | 204 + .../explorer-view/test/AcceptRename.test.ts | 228 + .../test/AdjustScrollAfterPaste.test.ts | 80 + .../test/ApplyFileOperations.test.ts | 51 + .../test/CanBeDroppedInto.test.ts | 59 + .../explorer-view/test/CancelEdit.test.ts | 224 + .../test/CancelTypeAhead.test.ts | 17 + packages/explorer-view/test/ClipBoard.test.ts | 34 + .../explorer-view/test/CollapseAll.test.ts | 38 + .../explorer-view/test/CommandMap.test.ts | 6 + .../test/CompareWithSelected.test.ts | 46 + ...ComputeExplorerRenamedDirentUpdate.test.ts | 119 + .../explorer-view/test/ConfirmDelete.test.ts | 26 + .../explorer-view/test/ConfirmPaste.test.ts | 25 + .../test/CopyFilesElectron.test.ts | 30 + packages/explorer-view/test/CopyPath.test.ts | 65 + .../test/CopyRelativePath.test.ts | 85 + packages/explorer-view/test/Create2.test.ts | 20 + .../test/CreateDecorationMap.test.ts | 95 + .../test/CreateNestedPath.test.ts | 42 + .../test/CreateUploadTree.test.ts | 106 + packages/explorer-view/test/Diff2.test.ts | 34 + .../test/DiffEditingSelection.test.ts | 24 + packages/explorer-view/test/DiffFocus.test.ts | 45 + .../explorer-view/test/DiffSelection.test.ts | 29 + packages/explorer-view/test/DiffValue.test.ts | 31 + .../explorer-view/test/EnsureUris.test.ts | 40 + packages/explorer-view/test/ExpandAll.test.ts | 74 + .../test/ExpandRecursively.test.ts | 92 + .../test/ExplorerStrings.test.ts | 104 + .../explorer-view/test/FileSystem.test.ts | 100 + .../test/FilterByFocusWord.test.ts | 26 + packages/explorer-view/test/Focus.test.ts | 16 + .../explorer-view/test/FocusFirst.test.ts | 78 + .../explorer-view/test/FocusIndex.test.ts | 169 + packages/explorer-view/test/FocusLast.test.ts | 80 + packages/explorer-view/test/FocusNext.test.ts | 110 + packages/explorer-view/test/FocusNone.test.ts | 16 + .../explorer-view/test/FocusPrevious.test.ts | 123 + .../test/GenerateUniqueName.test.ts | 143 + .../test/GetActionButtonVirtualDom.test.ts | 28 + .../test/GetActionVirtualDom.test.ts | 26 + .../explorer-view/test/GetActions.test.ts | 42 + .../explorer-view/test/GetChevronType.test.ts | 32 + .../test/GetChevronVirtualDom.test.ts | 16 + .../explorer-view/test/GetClickFn.test.ts | 52 + packages/explorer-view/test/GetCss.test.ts | 119 + .../explorer-view/test/GetDragData.test.ts | 26 + .../explorer-view/test/GetDragLabel.test.ts | 15 + .../explorer-view/test/GetDropHandler.test.ts | 14 + .../explorer-view/test/GetEditingIcon.test.ts | 121 + .../explorer-view/test/GetEditingType.test.ts | 13 + .../explorer-view/test/GetErrorCode.test.ts | 20 + .../test/GetErrorMessage.test.ts | 14 + .../test/GetErrorMessageDom.test.ts | 13 + .../explorer-view/test/GetExcluded.test.ts | 6 + .../test/GetExpandedDirents.test.ts | 27 + .../test/GetExpandedType.test.ts | 28 + .../test/GetExplorerItemVirtualDom.test.ts | 158 + .../test/GetExplorerMaxLineY.test.ts | 66 + .../test/GetExplorerWelcomeVirtualDom.test.ts | 130 + .../explorer-view/test/GetFileArray.test.ts | 40 + .../test/GetFileDecorations.test.ts | 166 + .../explorer-view/test/GetFileHandles.test.ts | 23 + .../test/GetFileIconVirtualDom.test.ts | 25 + .../explorer-view/test/GetFileIcons.test.ts | 103 + .../test/GetFileOperations.test.ts | 45 + .../test/GetFileOperationsCopy.test.ts | 87 + .../test/GetFileOperationsRename.test.ts | 16 + .../explorer-view/test/GetFilePaths.test.ts | 39 + .../test/GetFittingIndex.test.ts | 41 + .../test/GetFocusedIndexCancel.test.ts | 41 + .../test/GetFriendlyErrorMessage.test.ts | 19 + .../test/GetIconVirtualDom.test.ts | 22 + packages/explorer-view/test/GetIndex.test.ts | 25 + .../test/GetIndexFromPosition.test.ts | 302 + .../explorer-view/test/GetInputDom.test.ts | 48 + .../explorer-view/test/GetKeyBindings.test.ts | 7 + .../test/GetMenuEntries2.test.ts | 94 + .../test/GetMissingIconRequests.test.ts | 32 + .../test/GetMouseActions.test.ts | 14 + .../GetNewChildDirentsForNewDirent.test.ts | 256 + .../test/GetNewDirentsAccept.test.ts | 129 + .../test/GetNewDirentsForCancelRename.test.ts | 45 + .../test/GetNewDirentsForNewDirent.test.ts | 238 + .../test/GetNewDirentsForRename.test.ts | 45 + .../test/GetNewDropTargets.test.ts | 32 + .../test/GetNumberOfVisibleItems.test.ts | 26 + .../test/GetPasteHandler.test.ts | 22 + packages/explorer-view/test/GetPath.test.ts | 86 + .../explorer-view/test/GetPathParts.test.ts | 98 + .../test/GetPathSeparator.test.ts | 16 + packages/explorer-view/test/GetPaths.test.ts | 20 + .../test/GetProtoMapInternal.test.ts | 211 + .../explorer-view/test/GetRenderer.test.ts | 32 + .../test/GetRestoredDeltaY.test.ts | 14 + .../explorer-view/test/GetSavedRoot.test.ts | 6 + .../test/GetScrollBarVirtualDom.test.ts | 23 + .../explorer-view/test/GetSettings.test.ts | 75 + .../test/GetSiblingFileNames.test.ts | 97 + .../explorer-view/test/GetSymlinkType.test.ts | 18 + .../test/GetTreeItemIndent.test.ts | 18 + .../test/GetTreeItemIndentWithChevron.test.ts | 22 + .../test/GetVisibleExplorerItems.test.ts | 90 + .../test/HandleArrowLeft.test.ts | 122 + .../test/HandleArrowRight.test.ts | 111 + .../HandleArrowRightDirectoryExpanded.test.ts | 39 + .../explorer-view/test/HandleBlur.test.ts | 71 + .../test/HandleButtonClick.test.ts | 88 + .../explorer-view/test/HandleClickAt.test.ts | 83 + .../HandleClickCurrentButKeepFocus.test.ts | 11 + .../test/HandleClickDirectory.test.ts | 169 + .../test/HandleClickDirectoryExpanded.test.ts | 181 + .../HandleClickDirectoryExpanding.test.ts | 35 + .../test/HandleClickOpenFolder.test.ts | 17 + .../test/HandleClickSymlink.test.ts | 67 + .../test/HandleContextMenu.test.ts | 37 + .../test/HandleContextMenuKeyboard.test.ts | 26 + .../test/HandleContextMenuMouseAt.test.ts | 24 + .../explorer-view/test/HandleCopy.test.ts | 42 + packages/explorer-view/test/HandleCut.test.ts | 37 + .../test/HandleDoubleClick.test.ts | 198 + .../test/HandleDragLeave.test.ts | 9 + .../explorer-view/test/HandleDragOver.test.ts | 29 + .../explorer-view/test/HandleDrop.test.ts | 98 + .../test/HandleDropRootDefault.test.ts | 199 + .../test/HandleDropRootElectron.test.ts | 82 + .../explorer-view/test/HandleEscape.test.ts | 17 + .../explorer-view/test/HandleFocus.test.ts | 27 + .../test/HandleInputBlur.test.ts | 22 + .../explorer-view/test/HandleKeyDown.test.ts | 54 + .../explorer-view/test/HandlePaste.test.ts | 204 + .../test/HandlePasteCopy.test.ts | 145 + .../test/HandlePointerDown.test.ts | 36 + .../test/HandleRangeSelection.test.ts | 75 + .../explorer-view/test/HandleResize.test.ts | 63 + .../test/HandleSelection.test.ts | 20 + .../explorer-view/test/HandleUpload.test.ts | 24 + .../explorer-view/test/HandleWheel.test.ts | 59 + .../test/HandleWorkspaceChange.test.ts | 293 + packages/explorer-view/test/IsAscii.test.ts | 20 + .../test/IsDirectoryHandle.test.ts | 13 + packages/explorer-view/test/IsEqual.test.ts | 30 + .../explorer-view/test/IsExpanded.test.ts | 23 + .../test/IsExpandedDirectory.test.ts | 48 + .../explorer-view/test/IsFileHandle.test.ts | 13 + .../explorer-view/test/IsSymbolicLink.test.ts | 59 + .../explorer-view/test/IsTopLevel.test.ts | 25 + .../test/IsUriWithinRoot.test.ts | 22 + packages/explorer-view/test/Listen.test.ts | 11 + .../explorer-view/test/LoadContent.test.ts | 134 + packages/explorer-view/test/Main.test.ts | 11 + .../explorer-view/test/MakeExpanded.test.ts | 34 + packages/explorer-view/test/NewDirent.test.ts | 224 + packages/explorer-view/test/NewFile.test.ts | 79 + packages/explorer-view/test/NewFolder.test.ts | 60 + .../test/NormalizeDecorations.test.ts | 139 + .../test/OpenContainingFolder.test.ts | 19 + packages/explorer-view/test/OpenDiff.test.ts | 13 + packages/explorer-view/test/OpenUri.test.ts | 23 + .../explorer-view/test/OrderDirents.test.ts | 56 + .../test/PasteShouldMove.test.ts | 73 + packages/explorer-view/test/Path.test.ts | 25 + packages/explorer-view/test/Refresh.test.ts | 290 + .../test/RefreshChildDirents.test.ts | 55 + .../explorer-view/test/RemoveDirent.test.ts | 417 + .../explorer-view/test/RenameDirent.test.ts | 89 + packages/explorer-view/test/Render2.test.ts | 51 + .../explorer-view/test/RenderActions2.test.ts | 48 + packages/explorer-view/test/RenderCss.test.ts | 308 + .../explorer-view/test/RenderDragData.test.ts | 16 + .../test/RenderEditingSelection.test.ts | 16 + .../test/RenderEventListeners.test.ts | 7 + .../explorer-view/test/RenderFocus.test.ts | 43 + .../test/RenderFocusContext.test.ts | 41 + .../explorer-view/test/RenderItems.test.ts | 140 + .../explorer-view/test/RenderValue.test.ts | 51 + .../test/RequestFileIcons.test.ts | 65 + .../test/ResolveSymbolicLinks.test.ts | 186 + .../test/RestoreDirentType.test.ts | 18 + .../explorer-view/test/RestoreState.test.ts | 69 + .../explorer-view/test/RevealItem.test.ts | 58 + .../test/RevealItemHidden.test.ts | 57 + .../test/RevealItemVisible.test.ts | 15 + packages/explorer-view/test/SaveState.test.ts | 57 + .../explorer-view/test/ScrollInto.test.ts | 34 + packages/explorer-view/test/SelectAll.test.ts | 24 + .../explorer-view/test/SelectDown.test.ts | 128 + .../test/SelectForCompare.test.ts | 32 + .../explorer-view/test/SelectIndices.test.ts | 20 + packages/explorer-view/test/SelectUp.test.ts | 72 + .../SendMessagePortToFileSystemWorker.test.ts | 77 + .../SendMessagePortToIconThemeWorker.test.ts | 77 + packages/explorer-view/test/SetDeltaY.test.ts | 102 + .../test/SortExplorerItems.test.ts | 61 + packages/explorer-view/test/Terminate.test.ts | 9 + .../test/ToCollapsedDirent.test.ts | 92 + .../test/ToggleIndividualSelection.test.ts | 80 + .../explorer-view/test/TreeToArray.test.ts | 195 + .../test/UpdateDirentsAtPath.test.ts | 70 + .../test/UpdateEditingValue.test.ts | 250 + .../test/UpdateIconCache.test.ts | 33 + .../explorer-view/test/UpdateIcons.test.ts | 75 + .../explorer-view/test/UpdateRoot.test.ts | 32 + .../explorer-view/test/UpdateTree.test.ts | 45 + .../test/UploadFileSystemHandles.test.ts | 117 + .../test/ValidateFileName2.test.ts | 79 + .../test/ValidateFolderCopy.test.ts | 37 + .../test/ValidateOperations.test.ts | 263 + .../test/getFileHandleText.test.ts | 15 + packages/explorer-view/tsconfig.json | 25 + packages/server/package-lock.json | 2947 ++++ packages/server/package.json | 16 + packages/server/src/postinstall.js | 39 + packages/server/tsconfig.json | 23 + scripts/update-dependencies.sh | 37 + tsconfig.json | 18 + 835 files changed, 54172 insertions(+), 33 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .gitattributes create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/pr.yml create mode 100644 .github/workflows/release.yml create mode 100644 .nvmrc create mode 100644 eslint.config.js create mode 100644 lerna.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 packages/build/package-lock.json create mode 100644 packages/build/package.json create mode 100644 packages/build/src/build-static.ts create mode 100644 packages/build/src/build.ts create mode 100644 packages/build/src/bundleJs.ts create mode 100644 packages/build/src/computeNodeModulesCacheKey.ts create mode 100644 packages/build/src/dev.ts create mode 100644 packages/build/src/measureMemory.ts create mode 100644 packages/build/src/root.ts create mode 100644 packages/build/tsconfig.json create mode 100644 packages/e2e/extension/extension.json create mode 100644 packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json create mode 100644 packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js create mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json create mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js create mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json create mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js create mode 100644 packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json create mode 100644 packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js create mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json create mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js create mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json create mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js create mode 100644 packages/e2e/fixtures/sample.file-system-provider-permission/extension.json create mode 100644 packages/e2e/fixtures/sample.file-system-provider-permission/main.js create mode 100644 packages/e2e/fixtures/sample.icon-theme/extension.json create mode 100644 packages/e2e/fixtures/sample.icon-theme/icon-theme.json create mode 100644 packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg create mode 100644 packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg create mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json create mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js create mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json create mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js create mode 100644 packages/e2e/fixtures/sample.source-control-decoration/extension.json create mode 100644 packages/e2e/fixtures/sample.source-control-decoration/main.js create mode 100644 packages/e2e/package-lock.json create mode 100644 packages/e2e/package.json create mode 100644 packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts create mode 100644 packages/e2e/src/viewlet.explorer-accessibility.ts create mode 100644 packages/e2e/src/viewlet.explorer-blur.ts create mode 100644 packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts create mode 100644 packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts create mode 100644 packages/e2e/src/viewlet.explorer-collapse-all.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-path-empty.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-path-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-copy-path-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-blur.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-cancel.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-different-languages.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-nested.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-newline.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-folder-nested.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts create mode 100644 packages/e2e/src/viewlet.explorer-create-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts create mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts create mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts create mode 100644 packages/e2e/src/viewlet.explorer-cut-cancel.ts create mode 100644 packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-file-error.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-last-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-multiple-files.ts create mode 100644 packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts create mode 100644 packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-empty-workspace.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-all.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts create mode 100644 packages/e2e/src/viewlet.explorer-expand-recursively.ts create mode 100644 packages/e2e/src/viewlet.explorer-file-system-provider-error.ts create mode 100644 packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-leave.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-drop.ts create mode 100644 packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts create mode 100644 packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts create mode 100644 packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts create mode 100644 packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts create mode 100644 packages/e2e/src/viewlet.explorer-keyboard-navigation.ts create mode 100644 packages/e2e/src/viewlet.explorer-large-directory-performance.ts create mode 100644 packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts create mode 100644 packages/e2e/src/viewlet.explorer-long-file-name.ts create mode 100644 packages/e2e/src/viewlet.explorer-many-files-20000.ts create mode 100644 packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts create mode 100644 packages/e2e/src/viewlet.explorer-many-folders-20000.ts create mode 100644 packages/e2e/src/viewlet.explorer-mouse-navigation.ts create mode 100644 packages/e2e/src/viewlet.explorer-new-file-called-twice.ts create mode 100644 packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts create mode 100644 packages/e2e/src/viewlet.explorer-read-folder-error.ts create mode 100644 packages/e2e/src/viewlet.explorer-refresh.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-150-times.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-cancel.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-twice.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-file.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-folder-nested.ts create mode 100644 packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts create mode 100644 packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts create mode 100644 packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts create mode 100644 packages/e2e/src/viewlet.explorer-scroll.ts create mode 100644 packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts create mode 100644 packages/e2e/src/viewlet.explorer-select-all.ts create mode 100644 packages/e2e/src/viewlet.explorer-select-down.ts create mode 100644 packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts create mode 100644 packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts create mode 100644 packages/e2e/src/viewlet.explorer-select-multiple-files.ts create mode 100644 packages/e2e/src/viewlet.explorer-select-up.ts create mode 100644 packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts create mode 100644 packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts create mode 100644 packages/e2e/src/viewlet.explorer-sorting-emojis.ts create mode 100644 packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts create mode 100644 packages/e2e/src/viewlet.explorer-sorting-special-characters.ts create mode 100644 packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts create mode 100644 packages/e2e/src/viewlet.explorer-sorting.ts create mode 100644 packages/e2e/src/viewlet.explorer.empty.ts create mode 100644 packages/e2e/src/viewlet.explorer.open.ts create mode 100644 packages/e2e/tsconfig.json create mode 100644 packages/explorer-view/package-lock.json create mode 100644 packages/explorer-view/package.json create mode 100644 packages/explorer-view/src/explorerViewWorkerMain.ts create mode 100644 packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts create mode 100644 packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts create mode 100644 packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts create mode 100644 packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts create mode 100644 packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts create mode 100644 packages/explorer-view/src/parts/ActionType/ActionType.ts create mode 100644 packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts create mode 100644 packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts create mode 100644 packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts create mode 100644 packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts create mode 100644 packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts create mode 100644 packages/explorer-view/src/parts/Arrays/Arrays.ts create mode 100644 packages/explorer-view/src/parts/Assert/Assert.ts create mode 100644 packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts create mode 100644 packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts create mode 100644 packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts create mode 100644 packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts create mode 100644 packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts create mode 100644 packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts create mode 100644 packages/explorer-view/src/parts/Character/Character.ts create mode 100644 packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/ChevronType/ChevronType.ts create mode 100644 packages/explorer-view/src/parts/ClassNames/ClassNames.ts create mode 100644 packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts create mode 100644 packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts create mode 100644 packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts create mode 100644 packages/explorer-view/src/parts/CommandMap/CommandMap.ts create mode 100644 packages/explorer-view/src/parts/Compare/Compare.ts create mode 100644 packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts create mode 100644 packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts create mode 100644 packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts create mode 100644 packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts create mode 100644 packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts create mode 100644 packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts create mode 100644 packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts create mode 100644 packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts create mode 100644 packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts create mode 100644 packages/explorer-view/src/parts/CopyPath/CopyPath.ts create mode 100644 packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts create mode 100644 packages/explorer-view/src/parts/CountInRange/CountInRange.ts create mode 100644 packages/explorer-view/src/parts/Create/Create.ts create mode 100644 packages/explorer-view/src/parts/Create2/Create2.ts create mode 100644 packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts create mode 100644 packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts create mode 100644 packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts create mode 100644 packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts create mode 100644 packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts create mode 100644 packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts create mode 100644 packages/explorer-view/src/parts/CreateTree/CreateTree.ts create mode 100644 packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts create mode 100644 packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts create mode 100644 packages/explorer-view/src/parts/Diff/Diff.ts create mode 100644 packages/explorer-view/src/parts/Diff2/Diff2.ts create mode 100644 packages/explorer-view/src/parts/DiffCss/DiffCss.ts create mode 100644 packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts create mode 100644 packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts create mode 100644 packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts create mode 100644 packages/explorer-view/src/parts/DiffItems/DiffItems.ts create mode 100644 packages/explorer-view/src/parts/DiffModules/DiffModules.ts create mode 100644 packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts create mode 100644 packages/explorer-view/src/parts/DiffType/DiffType.ts create mode 100644 packages/explorer-view/src/parts/DiffValue/DiffValue.ts create mode 100644 packages/explorer-view/src/parts/DirentType/DirentType.ts create mode 100644 packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts create mode 100644 packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts create mode 100644 packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts create mode 100644 packages/explorer-view/src/parts/DropHandler/DropHandler.ts create mode 100644 packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts create mode 100644 packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts create mode 100644 packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts create mode 100644 packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts create mode 100644 packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts create mode 100644 packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts create mode 100644 packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts create mode 100644 packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts create mode 100644 packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts create mode 100644 packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts create mode 100644 packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts create mode 100644 packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts create mode 100644 packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts create mode 100644 packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts create mode 100644 packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts create mode 100644 packages/explorer-view/src/parts/FileOperation/FileOperation.ts create mode 100644 packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts create mode 100644 packages/explorer-view/src/parts/FileSystem/FileSystem.ts create mode 100644 packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts create mode 100644 packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts create mode 100644 packages/explorer-view/src/parts/Focus/Focus.ts create mode 100644 packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts create mode 100644 packages/explorer-view/src/parts/FocusId/FocusId.ts create mode 100644 packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts create mode 100644 packages/explorer-view/src/parts/FocusKey/FocusKey.ts create mode 100644 packages/explorer-view/src/parts/FocusLast/FocusLast.ts create mode 100644 packages/explorer-view/src/parts/FocusNext/FocusNext.ts create mode 100644 packages/explorer-view/src/parts/FocusNone/FocusNone.ts create mode 100644 packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts create mode 100644 packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts create mode 100644 packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts create mode 100644 packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetActions/GetActions.ts create mode 100644 packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts create mode 100644 packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts create mode 100644 packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts create mode 100644 packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts create mode 100644 packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts create mode 100644 packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts create mode 100644 packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts create mode 100644 packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts create mode 100644 packages/explorer-view/src/parts/GetCss/GetCss.ts create mode 100644 packages/explorer-view/src/parts/GetDragData/GetDragData.ts create mode 100644 packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts create mode 100644 packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts create mode 100644 packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts create mode 100644 packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts create mode 100644 packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts create mode 100644 packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts create mode 100644 packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts create mode 100644 packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts create mode 100644 packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts create mode 100644 packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts create mode 100644 packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts create mode 100644 packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts create mode 100644 packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts create mode 100644 packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts create mode 100644 packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts create mode 100644 packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts create mode 100644 packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts create mode 100644 packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts create mode 100644 packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts create mode 100644 packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts create mode 100644 packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts create mode 100644 packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts create mode 100644 packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts create mode 100644 packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts create mode 100644 packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts create mode 100644 packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts create mode 100644 packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts create mode 100644 packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts create mode 100644 packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts create mode 100644 packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts create mode 100644 packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts create mode 100644 packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts create mode 100644 packages/explorer-view/src/parts/GetIndex/GetIndex.ts create mode 100644 packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts create mode 100644 packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts create mode 100644 packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts create mode 100644 packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts create mode 100644 packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts create mode 100644 packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts create mode 100644 packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts create mode 100644 packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts create mode 100644 packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts create mode 100644 packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts create mode 100644 packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts create mode 100644 packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts create mode 100644 packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts create mode 100644 packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts create mode 100644 packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts create mode 100644 packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts create mode 100644 packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts create mode 100644 packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts create mode 100644 packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts create mode 100644 packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts create mode 100644 packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts create mode 100644 packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts create mode 100644 packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts create mode 100644 packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts create mode 100644 packages/explorer-view/src/parts/GetPath/GetPath.ts create mode 100644 packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts create mode 100644 packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts create mode 100644 packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts create mode 100644 packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts create mode 100644 packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts create mode 100644 packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts create mode 100644 packages/explorer-view/src/parts/GetPaths/GetPaths.ts create mode 100644 packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts create mode 100644 packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts create mode 100644 packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts create mode 100644 packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts create mode 100644 packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts create mode 100644 packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts create mode 100644 packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts create mode 100644 packages/explorer-view/src/parts/GetScheme/GetScheme.ts create mode 100644 packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts create mode 100644 packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts create mode 100644 packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts create mode 100644 packages/explorer-view/src/parts/GetSettings/GetSettings.ts create mode 100644 packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts create mode 100644 packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts create mode 100644 packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts create mode 100644 packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts create mode 100644 packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts create mode 100644 packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts create mode 100644 packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts create mode 100644 packages/explorer-view/src/parts/GetUnique/GetUnique.ts create mode 100644 packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts create mode 100644 packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts create mode 100644 packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts create mode 100644 packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts create mode 100644 packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts create mode 100644 packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts create mode 100644 packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts create mode 100644 packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts create mode 100644 packages/explorer-view/src/parts/HandleClick/HandleClick.ts create mode 100644 packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts create mode 100644 packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts create mode 100644 packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts create mode 100644 packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts create mode 100644 packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts create mode 100644 packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts create mode 100644 packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts create mode 100644 packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts create mode 100644 packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts create mode 100644 packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts create mode 100644 packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts create mode 100644 packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts create mode 100644 packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts create mode 100644 packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts create mode 100644 packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts create mode 100644 packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts create mode 100644 packages/explorer-view/src/parts/HandleCut/HandleCut.ts create mode 100644 packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts create mode 100644 packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts create mode 100644 packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts create mode 100644 packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts create mode 100644 packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts create mode 100644 packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts create mode 100644 packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts create mode 100644 packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts create mode 100644 packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts create mode 100644 packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts create mode 100644 packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts create mode 100644 packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts create mode 100644 packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts create mode 100644 packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts create mode 100644 packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts create mode 100644 packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts create mode 100644 packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts create mode 100644 packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts create mode 100644 packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts create mode 100644 packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts create mode 100644 packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts create mode 100644 packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts create mode 100644 packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts create mode 100644 packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts create mode 100644 packages/explorer-view/src/parts/HandleResize/HandleResize.ts create mode 100644 packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts create mode 100644 packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts create mode 100644 packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts create mode 100644 packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts create mode 100644 packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts create mode 100644 packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts create mode 100644 packages/explorer-view/src/parts/HasProperty/HasProperty.ts create mode 100644 packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts create mode 100644 packages/explorer-view/src/parts/Height/Height.ts create mode 100644 packages/explorer-view/src/parts/I18NString/I18NString.ts create mode 100644 packages/explorer-view/src/parts/IconRequest/IconRequest.ts create mode 100644 packages/explorer-view/src/parts/IconTheme/IconTheme.ts create mode 100644 packages/explorer-view/src/parts/Initialize/Initialize.ts create mode 100644 packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts create mode 100644 packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts create mode 100644 packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts create mode 100644 packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts create mode 100644 packages/explorer-view/src/parts/InputName/InputName.ts create mode 100644 packages/explorer-view/src/parts/InputSource/InputSource.ts create mode 100644 packages/explorer-view/src/parts/IsAscii/IsAscii.ts create mode 100644 packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts create mode 100644 packages/explorer-view/src/parts/IsEqual/IsEqual.ts create mode 100644 packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts create mode 100644 packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts create mode 100644 packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts create mode 100644 packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts create mode 100644 packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts create mode 100644 packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts create mode 100644 packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts create mode 100644 packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts create mode 100644 packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts create mode 100644 packages/explorer-view/src/parts/KeyCode/KeyCode.ts create mode 100644 packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts create mode 100644 packages/explorer-view/src/parts/Listen/Listen.ts create mode 100644 packages/explorer-view/src/parts/LoadContent/LoadContent.ts create mode 100644 packages/explorer-view/src/parts/Main/Main.ts create mode 100644 packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts create mode 100644 packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts create mode 100644 packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts create mode 100644 packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts create mode 100644 packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts create mode 100644 packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts create mode 100644 packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts create mode 100644 packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts create mode 100644 packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts create mode 100644 packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts create mode 100644 packages/explorer-view/src/parts/MouseAction/MouseAction.ts create mode 100644 packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts create mode 100644 packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts create mode 100644 packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts create mode 100644 packages/explorer-view/src/parts/NewDirent/NewDirent.ts create mode 100644 packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts create mode 100644 packages/explorer-view/src/parts/NewFile/NewFile.ts create mode 100644 packages/explorer-view/src/parts/NewFolder/NewFolder.ts create mode 100644 packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts create mode 100644 packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts create mode 100644 packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts create mode 100644 packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts create mode 100644 packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts create mode 100644 packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts create mode 100644 packages/explorer-view/src/parts/OpenUri/OpenUri.ts create mode 100644 packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts create mode 100644 packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts create mode 100644 packages/explorer-view/src/parts/Path/Path.ts create mode 100644 packages/explorer-view/src/parts/PathPart/PathPart.ts create mode 100644 packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts create mode 100644 packages/explorer-view/src/parts/PlatformType/PlatformType.ts create mode 100644 packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts create mode 100644 packages/explorer-view/src/parts/Px/Px.ts create mode 100644 packages/explorer-view/src/parts/RawDirent/RawDirent.ts create mode 100644 packages/explorer-view/src/parts/Refresh/Refresh.ts create mode 100644 packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts create mode 100644 packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts create mode 100644 packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts create mode 100644 packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts create mode 100644 packages/explorer-view/src/parts/Render2/Render2.ts create mode 100644 packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts create mode 100644 packages/explorer-view/src/parts/RenderCss/RenderCss.ts create mode 100644 packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts create mode 100644 packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts create mode 100644 packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts create mode 100644 packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts create mode 100644 packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts create mode 100644 packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts create mode 100644 packages/explorer-view/src/parts/RenderItems/RenderItems.ts create mode 100644 packages/explorer-view/src/parts/RenderValue/RenderValue.ts create mode 100644 packages/explorer-view/src/parts/Renderer/Renderer.ts create mode 100644 packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts create mode 100644 packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts create mode 100644 packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts create mode 100644 packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts create mode 100644 packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts create mode 100644 packages/explorer-view/src/parts/RestoreState/RestoreState.ts create mode 100644 packages/explorer-view/src/parts/RestoredState/RestoredState.ts create mode 100644 packages/explorer-view/src/parts/RevealItem/RevealItem.ts create mode 100644 packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts create mode 100644 packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts create mode 100644 packages/explorer-view/src/parts/RpcId/RpcId.ts create mode 100644 packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts create mode 100644 packages/explorer-view/src/parts/SaveState/SaveState.ts create mode 100644 packages/explorer-view/src/parts/SavedState/SavedState.ts create mode 100644 packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts create mode 100644 packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts create mode 100644 packages/explorer-view/src/parts/SelectAll/SelectAll.ts create mode 100644 packages/explorer-view/src/parts/SelectDown/SelectDown.ts create mode 100644 packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts create mode 100644 packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts create mode 100644 packages/explorer-view/src/parts/SelectUp/SelectUp.ts create mode 100644 packages/explorer-view/src/parts/Selection/Selection.ts create mode 100644 packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts create mode 100644 packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts create mode 100644 packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts create mode 100644 packages/explorer-view/src/parts/SetFocus/SetFocus.ts create mode 100644 packages/explorer-view/src/parts/Settings/Settings.ts create mode 100644 packages/explorer-view/src/parts/Severity/Severity.ts create mode 100644 packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts create mode 100644 packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts create mode 100644 packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts create mode 100644 packages/explorer-view/src/parts/Terminate/Terminate.ts create mode 100644 packages/explorer-view/src/parts/Timeout/Timeout.ts create mode 100644 packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts create mode 100644 packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts create mode 100644 packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts create mode 100644 packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts create mode 100644 packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts create mode 100644 packages/explorer-view/src/parts/Tree/Tree.ts create mode 100644 packages/explorer-view/src/parts/TreeItem/TreeItem.ts create mode 100644 packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts create mode 100644 packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts create mode 100644 packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts create mode 100644 packages/explorer-view/src/parts/UiStrings/UiStrings.ts create mode 100644 packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts create mode 100644 packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts create mode 100644 packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts create mode 100644 packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts create mode 100644 packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts create mode 100644 packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts create mode 100644 packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts create mode 100644 packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts create mode 100644 packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts create mode 100644 packages/explorer-view/src/parts/VError/VError.ts create mode 100644 packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts create mode 100644 packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts create mode 100644 packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts create mode 100644 packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts create mode 100644 packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts create mode 100644 packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts create mode 100644 packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts create mode 100644 packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts create mode 100644 packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts create mode 100644 packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts create mode 100644 packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts create mode 100644 packages/explorer-view/test/AcceptCreate.test.ts create mode 100644 packages/explorer-view/test/AcceptCreateFile.test.ts create mode 100644 packages/explorer-view/test/AcceptEdit.test.ts create mode 100644 packages/explorer-view/test/AcceptRename.test.ts create mode 100644 packages/explorer-view/test/AdjustScrollAfterPaste.test.ts create mode 100644 packages/explorer-view/test/ApplyFileOperations.test.ts create mode 100644 packages/explorer-view/test/CanBeDroppedInto.test.ts create mode 100644 packages/explorer-view/test/CancelEdit.test.ts create mode 100644 packages/explorer-view/test/CancelTypeAhead.test.ts create mode 100644 packages/explorer-view/test/ClipBoard.test.ts create mode 100644 packages/explorer-view/test/CollapseAll.test.ts create mode 100644 packages/explorer-view/test/CommandMap.test.ts create mode 100644 packages/explorer-view/test/CompareWithSelected.test.ts create mode 100644 packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts create mode 100644 packages/explorer-view/test/ConfirmDelete.test.ts create mode 100644 packages/explorer-view/test/ConfirmPaste.test.ts create mode 100644 packages/explorer-view/test/CopyFilesElectron.test.ts create mode 100644 packages/explorer-view/test/CopyPath.test.ts create mode 100644 packages/explorer-view/test/CopyRelativePath.test.ts create mode 100644 packages/explorer-view/test/Create2.test.ts create mode 100644 packages/explorer-view/test/CreateDecorationMap.test.ts create mode 100644 packages/explorer-view/test/CreateNestedPath.test.ts create mode 100644 packages/explorer-view/test/CreateUploadTree.test.ts create mode 100644 packages/explorer-view/test/Diff2.test.ts create mode 100644 packages/explorer-view/test/DiffEditingSelection.test.ts create mode 100644 packages/explorer-view/test/DiffFocus.test.ts create mode 100644 packages/explorer-view/test/DiffSelection.test.ts create mode 100644 packages/explorer-view/test/DiffValue.test.ts create mode 100644 packages/explorer-view/test/EnsureUris.test.ts create mode 100644 packages/explorer-view/test/ExpandAll.test.ts create mode 100644 packages/explorer-view/test/ExpandRecursively.test.ts create mode 100644 packages/explorer-view/test/ExplorerStrings.test.ts create mode 100644 packages/explorer-view/test/FileSystem.test.ts create mode 100644 packages/explorer-view/test/FilterByFocusWord.test.ts create mode 100644 packages/explorer-view/test/Focus.test.ts create mode 100644 packages/explorer-view/test/FocusFirst.test.ts create mode 100644 packages/explorer-view/test/FocusIndex.test.ts create mode 100644 packages/explorer-view/test/FocusLast.test.ts create mode 100644 packages/explorer-view/test/FocusNext.test.ts create mode 100644 packages/explorer-view/test/FocusNone.test.ts create mode 100644 packages/explorer-view/test/FocusPrevious.test.ts create mode 100644 packages/explorer-view/test/GenerateUniqueName.test.ts create mode 100644 packages/explorer-view/test/GetActionButtonVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetActionVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetActions.test.ts create mode 100644 packages/explorer-view/test/GetChevronType.test.ts create mode 100644 packages/explorer-view/test/GetChevronVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetClickFn.test.ts create mode 100644 packages/explorer-view/test/GetCss.test.ts create mode 100644 packages/explorer-view/test/GetDragData.test.ts create mode 100644 packages/explorer-view/test/GetDragLabel.test.ts create mode 100644 packages/explorer-view/test/GetDropHandler.test.ts create mode 100644 packages/explorer-view/test/GetEditingIcon.test.ts create mode 100644 packages/explorer-view/test/GetEditingType.test.ts create mode 100644 packages/explorer-view/test/GetErrorCode.test.ts create mode 100644 packages/explorer-view/test/GetErrorMessage.test.ts create mode 100644 packages/explorer-view/test/GetErrorMessageDom.test.ts create mode 100644 packages/explorer-view/test/GetExcluded.test.ts create mode 100644 packages/explorer-view/test/GetExpandedDirents.test.ts create mode 100644 packages/explorer-view/test/GetExpandedType.test.ts create mode 100644 packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetExplorerMaxLineY.test.ts create mode 100644 packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetFileArray.test.ts create mode 100644 packages/explorer-view/test/GetFileDecorations.test.ts create mode 100644 packages/explorer-view/test/GetFileHandles.test.ts create mode 100644 packages/explorer-view/test/GetFileIconVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetFileIcons.test.ts create mode 100644 packages/explorer-view/test/GetFileOperations.test.ts create mode 100644 packages/explorer-view/test/GetFileOperationsCopy.test.ts create mode 100644 packages/explorer-view/test/GetFileOperationsRename.test.ts create mode 100644 packages/explorer-view/test/GetFilePaths.test.ts create mode 100644 packages/explorer-view/test/GetFittingIndex.test.ts create mode 100644 packages/explorer-view/test/GetFocusedIndexCancel.test.ts create mode 100644 packages/explorer-view/test/GetFriendlyErrorMessage.test.ts create mode 100644 packages/explorer-view/test/GetIconVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetIndex.test.ts create mode 100644 packages/explorer-view/test/GetIndexFromPosition.test.ts create mode 100644 packages/explorer-view/test/GetInputDom.test.ts create mode 100644 packages/explorer-view/test/GetKeyBindings.test.ts create mode 100644 packages/explorer-view/test/GetMenuEntries2.test.ts create mode 100644 packages/explorer-view/test/GetMissingIconRequests.test.ts create mode 100644 packages/explorer-view/test/GetMouseActions.test.ts create mode 100644 packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts create mode 100644 packages/explorer-view/test/GetNewDirentsAccept.test.ts create mode 100644 packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts create mode 100644 packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts create mode 100644 packages/explorer-view/test/GetNewDirentsForRename.test.ts create mode 100644 packages/explorer-view/test/GetNewDropTargets.test.ts create mode 100644 packages/explorer-view/test/GetNumberOfVisibleItems.test.ts create mode 100644 packages/explorer-view/test/GetPasteHandler.test.ts create mode 100644 packages/explorer-view/test/GetPath.test.ts create mode 100644 packages/explorer-view/test/GetPathParts.test.ts create mode 100644 packages/explorer-view/test/GetPathSeparator.test.ts create mode 100644 packages/explorer-view/test/GetPaths.test.ts create mode 100644 packages/explorer-view/test/GetProtoMapInternal.test.ts create mode 100644 packages/explorer-view/test/GetRenderer.test.ts create mode 100644 packages/explorer-view/test/GetRestoredDeltaY.test.ts create mode 100644 packages/explorer-view/test/GetSavedRoot.test.ts create mode 100644 packages/explorer-view/test/GetScrollBarVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GetSettings.test.ts create mode 100644 packages/explorer-view/test/GetSiblingFileNames.test.ts create mode 100644 packages/explorer-view/test/GetSymlinkType.test.ts create mode 100644 packages/explorer-view/test/GetTreeItemIndent.test.ts create mode 100644 packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts create mode 100644 packages/explorer-view/test/GetVisibleExplorerItems.test.ts create mode 100644 packages/explorer-view/test/HandleArrowLeft.test.ts create mode 100644 packages/explorer-view/test/HandleArrowRight.test.ts create mode 100644 packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts create mode 100644 packages/explorer-view/test/HandleBlur.test.ts create mode 100644 packages/explorer-view/test/HandleButtonClick.test.ts create mode 100644 packages/explorer-view/test/HandleClickAt.test.ts create mode 100644 packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts create mode 100644 packages/explorer-view/test/HandleClickDirectory.test.ts create mode 100644 packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts create mode 100644 packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts create mode 100644 packages/explorer-view/test/HandleClickOpenFolder.test.ts create mode 100644 packages/explorer-view/test/HandleClickSymlink.test.ts create mode 100644 packages/explorer-view/test/HandleContextMenu.test.ts create mode 100644 packages/explorer-view/test/HandleContextMenuKeyboard.test.ts create mode 100644 packages/explorer-view/test/HandleContextMenuMouseAt.test.ts create mode 100644 packages/explorer-view/test/HandleCopy.test.ts create mode 100644 packages/explorer-view/test/HandleCut.test.ts create mode 100644 packages/explorer-view/test/HandleDoubleClick.test.ts create mode 100644 packages/explorer-view/test/HandleDragLeave.test.ts create mode 100644 packages/explorer-view/test/HandleDragOver.test.ts create mode 100644 packages/explorer-view/test/HandleDrop.test.ts create mode 100644 packages/explorer-view/test/HandleDropRootDefault.test.ts create mode 100644 packages/explorer-view/test/HandleDropRootElectron.test.ts create mode 100644 packages/explorer-view/test/HandleEscape.test.ts create mode 100644 packages/explorer-view/test/HandleFocus.test.ts create mode 100644 packages/explorer-view/test/HandleInputBlur.test.ts create mode 100644 packages/explorer-view/test/HandleKeyDown.test.ts create mode 100644 packages/explorer-view/test/HandlePaste.test.ts create mode 100644 packages/explorer-view/test/HandlePasteCopy.test.ts create mode 100644 packages/explorer-view/test/HandlePointerDown.test.ts create mode 100644 packages/explorer-view/test/HandleRangeSelection.test.ts create mode 100644 packages/explorer-view/test/HandleResize.test.ts create mode 100644 packages/explorer-view/test/HandleSelection.test.ts create mode 100644 packages/explorer-view/test/HandleUpload.test.ts create mode 100644 packages/explorer-view/test/HandleWheel.test.ts create mode 100644 packages/explorer-view/test/HandleWorkspaceChange.test.ts create mode 100644 packages/explorer-view/test/IsAscii.test.ts create mode 100644 packages/explorer-view/test/IsDirectoryHandle.test.ts create mode 100644 packages/explorer-view/test/IsEqual.test.ts create mode 100644 packages/explorer-view/test/IsExpanded.test.ts create mode 100644 packages/explorer-view/test/IsExpandedDirectory.test.ts create mode 100644 packages/explorer-view/test/IsFileHandle.test.ts create mode 100644 packages/explorer-view/test/IsSymbolicLink.test.ts create mode 100644 packages/explorer-view/test/IsTopLevel.test.ts create mode 100644 packages/explorer-view/test/IsUriWithinRoot.test.ts create mode 100644 packages/explorer-view/test/Listen.test.ts create mode 100644 packages/explorer-view/test/LoadContent.test.ts create mode 100644 packages/explorer-view/test/Main.test.ts create mode 100644 packages/explorer-view/test/MakeExpanded.test.ts create mode 100644 packages/explorer-view/test/NewDirent.test.ts create mode 100644 packages/explorer-view/test/NewFile.test.ts create mode 100644 packages/explorer-view/test/NewFolder.test.ts create mode 100644 packages/explorer-view/test/NormalizeDecorations.test.ts create mode 100644 packages/explorer-view/test/OpenContainingFolder.test.ts create mode 100644 packages/explorer-view/test/OpenDiff.test.ts create mode 100644 packages/explorer-view/test/OpenUri.test.ts create mode 100644 packages/explorer-view/test/OrderDirents.test.ts create mode 100644 packages/explorer-view/test/PasteShouldMove.test.ts create mode 100644 packages/explorer-view/test/Path.test.ts create mode 100644 packages/explorer-view/test/Refresh.test.ts create mode 100644 packages/explorer-view/test/RefreshChildDirents.test.ts create mode 100644 packages/explorer-view/test/RemoveDirent.test.ts create mode 100644 packages/explorer-view/test/RenameDirent.test.ts create mode 100644 packages/explorer-view/test/Render2.test.ts create mode 100644 packages/explorer-view/test/RenderActions2.test.ts create mode 100644 packages/explorer-view/test/RenderCss.test.ts create mode 100644 packages/explorer-view/test/RenderDragData.test.ts create mode 100644 packages/explorer-view/test/RenderEditingSelection.test.ts create mode 100644 packages/explorer-view/test/RenderEventListeners.test.ts create mode 100644 packages/explorer-view/test/RenderFocus.test.ts create mode 100644 packages/explorer-view/test/RenderFocusContext.test.ts create mode 100644 packages/explorer-view/test/RenderItems.test.ts create mode 100644 packages/explorer-view/test/RenderValue.test.ts create mode 100644 packages/explorer-view/test/RequestFileIcons.test.ts create mode 100644 packages/explorer-view/test/ResolveSymbolicLinks.test.ts create mode 100644 packages/explorer-view/test/RestoreDirentType.test.ts create mode 100644 packages/explorer-view/test/RestoreState.test.ts create mode 100644 packages/explorer-view/test/RevealItem.test.ts create mode 100644 packages/explorer-view/test/RevealItemHidden.test.ts create mode 100644 packages/explorer-view/test/RevealItemVisible.test.ts create mode 100644 packages/explorer-view/test/SaveState.test.ts create mode 100644 packages/explorer-view/test/ScrollInto.test.ts create mode 100644 packages/explorer-view/test/SelectAll.test.ts create mode 100644 packages/explorer-view/test/SelectDown.test.ts create mode 100644 packages/explorer-view/test/SelectForCompare.test.ts create mode 100644 packages/explorer-view/test/SelectIndices.test.ts create mode 100644 packages/explorer-view/test/SelectUp.test.ts create mode 100644 packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts create mode 100644 packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts create mode 100644 packages/explorer-view/test/SetDeltaY.test.ts create mode 100644 packages/explorer-view/test/SortExplorerItems.test.ts create mode 100644 packages/explorer-view/test/Terminate.test.ts create mode 100644 packages/explorer-view/test/ToCollapsedDirent.test.ts create mode 100644 packages/explorer-view/test/ToggleIndividualSelection.test.ts create mode 100644 packages/explorer-view/test/TreeToArray.test.ts create mode 100644 packages/explorer-view/test/UpdateDirentsAtPath.test.ts create mode 100644 packages/explorer-view/test/UpdateEditingValue.test.ts create mode 100644 packages/explorer-view/test/UpdateIconCache.test.ts create mode 100644 packages/explorer-view/test/UpdateIcons.test.ts create mode 100644 packages/explorer-view/test/UpdateRoot.test.ts create mode 100644 packages/explorer-view/test/UpdateTree.test.ts create mode 100644 packages/explorer-view/test/UploadFileSystemHandles.test.ts create mode 100644 packages/explorer-view/test/ValidateFileName2.test.ts create mode 100644 packages/explorer-view/test/ValidateFolderCopy.test.ts create mode 100644 packages/explorer-view/test/ValidateOperations.test.ts create mode 100644 packages/explorer-view/test/getFileHandleText.test.ts create mode 100644 packages/explorer-view/tsconfig.json create mode 100644 packages/server/package-lock.json create mode 100644 packages/server/package.json create mode 100644 packages/server/src/postinstall.js create mode 100644 packages/server/tsconfig.json create mode 100644 scripts/update-dependencies.sh create mode 100644 tsconfig.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..1cbcccb --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,13 @@ +{ + "name": "text-search-worker", + "image": "mcr.microsoft.com/devcontainers/node:24", + "postCreateCommand": "npm ci", + "postStartCommand": "npm run dev", + "customizations": { + "vscode": { + "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] + } + }, + "forwardPorts": [3000], + "remoteUser": "node" +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..94f480d --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e23ced9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,80 @@ +name: CI + +on: + push: + branches: + - main + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + ci: + strategy: + matrix: + os: [ubuntu-24.04, macos-15, windows-2025] + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version-file: '.nvmrc' + - name: Compute node modules cache key + id: nodeModulesCacheKey + run: echo "value=$(node packages/build/src/computeNodeModulesCacheKey.ts)" >> $GITHUB_OUTPUT + shell: bash + - uses: actions/cache@v5 + id: npm-cache + with: + path: '**/node_modules' + key: ${{ runner.os }}-cacheNodeModules-${{ steps.nodeModulesCacheKey.outputs.value }} + - name: npm ci + run: npm ci --ignore-scripts && npm run postinstall + if: steps.npm-cache.outputs.cache-hit != 'true' + - run: npm run build + - run: npm run build:static + - run: npm test + - run: npm run type-check + - run: npm run lint + - name: install playwright dependencies + working-directory: ./packages/e2e + run: npx playwright install chromium + if: steps.npm-cache.outputs.cache-hit != 'true' + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - name: e2e + working-directory: ./packages/e2e + run: npm run e2e:headless + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - name: measure + run: npm run measure + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - name: Upload artifact + if: matrix.os == 'ubuntu-24.04' + uses: actions/upload-pages-artifact@v4 + with: + path: ./.tmp/static + - name: Clean up + run: rm -rf .tmp + shell: bash + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-24.04 + needs: ci + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..52f66f0 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,52 @@ +name: PR + +on: + pull_request: + branches: + - main + +jobs: + pr: + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04, macos-15, windows-2025] + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version-file: '.nvmrc' + - name: Compute node modules cache key + id: nodeModulesCacheKey + run: echo "value=$(node packages/build/src/computeNodeModulesCacheKey.ts)" >> $GITHUB_OUTPUT + shell: bash + - uses: actions/cache@v5 + id: npm-cache + with: + path: '**/node_modules' + key: ${{ runner.os }}-cacheNodeModules-${{ steps.nodeModulesCacheKey.outputs.value }} + - name: npm ci + run: npm ci --ignore-scripts && npm run postinstall + if: steps.npm-cache.outputs.cache-hit != 'true' + - run: npm run build + - run: npm run build:static + - run: npm test + - run: npm run type-check + - run: npm run lint + - name: install playwright dependencies + working-directory: ./packages/e2e + run: npx playwright install chromium + if: steps.npm-cache.outputs.cache-hit != 'true' + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - name: e2e + working-directory: ./packages/e2e + run: npm run e2e:headless + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - name: measure + run: npm run measure + env: + PLAYWRIGHT_BROWSERS_PATH: 0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b3bedfc --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,112 @@ +# Based on https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/release.yml by BurntSushi (License MIT) + +name: release +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + +permissions: + id-token: write # Required for OIDC + contents: write + +jobs: + create-release: + name: create-release + runs-on: ubuntu-24.04 + outputs: + upload_url: ${{ steps.release.outputs.upload_url }} + rg_version: ${{ env.RG_VERSION }} + steps: + - name: Get the release version from the tag + shell: bash + if: env.RG_VERSION == '' + run: | + echo "RG_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + echo "version is: ${{ env.RG_VERSION }}" + - name: Create GitHub release + id: release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.RG_VERSION }} + name: ${{ env.RG_VERSION }} + draft: true + + build-release: + name: build-release + needs: ['create-release'] + strategy: + fail-fast: true + matrix: + os: [windows-2025, macos-15, ubuntu-24.04] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version-file: '.nvmrc' + registry-url: 'https://registry.npmjs.org' + - name: Compute node modules cache key + id: nodeModulesCacheKey + run: echo "value=$(node packages/build/src/computeNodeModulesCacheKey.ts)" >> $GITHUB_OUTPUT + shell: bash + - uses: actions/cache@v5 + id: npm-cache + with: + path: '**/node_modules' + key: ${{ runner.os }}-cacheNodeModules-${{ steps.nodeModulesCacheKey.outputs.value }} + - name: npm ci + run: npm ci --ignore-scripts && npm run postinstall + if: steps.npm-cache.outputs.cache-hit != 'true' + - run: npm run build + - run: npm run build:static + - run: npm test + - run: npm run type-check + - run: npm run lint + - name: install playwright dependencies + working-directory: ./packages/e2e + run: npx playwright install chromium + if: steps.npm-cache.outputs.cache-hit != 'true' + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - name: e2e + working-directory: ./packages/e2e + run: npm run e2e:headless + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - name: measure + run: npm run measure + env: + PLAYWRIGHT_BROWSERS_PATH: 0 + - uses: actions/upload-artifact@v6 + if: matrix.os == 'ubuntu-24.04' + with: + name: dist + path: ./.tmp/dist + + publish-release: + name: publish-release + needs: ['create-release', 'build-release'] + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + - uses: actions/download-artifact@v7 + with: + name: dist + path: ./.tmp/dist + - uses: actions/setup-node@v6 + with: + node-version-file: '.nvmrc' + registry-url: 'https://registry.npmjs.org' + + - run: npm publish --access public + working-directory: ./.tmp/dist + + - name: Publish GitHub release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="${{ needs.create-release.outputs.rg_version }}" + gh release edit $VERSION --draft=false diff --git a/.gitignore b/.gitignore index 872d5f6..b71ccd4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +.vscode +.tmp +dist + # Logs logs *.log @@ -5,6 +9,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* +.pnpm-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json @@ -56,6 +61,12 @@ web_modules/ # Optional stylelint cache .stylelintcache +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + # Optional REPL history .node_repl_history @@ -67,8 +78,10 @@ web_modules/ # dotenv environment variable files .env -.env.* -!.env.example +.env.development.local +.env.test.local +.env.production.local +.env.local # parcel-bundler cache (https://parceljs.org/) .cache @@ -81,7 +94,6 @@ out # Nuxt.js build / generate output .nuxt dist -.output # Gatsby files .cache/ @@ -92,17 +104,9 @@ dist # vuepress build output .vuepress/dist -# vuepress v2.x temp directory +# vuepress v2.x temp and cache directory .temp - -# Sveltekit cache directory -.svelte-kit/ - -# vitepress build output -**/.vitepress/dist - -# vitepress cache directory -**/.vitepress/cache +.cache # Docusaurus cache and generated files .docusaurus @@ -116,28 +120,15 @@ dist # DynamoDB Local files .dynamodb/ -# Firebase cache directory -.firebase/ - # TernJS port file .tern-port # Stores VSCode versions used for testing VSCode extensions .vscode-test -# pnpm -.pnpm-store - -# yarn v3 +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz .pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions - -# Vite files -vite.config.js.timestamp-* -vite.config.ts.timestamp-* -.vite/ diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..e8416a1 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v24.13.0 diff --git a/LICENSE b/LICENSE index d87769d..4b5ff5f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 Lvce Editor +Copyright (c) 2024 Lvce Editor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 08101d2..a05f462 100644 --- a/README.md +++ b/README.md @@ -1 +1,12 @@ -# pull-request-github \ No newline at end of file +# Explorer View + +WebWorker for the explorer view functionality in Lvce Editor. + +## Contributing + +```sh +git clone git@github.com:lvce-editor/explorer-view.git && +cd explorer-view && +npm ci && +npm test +``` diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..5f1e291 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,49 @@ +import * as config from '@lvce-editor/eslint-config' +import * as actions from '@lvce-editor/eslint-plugin-github-actions' + +export default [ + ...config.default, + { + files: ['**/*.ts'], + rules: { + '@cspell/spellchecker': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + 'no-case-declarations': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/restrict-plus-operands': 'off', + '@typescript-eslint/no-unnecessary-condition': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/no-dynamic-delete': 'off', + '@typescript-eslint/prefer-readonly-parameter-types': 'off', + 'prefer-destructuring': 'off', + 'unicorn/no-for-loop': 'off', + 'jest/no-identical-title': 'off', + 'unicorn/prefer-single-call': 'off', + 'unicorn/no-immediate-mutation': 'off', + 'unicorn/empty-brace-spaces': 'off', + '@typescript-eslint/only-throw-error': 'off', + '@typescript-eslint/await-thenable': 'off', + '@typescript-eslint/no-import-type-side-effects': 'error', + }, + }, + { + files: ['**/*.test.ts'], + rules: { + '@typescript-eslint/unbound-method': 'off', + }, + }, + ...actions.default, + { + rules: { + 'github-actions/needs': 'off', + 'github-actions/permissions': 'off', + }, + }, +] diff --git a/lerna.json b/lerna.json new file mode 100644 index 0000000..f73089e --- /dev/null +++ b/lerna.json @@ -0,0 +1,4 @@ +{ + "packages": ["packages/*"], + "version": "0.0.0-dev" +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..99c6ac9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,14157 @@ +{ + "name": "@lvce-editor/explorer-view-monorepo", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@lvce-editor/explorer-view-monorepo", + "version": "0.0.0-dev", + "hasInstallScript": true, + "license": "MIT", + "devDependencies": { + "@lerna/legacy-package-management": "^8.2.4", + "@lvce-editor/eslint-config": "^11.2.0", + "eslint": "^10.2.0", + "lerna": "^8.2.4", + "prettier": "^3.8.4", + "typescript": "^6.0.3" + } + }, + "node_modules/@altano/repository-tools": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@altano/repository-tools/-/repository-tools-2.0.3.tgz", + "integrity": "sha512-cSR/ZYDF6Wp9OeAJMyLYYN1GenAAhV17W+w38ELP+3c5Ltsy9jkkCymi33nz/qnXyef3n6Fbr1h2yt3dvUN5sQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspell/cspell-bundled-dicts": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-10.0.1.tgz", + "integrity": "sha512-WvkSDNX4Uyyj/ZgbPO6L38iFNMfK1EqsH1FteRiI2qLz6QZMXRFrIt12OqiWIplzZDDaVpBH9FCJOPJll0fjCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-ada": "^4.1.1", + "@cspell/dict-al": "^1.1.1", + "@cspell/dict-aws": "^4.0.17", + "@cspell/dict-bash": "^4.2.2", + "@cspell/dict-companies": "^3.2.11", + "@cspell/dict-cpp": "^7.0.2", + "@cspell/dict-cryptocurrencies": "^5.0.5", + "@cspell/dict-csharp": "^4.0.8", + "@cspell/dict-css": "^4.1.1", + "@cspell/dict-dart": "^2.3.2", + "@cspell/dict-data-science": "^2.0.13", + "@cspell/dict-django": "^4.1.6", + "@cspell/dict-docker": "^1.1.17", + "@cspell/dict-dotnet": "^5.0.13", + "@cspell/dict-elixir": "^4.0.8", + "@cspell/dict-en_us": "^4.4.33", + "@cspell/dict-en-common-misspellings": "^2.1.12", + "@cspell/dict-en-gb-mit": "^3.1.22", + "@cspell/dict-filetypes": "^3.0.18", + "@cspell/dict-flutter": "^1.1.1", + "@cspell/dict-fonts": "^4.0.6", + "@cspell/dict-fsharp": "^1.1.1", + "@cspell/dict-fullstack": "^3.2.9", + "@cspell/dict-gaming-terms": "^1.1.2", + "@cspell/dict-git": "^3.1.0", + "@cspell/dict-golang": "^6.0.26", + "@cspell/dict-google": "^1.0.9", + "@cspell/dict-haskell": "^4.0.6", + "@cspell/dict-html": "^4.0.15", + "@cspell/dict-html-symbol-entities": "^4.0.5", + "@cspell/dict-java": "^5.0.12", + "@cspell/dict-julia": "^1.1.1", + "@cspell/dict-k8s": "^1.0.12", + "@cspell/dict-kotlin": "^1.1.1", + "@cspell/dict-latex": "^5.1.0", + "@cspell/dict-lorem-ipsum": "^4.0.5", + "@cspell/dict-lua": "^4.0.8", + "@cspell/dict-makefile": "^1.0.5", + "@cspell/dict-markdown": "^2.0.16", + "@cspell/dict-monkeyc": "^1.0.12", + "@cspell/dict-node": "^5.0.9", + "@cspell/dict-npm": "^5.2.38", + "@cspell/dict-php": "^4.1.1", + "@cspell/dict-powershell": "^5.0.15", + "@cspell/dict-public-licenses": "^2.0.16", + "@cspell/dict-python": "^4.2.26", + "@cspell/dict-r": "^2.1.1", + "@cspell/dict-ruby": "^5.1.1", + "@cspell/dict-rust": "^4.1.2", + "@cspell/dict-scala": "^5.0.9", + "@cspell/dict-shell": "^1.1.2", + "@cspell/dict-software-terms": "^5.2.2", + "@cspell/dict-sql": "^2.2.1", + "@cspell/dict-svelte": "^1.0.7", + "@cspell/dict-swift": "^2.0.6", + "@cspell/dict-terraform": "^1.1.3", + "@cspell/dict-typescript": "^3.2.3", + "@cspell/dict-vue": "^3.0.5", + "@cspell/dict-zig": "^1.0.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-performance-monitor": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-performance-monitor/-/cspell-performance-monitor-10.0.1.tgz", + "integrity": "sha512-9tVcHXwRnbazUv4WSG0h3MqV4+LgmLNgSALAQUflPPW0EMxTf7C4Dmv9cgxJyCEQrdnVKCr58nPPaahhz9LJUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-pipe": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-10.0.1.tgz", + "integrity": "sha512-HPeXMD9AZ3V/qPkvQaPcak+C7cJ2z7JTHN8smd6J8L2aThLRky2cHc2OyeaHPSHB7WA47b4z2n5u5nawZhv5VQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-resolver": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-10.0.1.tgz", + "integrity": "sha512-PIzkZHD1fGUQx1XteK2d1iQ0Mzq/maYcoB4jkvAiiR6WqP3MWYNKFdI9z+R5pOq5KgMfW+5Ig1q0oSR6h8irlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-directory": "^5.0.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-service-bus": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-10.0.1.tgz", + "integrity": "sha512-y6NcIGP2IdXaBL4PVH8vxsr7K27wzz3Ech87UtUtrDSXAiVEOvXgAIknEOUVp59rTlUE8Rn4IRURC6f/hgMyfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-types": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-10.0.1.tgz", + "integrity": "sha512-kLgLShnWADDVreKC63pBrWkcvxgZzFIfO34Jhx/SWfuOIA3cD8AXT+HjyuLfoGJ7mUb58hv2kUziKzEy4INb1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/dict-ada": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", + "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-al": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", + "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-aws": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.17.tgz", + "integrity": "sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-bash": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.3.tgz", + "integrity": "sha512-ljUZoKHbDqw5Sx0qpL2qTUlmkmr+vhZH/sCNrNaBZKTbdgiswErSnIF1jRbGmEitJNxHRHWsuZyVgnTGfVO1Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-shell": "1.2.0" + } + }, + "node_modules/@cspell/dict-companies": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.11.tgz", + "integrity": "sha512-0cmafbcz2pTHXLd59eLR1gvDvN6aWAOM0+cIL4LLF9GX9yB2iKDNrKsvs4tJRqutoaTdwNFBbV0FYv+6iCtebQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cpp": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-7.0.2.tgz", + "integrity": "sha512-dfbeERiVNeqmo/npivdR6rDiBCqZi3QtjH2Z0HFcXwpdj6i97dX1xaKyK2GUsO/p4u1TOv63Dmj5Vm48haDpuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cryptocurrencies": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", + "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-csharp": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.8.tgz", + "integrity": "sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-css": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.2.tgz", + "integrity": "sha512-+ylGoKdwZ2sVOCOnU2Eq5wDZx+RaVX3HoKyNHGGsFvhSw6IidQ6tH/mAPKBDofViHJoWCPNlklE0lTr6MDG3QA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dart": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.2.tgz", + "integrity": "sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-data-science": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.14.tgz", + "integrity": "sha512-jl6Ds4u5u5JT+yY30pWQpAbdCHfy3lCcNkLbpL/AZKoUaLEoXbaYsps9xQtvD7DyaiXxiLZkdH2yHHXtoFtZyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-django": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.6.tgz", + "integrity": "sha512-SdbSFDGy9ulETqNz15oWv2+kpWLlk8DJYd573xhIkeRdcXOjskRuxjSZPKfW7O3NxN/KEf3gm3IevVOiNuFS+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-docker": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.17.tgz", + "integrity": "sha512-OcnVTIpHIYYKhztNTyK8ShAnXTfnqs43hVH6p0py0wlcwRIXe5uj4f12n7zPf2CeBI7JAlPjEsV0Rlf4hbz/xQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dotnet": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.13.tgz", + "integrity": "sha512-xPp7jMnFpOri7tzmqmm/dXMolXz1t2bhNqxYkOyMqXhvs08oc7BFs+EsbDY0X7hqiISgeFZGNqn0dOCr+ncPYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-elixir": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.8.tgz", + "integrity": "sha512-CyfphrbMyl4Ms55Vzuj+mNmd693HjBFr9hvU+B2YbFEZprE5AG+EXLYTMRWrXbpds4AuZcvN3deM2XVB80BN/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en_us": { + "version": "4.4.35", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.35.tgz", + "integrity": "sha512-xWpxBCc/FzzMMo/A+0qwARVaIIhR0Ql8yhhv4rvsvg+GfQF+LG9yzg2GwTM5N2rjvzmM3nKuR9zxFZq2I6fJSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en-common-misspellings": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.1.12.tgz", + "integrity": "sha512-14Eu6QGqyksqOd4fYPuRb58lK1Va7FQK9XxFsRKnZU8LhL3N+kj7YKDW+7aIaAN/0WGEqslGP6lGbQzNti8Akw==", + "dev": true, + "license": "CC BY-SA 4.0" + }, + "node_modules/@cspell/dict-en-gb-mit": { + "version": "3.1.24", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb-mit/-/dict-en-gb-mit-3.1.24.tgz", + "integrity": "sha512-Oowb/Uzkh7OmDRdCcETzMc9imEb4IpLlHJXoYjX8A8DS2X/54gqSjI915JFB8hKtFjBko5OM0BLQ+6cZhFEMmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-filetypes": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.18.tgz", + "integrity": "sha512-yU7RKD/x1IWmDLzWeiItMwgV+6bUcU/af23uS0+uGiFUbsY1qWV/D4rxlAAO6Z7no3J2z8aZOkYIOvUrJq0Rcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-flutter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.1.tgz", + "integrity": "sha512-UlOzRcH2tNbFhZmHJN48Za/2/MEdRHl2BMkCWZBYs+30b91mWvBfzaN4IJQU7dUZtowKayVIF9FzvLZtZokc5A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fonts": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.6.tgz", + "integrity": "sha512-aR/0csY01dNb0A1tw/UmN9rKgHruUxsYsvXu6YlSBJFu60s26SKr/k1o4LavpHTQ+lznlYMqAvuxGkE4Flliqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fsharp": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.1.tgz", + "integrity": "sha512-imhs0u87wEA4/cYjgzS0tAyaJpwG7vwtC8UyMFbwpmtw+/bgss+osNfyqhYRyS/ehVCWL17Ewx2UPkexjKyaBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fullstack": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.9.tgz", + "integrity": "sha512-diZX+usW5aZ4/b2T0QM/H/Wl9aNMbdODa1Jq0ReBr/jazmNeWjd+PyqeVgzd1joEaHY+SAnjrf/i9CwKd2ZtWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-gaming-terms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.2.tgz", + "integrity": "sha512-9XnOvaoTBscq0xuD6KTEIkk9hhdfBkkvJAIsvw3JMcnp1214OCGW8+kako5RqQ2vTZR3Tnf3pc57o7VgkM0q1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-git": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.1.0.tgz", + "integrity": "sha512-KEt9zGkxqGy2q1nwH4CbyqTSv5nadpn8BAlDnzlRcnL0Xb3LX9xTgSGShKvzb0bw35lHoYyLWN2ZKAqbC4pgGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-golang": { + "version": "6.0.26", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.26.tgz", + "integrity": "sha512-YKA7Xm5KeOd14v5SQ4ll6afe9VSy3a2DWM7L9uBq4u3lXToRBQ1W5PRa+/Q9udd+DTURyVVnQ+7b9cnOlNxaRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-google": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.9.tgz", + "integrity": "sha512-biL65POqialY0i4g6crj7pR6JnBkbsPovB2WDYkj3H4TuC/QXv7Pu5pdPxeUJA6TSCHI7T5twsO4VSVyRxD9CA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-haskell": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.6.tgz", + "integrity": "sha512-ib8SA5qgftExpYNjWhpYIgvDsZ/0wvKKxSP+kuSkkak520iPvTJumEpIE+qPcmJQo4NzdKMN8nEfaeci4OcFAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.15.tgz", + "integrity": "sha512-GJYnYKoD9fmo2OI0aySEGZOjThnx3upSUvV7mmqUu8oG+mGgzqm82P/f7OqsuvTaInZZwZbo+PwJQd/yHcyFIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html-symbol-entities": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.5.tgz", + "integrity": "sha512-429alTD4cE0FIwpMucvSN35Ld87HCyuM8mF731KU5Rm4Je2SG6hmVx7nkBsLyrmH3sQukTcr1GaiZsiEg8svPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-java": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.12.tgz", + "integrity": "sha512-qPSNhTcl7LGJ5Qp6VN71H8zqvRQK04S08T67knMq9hTA8U7G1sTKzLmBaDOFhq17vNX/+rT+rbRYp+B5Nwza1A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-julia": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.1.tgz", + "integrity": "sha512-WylJR9TQ2cgwd5BWEOfdO3zvDB+L7kYFm0I9u0s9jKHWQ6yKmfKeMjU9oXxTBxIufhCXm92SKwwVNAC7gjv+yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-k8s": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.12.tgz", + "integrity": "sha512-2LcllTWgaTfYC7DmkMPOn9GsBWsA4DZdlun4po8s2ysTP7CPEnZc1ZfK6pZ2eI4TsZemlUQQ+NZxMe9/QutQxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-kotlin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.1.tgz", + "integrity": "sha512-J3NzzfgmxRvEeOe3qUXnSJQCd38i/dpF9/t3quuWh6gXM+krsAXP75dY1CzDmS8mrJAlBdVBeAW5eAZTD8g86Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-latex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-5.1.0.tgz", + "integrity": "sha512-qxT4guhysyBt0gzoliXYEBYinkAdEtR2M7goRaUH0a7ltCsoqqAeEV8aXYRIdZGcV77gYSobvu3jJL038tlPAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lorem-ipsum": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.5.tgz", + "integrity": "sha512-9a4TJYRcPWPBKkQAJ/whCu4uCAEgv/O2xAaZEI0n4y1/l18Yyx8pBKoIX5QuVXjjmKEkK7hi5SxyIsH7pFEK9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lua": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.8.tgz", + "integrity": "sha512-N4PkgNDMu9JVsRu7JBS/3E/dvfItRgk9w5ga2dKq+JupP2Y3lojNaAVFhXISh4Y0a6qXDn2clA6nvnavQ/jjLA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-makefile": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.5.tgz", + "integrity": "sha512-4vrVt7bGiK8Rx98tfRbYo42Xo2IstJkAF4tLLDMNQLkQ86msDlYSKG1ZCk8Abg+EdNcFAjNhXIiNO+w4KflGAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-markdown": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.17.tgz", + "integrity": "sha512-H8bAxih6U8NOnSPL7R8My+tqjaB4tmnJTjERuz4zYqmf+cH+5xshX3UVgKlwWFcyjsYfv/zEDuRdMctQv1q6HQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@cspell/dict-css": "^4.1.2", + "@cspell/dict-html": "^4.0.15", + "@cspell/dict-html-symbol-entities": "^4.0.5", + "@cspell/dict-typescript": "^3.2.3" + } + }, + "node_modules/@cspell/dict-monkeyc": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.12.tgz", + "integrity": "sha512-MN7Vs11TdP5mbdNFQP5x2Ac8zOBm97ARg6zM5Sb53YQt/eMvXOMvrep7+/+8NJXs0jkp70bBzjqU4APcqBFNAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-node": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.9.tgz", + "integrity": "sha512-hO+ga+uYZ/WA4OtiMEyKt5rDUlUyu3nXMf8KVEeqq2msYvAPdldKBGH7lGONg6R/rPhv53Rb+0Y1SLdoK1+7wQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-npm": { + "version": "5.2.41", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.41.tgz", + "integrity": "sha512-To3xsfRmMBYVXtWVEdUgV35M9a/JZ54dSuoY6m6D3uHKKL3I326Wmy4xifZ3PU8MQaWhyEH7zbIcUEtKwTQMcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-php": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.1.1.tgz", + "integrity": "sha512-EXelI+4AftmdIGtA8HL8kr4WlUE11OqCSVlnIgZekmTkEGSZdYnkFdiJ5IANSALtlQ1mghKjz+OFqVs6yowgWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-powershell": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.15.tgz", + "integrity": "sha512-l4S5PAcvCFcVDMJShrYD0X6Huv9dcsQPlsVsBGbH38wvuN7gS7+GxZFAjTNxDmTY1wrNi1cCatSg6Pu2BW4rgg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-public-licenses": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.16.tgz", + "integrity": "sha512-EQRrPvEOmwhwWezV+W7LjXbIBjiy6y/shrET6Qcpnk3XANTzfvWflf9PnJ5kId/oKWvihFy0za0AV1JHd03pSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-python": { + "version": "4.2.27", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.27.tgz", + "integrity": "sha512-Rj6xQgYS4X6ienjgAZF+njA0GRY4oSPouJWv0vfikCTn6EWlfk0V6Dy1HP3Migj1O+IC2NmespgVq+BZNSp8OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-data-science": "^2.0.14" + } + }, + "node_modules/@cspell/dict-r": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.1.tgz", + "integrity": "sha512-71Ka+yKfG4ZHEMEmDxc6+blFkeTTvgKbKAbwiwQAuKl3zpqs1Y0vUtwW2N4b3LgmSPhV3ODVY0y4m5ofqDuKMw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-ruby": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.1.1.tgz", + "integrity": "sha512-LHrp84oEV6q1ZxPPyj4z+FdKyq1XAKYPtmGptrd+uwHbrF/Ns5+fy6gtSi7pS+uc0zk3JdO9w/tPK+8N1/7WUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-rust": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.1.2.tgz", + "integrity": "sha512-O1FHrumYcO+HZti3dHfBPUdnDFkI+nbYK3pxYmiM1sr+G0ebOd6qchmswS0Wsc6ZdEVNiPYJY/gZQR6jfW3uOg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-scala": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.9.tgz", + "integrity": "sha512-AjVcVAELgllybr1zk93CJ5wSUNu/Zb5kIubymR/GAYkMyBdYFCZ3Zbwn4Zz8GJlFFAbazABGOu0JPVbeY59vGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-shell": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.2.0.tgz", + "integrity": "sha512-PVctvT22lJ49niMiakO8xieY7ELCAzjSqhejWR7bAMb5AZ9F4WDEs+XdGMnoVHWeXq7K5rcepLPmEJb+37zzIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-software-terms": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.2.2.tgz", + "integrity": "sha512-0CaYd6TAsKtEoA7tNswm1iptEblTzEe3UG8beG2cpSTHk7afWIVMtJLgXDv0f/Li67Lf3Z1Jf3JeXR7GsJ2TRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-sql": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.1.tgz", + "integrity": "sha512-qDHF8MpAYCf4pWU8NKbnVGzkoxMNrFqBHyG/dgrlic5EQiKANCLELYtGlX5auIMDLmTf1inA0eNtv74tyRJ/vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-svelte": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.7.tgz", + "integrity": "sha512-hGZsGqP0WdzKkdpeVLBivRuSNzOTvN036EBmpOwxH+FTY2DuUH7ecW+cSaMwOgmq5JFSdTcbTNFlNC8HN8lhaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-swift": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.6.tgz", + "integrity": "sha512-PnpNbrIbex2aqU1kMgwEKvCzgbkHtj3dlFLPMqW1vSniop7YxaDTtvTUO4zA++ugYAEL+UK8vYrBwDPTjjvSnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-terraform": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.3.tgz", + "integrity": "sha512-gr6wxCydwSFyyBKhBA2xkENXtVFToheqYYGFvlMZXWjviynXmh+NK/JTvTCk/VHk3+lzbO9EEQKee6VjrAUSbA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-typescript": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz", + "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-vue": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.5.tgz", + "integrity": "sha512-Mqutb8jbM+kIcywuPQCCaK5qQHTdaByoEO2J9LKFy3sqAdiBogNkrplqUK0HyyRFgCfbJUgjz3N85iCMcWH0JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-zig": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-zig/-/dict-zig-1.0.0.tgz", + "integrity": "sha512-XibBIxBlVosU06+M6uHWkFeT0/pW5WajDRYdXG2CgHnq85b0TI/Ks0FuBJykmsgi2CAD3Qtx8UHFEtl/DSFnAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dynamic-import": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-10.0.1.tgz", + "integrity": "sha512-mP1gdq00aIcH8HxNMqnH11X6BKxLcneDtFgl/ecjIKnaGKwi44m8AndP5Kr4ODaYdl8UUw9O3dJh7KaQXnLHZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "10.0.1", + "import-meta-resolve": "^4.2.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/eslint-plugin": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/eslint-plugin/-/eslint-plugin-10.0.1.tgz", + "integrity": "sha512-VgRVWIWyM5bz2d7eC3/F4ON1fhMdrFB0R6slXmJewDDbJMDloSsMsWCSktiFET3a0TX/DTjOGGDzBN9tqGDGPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "10.0.1", + "@cspell/url": "10.0.1", + "cspell-lib": "10.0.1", + "synckit": "^0.11.13" + }, + "engines": { + "node": ">=22.18.0" + }, + "peerDependencies": { + "eslint": "^8 || ^9 || ^10" + } + }, + "node_modules/@cspell/filetypes": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-10.0.1.tgz", + "integrity": "sha512-Z5S35giU5IW49fBBq6BksUbE8PC4IYPfaKuwl5Nl9jkf/OkAKiBmCowKX45NzRUQInwK/GSqqIUifrNeI6LdLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/rpc": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/rpc/-/rpc-10.0.1.tgz", + "integrity": "sha512-axSRKv3zEAmBm66iD/FV/MPmE4/Yf7c3PZiwTW894Yd3iEhtn3KPKeTrqQ2/tDrhB1Z2qTsap/Hue0MK4o5WXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/strong-weak-map": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-10.0.1.tgz", + "integrity": "sha512-lenN1DVyPi8nJLSMSJJ670ddTjyiruLueuSZO1qLcxBqUhgxDt/mALu9N/1m6WdOVcg6m/5cLiZVg2KOo2UzRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/url": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/url/-/url-10.0.1.tgz", + "integrity": "sha512-abYYgI29wJhWIfWTYrYuzRYDcHQUQ1N5ylnhxYn1NJnIQMqUWGLbDmt12JABtZ+R6h6UNatQrS7rhP86etvJyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@e18e/eslint-plugin": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@e18e/eslint-plugin/-/eslint-plugin-0.5.1.tgz", + "integrity": "sha512-mqUozeyNI9xvJbjrOO7y765dT7Kud3bwCm/DHwctxdEngPdJWQaS9BNGgpM1wCCzZfOtlKQh4ZRhm3VRomT9KA==", + "dev": true, + "license": "MIT", + "dependencies": { + "empathic": "^2.0.1", + "module-replacements": "^3.0.0-beta.8", + "semver": "^7.8.2" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0", + "oxlint": "^1.68.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "oxlint": { + "optional": true + } + } + }, + "node_modules/@e18e/eslint-plugin/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/css": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/css/-/css-1.3.0.tgz", + "integrity": "sha512-MwY657chvFQWtXmO86syZgD+JpWlzDq7VkKZyi65PwHDbhELQPMzPXh5s8rhrjptG6FCuls0puCmlXk66+14uA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "@eslint/css-tree": "^4.0.4", + "@eslint/plugin-kit": "^0.7.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/css-tree": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-4.0.4.tgz", + "integrity": "sha512-nxMparyhqVWQvadx9x8dIfubfIPOE+X2b2waua8fzdnM9vdp9rgVtwEZlG0TmCwEUz/d/f40fzvO/eqBwdxz0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.28.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@eslint/json/-/json-2.0.0.tgz", + "integrity": "sha512-P32ZJMIopNWQd1SFhd0tgjfA/hgzUuVSqHmMi2273QaLWHWimXq6V+qL4DNKnjGzO/aNECtYW+rEJ/pWB6uP+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanwhocodes/momoa": "^3.3.10", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/markdown": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@eslint/markdown/-/markdown-8.0.2.tgz", + "integrity": "sha512-W+/0qHp0WbvFEljUvvECNpSWrUHpBWIWwp7F3QqEwQKmaRCmfEWvk6VfUia9pTQ0th6HyBGBsPfg/kG3/aQxLA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "examples/*" + ], + "dependencies": { + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "github-slugger": "^2.0.0", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-frontmatter": "^2.0.1", + "mdast-util-gfm": "^3.1.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "micromark-extension-gfm": "^3.0.0", + "micromark-extension-math": "^3.1.0", + "micromark-util-normalize-identifier": "^2.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/momoa": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.10.tgz", + "integrity": "sha512-KWiFQpSAqEIyrTXko3hFNLeQvSK8zXlJQzhhxsyVn58WFRYXST99b3Nqnu+ttOtjds2Pl2grUHGpe2NzhPynuQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", + "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@jest/diff-sequences": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@lerna/create": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.2.4.tgz", + "integrity": "sha512-A8AlzetnS2WIuhijdAzKUyFpR5YbLLfV3luQ4lzBgIBgRfuoBDZeF+RSZPhra+7A6/zTUlrbhKZIOi/MNhqgvQ==", + "deprecated": "This package is an implementation detail of Lerna and is no longer published separately.", + "dev": true, + "license": "MIT", + "dependencies": { + "@npmcli/arborist": "7.5.4", + "@npmcli/package-json": "5.2.0", + "@npmcli/run-script": "8.1.0", + "@nx/devkit": ">=17.1.2 < 21", + "@octokit/plugin-enterprise-rest": "6.0.1", + "@octokit/rest": "20.1.2", + "aproba": "2.0.0", + "byte-size": "8.1.1", + "chalk": "4.1.0", + "clone-deep": "4.0.1", + "cmd-shim": "6.0.3", + "color-support": "1.1.3", + "columnify": "1.6.0", + "console-control-strings": "^1.1.0", + "conventional-changelog-core": "5.0.1", + "conventional-recommended-bump": "7.0.1", + "cosmiconfig": "9.0.0", + "dedent": "1.5.3", + "execa": "5.0.0", + "fs-extra": "^11.2.0", + "get-stream": "6.0.0", + "git-url-parse": "14.0.0", + "glob-parent": "6.0.2", + "graceful-fs": "4.2.11", + "has-unicode": "2.0.1", + "ini": "^1.3.8", + "init-package-json": "6.0.3", + "inquirer": "^8.2.4", + "is-ci": "3.0.1", + "is-stream": "2.0.0", + "js-yaml": "4.1.0", + "libnpmpublish": "9.0.9", + "load-json-file": "6.2.0", + "make-dir": "4.0.0", + "minimatch": "3.0.5", + "multimatch": "5.0.0", + "node-fetch": "2.6.7", + "npm-package-arg": "11.0.2", + "npm-packlist": "8.0.2", + "npm-registry-fetch": "^17.1.0", + "nx": ">=17.1.2 < 21", + "p-map": "4.0.0", + "p-map-series": "2.1.0", + "p-queue": "6.6.2", + "p-reduce": "^2.1.0", + "pacote": "^18.0.6", + "pify": "5.0.0", + "read-cmd-shim": "4.0.0", + "resolve-from": "5.0.0", + "rimraf": "^4.4.1", + "semver": "^7.3.4", + "set-blocking": "^2.0.0", + "signal-exit": "3.0.7", + "slash": "^3.0.0", + "ssri": "^10.0.6", + "string-width": "^4.2.3", + "tar": "6.2.1", + "temp-dir": "1.0.0", + "through": "2.3.8", + "tinyglobby": "0.2.12", + "upath": "2.0.1", + "uuid": "^10.0.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "5.0.1", + "wide-align": "1.1.5", + "write-file-atomic": "5.0.1", + "write-pkg": "4.0.0", + "yargs": "17.7.2", + "yargs-parser": "21.1.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-darwin-arm64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.8.4.tgz", + "integrity": "sha512-8Y7+4wj1qoZsuDRpnuiHzSIsMt3VqtJ0su8dgd/MyGccvvi4pndan2R5yTiVw/wmbMxtBmZ6PO6Z8dgSIrMVog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-darwin-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.8.4.tgz", + "integrity": "sha512-2lfuxRc56QWnAysMhcD03tpCPiRzV1+foUq0MhV2sSBIybXmgV4wHLkPZNhlBCl4FNXrWiZiN1OJ2X9AGiOdug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-freebsd-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.8.4.tgz", + "integrity": "sha512-99vnUXZy+OUBHU+8Yhabre2qafepKg9GKkQkhmXvJGqOmuIsepK7wirUFo2PiVM8YhS6UV2rv6hKAZcQ7skYyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.8.4.tgz", + "integrity": "sha512-dht73zpnpzEUEzMHFQs4mfiwZH3WcJgQNWkD5p7WkeJewHq2Yyd0eG5Jg3kB7wnFtwPUV1eNJRM5rephgylkLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.8.4.tgz", + "integrity": "sha512-syXxbJZ0yPaqzVmB28QJgUtaarSiW/PQmv/5Z2Ps8rCi7kYylISPVNjP1NNiIOcGDRWbHqoBfM0bEGPfSp0rBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.8.4.tgz", + "integrity": "sha512-AlZZFolS/S0FahRKG7rJ0Z9CgmIkyzHgGaoy3qNEMDEjFhR3jt2ZZSLp90W7zjgrxojOo90ajNMrg2UmtcQRDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-x64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.8.4.tgz", + "integrity": "sha512-MSu+xVNdR95tuuO+eL/a/ZeMlhfrZ627On5xaCZXnJ+lFxNg/S4nlKZQk0Eq5hYALCd/GKgFGasRdlRdOtvGPg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-x64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.8.4.tgz", + "integrity": "sha512-KxpQpyLCgIIHWZ4iRSUN9ohCwn1ZSDASbuFCdG3mohryzCy8WrPkuPcb+68J3wuQhmA5w//Xpp/dL0hHoit9zQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-win32-arm64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.8.4.tgz", + "integrity": "sha512-ffLBrxM9ibk+eWSY995kiFFRTSRb9HkD5T1s/uZyxV6jfxYPaZDBAWAETDneyBXps7WtaOMu+kVZlXQ3X+TfIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-win32-x64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.8.4.tgz", + "integrity": "sha512-JxuuZc4h8EBqoYAiRHwskimpTJx70yn4lhIRFBoW5ICkxXW1Rw0yip/1UVsWRHXg/x9BxmH7VVazdfaQWmGu6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@lerna/create/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@lerna/create/node_modules/nx": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/nx/-/nx-20.8.4.tgz", + "integrity": "sha512-/++x0OM3/UTmDR+wmPeV13tSxeTr+QGzj3flgtH9DiOPmQnn2CjHWAMZiOhcSh/hHoE/V3ySL4757InQUsVtjQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@napi-rs/wasm-runtime": "0.2.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.2", + "@zkochan/js-yaml": "0.0.7", + "axios": "^1.8.3", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "front-matter": "^4.0.2", + "ignore": "^5.0.4", + "jest-diff": "^29.4.1", + "jsonc-parser": "3.2.0", + "lines-and-columns": "2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "resolve.exports": "2.0.3", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "yaml": "^2.6.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "20.8.4", + "@nx/nx-darwin-x64": "20.8.4", + "@nx/nx-freebsd-x64": "20.8.4", + "@nx/nx-linux-arm-gnueabihf": "20.8.4", + "@nx/nx-linux-arm64-gnu": "20.8.4", + "@nx/nx-linux-arm64-musl": "20.8.4", + "@nx/nx-linux-x64-gnu": "20.8.4", + "@nx/nx-linux-x64-musl": "20.8.4", + "@nx/nx-win32-arm64-msvc": "20.8.4", + "@nx/nx-win32-x64-msvc": "20.8.4" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/@lerna/create/node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@lerna/create/node_modules/ora": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/create/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/legacy-package-management": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@lerna/legacy-package-management/-/legacy-package-management-8.2.4.tgz", + "integrity": "sha512-NSujwnA8bH7qSGAtNXp9JqGE8nxelKEIg0q5E6vLJfaTq/TcNyFjvesYTpNjPEdZ3eMneBG3nV5ccryo1ddUHg==", + "deprecated": "In v9 of lerna, released in September 2025, the `lerna bootstrap`, `lerna add` and `lerna link` commands were finally fully removed after over 2 years of being deprecated. If you are still using these commands, please migrate to using your package manager's long-supported `workspaces` feature. You may find https://lerna.js.org/docs/legacy-package-management useful for this transition.", + "dev": true, + "license": "MIT", + "dependencies": { + "@npmcli/arborist": "7.5.4", + "@npmcli/package-json": "5.2.0", + "@npmcli/run-script": "8.1.0", + "@nx/devkit": ">=17.1.2 < 21", + "@octokit/rest": "20.1.2", + "aproba": "2.0.0", + "byte-size": "8.1.1", + "chalk": "4.1.0", + "clone-deep": "4.0.1", + "cmd-shim": "6.0.3", + "color-support": "1.1.3", + "columnify": "1.6.0", + "console-control-strings": "^1.1.0", + "conventional-changelog-core": "5.0.1", + "conventional-recommended-bump": "7.0.1", + "cosmiconfig": "9.0.0", + "dedent": "1.5.3", + "execa": "5.0.0", + "file-url": "3.0.0", + "find-up": "5.0.0", + "fs-extra": "^11.2.0", + "get-port": "5.1.1", + "get-stream": "6.0.0", + "git-url-parse": "14.0.0", + "glob-parent": "6.0.2", + "graceful-fs": "4.2.11", + "has-unicode": "2.0.1", + "ini": "^1.3.8", + "inquirer": "8.2.4", + "is-ci": "3.0.1", + "is-stream": "2.0.0", + "libnpmpublish": "9.0.9", + "load-json-file": "6.2.0", + "make-dir": "4.0.0", + "minimatch": "3.0.5", + "multimatch": "5.0.0", + "node-fetch": "2.6.7", + "npm-package-arg": "11.0.2", + "npm-packlist": "8.0.2", + "npm-registry-fetch": "^17.1.0", + "p-map": "4.0.0", + "p-map-series": "2.1.0", + "p-queue": "6.6.2", + "p-waterfall": "2.1.1", + "pacote": "^18.0.6", + "pify": "5.0.0", + "pretty-format": "29.4.3", + "read-cmd-shim": "4.0.0", + "resolve-from": "5.0.0", + "rimraf": "^4.4.1", + "semver": "7.5.2", + "set-blocking": "^2.0.0", + "signal-exit": "3.0.7", + "slash": "3.0.0", + "ssri": "^10.0.6", + "string-width": "^4.2.3", + "tar": "6.2.1", + "temp-dir": "1.0.0", + "tempy": "1.0.0", + "through": "2.3.8", + "tinyglobby": "0.2.12", + "upath": "2.0.1", + "uuid": "^10.0.0", + "wide-align": "1.1.5", + "write-file-atomic": "5.0.1", + "write-pkg": "4.0.0", + "yargs": "17.7.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@lvce-editor/eslint-config": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-config/-/eslint-config-11.2.0.tgz", + "integrity": "sha512-T6SkTON8D2FJnv7kbr5Uye7gWuacQREvI9XSd40PQyyteY/UZzAMD+8bMWaL11G5E2AG4imrVMVtX1cQG+W4Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/eslint-plugin": "10.0.1", + "@e18e/eslint-plugin": "^0.5.0", + "@eslint/css": "1.3.0", + "@eslint/js": "10.0.1", + "@eslint/json": "2.0.0", + "@eslint/markdown": "8.0.2", + "@lvce-editor/eslint-plugin-e2e": "11.2.0", + "@lvce-editor/eslint-plugin-github-actions": "11.2.0", + "@lvce-editor/eslint-plugin-nvmrc": "11.2.0", + "@lvce-editor/eslint-plugin-regex": "11.2.0", + "@lvce-editor/eslint-plugin-rpc": "11.2.0", + "@lvce-editor/eslint-plugin-tsconfig": "11.2.0", + "eslint-plugin-jest": "29.15.2", + "eslint-plugin-n": "18.0.1", + "eslint-plugin-package-json": "1.3.0", + "eslint-plugin-perfectionist": "5.9.0", + "eslint-plugin-sonarjs": "4.0.3", + "eslint-plugin-unicorn": "64.0.0", + "eslint-plugin-yml": "3.4.0", + "typescript-eslint": "8.60.1" + }, + "peerDependencies": { + "eslint": "^10" + } + }, + "node_modules/@lvce-editor/eslint-plugin-e2e": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-e2e/-/eslint-plugin-e2e-11.2.0.tgz", + "integrity": "sha512-K/brulzQ8VgOJQWQ3RNjMFeUGLCNTRwFv7H8p6UJZcQqSCGmFc69lgG8Yjnz0CVdVcJm+KvumNdr1x7tqJcXZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/eslint-plugin-github-actions": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-github-actions/-/eslint-plugin-github-actions-11.2.0.tgz", + "integrity": "sha512-5v1lqcHnyGPBQlR3xnoTXN5FX1q2cB+DvTcNoNwuz1EPK4eJyeRj6DZiT5BaR5Qa5DTyhsaG3ZLcmOLAi9qZ8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-compat-utils": "0.6.5", + "yaml-eslint-parser": "2.0.0" + } + }, + "node_modules/@lvce-editor/eslint-plugin-nvmrc": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-nvmrc/-/eslint-plugin-nvmrc-11.2.0.tgz", + "integrity": "sha512-d8sm80TXioU9kBR283SFJIPgIWPoCf+1VgrL1EPzkmmtx2XQaJ/k8u47eJctFLmcEPDFt8LbaxIV2HDX36/s0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/eslint-plugin-regex": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-regex/-/eslint-plugin-regex-11.2.0.tgz", + "integrity": "sha512-e9u7yxWBWilqXLZNdm5mAPLkHW6uYnhXG5lKkE4ZHkcKmR018xP0ta/5iHB7B+u8cJ4gqwrXFsHFl3oJTINerQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/eslint-plugin-rpc": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-rpc/-/eslint-plugin-rpc-11.2.0.tgz", + "integrity": "sha512-DMvBVADJHw0qmx6A5Q7czGF5F6qMs67UV4eCvjowYKl+6MwafuZexFFRRUKVQR7tx6zGk0kLEfv7AS2NIZAOKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/eslint-plugin-tsconfig": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-tsconfig/-/eslint-plugin-tsconfig-11.2.0.tgz", + "integrity": "sha512-6jWkzuAKLc2jCKGfzZRQbLKvYDh2F4BVX7Z7MDel9GdUMGGenc0X7qlRZ0MTT3A6CROaN/wmFFEu1lrcuqQDEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/json": "2.0.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", + "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emnapi/core": "^1.1.0", + "@emnapi/runtime": "^1.1.0", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.5.4.tgz", + "integrity": "sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.1", + "@npmcli/installed-package-contents": "^2.1.0", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.1.1", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.1.0", + "@npmcli/query": "^3.1.0", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", + "bin-links": "^4.0.4", + "cacache": "^18.0.3", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.2", + "json-parse-even-better-errors": "^3.0.2", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^10.2.2", + "minimatch": "^9.0.4", + "nopt": "^7.2.1", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.2", + "npm-pick-manifest": "^9.0.1", + "npm-registry-fetch": "^17.0.1", + "pacote": "^18.0.6", + "parse-conflict-json": "^3.0.0", + "proc-log": "^4.2.0", + "proggy": "^2.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.6", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", + "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "ini": "^4.1.3", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^4.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz", + "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.1.tgz", + "integrity": "sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==", + "dev": true, + "license": "ISC", + "dependencies": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^18.0.0", + "proc-log": "^4.1.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", + "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", + "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^4.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", + "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/query": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-3.1.0.tgz", + "integrity": "sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz", + "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", + "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@nx/devkit": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-20.8.4.tgz", + "integrity": "sha512-3r+6QmIXXAWL6K7m8vAbW31aniAZmZAZXeMhOhWcJoOAU7ggpCQaM8JP8/kO5ov/Bmhyf0i/SSVXI6kwiR5WNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 19 <= 21" + } + }, + "node_modules/@nx/devkit/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@nx/devkit/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@nx/devkit/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/nx-darwin-arm64": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-21.6.11.tgz", + "integrity": "sha512-4hXhV7ShXIlfPEjjm7dJY383xM2vTcnkKr5FUncAU08GKkkL67ib5CMlQADtdi32ewfCZntqiT8gUfFFSNvKtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@nx/nx-darwin-x64": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-21.6.11.tgz", + "integrity": "sha512-VxjKkzyhdO47X7d4JPx/f6HslERKetFmouDUBIoqbKDPVWpRegGMsRKcMYh4l61usxI1Qa2U4Ec6MgO5Fnm41g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@nx/nx-freebsd-x64": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-21.6.11.tgz", + "integrity": "sha512-3jDn7Tb3FMFfeFTM/XKAcI+J92kDLNmxUS/N/n/+kF/XYLPgMUZQqSeDpVifk4fgy0BCoH8DSMQIqTQau6dV/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-21.6.11.tgz", + "integrity": "sha512-37tpiVod5FN/EAuCGh+uad/6nsfDFze02OjYReUPKeYPs8Q7Ac/V9j4kn/y5uZhKSle+9+sa2QR/K79B0+lNxw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-arm64-gnu": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-21.6.11.tgz", + "integrity": "sha512-r+czH0OtldQqFm2B6BBBUPW8aO+sBMvpZCgN855vko30WaCeXo8Fkuk71rQMxByz0jnoCxSnzLtEWVZm1rmJYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-arm64-musl": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-21.6.11.tgz", + "integrity": "sha512-0FAPyWEGPCukXxR1qowvFx6Q/cU906vwPlAQtcbrBU1e2H2aMUslk9EmL8iHb5MsHdmGcFyFemwr9oN8gxmz4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-x64-gnu": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-21.6.11.tgz", + "integrity": "sha512-+bWJWXJ8tdddl1L3bTKE0VmvTmdsk4zzUr6P9ts9hXQbwoWqMcuA6LNqOhUfzVOL3VioirRMtKMfFuUAUhi3Yg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-x64-musl": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-21.6.11.tgz", + "integrity": "sha512-Mh09mLc+yeJk7DKfx7x6XfB+bm2dP1/7gyUuRQj4WjkT+Il2ZponyTuH8LmX06Jpr7efAAFk+8lBXeleV7XvMw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-win32-arm64-msvc": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-21.6.11.tgz", + "integrity": "sha512-d7ZeCCDwaeyKiWD2JLSSxMSuSHHwIdpbnMtZtzRE6tDdAgs6e9F36/OBNQB3IRXH8V6QKOy2OGDyWeOKr01X9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@nx/nx-win32-x64-msvc": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-21.6.11.tgz", + "integrity": "sha512-otHSkhyoGilttV4RRkVmLLGb2W+Ia4b90lWxLnEm9jAAKmA9O2FUG2vAvKDHNcqTyDwwCcHfHxslgnR1u/3OIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", + "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.4.1", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^8.4.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.4.4-cjs.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.4-cjs.2.tgz", + "integrity": "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.7.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", + "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "13.3.2-cjs.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.2-cjs.1.tgz", + "integrity": "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.8.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^5" + } + }, + "node_modules/@octokit/request": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", + "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^9.0.6", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", + "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/rest": { + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.2.tgz", + "integrity": "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^5.0.2", + "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", + "@octokit/plugin-request-log": "^4.0.0", + "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@ota-meshi/ast-token-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@ota-meshi/ast-token-store/-/ast-token-store-0.3.0.tgz", + "integrity": "sha512-XRO0zi2NIUKq2lUk3T1ecFSld1fMWRKE6naRFGkgkdeosx7IslyUKNv5Dcb5PJTja9tHJoFu0v/7yEpAkrkrTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sigstore/bundle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", + "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.3.tgz", + "integrity": "sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", + "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^13.0.1", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", + "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^2.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", + "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", + "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/type-utils": "8.60.1", + "@typescript-eslint/utils": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.60.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/project-service": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", + "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", + "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", + "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.61.1", + "@typescript-eslint/types": "^8.61.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", + "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", + "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", + "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/project-service": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", + "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", + "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", + "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.61.1", + "@typescript-eslint/tsconfig-utils": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", + "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", + "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", + "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", + "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bin-links": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.4.tgz", + "integrity": "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/byte-size": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz", + "integrity": "sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", + "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-regexp/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cmd-shim": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.3.tgz", + "integrity": "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/columnify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/comment-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-5.0.0.tgz", + "integrity": "sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "dev": true, + "license": "ISC" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-5.0.1.tgz", + "integrity": "sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^6.0.0", + "conventional-commits-parser": "^4.0.0", + "dateformat": "^3.0.3", + "get-pkg-repo": "^4.2.1", + "git-raw-commits": "^3.0.0", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^5.0.0", + "normalize-package-data": "^3.0.3", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz", + "integrity": "sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz", + "integrity": "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-filter": "^3.0.0", + "dateformat": "^3.0.3", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "meow": "^8.1.2", + "semver": "^7.0.0", + "split": "^1.0.1" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-commits-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", + "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-commits-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", + "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.3.5", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-7.0.1.tgz", + "integrity": "sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^3.0.0", + "conventional-commits-filter": "^3.0.0", + "conventional-commits-parser": "^4.0.0", + "git-raw-commits": "^3.0.0", + "git-semver-tags": "^5.0.0", + "meow": "^8.1.2" + }, + "bin": { + "conventional-recommended-bump": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cspell-config-lib": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-10.0.1.tgz", + "integrity": "sha512-hMpo/0j6k7pbiqrLDOLJKD2IGP9XwhjKf2miiM6p84Xeo4nyuFZaxxDCQ68R851HSYFrrdltgpoipMbj1h2Tnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "10.0.1", + "comment-json": "^5.0.0", + "smol-toml": "^1.6.1", + "yaml": "^2.9.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-dictionary": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-10.0.1.tgz", + "integrity": "sha512-3cZ659vgsZWkzGQJR/sNqGDVt/OnvTSieLKI76V++4t1bHJfochb9ZrrwsuMsb1VPGiyqClUP1/O6WrefF/FVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-performance-monitor": "10.0.1", + "@cspell/cspell-pipe": "10.0.1", + "@cspell/cspell-types": "10.0.1", + "cspell-trie-lib": "10.0.1", + "fast-equals": "^6.0.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-glob": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-10.0.1.tgz", + "integrity": "sha512-7bII9J3aSSpZDwhx7w+zfQXbMxHZQ3be0ilUp5bHrsjz6o07v/NqOHMGcwKdPn1sw2dxDz9sv057xE5pqXnSdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "10.0.1", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-grammar": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-10.0.1.tgz", + "integrity": "sha512-xC9AFYmaI9wsO//a7S5tdDGKGJVD5UEEsTg+Up2fi7lPfXIryisYmV6tePNL1SEg0idYss4ja8LUZ3Mib09BjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "10.0.1", + "@cspell/cspell-types": "10.0.1" + }, + "bin": { + "cspell-grammar": "bin.mjs" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-io": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-10.0.1.tgz", + "integrity": "sha512-8C2ka07faxflnaqEBO3pektS21XViE/SEHT7F5ZD1ou7FyMR5u3xawTBJSczClfsxLt/WYeztBYrpmGAjmjksw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-service-bus": "10.0.1", + "@cspell/url": "10.0.1" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-lib": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-10.0.1.tgz", + "integrity": "sha512-RpsIPiLzc4/YMW8BMRKpyJ81x439qjYWcqgdKeXnMkbKM88J9PexzutfFf/4v97v96KzfNitEzMpbI0uj8OeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-bundled-dicts": "10.0.1", + "@cspell/cspell-performance-monitor": "10.0.1", + "@cspell/cspell-pipe": "10.0.1", + "@cspell/cspell-resolver": "10.0.1", + "@cspell/cspell-types": "10.0.1", + "@cspell/dynamic-import": "10.0.1", + "@cspell/filetypes": "10.0.1", + "@cspell/rpc": "10.0.1", + "@cspell/strong-weak-map": "10.0.1", + "@cspell/url": "10.0.1", + "cspell-config-lib": "10.0.1", + "cspell-dictionary": "10.0.1", + "cspell-glob": "10.0.1", + "cspell-grammar": "10.0.1", + "cspell-io": "10.0.1", + "cspell-trie-lib": "10.0.1", + "env-paths": "^4.0.0", + "gensequence": "^8.0.8", + "import-fresh": "^4.0.0", + "resolve-from": "^5.0.0", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-uri": "^3.1.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-lib/node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cspell-lib/node_modules/import-fresh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-4.0.0.tgz", + "integrity": "sha512-Fpi660c7VPDM3fPKYovStd9IP1CPOikf6v/dGxJJMmHPcwYQIMJ4W7kO1avBYEpMqkCh+Dx3Ln6H7VYqgztLjw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cspell-trie-lib": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-10.0.1.tgz", + "integrity": "sha512-BFvhalSkRQFjKrZ//FKK7fRGrZFpifnxB5AwCkzsIsBZqicsfafcQ1xP21qpb0QqyV/IomjNgviG+tRJs+0rMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + }, + "peerDependencies": { + "@cspell/cspell-types": "10.0.1" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/del/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", + "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-newline": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz", + "integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.372", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", + "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz", + "integrity": "sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", + "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.5.tgz", + "integrity": "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-fix-utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/eslint-fix-utils/-/eslint-fix-utils-0.4.2.tgz", + "integrity": "sha512-n7ZTcwwkP5scedlhvWMcqxED+O1NzXcj5Rxn/0kJQMP88k02vRcBfQ1qsk/JHb6Aw8bajFoetFCCBiNIcNCsvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/estree": ">=1", + "eslint": ">=8" + }, + "peerDependenciesMeta": { + "@types/estree": { + "optional": true + } + } + }, + "node_modules/eslint-json-compat-utils": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-json-compat-utils/-/eslint-json-compat-utils-0.2.3.tgz", + "integrity": "sha512-RbBmDFyu7FqnjE8F0ZxPNzx5UaptdeS9Uu50r7A+D7s/+FCX+ybiyViYEgFUaFIFqSWJgZRTpL5d8Kanxxl2lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esquery": "^1.6.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": "*", + "jsonc-eslint-parser": "^2.4.0 || ^3.0.0" + }, + "peerDependenciesMeta": { + "@eslint/json": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-es-x/node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-es-x/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "29.15.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.2.tgz", + "integrity": "sha512-kEN4r9RZl1xcsb4arGq89LrcVdOUFII/JSCwtTPJyv16mDwmPrcuEQwpxqZHeINvcsd7oK5O/rhdGlxFRaZwvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.0.0" + }, + "engines": { + "node": "^20.12.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "jest": "*", + "typescript": ">=4.8.4 <7.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-n": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.0.1.tgz", + "integrity": "sha512-q3ARhk+eZRc7myR0KHx+R3/GJeOHF+Ir6PK95Pu2tEX8Sl/4BIpmmVLva2kPrjC2gCmn6WHlHm+3yeo6Rxhycw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "globrex": "^0.1.2", + "ignore": "^5.3.2", + "semver": "^7.6.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.57.1", + "ts-declaration-location": "^1.0.6", + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "ts-declaration-location": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-package-json": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-package-json/-/eslint-plugin-package-json-1.3.0.tgz", + "integrity": "sha512-YC4lXD7sZJ5Pj8NrK9npvIBzMH9WMrkXb4VaBXRqyxTriCwqFcEJMX51K3TjkzLiXS3eUQ3CzimKWNPiSpq5tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@altano/repository-tools": "^2.0.1", + "change-case": "^5.4.4", + "detect-indent": "^7.0.2", + "detect-newline": "^4.0.1", + "eslint-fix-utils": "~0.4.1", + "eslint-json-compat-utils": "^0.2.3", + "jsonc-eslint-parser": "^3.1.0", + "package-json-validator": "^1.5.0", + "semver": "^7.7.3", + "sort-object-keys": "^2.0.0", + "sort-package-json": "^3.4.0" + }, + "engines": { + "node": "^22.22.2 || >=24.15.0" + }, + "peerDependencies": { + "@eslint/json": ">=1.0.0", + "eslint": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@eslint/json": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-package-json/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-perfectionist": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-5.9.0.tgz", + "integrity": "sha512-8TWzg02zmnBdZwCkWLi8jhzqXI+fE7Z/RwV8SL6xD45tJ8Bp3wGuYL2XtQgfe/Wd0eBqOUX+s6ey73IyszvKTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.58.2", + "natural-orderby": "^5.0.0" + }, + "engines": { + "node": "^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "eslint": "^8.45.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-4.0.3.tgz", + "integrity": "sha512-5drkJKLC9qQddIiaATV0e8+ygbUc7b0Ti6VB7M2d3jmKNh3X0RaiIJYTs3dr9xnlhlrxo+/s1FoO3Jgv6O/c7g==", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "builtin-modules": "^3.3.0", + "bytes": "^3.1.2", + "functional-red-black-tree": "^1.0.1", + "globals": "^17.4.0", + "jsx-ast-utils-x": "^0.1.0", + "lodash.merge": "^4.6.2", + "minimatch": "^10.2.5", + "scslre": "^0.3.0", + "semver": "^7.7.4", + "ts-api-utils": "^2.5.0", + "typescript": ">=5" + }, + "peerDependencies": { + "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/globals": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "64.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-64.0.0.tgz", + "integrity": "sha512-rNZwalHh8i0UfPlhNwg5BTUO1CMdKNmjqe+TgzOTZnpKoi8VBgsW7u9qCHIdpxEzZ1uwrJrPF0uRb7l//K38gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "@eslint-community/eslint-utils": "^4.9.1", + "change-case": "^5.4.4", + "ci-info": "^4.4.0", + "clean-regexp": "^1.0.0", + "core-js-compat": "^3.49.0", + "find-up-simple": "^1.0.1", + "globals": "^17.4.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.13.0", + "semver": "^7.7.4", + "strip-indent": "^4.1.1" + }, + "engines": { + "node": "^20.10.0 || >=21.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=9.38.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-yml": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-3.4.0.tgz", + "integrity": "sha512-j6U3ESrAkidkvNb3HFN2UMxke46GNp6bsJokabXCICcgomSy3YU4oED9cjzkZ58nYxWD5qnWV1b/2YlqyWMOxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/core": "^1.0.1", + "@eslint/plugin-kit": "^0.7.0", + "@ota-meshi/ast-token-store": "^0.3.0", + "diff-sequences": "^29.0.0", + "escape-string-regexp": "5.0.0", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^2.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=9.38.0" + } + }, + "node_modules/eslint-plugin-yml/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.0.0.tgz", + "integrity": "sha512-PFhhIGgdM79r5Uztdj9Zb6Tt1zKafqVfdMGwVca1z5z6fbX7DmsySSuJd8HiP6I1j505DCS83cLxo5rmSNeVEA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz", + "integrity": "sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, + "node_modules/front-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/front-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/gensequence": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-8.0.8.tgz", + "integrity": "sha512-omMVniXEXpdx/vKxGnPRoO2394Otlze28TyxECbFVyoSpZ9H3EO7lemjcB12OpQJzRW4e5tt/dL1rOxry6aMHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "get-pkg-repo": "src/cli.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-pkg-repo/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/get-pkg-repo/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/git-hooks-list": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.2.1.tgz", + "integrity": "sha512-WNvqJjOxxs/8ZP9+DWdwWJ7cDsd60NHf39XnD82pDVrKO5q7xfPqpkK6hwEAmBa/ZSEE4IOoR75EzbbIuwGlMw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/fisker/git-hooks-list?sponsor=1" + } + }, + "node_modules/git-raw-commits": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", + "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^7.0.0", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-remote-origin-url/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/git-semver-tags": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-5.0.1.tgz", + "integrity": "sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^8.1.2", + "semver": "^7.0.0" + }, + "bin": { + "git-semver-tags": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/git-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-ssh": "^1.4.0", + "parse-url": "^8.1.0" + } + }, + "node_modules/git-url-parse": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-14.0.0.tgz", + "integrity": "sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "git-up": "^7.0.0" + } + }, + "node_modules/gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", + "dev": true, + "license": "BSD", + "dependencies": { + "ini": "^1.3.2" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-directory": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", + "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "6.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", + "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/init-package-json": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-6.0.3.tgz", + "integrity": "sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^5.0.0", + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^3.0.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-builtin-module": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", + "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^5.0.0" + }, + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-builtin-module/node_modules/builtin-modules": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.2.0.tgz", + "integrity": "sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-safe-filename": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", + "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ssh": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", + "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.1" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-nice": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", + "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-eslint-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-3.1.0.tgz", + "integrity": "sha512-75EA7EWZExL/j+MDKQrRbdzcRI2HOkRlmUw8fZJc1ioqFEOvBsq7Rt+A6yCxOt9w/TYNpkt52gC6nm/g5tFIng==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^5.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsx-ast-utils-x": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils-x/-/jsx-ast-utils-x-0.1.0.tgz", + "integrity": "sha512-eQQBjBnsVtGacsG9uJNB8qOr3yA8rga4wAaGG1qRcBzSIvfhERLrWxMAM1hp5fcS6Abo8M4+bUBTekYR0qTPQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/just-diff": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", + "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", + "dev": true, + "license": "MIT" + }, + "node_modules/just-diff-apply": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", + "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lerna": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-8.2.4.tgz", + "integrity": "sha512-0gaVWDIVT7fLfprfwpYcQajb7dBJv3EGavjG7zvJ+TmGx3/wovl5GklnSwM2/WeE0Z2wrIz7ndWhBcDUHVjOcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lerna/create": "8.2.4", + "@npmcli/arborist": "7.5.4", + "@npmcli/package-json": "5.2.0", + "@npmcli/run-script": "8.1.0", + "@nx/devkit": ">=17.1.2 < 21", + "@octokit/plugin-enterprise-rest": "6.0.1", + "@octokit/rest": "20.1.2", + "aproba": "2.0.0", + "byte-size": "8.1.1", + "chalk": "4.1.0", + "clone-deep": "4.0.1", + "cmd-shim": "6.0.3", + "color-support": "1.1.3", + "columnify": "1.6.0", + "console-control-strings": "^1.1.0", + "conventional-changelog-angular": "7.0.0", + "conventional-changelog-core": "5.0.1", + "conventional-recommended-bump": "7.0.1", + "cosmiconfig": "9.0.0", + "dedent": "1.5.3", + "envinfo": "7.13.0", + "execa": "5.0.0", + "fs-extra": "^11.2.0", + "get-port": "5.1.1", + "get-stream": "6.0.0", + "git-url-parse": "14.0.0", + "glob-parent": "6.0.2", + "graceful-fs": "4.2.11", + "has-unicode": "2.0.1", + "import-local": "3.1.0", + "ini": "^1.3.8", + "init-package-json": "6.0.3", + "inquirer": "^8.2.4", + "is-ci": "3.0.1", + "is-stream": "2.0.0", + "jest-diff": ">=29.4.3 < 30", + "js-yaml": "4.1.0", + "libnpmaccess": "8.0.6", + "libnpmpublish": "9.0.9", + "load-json-file": "6.2.0", + "make-dir": "4.0.0", + "minimatch": "3.0.5", + "multimatch": "5.0.0", + "node-fetch": "2.6.7", + "npm-package-arg": "11.0.2", + "npm-packlist": "8.0.2", + "npm-registry-fetch": "^17.1.0", + "nx": ">=17.1.2 < 21", + "p-map": "4.0.0", + "p-map-series": "2.1.0", + "p-pipe": "3.1.0", + "p-queue": "6.6.2", + "p-reduce": "2.1.0", + "p-waterfall": "2.1.1", + "pacote": "^18.0.6", + "pify": "5.0.0", + "read-cmd-shim": "4.0.0", + "resolve-from": "5.0.0", + "rimraf": "^4.4.1", + "semver": "^7.3.8", + "set-blocking": "^2.0.0", + "signal-exit": "3.0.7", + "slash": "3.0.0", + "ssri": "^10.0.6", + "string-width": "^4.2.3", + "tar": "6.2.1", + "temp-dir": "1.0.0", + "through": "2.3.8", + "tinyglobby": "0.2.12", + "typescript": ">=3 < 6", + "upath": "2.0.1", + "uuid": "^10.0.0", + "validate-npm-package-license": "3.0.4", + "validate-npm-package-name": "5.0.1", + "wide-align": "1.1.5", + "write-file-atomic": "5.0.1", + "write-pkg": "4.0.0", + "yargs": "17.7.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "lerna": "dist/cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/lerna/node_modules/@nx/nx-darwin-arm64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.8.4.tgz", + "integrity": "sha512-8Y7+4wj1qoZsuDRpnuiHzSIsMt3VqtJ0su8dgd/MyGccvvi4pndan2R5yTiVw/wmbMxtBmZ6PO6Z8dgSIrMVog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-darwin-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.8.4.tgz", + "integrity": "sha512-2lfuxRc56QWnAysMhcD03tpCPiRzV1+foUq0MhV2sSBIybXmgV4wHLkPZNhlBCl4FNXrWiZiN1OJ2X9AGiOdug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-freebsd-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.8.4.tgz", + "integrity": "sha512-99vnUXZy+OUBHU+8Yhabre2qafepKg9GKkQkhmXvJGqOmuIsepK7wirUFo2PiVM8YhS6UV2rv6hKAZcQ7skYyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.8.4.tgz", + "integrity": "sha512-dht73zpnpzEUEzMHFQs4mfiwZH3WcJgQNWkD5p7WkeJewHq2Yyd0eG5Jg3kB7wnFtwPUV1eNJRM5rephgylkLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-arm64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.8.4.tgz", + "integrity": "sha512-syXxbJZ0yPaqzVmB28QJgUtaarSiW/PQmv/5Z2Ps8rCi7kYylISPVNjP1NNiIOcGDRWbHqoBfM0bEGPfSp0rBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-arm64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.8.4.tgz", + "integrity": "sha512-AlZZFolS/S0FahRKG7rJ0Z9CgmIkyzHgGaoy3qNEMDEjFhR3jt2ZZSLp90W7zjgrxojOo90ajNMrg2UmtcQRDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-x64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.8.4.tgz", + "integrity": "sha512-MSu+xVNdR95tuuO+eL/a/ZeMlhfrZ627On5xaCZXnJ+lFxNg/S4nlKZQk0Eq5hYALCd/GKgFGasRdlRdOtvGPg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-x64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.8.4.tgz", + "integrity": "sha512-KxpQpyLCgIIHWZ4iRSUN9ohCwn1ZSDASbuFCdG3mohryzCy8WrPkuPcb+68J3wuQhmA5w//Xpp/dL0hHoit9zQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-win32-arm64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.8.4.tgz", + "integrity": "sha512-ffLBrxM9ibk+eWSY995kiFFRTSRb9HkD5T1s/uZyxV6jfxYPaZDBAWAETDneyBXps7WtaOMu+kVZlXQ3X+TfIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-win32-x64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.8.4.tgz", + "integrity": "sha512-JxuuZc4h8EBqoYAiRHwskimpTJx70yn4lhIRFBoW5ICkxXW1Rw0yip/1UVsWRHXg/x9BxmH7VVazdfaQWmGu6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/lerna/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/lerna/node_modules/nx": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/nx/-/nx-20.8.4.tgz", + "integrity": "sha512-/++x0OM3/UTmDR+wmPeV13tSxeTr+QGzj3flgtH9DiOPmQnn2CjHWAMZiOhcSh/hHoE/V3ySL4757InQUsVtjQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@napi-rs/wasm-runtime": "0.2.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.2", + "@zkochan/js-yaml": "0.0.7", + "axios": "^1.8.3", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "front-matter": "^4.0.2", + "ignore": "^5.0.4", + "jest-diff": "^29.4.1", + "jsonc-parser": "3.2.0", + "lines-and-columns": "2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "resolve.exports": "2.0.3", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "yaml": "^2.6.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "20.8.4", + "@nx/nx-darwin-x64": "20.8.4", + "@nx/nx-freebsd-x64": "20.8.4", + "@nx/nx-linux-arm-gnueabihf": "20.8.4", + "@nx/nx-linux-arm64-gnu": "20.8.4", + "@nx/nx-linux-arm64-musl": "20.8.4", + "@nx/nx-linux-x64-gnu": "20.8.4", + "@nx/nx-linux-x64-musl": "20.8.4", + "@nx/nx-win32-arm64-msvc": "20.8.4", + "@nx/nx-win32-x64-msvc": "20.8.4" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/lerna/node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lerna/node_modules/ora": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lerna/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lerna/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libnpmaccess": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-8.0.6.tgz", + "integrity": "sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^11.0.2", + "npm-registry-fetch": "^17.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/libnpmpublish": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-9.0.9.tgz", + "integrity": "sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==", + "dev": true, + "license": "ISC", + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.1", + "npm-package-arg": "^11.0.2", + "npm-registry-fetch": "^17.0.1", + "proc-log": "^4.2.0", + "semver": "^7.3.7", + "sigstore": "^2.2.0", + "ssri": "^10.0.6" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/load-json-file/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.28.1.tgz", + "integrity": "sha512-U9w+PzSZ00Z5m9rZ5ARVFL5xOfuCHdKYi/1RRwDCJsboFgJDNT3zT6PIPD7mZQYaQLhsZM3GfDRgSMRHhSmVng==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/module-replacements": { + "version": "3.0.0-beta.8", + "resolved": "https://registry.npmjs.org/module-replacements/-/module-replacements-3.0.0-beta.8.tgz", + "integrity": "sha512-sc8TepP9elxoOBXEpxmhPzKKjTjbswHVcmsKGbgvm3k6jZlLu/WMV/Lfmga6IGMgHU/V3WtY2s6VEgM4nTElUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/multimatch/node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-orderby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-5.0.0.tgz", + "integrity": "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.3.1.tgz", + "integrity": "sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^4.1.0", + "semver": "^7.3.5", + "tar": "^6.2.1", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-machine-id": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", + "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", + "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", + "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^2.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nx": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/nx/-/nx-21.6.11.tgz", + "integrity": "sha512-AAgJGhS+7xlsmZF6ArKX1vgONxf7IymUYZ1BxGXHVa5927rGfgKoMaPOgwwtvN0OL3o/QYaNGwlDfIzCvlpOLQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@napi-rs/wasm-runtime": "0.2.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.2", + "@zkochan/js-yaml": "0.0.7", + "axios": "^1.12.0", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "front-matter": "^4.0.2", + "ignore": "^5.0.4", + "jest-diff": "^30.0.2", + "jsonc-parser": "3.2.0", + "lines-and-columns": "2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "resolve.exports": "2.0.3", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tree-kill": "^1.2.2", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "yaml": "^2.6.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "21.6.11", + "@nx/nx-darwin-x64": "21.6.11", + "@nx/nx-freebsd-x64": "21.6.11", + "@nx/nx-linux-arm-gnueabihf": "21.6.11", + "@nx/nx-linux-arm64-gnu": "21.6.11", + "@nx/nx-linux-arm64-musl": "21.6.11", + "@nx/nx-linux-x64-gnu": "21.6.11", + "@nx/nx-linux-x64-musl": "21.6.11", + "@nx/nx-win32-arm64-msvc": "21.6.11", + "@nx/nx-win32-x64-msvc": "21.6.11" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/nx/node_modules/@jest/schemas": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/nx/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/nx/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/nx/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/nx/node_modules/jest-diff": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", + "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/diff-sequences": "30.4.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nx/node_modules/ora": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nx/node_modules/pretty-format": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "30.4.1", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/nx/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nx/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz", + "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-pipe": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", + "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-waterfall": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz", + "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/package-json-validator": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/package-json-validator/-/package-json-validator-1.5.2.tgz", + "integrity": "sha512-eHXskJQU4aCiSfjhRfTVtCJ+22/EzLHgYgZv5Gj3teb3NJrnTMzq5BnKAWKvR+PLpknCO1PmOCImDuO+dX4Vaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "npm-package-arg": "^13.0.2", + "semver": "^7.7.2", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/package-json-validator/node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/package-json-validator/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/package-json-validator/node_modules/npm-package-arg": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", + "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/package-json-validator/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/package-json-validator/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/package-json-validator/node_modules/validate-npm-package-name": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", + "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/pacote": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", + "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/package-json": "^5.1.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^8.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-conflict-json": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz", + "integrity": "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-json/node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-path": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.0" + } + }, + "node_modules/parse-url": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-path": "^7.0.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", + "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/proggy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proggy/-/proggy-2.0.0.tgz", + "integrity": "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/promise-call-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.2.tgz", + "integrity": "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promzard": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-1.0.2.tgz", + "integrity": "sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "read": "^3.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/protocols": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/react-is-19": { + "name": "react-is", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", + "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/read": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz", + "integrity": "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-cmd-shim": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", + "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/refa": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", + "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-ast-analysis": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", + "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.1" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regjsparser": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", + "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.7.tgz", + "integrity": "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scslre": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", + "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.0", + "regexp-ast-analysis": "^0.7.0" + }, + "engines": { + "node": "^14.0.0 || >=16.0.0" + } + }, + "node_modules/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sigstore": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", + "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^2.3.2", + "@sigstore/tuf": "^2.3.4", + "@sigstore/verify": "^1.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/smol-toml": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", + "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sort-object-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-2.1.0.tgz", + "integrity": "sha512-SOiEnthkJKPv2L6ec6HMwhUcN0/lppkeYuN1x63PbyPRrgSPIuBJCiYxYyvWRTtjMlOi14vQUCGUJqS6PLVm8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/sort-package-json": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.7.1.tgz", + "integrity": "sha512-ssk1HG7whF8N/T1IsNAQrtHG5Cbdi0rAgRJZXYBr9hF5xaHnBNzUx/W6LcthEW7FhOwvZssbESZuO+GxssqAyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-indent": "^7.0.2", + "detect-newline": "^4.0.1", + "git-hooks-list": "^4.1.1", + "is-plain-obj": "^4.1.0", + "semver": "^7.7.3", + "sort-object-keys": "^2.0.1", + "tinyglobby": "^0.2.15" + }, + "bin": { + "sort-package-json": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/sort-package-json/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sort-package-json/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sort-package-json/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.3.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tempy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.0.tgz", + "integrity": "sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", + "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/treeverse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", + "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tuf-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", + "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "2.0.1", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", + "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.60.1", + "@typescript-eslint/parser": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", + "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/typescript-eslint/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/typescript-eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript-eslint/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript-eslint/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true, + "license": "ISC" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/write-json-file": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", + "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.15", + "make-dir": "^2.1.0", + "pify": "^4.0.1", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-json-file/node_modules/detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/write-json-file/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-json-file/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/write-json-file/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/write-json-file/node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/write-pkg": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz", + "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sort-keys": "^2.0.0", + "type-fest": "^0.4.1", + "write-json-file": "^3.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/write-pkg/node_modules/type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=6" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yaml-eslint-parser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-2.0.0.tgz", + "integrity": "sha512-h0uDm97wvT2bokfwwTmY6kJ1hp6YDFL0nRHwNKz8s/VD1FH/vvZjAKoMUE+un0eaYBSG7/c6h+lJTP+31tjgTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^5.0.0", + "yaml": "^2.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3ca96cb --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "@lvce-editor/explorer-view-monorepo", + "version": "0.0.0-dev", + "license": "MIT", + "type": "module", + "scripts": { + "build": "node packages/build/src/build.ts", + "build:static": "node packages/build/src/build-static.ts", + "build:watch": "./packages/build/node_modules/.bin/esbuild --format=esm --bundle --external:node:buffer --external:electron --external:ws --external:node:worker_threads --watch packages/explorer-view/src/explorerViewWorkerMain.ts --outfile=.tmp/dist/dist/explorerViewWorkerMain.js", + "dev": "node packages/build/src/dev.ts", + "e2e": "cd packages/e2e && npm run e2e", + "format": "prettier --write .", + "postinstall": "lerna bootstrap --ci", + "lint": "eslint . && prettier --check .", + "measure": "cd packages/build && npm run measure", + "measure:visible": "cd packages/build && npm run measure:visible", + "test": "lerna run test", + "type-check": "tsc -b" + }, + "prettier": { + "semi": false, + "singleQuote": true, + "printWidth": 150 + }, + "devDependencies": { + "@lerna/legacy-package-management": "^8.2.4", + "@lvce-editor/eslint-config": "^11.2.0", + "eslint": "^10.2.0", + "lerna": "^8.2.4", + "prettier": "^3.8.4", + "typescript": "^6.0.3" + } +} diff --git a/packages/build/package-lock.json b/packages/build/package-lock.json new file mode 100644 index 0000000..a2844e4 --- /dev/null +++ b/packages/build/package-lock.json @@ -0,0 +1,3157 @@ +{ + "name": "build", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "build", + "version": "0.0.0-dev", + "license": "MIT", + "devDependencies": { + "@babel/preset-typescript": "^7.29.7", + "@lvce-editor/measure-memory": "^3.1.0", + "@lvce-editor/verror": "^1.7.0", + "@rollup/plugin-babel": "^7.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@types/node": "^25.5.0", + "esbuild": "^0.28.1", + "execa": "^9.6.1", + "rollup": "^4.60.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lvce-editor/measure-memory": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/measure-memory/-/measure-memory-3.1.0.tgz", + "integrity": "sha512-jLE+dCHktuRH0QrfLLbgLKhfiZ7M0JtYCq6ww6ho+/VkrplrMownnvnL/SvZzwu/Pm4Zp9ffUZ8XMkXg+zcVxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chrome-remote-interface": "^0.33.3", + "execa": "^9.6.1", + "express": "^5.2.1" + } + }, + "node_modules/@lvce-editor/verror": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/verror/-/verror-1.7.0.tgz", + "integrity": "sha512-+LGuAEIC2L7pbvkyAQVWM2Go0dAy+UWEui28g07zNtZsCBhm+gusBK8PNwLJLV5Jay+TyUYuwLIbJdjLLzqEBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-babel": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-7.1.0.tgz", + "integrity": "sha512-h9Y+xYha6p4wKO+FwdiPIkE+eIYCm8MzZPpX1iARIoFBnmKP9CnpT1p9dDf/DTFm6fyN8PmuLyRI5qZgchnitw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1", + "workerpool": "^9.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz", + "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz", + "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz", + "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz", + "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz", + "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz", + "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz", + "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz", + "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz", + "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz", + "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz", + "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz", + "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz", + "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz", + "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz", + "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz", + "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz", + "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz", + "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz", + "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz", + "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz", + "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz", + "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz", + "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz", + "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz", + "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0", + "peer": true + }, + "node_modules/chrome-remote-interface": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.3.tgz", + "integrity": "sha512-zNnn0prUL86Teru6UCAZ1yU1XeXljHl3gj7OrfPcarEfU62OUU4IujDPdTDW3dAWwRqN3ZMG/Chhkh2gPL/wiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "2.11.x", + "ws": "^7.2.0" + }, + "bin": { + "chrome-remote-interface": "bin/client.js" + } + }, + "node_modules/commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.372", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", + "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz", + "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.0", + "@rollup/rollup-android-arm64": "4.62.0", + "@rollup/rollup-darwin-arm64": "4.62.0", + "@rollup/rollup-darwin-x64": "4.62.0", + "@rollup/rollup-freebsd-arm64": "4.62.0", + "@rollup/rollup-freebsd-x64": "4.62.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.0", + "@rollup/rollup-linux-arm-musleabihf": "4.62.0", + "@rollup/rollup-linux-arm64-gnu": "4.62.0", + "@rollup/rollup-linux-arm64-musl": "4.62.0", + "@rollup/rollup-linux-loong64-gnu": "4.62.0", + "@rollup/rollup-linux-loong64-musl": "4.62.0", + "@rollup/rollup-linux-ppc64-gnu": "4.62.0", + "@rollup/rollup-linux-ppc64-musl": "4.62.0", + "@rollup/rollup-linux-riscv64-gnu": "4.62.0", + "@rollup/rollup-linux-riscv64-musl": "4.62.0", + "@rollup/rollup-linux-s390x-gnu": "4.62.0", + "@rollup/rollup-linux-x64-gnu": "4.62.0", + "@rollup/rollup-linux-x64-musl": "4.62.0", + "@rollup/rollup-openbsd-x64": "4.62.0", + "@rollup/rollup-openharmony-arm64": "4.62.0", + "@rollup/rollup-win32-arm64-msvc": "4.62.0", + "@rollup/rollup-win32-ia32-msvc": "4.62.0", + "@rollup/rollup-win32-x64-gnu": "4.62.0", + "@rollup/rollup-win32-x64-msvc": "4.62.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/packages/build/package.json b/packages/build/package.json new file mode 100644 index 0000000..1273c30 --- /dev/null +++ b/packages/build/package.json @@ -0,0 +1,25 @@ +{ + "name": "build", + "version": "0.0.0-dev", + "main": "index.js", + "type": "module", + "scripts": { + "measure": "node --experimental-strip-types src/measureMemory.ts", + "measure:visible": "node --experimental-strip-types src/measureMemory.ts --no-headless" + }, + "keywords": [], + "author": "", + "license": "MIT", + "description": "", + "devDependencies": { + "@babel/preset-typescript": "^7.29.7", + "@lvce-editor/measure-memory": "^3.1.0", + "@lvce-editor/verror": "^1.7.0", + "@rollup/plugin-babel": "^7.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@types/node": "^25.5.0", + "esbuild": "^0.28.1", + "execa": "^9.6.1", + "rollup": "^4.60.0" + } +} diff --git a/packages/build/src/build-static.ts b/packages/build/src/build-static.ts new file mode 100644 index 0000000..74a3f1e --- /dev/null +++ b/packages/build/src/build-static.ts @@ -0,0 +1,39 @@ +import { cp, readFile, writeFile } from 'node:fs/promises' +import { join } from 'node:path' +import { pathToFileURL } from 'node:url' +import { root } from './root.ts' + +const sharedProcessPath = join(root, 'packages', 'server', 'node_modules', '@lvce-editor', 'shared-process', 'index.js') + +const sharedProcessUrl = pathToFileURL(sharedProcessPath).toString() + +const sharedProcess = await import(sharedProcessUrl) + +process.env.PATH_PREFIX = '/explorer-view' +const { commitHash } = await sharedProcess.exportStatic({ + root, + extensionPath: '', + testPath: 'packages/e2e', +}) + +const rendererWorkerPath = join(root, 'dist', commitHash, 'packages', 'renderer-worker', 'dist', 'rendererWorkerMain.js') + +export const getRemoteUrl = (path: string): string => { + const url = pathToFileURL(path).toString().slice(8) + return `/remote/${url}` +} + +const content = await readFile(rendererWorkerPath, 'utf8') +const workerPath = join(root, '.tmp/dist/dist/explorerViewWorkerMain.js') +const remoteUrl = getRemoteUrl(workerPath) + +const occurrence = `// const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\` +const explorerWorkerUrl = \`${remoteUrl}\`` +const replacement = `const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\`` +if (!content.includes(occurrence)) { + throw new Error('occurrence not found') +} +const newContent = content.replace(occurrence, replacement) +await writeFile(rendererWorkerPath, newContent) + +await cp(join(root, 'dist'), join(root, '.tmp', 'static'), { recursive: true }) diff --git a/packages/build/src/build.ts b/packages/build/src/build.ts new file mode 100644 index 0000000..ddce738 --- /dev/null +++ b/packages/build/src/build.ts @@ -0,0 +1,74 @@ +import { execa } from 'execa' +import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { join } from 'node:path' +import { bundleJs } from './bundleJs.ts' +import { root } from './root.ts' + +const dist = join(root, '.tmp', 'dist') + +const readJson = async (path: string): Promise => { + const content = await readFile(path, 'utf8') + return JSON.parse(content) +} + +const writeJson = async (path: string, json: any): Promise => { + await writeFile(path, JSON.stringify(json, null, 2) + '\n') +} + +const getGitTagFromGit = async (): Promise => { + const { stdout, stderr, exitCode } = await execa('git', ['describe', '--exact-match', '--tags'], { + reject: false, + }) + if (exitCode) { + if (exitCode === 128 && stderr.startsWith('fatal: no tag exactly matches')) { + return '0.0.0-dev' + } + return '0.0.0-dev' + } + if (stdout.startsWith('v')) { + return stdout.slice(1) + } + return stdout +} + +const getVersion = async (): Promise => { + const { env } = process + const { RG_VERSION, GIT_TAG } = env + if (RG_VERSION) { + if (RG_VERSION.startsWith('v')) { + return RG_VERSION.slice(1) + } + return RG_VERSION + } + if (GIT_TAG) { + if (GIT_TAG.startsWith('v')) { + return GIT_TAG.slice(1) + } + return GIT_TAG + } + return getGitTagFromGit() +} + +await rm(dist, { recursive: true, force: true }) +await mkdir(dist, { recursive: true }) + +await bundleJs() + +const version = await getVersion() + +const packageJson = await readJson(join(root, 'packages', 'explorer-view', 'package.json')) + +delete packageJson.scripts +delete packageJson.devDependencies +delete packageJson.prettier +delete packageJson.jest +delete packageJson.xo +delete packageJson.directories +delete packageJson.nodemonConfig +packageJson.version = version +packageJson.main = 'dist/explorerViewWorkerMain.js' + +await writeJson(join(dist, 'package.json'), packageJson) + +await cp(join(root, 'README.md'), join(dist, 'README.md')) +await cp(join(root, 'LICENSE'), join(dist, 'LICENSE')) diff --git a/packages/build/src/bundleJs.ts b/packages/build/src/bundleJs.ts new file mode 100644 index 0000000..67bcbc5 --- /dev/null +++ b/packages/build/src/bundleJs.ts @@ -0,0 +1,37 @@ +import pluginTypeScript from '@babel/preset-typescript' +import { babel } from '@rollup/plugin-babel' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import { join } from 'path' +import { rollup, type RollupOptions } from 'rollup' +import { root } from './root.ts' + +const options: RollupOptions = { + input: join(root, 'packages/explorer-view/src/explorerViewWorkerMain.ts'), + preserveEntrySignatures: 'strict', + treeshake: { + propertyReadSideEffects: false, + }, + output: { + file: join(root, '.tmp/dist/dist/explorerViewWorkerMain.js'), + format: 'es', + freeze: false, + generatedCode: { + constBindings: true, + objectShorthand: true, + }, + }, + external: ['ws', 'electron'], + plugins: [ + babel({ + babelHelpers: 'bundled', + extensions: ['.js', '.jsx', '.ts', '.tsx'], + presets: [pluginTypeScript], + }), + nodeResolve(), + ], +} + +export const bundleJs = async (): Promise => { + const input = await rollup(options) + await input.write(options.output as any) +} diff --git a/packages/build/src/computeNodeModulesCacheKey.ts b/packages/build/src/computeNodeModulesCacheKey.ts new file mode 100644 index 0000000..ab1e87d --- /dev/null +++ b/packages/build/src/computeNodeModulesCacheKey.ts @@ -0,0 +1,67 @@ +import { createHash } from 'node:crypto' +import { readdirSync } from 'node:fs' +import { readFile } from 'node:fs/promises' +import { join } from 'node:path' +import { root } from './root.ts' + +const getPackageLocations = (): string[] => { + const packageLocations: string[] = [] + const packagesFolder = join(root, 'packages') + const dirents = readdirSync(packagesFolder) + for (const dirent of dirents) { + packageLocations.push(`packages/${dirent}/package-lock.json`) + } + packageLocations.push('package-lock.json') + return packageLocations +} + +const locations: string[] = [ + 'lerna.json', + ...getPackageLocations(), + '.github/workflows/pr.yml', + '.github/workflows/ci.yml', + '.github/workflows/release.yml', + 'packages/build/src/computeNodeModulesCacheKey.ts', + 'packages/server/src/postinstall.js', +] + +const packagesFolder = join(root, 'packages') + +const dirents = readdirSync(packagesFolder) +for (const dirent of dirents) { + locations.push(`packages/${dirent}/package-lock.json`) +} + +const getAbsolutePath = (relativePath: string): string => { + return join(root, relativePath) +} + +const getContent = (absolutePath: string): Promise => { + return readFile(absolutePath, 'utf8') +} + +export const computeHash = (contents: string | string[]): string => { + const hash = createHash('sha1') + if (Array.isArray(contents)) { + for (const content of contents) { + hash.update(content) + } + } else if (typeof contents === 'string') { + hash.update(contents) + } + return hash.digest('hex') +} + +const computeCacheKey = async (locations: string[]): Promise => { + const absolutePaths = locations.map(getAbsolutePath) + const contents = await Promise.all(absolutePaths.map(getContent)) + const hash = computeHash(contents) + return hash +} + +const main = async (): Promise => { + const hash = await computeCacheKey(locations) + process.stdout.write(hash) +} + +main() diff --git a/packages/build/src/dev.ts b/packages/build/src/dev.ts new file mode 100644 index 0000000..c427969 --- /dev/null +++ b/packages/build/src/dev.ts @@ -0,0 +1,15 @@ +import { execa } from 'execa' +import { root } from './root.ts' + +const main = async (): Promise => { + execa(`npm`, ['run', 'build:watch'], { + cwd: root, + stdio: 'inherit', + }) + execa('node', ['packages/server/node_modules/@lvce-editor/server/bin/server.js', '--test-path=packages/e2e'], { + cwd: root, + stdio: 'inherit', + }) +} + +main() diff --git a/packages/build/src/measureMemory.ts b/packages/build/src/measureMemory.ts new file mode 100644 index 0000000..db99ef7 --- /dev/null +++ b/packages/build/src/measureMemory.ts @@ -0,0 +1,21 @@ +import { measureMemory } from '@lvce-editor/measure-memory' +import { join } from 'node:path' +import { root } from './root.ts' + +const threshold = 570_000 + +const instantiations = 9000 + +const instantiationsPath = join(root, 'packages', 'explorer-view') + +const workerPath = join(root, '.tmp/dist/dist/explorerViewWorkerMain.js') + +const playwrightPath = import.meta.resolve('../../e2e/node_modules/playwright/index.mjs') + +await measureMemory({ + playwrightPath, + workerPath, + threshold, + instantiations, + instantiationsPath, +}) diff --git a/packages/build/src/root.ts b/packages/build/src/root.ts new file mode 100644 index 0000000..6a29f4c --- /dev/null +++ b/packages/build/src/root.ts @@ -0,0 +1,5 @@ +import { join } from 'node:path' + +const __dirname = import.meta.dirname + +export const root: string = join(__dirname, '..', '..', '..') diff --git a/packages/build/tsconfig.json b/packages/build/tsconfig.json new file mode 100644 index 0000000..a80b0c5 --- /dev/null +++ b/packages/build/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "lib": ["esnext"], + "checkJs": true, + "target": "esnext", + "types": ["node"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "skipLibCheck": true, + "noEmit": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "assumeChangesOnlyAffectDirectDependencies": true, + "strict": true, + "noImplicitAny": false, + "composite": true, + "allowImportingTsExtensions": true, + "rootDir": ".", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noUnusedLocals": true + }, + "include": ["src", "test"] +} diff --git a/packages/e2e/extension/extension.json b/packages/e2e/extension/extension.json new file mode 100644 index 0000000..600e5f1 --- /dev/null +++ b/packages/e2e/extension/extension.json @@ -0,0 +1,3 @@ +{ + "name": "test" +} diff --git a/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json b/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json new file mode 100644 index 0000000..3cbd42b --- /dev/null +++ b/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js b/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js new file mode 100644 index 0000000..6b4225f --- /dev/null +++ b/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js @@ -0,0 +1,31 @@ +const contents = Object.create(null) + +class FileNotFoundError extends Error { + constructor(uri) { + super(`File not found`) + this.name = 'FileNotFoundError' + this.code = 'ENOENT' + } +} + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + }, + rename(oldUri, newUri) {}, + readFile(uri) { + return contents[uri] + }, + pathSeparator: '/', + readDirWithFileTypes(uri) { + throw new FileNotFoundError(uri) + }, + remove(uri) { + throw new Error(`oops`) + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json new file mode 100644 index 0000000..3cbd42b --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js new file mode 100644 index 0000000..5d88002 --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js @@ -0,0 +1,33 @@ +const contents = Object.create(null) + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + + if (uri.endsWith('/file4.txt')) { + throw new Error(`Error: Failed to write to file "${uri}": EACCES: permission denied, open '${uri}'`) + } + }, + rename(oldUri, newUri) { + throw new Error(`Permission Denied`) + }, + readFile(uri) {}, + pathSeparator: '/', + readDirWithFileTypes(uri) { + const results = [] + for (const [key, value] of Object.entries(contents)) { + if (key.startsWith(uri)) { + results.push({ + type: 7, + name: key.slice(key.lastIndexOf('/')), + }) + } + } + return results + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json new file mode 100644 index 0000000..3cbd42b --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js new file mode 100644 index 0000000..f7e987f --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js @@ -0,0 +1,32 @@ +const contents = Object.create(null) + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + if (uri === '/file4.txt') { + throw new Error(`Permission Denied`) + } + }, + rename(oldUri, newUri) { + throw new Error(`Permission Denied`) + }, + readFile(uri) {}, + pathSeparator: '/', + readDirWithFileTypes(uri) { + const results = [] + for (const [key, value] of Object.entries(contents)) { + if (key.startsWith(uri)) { + results.push({ + type: 7, + name: key.slice(key.lastIndexOf('/')), + }) + } + } + return results + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json b/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json new file mode 100644 index 0000000..3cbd42b --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js b/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js new file mode 100644 index 0000000..ab3c426 --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js @@ -0,0 +1,30 @@ +const contents = Object.create(null) + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + }, + rename(oldUri, newUri) {}, + readFile(uri) {}, + pathSeparator: '/', + readDirWithFileTypes(uri) { + const results = [] + for (const [key, value] of Object.entries(contents)) { + if (key.startsWith(uri)) { + results.push({ + type: 7, + name: key.slice(key.lastIndexOf('/')), + }) + } + } + return results + }, + remove(uri) { + throw new Error(`oops`) + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json new file mode 100644 index 0000000..600e5f1 --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json @@ -0,0 +1,3 @@ +{ + "name": "test" +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js new file mode 100644 index 0000000..c6e9859 --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js @@ -0,0 +1,36 @@ +// @ts-nocheck +const rootUri = 'extension-host://xyz://' +const folderUri = `${rootUri}stress-folder` +const folderEntry = { + type: 2, + name: 'stress-folder', +} +const totalItems = 10_000_000 + +const fileSystemProvider = { + id: 'xyz', + pathSeparator: '/', + rename() {}, + readFile() { + return '' + }, + writeFile() {}, + readDirWithFileTypes(uri) { + if (uri === rootUri) { + return [folderEntry] + } + if (uri === folderUri) { + return Array.from({ length: totalItems }, (_, index) => { + return { + type: 1, + name: `item-${index.toString().padStart(8, '0')}.txt`, + } + }) + } + return [] + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json new file mode 100644 index 0000000..600e5f1 --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json @@ -0,0 +1,3 @@ +{ + "name": "test" +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js new file mode 100644 index 0000000..27af635 --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js @@ -0,0 +1,36 @@ +// @ts-nocheck +const rootUri = 'extension-host://xyz://' +const folderUri = `${rootUri}stress-folder` +const folderEntry = { + type: 2, + name: 'stress-folder', +} +const totalItems = 1_000_000 + +const fileSystemProvider = { + id: 'xyz', + pathSeparator: '/', + rename() {}, + readFile() { + return '' + }, + writeFile() {}, + readDirWithFileTypes(uri) { + if (uri === rootUri) { + return [folderEntry] + } + if (uri === folderUri) { + return Array.from({ length: totalItems }, (_, index) => { + return { + type: 1, + name: `item-${index.toString().padStart(7, '0')}.txt`, + } + }) + } + return [] + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-permission/extension.json b/packages/e2e/fixtures/sample.file-system-provider-permission/extension.json new file mode 100644 index 0000000..3cbd42b --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-permission/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample.file-system-provider-permission/main.js b/packages/e2e/fixtures/sample.file-system-provider-permission/main.js new file mode 100644 index 0000000..b0a026b --- /dev/null +++ b/packages/e2e/fixtures/sample.file-system-provider-permission/main.js @@ -0,0 +1,29 @@ +const contents = Object.create(null) + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + }, + rename(oldUri, newUri) { + throw new Error(`Permission Denied`) + }, + readFile(uri) {}, + pathSeparator: '/', + readDirWithFileTypes(uri) { + const results = [] + for (const [key, value] of Object.entries(contents)) { + if (key.startsWith(uri)) { + results.push({ + type: 7, + name: key.slice(key.lastIndexOf('/')), + }) + } + } + return results + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) +} diff --git a/packages/e2e/fixtures/sample.icon-theme/extension.json b/packages/e2e/fixtures/sample.icon-theme/extension.json new file mode 100644 index 0000000..9233c12 --- /dev/null +++ b/packages/e2e/fixtures/sample.icon-theme/extension.json @@ -0,0 +1,8 @@ +{ + "iconThemes": [ + { + "id": "test-icon-theme", + "path": "icon-theme.json" + } + ] +} diff --git a/packages/e2e/fixtures/sample.icon-theme/icon-theme.json b/packages/e2e/fixtures/sample.icon-theme/icon-theme.json new file mode 100644 index 0000000..c53d17b --- /dev/null +++ b/packages/e2e/fixtures/sample.icon-theme/icon-theme.json @@ -0,0 +1,6 @@ +{ + "iconDefinitions": { + "_file": "/icons/default_file.svg", + "_folder": "/icons/default_folder.svg" + } +} diff --git a/packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg b/packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg new file mode 100644 index 0000000..e916d41 --- /dev/null +++ b/packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg b/packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg new file mode 100644 index 0000000..d28e7dd --- /dev/null +++ b/packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json b/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json new file mode 100644 index 0000000..95b15b6 --- /dev/null +++ b/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz", "onSourceControl:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js b/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js new file mode 100644 index 0000000..73bf887 --- /dev/null +++ b/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js @@ -0,0 +1,50 @@ +const contents = Object.create(null) + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + }, + mkdir(uri) { + contents[uri] = '' + }, + rename(oldUri, newUri) {}, + readFile(uri) {}, + exists(uri) { + return false + }, + pathSeparator: '/', + readDirWithFileTypes(uri) { + const results = [] + for (const [key, value] of Object.entries(contents)) { + if (key.startsWith(uri)) { + results.push({ + type: 7, + name: key.slice(key.lastIndexOf('/') + 1), + }) + } + } + return results + }, +} + +const sourceControlProvider = { + id: 'xyz', + getChangedFiles() { + return [] + }, + getBadgeCount() { + return 0 + }, + getFileDecorations(uris) { + return null + }, + isActive() { + return true + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) + vscode.registerSourceControlProvider(sourceControlProvider) +} diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json b/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json new file mode 100644 index 0000000..95b15b6 --- /dev/null +++ b/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz", "onSourceControl:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js b/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js new file mode 100644 index 0000000..3b3b85e --- /dev/null +++ b/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js @@ -0,0 +1,50 @@ +const contents = Object.create(null) + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + }, + mkdir(uri) { + contents[uri] = '' + }, + rename(oldUri, newUri) {}, + readFile(uri) {}, + exists(uri) { + return false + }, + pathSeparator: '/', + readDirWithFileTypes(uri) { + const results = [] + for (const [key, value] of Object.entries(contents)) { + if (key.startsWith(uri)) { + results.push({ + type: 7, + name: key.slice(key.lastIndexOf('/') + 1), + }) + } + } + return results + }, +} + +const sourceControlProvider = { + id: 'xyz', + getChangedFiles() { + return [] + }, + getBadgeCount() { + return 0 + }, + getFileDecorations(uris) { + return {} + }, + isActive() { + return true + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) + vscode.registerSourceControlProvider(sourceControlProvider) +} diff --git a/packages/e2e/fixtures/sample.source-control-decoration/extension.json b/packages/e2e/fixtures/sample.source-control-decoration/extension.json new file mode 100644 index 0000000..95b15b6 --- /dev/null +++ b/packages/e2e/fixtures/sample.source-control-decoration/extension.json @@ -0,0 +1,10 @@ +{ + "browser": "main.js", + "main": "main.js", + "activation": ["onFileSystem:xyz", "onSourceControl:xyz"], + "fileSystems": [ + { + "scheme": "xyz" + } + ] +} diff --git a/packages/e2e/fixtures/sample.source-control-decoration/main.js b/packages/e2e/fixtures/sample.source-control-decoration/main.js new file mode 100644 index 0000000..8f344c6 --- /dev/null +++ b/packages/e2e/fixtures/sample.source-control-decoration/main.js @@ -0,0 +1,57 @@ +const contents = Object.create(null) + +const fileSystemProvider = { + id: 'xyz', + writeFile(uri, content) { + contents[uri] = content + }, + mkdir(uri) { + contents[uri] = '' + }, + rename(oldUri, newUri) {}, + readFile(uri) {}, + exists(uri) { + return false + }, + pathSeparator: '/', + readDirWithFileTypes(uri) { + const results = [] + for (const [key, value] of Object.entries(contents)) { + if (key.startsWith(uri)) { + results.push({ + type: 7, + name: key.slice(key.lastIndexOf('/') + 1), + }) + } + } + return results + }, +} + +const sourceControlProvider = { + id: 'xyz', + getChangedFiles() { + return [] + }, + getBadgeCount() { + return 0 + }, + getFileDecorations(uris) { + const filtered = uris.filter((uri) => uri.endsWith('a')) + const decorations = filtered.map((item) => { + return { + decoration: 'ignored', + uri: item, + } + }) + return decorations + }, + isActive() { + return true + }, +} + +export const activate = () => { + vscode.registerFileSystemProvider(fileSystemProvider) + vscode.registerSourceControlProvider(sourceControlProvider) +} diff --git a/packages/e2e/package-lock.json b/packages/e2e/package-lock.json new file mode 100644 index 0000000..8031a18 --- /dev/null +++ b/packages/e2e/package-lock.json @@ -0,0 +1,116 @@ +{ + "name": "e2e", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "e2e", + "version": "0.0.0-dev", + "license": "MIT", + "devDependencies": { + "@lvce-editor/test-with-playwright": "^18.0.0" + } + }, + "node_modules/@lvce-editor/test-with-playwright": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/test-with-playwright/-/test-with-playwright-18.0.0.tgz", + "integrity": "sha512-mgoFHKo4mkP08jFPQOcMjPignQOJw3pEhP+NghWOuDL4BLQ9b7W2pRIBb8D8Jqs+8eXfjjUaguts7dLava515g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lvce-editor/test-with-playwright-worker": "18.0.0", + "@lvce-editor/test-worker": "^16.0.0" + }, + "bin": { + "test-with-playwright": "bin/test-with-playwright.js" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/@lvce-editor/test-with-playwright-worker": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/test-with-playwright-worker/-/test-with-playwright-worker-18.0.0.tgz", + "integrity": "sha512-pbeX0ipyA1EVUCrIkmotjtjIwNf7p7+ZONxwl49lf3bBRdwo08qc/ji8B0l+WuZ9QX1aRVuO/aCzhmxMnV5G2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@playwright/test": "1.61.0" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/@lvce-editor/test-worker": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/test-worker/-/test-worker-16.0.0.tgz", + "integrity": "sha512-iJkbCyXP8Tm1I5zDgkFHwr0kP6l/Vh1dBOqX7lPlC8k6olytvUCuqRE1xHDHcYmoCMQAgmS7ilb17YWenrZM5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@playwright/test": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.0.tgz", + "integrity": "sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.61.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.0.tgz", + "integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.61.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz", + "integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/packages/e2e/package.json b/packages/e2e/package.json new file mode 100644 index 0000000..a10961d --- /dev/null +++ b/packages/e2e/package.json @@ -0,0 +1,15 @@ +{ + "name": "e2e", + "version": "0.0.0-dev", + "license": "MIT", + "type": "module", + "main": "index.js", + "scripts": { + "e2e": "node ./node_modules/@lvce-editor/test-with-playwright/bin/test-with-playwright.js --only-extension=. --test-path=.", + "e2e:headless": "node ./node_modules/@lvce-editor/test-with-playwright/bin/test-with-playwright.js --only-extension=. --test-path=. --headless", + "type-check": "tsc" + }, + "devDependencies": { + "@lvce-editor/test-with-playwright": "^18.0.0" + } +} diff --git a/packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts b/packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts new file mode 100644 index 0000000..cbb4484 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts @@ -0,0 +1,33 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-accept-edit-when-not-editing' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act - call acceptEdit when not in editing mode + await Explorer.acceptEdit() + + // assert - should not cause any errors and explorer should remain unchanged + const items = Locator('.TreeItem') + await expect(items).toHaveCount(3) + + const file1 = Locator('text=file1.txt') + await expect(file1).toBeVisible() + + const file2 = Locator('text=file2.txt') + await expect(file2).toBeVisible() + + const file3 = Locator('text=file3.txt') + await expect(file3).toBeVisible() + + // assert - no input box should be visible since we're not in editing mode + const inputBox = Locator('input') + await expect(inputBox).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-accessibility.ts b/packages/e2e/src/viewlet.explorer-accessibility.ts new file mode 100644 index 0000000..8b91f15 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-accessibility.ts @@ -0,0 +1,69 @@ +import type { Test } from '@lvce-editor/test-with-playwright' +// manual accessibility tests + +// explorer +// nvda says: "Files explorer tree" +// windows narrator says: "Files explorer, tree" +// orca says: "Files explorer tree" + +// explorer item +// nvda says: "sample folder, collapsed, two of five, level 1" +// windows narrator says: "sample folder, two of five, collapsed, selected, heading level 1" ❌ +// orca says: "sample-folder, collapsed" + +export const name = 'viewlet.explorer-accessibility' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/languages`) + await FileSystem.mkdir(`${tmpDir}/sample-folder`) + await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') + await FileSystem.writeFile(`${tmpDir}/languages/index.html`, 'div') + await FileSystem.writeFile(`${tmpDir}/sample-folder/a.txt`, '') + await FileSystem.writeFile(`${tmpDir}/sample-folder/b.txt`, '') + await FileSystem.writeFile(`${tmpDir}/sample-folder/c.txt`, '') + + // act + await Workspace.setPath(tmpDir) + + const titleLanguages = '/languages' + const treeItemLanguages = Locator(`.TreeItem[title$="${titleLanguages}"]`) + await expect(treeItemLanguages).toHaveAttribute('tabindex', null) + await expect(treeItemLanguages).toHaveAttribute('role', 'treeitem') + await expect(treeItemLanguages).toHaveAttribute('aria-level', '1') + await expect(treeItemLanguages).toHaveAttribute('aria-posinset', '1') + await expect(treeItemLanguages).toHaveAttribute('aria-setsize', '3') + await expect(treeItemLanguages).toHaveAttribute('aria-expanded', 'false') + + const titleSampleFolder = '/sample-folder' + const treeItemSampleFolder = Locator(`.TreeItem[title$="${titleSampleFolder}"]`) + await expect(treeItemSampleFolder).toHaveAttribute('tabindex', null) + await expect(treeItemSampleFolder).toHaveAttribute('role', 'treeitem') + await expect(treeItemSampleFolder).toHaveAttribute('aria-level', '1') + await expect(treeItemSampleFolder).toHaveAttribute('aria-posinset', '2') + await expect(treeItemSampleFolder).toHaveAttribute('aria-setsize', '3') + await expect(treeItemSampleFolder).toHaveAttribute('aria-expanded', 'false') + + const titleTest = '/test.txt' + const treeItemTestTxt = Locator(`.TreeItem[title$="${titleTest}"]`) + await expect(treeItemTestTxt).toHaveAttribute('tabindex', null) + await expect(treeItemTestTxt).toHaveAttribute('aria-level', '1') + await expect(treeItemTestTxt).toHaveAttribute('aria-posinset', '3') + await expect(treeItemTestTxt).toHaveAttribute('aria-setsize', '3') + // await expect(treeItemTestTxt).not.toHaveAttribute('aria-expanded', 'false') // TODO + + await Explorer.handleClick(0) + await expect(treeItemLanguages).toHaveAttribute('aria-level', '1') + await expect(treeItemLanguages).toHaveAttribute('aria-posinset', '1') + await expect(treeItemLanguages).toHaveAttribute('aria-setsize', '3') + await expect(treeItemLanguages).toHaveAttribute('aria-expanded', 'true') + + const titleIndexHtml = '/languages/index.html' + const treeItemIndexHtml = Locator(`.TreeItem[title$="${titleIndexHtml}"]`) + await expect(treeItemIndexHtml).toHaveAttribute('tabindex', null) + await expect(treeItemIndexHtml).toHaveAttribute('aria-level', '2') + await expect(treeItemIndexHtml).toHaveAttribute('aria-posinset', '1') + await expect(treeItemIndexHtml).toHaveAttribute('aria-setsize', '1') + // await expect(treeItemIndexHtml).not.toHaveAttribute('aria-expanded', 'false') // TODO +} diff --git a/packages/e2e/src/viewlet.explorer-blur.ts b/packages/e2e/src/viewlet.explorer-blur.ts new file mode 100644 index 0000000..fb3dac9 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-blur.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-blur' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.selectIndices([0, 1]) + + // act + await Explorer.handleBlur() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveClass('TreeItem') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveClass('TreeItem') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).toHaveClass('TreeItem') +} diff --git a/packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts b/packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts new file mode 100644 index 0000000..58b8e26 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-click-empty-space-clears-multiple-selection' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.selectIndices([0, 1]) + + const focusedListItems = Locator('.Explorer .ListItems.FocusOutline') + const file1 = Locator('.TreeItem').nth(0) + const file2 = Locator('.TreeItem').nth(1) + const file3 = Locator('.TreeItem').nth(2) + + // act + await Explorer.handleClickAt(false, 0, false, false, 20, 10_000) + + // assert + await expect(focusedListItems).toBeVisible() + await expect(file1).toHaveClass('TreeItem') + await expect(file2).toHaveClass('TreeItem') + await expect(file3).toHaveClass('TreeItem') +} diff --git a/packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts b/packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts new file mode 100644 index 0000000..8bc7abb --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-click-empty-space-clears-selection' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await Workspace.setPath(tmpDir) + await Explorer.selectIndices([0]) + + const focusedListItems = Locator('.Explorer .ListItems.FocusOutline') + const file1 = Locator('.TreeItem').nth(0) + const file2 = Locator('.TreeItem').nth(1) + + // act + await Explorer.handleClickAt(false, 0, false, false, 20, 10_000) + + // assert + await expect(focusedListItems).toBeVisible() + await expect(file1).toHaveClass('TreeItem') + await expect(file2).toHaveClass('TreeItem') +} diff --git a/packages/e2e/src/viewlet.explorer-collapse-all.ts b/packages/e2e/src/viewlet.explorer-collapse-all.ts new file mode 100644 index 0000000..d5310f7 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-collapse-all.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-collapse-all' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a/b`) + await FileSystem.mkdir(`${tmpDir}/a/b/c`) + await FileSystem.mkdir(`${tmpDir}/a/b/c/d`) + await Workspace.setPath(tmpDir) + await Explorer.expandRecursively() + await Explorer.focusLast() + + // act + await Explorer.collapseAll() + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + await expect(treeItems).toHaveCount(1) + await expect(firstTreeItem).toHaveText('a') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts b/packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts new file mode 100644 index 0000000..181b2bf --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts @@ -0,0 +1,21 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-compare-with-selected' + +export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'left') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'right') + await Workspace.setPath(tmpDir) + await Explorer.openContextMenu(0) + await ContextMenu.selectItem('Select for Compare') + + // act + await Explorer.openContextMenu(1) + await ContextMenu.selectItem('Compare with Selected') + + // assert + const diffEditor = Locator('.DiffEditor') + await expect(diffEditor).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts new file mode 100644 index 0000000..918269f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts @@ -0,0 +1,20 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-copy-path-file' + +export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.expandRecursively() + + // act + await Explorer.openContextMenu(1) + await ContextMenu.selectItem('Copy Path') + + // assert + await ClipBoard.shouldHaveText('memfs:///workspace/a/b.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts new file mode 100644 index 0000000..2535d0d --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts @@ -0,0 +1,19 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-copy-path-root' + +export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(-1) + + // act + await Explorer.openContextMenu(-1) + await ContextMenu.selectItem('Copy Path') + + // assert + await ClipBoard.shouldHaveText('memfs:///workspace') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts new file mode 100644 index 0000000..5997c03 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts @@ -0,0 +1,20 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-copy-relative-path-file' + +export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.expandRecursively() + + // act + await Explorer.openContextMenu(1) + await ContextMenu.selectItem('Copy Relative Path') + + // assert + await ClipBoard.shouldHaveText('a/b.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts new file mode 100644 index 0000000..18c361b --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts @@ -0,0 +1,20 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item' + +export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(-1) + await ClipBoard.writeText('unchanged') + + // act + await Explorer.openContextMenu(-1) + await ContextMenu.selectItem('Copy Relative Path') + + // assert + await ClipBoard.shouldHaveText('unchanged') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts new file mode 100644 index 0000000..10d5e28 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-create-file-error-already-exists' + +export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(-1) + + // act + await Explorer.openContextMenu(-1) + await ContextMenu.selectItem('New File...') + await Explorer.updateEditingValue('file1.txt') + + // assert + const inputBox = Locator('input') + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('A file or folder **file1.txt** already exists at this location. Please choose a different name.') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts new file mode 100644 index 0000000..49bdf7e --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-create-folder-error-already-exists' + +export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/folder1`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(-1) + + // act + await Explorer.openContextMenu(-1) + await ContextMenu.selectItem('New Folder...') + await Explorer.updateEditingValue('folder1') + + // assert + const inputBox = Locator('input') + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('A file or folder **folder1** already exists at this location. Please choose a different name.') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts b/packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts new file mode 100644 index 0000000..3d45ab6 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-delete-file-with-focus' + +export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(2) + await Workspace.setPath(tmpDir) + + // act + await Explorer.openContextMenu(0) + await ContextMenu.selectItem('Delete') + + // assert + const file1 = Locator('text=file1.txt') + await expect(file1).toBeHidden() + const listItems = Locator('.Explorer .ListItems') + await expect(listItems).toBeFocused() +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts b/packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts new file mode 100644 index 0000000..b4431d7 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-delete-file' + +export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + await Workspace.setPath(tmpDir) + + // act + await Explorer.openContextMenu(0) + await ContextMenu.selectItem('Delete') + + // assert + const file1 = Locator('text=file1.txt') + await expect(file1).toBeHidden() + const listItems = Locator('.Explorer .ListItems') + await expect(listItems).toBeFocused() +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts b/packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts new file mode 100644 index 0000000..dbcfb8d --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-paste-root-no-focused-item' + +export const test: Test = async ({ ClipBoard, ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + await Explorer.handleCopy() + await Explorer.focusIndex(-1) + + // act + await Explorer.openContextMenu(-1) + await ContextMenu.selectItem('Paste') + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('file.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts b/packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts new file mode 100644 index 0000000..f54a0d6 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts @@ -0,0 +1,17 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-remove-folder-from-workspace' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + + // act + await Explorer.openContextMenu(-1) + + // assert + const menuItem = Locator('text=Remove folder from workspace') + await expect(menuItem).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts b/packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts new file mode 100644 index 0000000..a63c95c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts @@ -0,0 +1,20 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-context-menu-select-for-compare' + +export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await Workspace.setPath(tmpDir) + await Explorer.openContextMenu(0) + await ContextMenu.selectItem('Select for Compare') + + // act + await Explorer.openContextMenu(1) + + // assert + const compareWithSelected = Locator('text=Compare with Selected') + await expect(compareWithSelected).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts new file mode 100644 index 0000000..d9df069 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts @@ -0,0 +1,31 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-and-paste-file' + +export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') + await FileSystem.mkdir(`${tmpDir}/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + + // act + await Explorer.handleCopy() + await Explorer.focusIndex(-1) + await Explorer.handlePaste() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + await expect(file1).toHaveAttribute('aria-expanded', 'true') + const file3 = Locator('.TreeItem').nth(1) + await expect(file3).toHaveText('b') + await expect(file3).toHaveAttribute('aria-expanded', 'false') // TODO should be true + const file4 = Locator('.TreeItem').nth(2) + await expect(file4).toHaveText('file.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts new file mode 100644 index 0000000..95728d9 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts @@ -0,0 +1,22 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-and-paste-folder-error' + +export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.mkdir(`${tmpDir}/a/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + + // act + await Explorer.handleCopy() + await Explorer.focusIndex(1) + await Explorer.handlePaste() + + // assert + // TODO error message should be displayed +} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts new file mode 100644 index 0000000..dd06566 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts @@ -0,0 +1,34 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-and-paste-folder-with-items' + +export const skip = 1 + +export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/file.txt`, '') + await FileSystem.mkdir(`${tmpDir}/a/c`) + await FileSystem.mkdir(`${tmpDir}/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + + // act + await Explorer.handleCopy() + await Explorer.focusIndex(3) + await Explorer.handlePaste() + await Explorer.expandAll() + + // assert + const treeItems = Locator('.TreeItem') + await expect(treeItems).toHaveCount(2) + const file1 = treeItems.nth(0) + await expect(file1).toHaveText('b') + await expect(file1).toHaveAttribute('aria-expanded', 'true') + const file2 = treeItems.nth(1) + await expect(file2).toHaveText('a') + // await expect(file1).toHaveAttribute('aria-expanded', 'false') +} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts new file mode 100644 index 0000000..ad95428 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-and-paste-folder' + +export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.mkdir(`${tmpDir}/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + + // act + await Explorer.handleCopy() + await Explorer.focusIndex(1) + await Explorer.handlePaste() + await Explorer.expandAll() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('b') + await expect(file1).toHaveAttribute('aria-expanded', 'true') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('a') + // await expect(file1).toHaveAttribute('aria-expanded', 'false') +} diff --git a/packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts b/packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts new file mode 100644 index 0000000..3a3c6d7 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts @@ -0,0 +1,54 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-paste-error-scenarios' +export const skip = 1 + +export const test: Test = async ({ ClipBoard, Command, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/source`) + await FileSystem.writeFile(`${tmpDir}/source/file.txt`, 'content') + await FileSystem.mkdir(`${tmpDir}/target`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + + // Test 1: Copy file to read-only directory + await Command.execute('FileSystem.setReadOnly', `${tmpDir}/target`, true) + await Explorer.handleCopy() + await Explorer.focusIndex(2) + await Explorer.handlePaste() + + // Should show error message for read-only target + const errorMessage = Locator('.ErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('Permission denied') + + // Test 2: Paste without copying anything first + await Explorer.handlePaste() + await expect(errorMessage).toBeVisible() + + // Test 3: Copy non-existent file (simulate file deletion after copy) + await Command.execute('FileSystem.setReadOnly', `${tmpDir}/target`, false) + await Explorer.handleCopy() + await Command.execute('FileSystem.deleteFile', `${tmpDir}/source/file.txt`) + await Explorer.focusIndex(2) + await Explorer.handlePaste() + + // Should handle missing source gracefully + await expect(errorMessage).toBeVisible() + + // Test 4: Copy file with invalid characters in name + await FileSystem.writeFile(`${tmpDir}/source/invalid|file.txt`, 'content') + await Explorer.focusIndex(1) + await Explorer.expandRecursively() + await Explorer.focusIndex(2) + await Explorer.handleCopy() + await Explorer.focusIndex(3) + await Explorer.handlePaste() + + // Should handle invalid characters + await expect(errorMessage).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-copy-path-empty.ts b/packages/e2e/src/viewlet.explorer-copy-path-empty.ts new file mode 100644 index 0000000..a065108 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-path-empty.ts @@ -0,0 +1,17 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-path-empty' + +export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await Workspace.setPath(tmpDir) + await Explorer.expandRecursively() + + // act + await Explorer.copyPath() + + // assert + await ClipBoard.shouldHaveText('memfs:///workspace') +} diff --git a/packages/e2e/src/viewlet.explorer-copy-path-file.ts b/packages/e2e/src/viewlet.explorer-copy-path-file.ts new file mode 100644 index 0000000..67b34c7 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-path-file.ts @@ -0,0 +1,20 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-path-file' + +export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + + // act + await Explorer.copyPath() + + // assert + await ClipBoard.shouldHaveText('memfs:///workspace/a/b.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-copy-path-folder.ts b/packages/e2e/src/viewlet.explorer-copy-path-folder.ts new file mode 100644 index 0000000..4fa4164 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-copy-path-folder.ts @@ -0,0 +1,18 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-copy-path-folder' + +export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + + // act + await Explorer.copyPath() + + // assert + await ClipBoard.shouldHaveText('memfs:///workspace/a') +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts b/packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts new file mode 100644 index 0000000..043bda9 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts @@ -0,0 +1,26 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-blur-no-name' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.handleInputBlur() + + // assert + await expect(inputBox).toBeHidden() + const items = Locator('.TreeItem') + await expect(items).toHaveCount(1) +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-blur.ts b/packages/e2e/src/viewlet.explorer-create-file-blur.ts new file mode 100644 index 0000000..ebdbcf1 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-blur.ts @@ -0,0 +1,26 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-blur' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('created.txt') + await Explorer.handleInputBlur() + + // assert + const newFile = Locator('.Explorer').locator('text=created.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-cancel.ts b/packages/e2e/src/viewlet.explorer-create-file-cancel.ts new file mode 100644 index 0000000..d1286ee --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-cancel.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-cancel' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('created.txt') + await Explorer.cancelEdit() + + // assert + await expect(inputBox).toBeHidden() + const items = Locator('.TreeItem') + await expect(items).toHaveCount(1) +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-different-languages.ts b/packages/e2e/src/viewlet.explorer-create-file-different-languages.ts new file mode 100644 index 0000000..d385a9d --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-different-languages.ts @@ -0,0 +1,104 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-different-languages' + +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + + await Workspace.setPath(tmpDir) + + // Test 1: Create file with German characters + await Explorer.newFile() + const inputBox1 = Locator('input') + await expect(inputBox1).toBeVisible() + await expect(inputBox1).toBeFocused() + await Explorer.updateEditingValue('Müller.txt') + await Explorer.acceptEdit() + const newFile1 = Locator('.Explorer').locator('text=Müller.txt') + await expect(newFile1).toBeVisible() + + // Test 2: Create file with French characters + await Explorer.newFile() + const inputBox2 = Locator('input') + await expect(inputBox2).toBeVisible() + await expect(inputBox2).toBeFocused() + await Explorer.updateEditingValue('Français.txt') + await Explorer.acceptEdit() + const newFile2 = Locator('.Explorer').locator('text=Français.txt') + await expect(newFile2).toBeVisible() + + // Test 3: Create file with Spanish characters + await Explorer.newFile() + const inputBox3 = Locator('input') + await expect(inputBox3).toBeVisible() + await expect(inputBox3).toBeFocused() + await Explorer.updateEditingValue('Niño.txt') + await Explorer.acceptEdit() + const newFile3 = Locator('.Explorer').locator('text=Niño.txt') + await expect(newFile3).toBeVisible() + + // Test 4: Create file with Russian characters + await Explorer.newFile() + const inputBox4 = Locator('input') + await expect(inputBox4).toBeVisible() + await expect(inputBox4).toBeFocused() + await Explorer.updateEditingValue('Русский.txt') + await Explorer.acceptEdit() + const newFile4 = Locator('.Explorer').locator('text=Русский.txt') + await expect(newFile4).toBeVisible() + + // Test 5: Create file with Chinese characters + await Explorer.newFile() + const inputBox5 = Locator('input') + await expect(inputBox5).toBeVisible() + await expect(inputBox5).toBeFocused() + await Explorer.updateEditingValue('中文.txt') + await Explorer.acceptEdit() + const newFile5 = Locator('.Explorer').locator('text=中文.txt') + await expect(newFile5).toBeVisible() + + // Test 6: Create file with Japanese characters + await Explorer.newFile() + const inputBox6 = Locator('input') + await expect(inputBox6).toBeVisible() + await expect(inputBox6).toBeFocused() + await Explorer.updateEditingValue('こんにちは.txt') + await Explorer.acceptEdit() + const newFile6 = Locator('.Explorer').locator('text=こんにちは.txt') + await expect(newFile6).toBeVisible() + + // Test 7: Create file with Korean characters + await Explorer.newFile() + const inputBox7 = Locator('input') + await expect(inputBox7).toBeVisible() + await expect(inputBox7).toBeFocused() + await Explorer.updateEditingValue('안녕하세요.txt') + await Explorer.acceptEdit() + const newFile7 = Locator('.Explorer').locator('text=안녕하세요.txt') + await expect(newFile7).toBeVisible() + + // Test 8: Create file with Arabic characters + await Explorer.newFile() + const inputBox8 = Locator('input') + await expect(inputBox8).toBeVisible() + await expect(inputBox8).toBeFocused() + await Explorer.updateEditingValue('العربية.txt') + await Explorer.acceptEdit() + const newFile8 = Locator('.Explorer').locator('text=العربية.txt') + await expect(newFile8).toBeVisible() + + // Test 9: Create file with Hebrew characters + await Explorer.newFile() + const inputBox9 = Locator('input') + await expect(inputBox9).toBeVisible() + await expect(inputBox9).toBeFocused() + await Explorer.updateEditingValue('עברית.txt') + await Explorer.acceptEdit() + const newFile9 = Locator('.Explorer').locator('text=עברית.txt') + await expect(newFile9).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts b/packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts new file mode 100644 index 0000000..3395f97 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts @@ -0,0 +1,19 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-double-click-empty-space' + +export const test: Test = async ({ Command, expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + + // act + await Command.execute('Explorer.handleClickAt', false, 0, false, false, 20, 100) + await Command.execute('Explorer.handleDoubleClick', 20, 100) + + // assert + const inputBox = Locator('.Explorer input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts new file mode 100644 index 0000000..a8a05df --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts @@ -0,0 +1,21 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-already-exists' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + await Explorer.newFile() + + // act + await Explorer.updateEditingValue('file1.txt') + + // assert + const inputBox = Locator('input') + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText(`A file or folder **file1.txt** already exists at this location. Please choose a different name.`) +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts new file mode 100644 index 0000000..b45b36c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('\\') + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('A file or folder name cannot start with a backslash.') +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts new file mode 100644 index 0000000..68672d0 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-file-name-cannot-start-with-slash' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('.') + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts new file mode 100644 index 0000000..ee97c1c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-file-name-cannot-start-with-slash' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('/') + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('A file or folder name cannot start with a slash.') +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts b/packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts new file mode 100644 index 0000000..ff37082 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-no-name-provided' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.acceptEdit() + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('A file or folder name must be provided.') +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts new file mode 100644 index 0000000..40f1f54 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts @@ -0,0 +1,45 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-permission-denied-escape-then-create-again' + +export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { + // arrange + const uri = import.meta.resolve('../fixtures/sample.file-system-provider-create-file-error-permission-denied') + await Extension.addWebExtension(uri) + const prefix = 'extension-host://xyz://' + await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') + await Workspace.setPath(`${prefix}/`) + + const inputBox = Locator('input') + const errorMessage = Locator('.ExplorerErrorMessage') + const items = Locator('.TreeItem') + + // act + await Explorer.newFile() + await Explorer.updateEditingValue('file4.txt') + await Explorer.acceptEdit() + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('Error: Failed to execute file system provider: Permission Denied') + + // act + await Explorer.cancelEdit() + + // assert + await expect(inputBox).toBeHidden() + await expect(items).toHaveCount(3) + + // act + await Explorer.newFile() + + // assert + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + await expect(inputBox).toHaveValue('') + await expect(errorMessage).toBeHidden() + await expect(items).toHaveCount(4) +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts new file mode 100644 index 0000000..c2a329f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts @@ -0,0 +1,34 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-permission-denied' + +export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { + // arrange + const uri = import.meta.resolve('../fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path') + await Extension.addWebExtension(uri) + const prefix = 'extension-host://xyz://' + await FileSystem.writeFile(`${prefix}/usr/lib/lvce/resources/app/playground/file1.txt`, 'content 1') + await FileSystem.writeFile(`${prefix}/usr/lib/lvce/resources/app/playground/file2.txt`, 'content 2') + await FileSystem.writeFile(`${prefix}/usr/lib/lvce/resources/app/playground/file3.txt`, 'content 3') + await Workspace.setPath(`${prefix}/`) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('file4.txt') + await Explorer.acceptEdit() + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText( + `Error: Failed to execute file system provider: Error: Failed to write to file "/file4.txt": EACCES: permission denied, open '/file4.txt'`, + ) +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts new file mode 100644 index 0000000..27feb5a --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts @@ -0,0 +1,32 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-permission-denied' + +export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { + // arrange + const uri = import.meta.resolve('../fixtures/sample.file-system-provider-create-file-error-permission-denied') + await Extension.addWebExtension(uri) + const prefix = 'extension-host://xyz://' + await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') + await Workspace.setPath(`${prefix}/`) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('file4.txt') + await Explorer.acceptEdit() + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('Error: Failed to execute file system provider: Permission Denied') +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts b/packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts new file mode 100644 index 0000000..b25283b --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-explorer-collapses' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.newFile() + const inputBox = Locator('input') + await Explorer.updateEditingValue('test-file.txt') + + // act + await Explorer.collapseAll() + + // assert + await expect(inputBox).toBeHidden() + + // TODO focus should be at on tree +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts b/packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts new file mode 100644 index 0000000..8592c1b --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-inside-closed-folder' + +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/folder1`) + await FileSystem.writeFile(`${tmpDir}/folder1/existing.txt`, 'content') + await FileSystem.mkdir(`${tmpDir}/folder2`) + await FileSystem.mkdir(`${tmpDir}/folder2/nested`) + await FileSystem.writeFile(`${tmpDir}/folder2/nested/file.txt`, 'content') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(1) + + // act + await Explorer.newFile() + + // assert + const folder2 = Locator('.Explorer').locator('text=folder2') + await expect(folder2).toBeVisible() + await expect(folder2).toHaveAttribute('aria-expanded', 'true') + const newFile = Locator('.Explorer').locator('text=created.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts b/packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts new file mode 100644 index 0000000..53ae187 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-inside-folder' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.mkdir(`${tmpDir}/b`) + await FileSystem.mkdir(`${tmpDir}/c`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('created.txt') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=created.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-nested.ts b/packages/e2e/src/viewlet.explorer-create-file-nested.ts new file mode 100644 index 0000000..555298f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-nested.ts @@ -0,0 +1,35 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-nested' + +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('a/b/created.txt') + await Explorer.acceptEdit() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('b') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).toHaveText('created.txt') + const file4 = Locator('.TreeItem').nth(3) + await expect(file4).toHaveText('file1.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts b/packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts new file mode 100644 index 0000000..3304370 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts @@ -0,0 +1,35 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-opens-in-editor' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert - input box is visible + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act - create new file + await Explorer.updateEditingValue('new-file.txt') + await Explorer.acceptEdit() + + // assert - file is visible in explorer + const newFile = Locator('.Explorer').locator('text=new-file.txt') + await expect(newFile).toBeVisible() + + // assert - input should be hidden after accepting + await expect(inputBox).toBeHidden() + + // assert - file should be opened in editor (check for editor tab or editor view) + // The file should be opened, which means there should be an editor tab or editor content visible + const editorTab = Locator('[title*="new-file.txt"]').first() + await expect(editorTab).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts b/packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts new file mode 100644 index 0000000..9653161 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-starting-with-dot' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('.editorconfig') + + // assert + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts b/packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts new file mode 100644 index 0000000..9a0099c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts @@ -0,0 +1,46 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-switch-folders' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.mkdir(`${tmpDir}/b`) + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + + // act - start creating file in folder a + await Explorer.focusIndex(0) // focus on folder a + await Explorer.newFile() + + // assert - input should be visible in folder a + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act - type some content for the file in folder a + await inputBox.type('file-in-a.txt') + + // act - switch to folder b and start creating file there + await Explorer.focusIndex(1) // focus on folder b + await Explorer.newFile() + + // assert - only one input should be visible (the new one in folder b) + const inputBoxes = Locator('input') + await expect(inputBoxes).toHaveCount(1) + await expect(inputBoxes).toBeVisible() + await expect(inputBoxes).toBeFocused() + + // act - type content for the file in folder b + await inputBoxes.type('file-in-b.txt') + await Explorer.updateEditingValue('file-in-b.txt') + await Explorer.acceptEdit() + + // assert - file should be created in folder b + const newFile = Locator('.Explorer').locator('text=file-in-b.txt') + await expect(newFile).toBeVisible() + + // assert - no input should be visible after accepting + await expect(inputBoxes).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts b/packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts new file mode 100644 index 0000000..5db01fc --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-when-file-is-focused' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('created.txt') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=created.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts b/packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts new file mode 100644 index 0000000..72e3b8f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-with-emoji-extension' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('created.😀') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=created.😀') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts b/packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts new file mode 100644 index 0000000..4f8c992 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-with-emoji' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('🚀 rocket.txt') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=🚀 rocket.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts b/packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts new file mode 100644 index 0000000..a3aed74 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-with-greek-characters' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('αρχείο.txt') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=αρχείο.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-newline.ts b/packages/e2e/src/viewlet.explorer-create-file-with-newline.ts new file mode 100644 index 0000000..3bff927 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-with-newline.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-with-newline' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('file\nwith\nnewline.txt') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=file\nwith\nnewline.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts b/packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts new file mode 100644 index 0000000..e6e3cb3 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts @@ -0,0 +1,33 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-with-non-breaking-space' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + const fileName = `my\u00A0file.txt` + await Explorer.updateEditingValue(fileName) + await Explorer.acceptEdit() + + // assert + const dirents = await FileSystem.readDir(tmpDir) + const hasCreatedFile = dirents.some((dirent) => dirent.name === fileName) + if (!hasCreatedFile) { + throw new Error(`Expected directory to contain ${JSON.stringify(fileName)} but got ${JSON.stringify(dirents)}`) + } +} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts b/packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts new file mode 100644 index 0000000..9e473be --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-with-spaces' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('my file with spaces.txt') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=my file with spaces.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-file.ts b/packages/e2e/src/viewlet.explorer-create-file.ts new file mode 100644 index 0000000..6110bfd --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-file.ts @@ -0,0 +1,31 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file' + +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('created.txt') + await Explorer.acceptEdit() + + // assert + const newFile = Locator('.Explorer').locator('text=created.txt') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts b/packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts new file mode 100644 index 0000000..49d7744 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts @@ -0,0 +1,53 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-folder-nested-150-times' + +const depth = 150 + +const getFolderName = (index: number): string => { + return `folder-${index.toString().padStart(3, '0')}` +} + +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + + const inputBox = Locator('input') + + // act + for (let index = 0; index < depth; index++) { + const folderName = getFolderName(index) + + if (index > 0) { + await Explorer.focusIndex(index - 1) + } + await Explorer.newFolder() + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + await Explorer.updateEditingValue(folderName) + await Explorer.acceptEdit() + await expect(inputBox).toBeHidden() + } + + // assert + const treeItems = Locator('.TreeItem') + await expect(treeItems).toHaveCount(depth + 1) + + const deepestFolder = Locator('.TreeItem', { hasText: getFolderName(depth - 1) }) + await expect(deepestFolder).toBeVisible() + + let currentPath = tmpDir + for (let index = 0; index < depth; index++) { + const folderName = getFolderName(index) + const dirents = await FileSystem.readDir(currentPath) + const hasFolder = dirents.some((dirent) => dirent.name === folderName) + if (!hasFolder) { + throw new Error(`Expected ${JSON.stringify(currentPath)} to contain ${JSON.stringify(folderName)} but got ${JSON.stringify(dirents)}`) + } + currentPath = `${currentPath}/${folderName}` + } +} diff --git a/packages/e2e/src/viewlet.explorer-create-folder-nested.ts b/packages/e2e/src/viewlet.explorer-create-folder-nested.ts new file mode 100644 index 0000000..20b6ac9 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-folder-nested.ts @@ -0,0 +1,33 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-folder-nested' + +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + await Explorer.newFolder() + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('a/b/c') + await Explorer.acceptEdit() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + await expect(file1).toHaveAttribute('aria-expanded', 'true') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('b') + await expect(file2).toHaveAttribute('aria-expanded', 'true') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).toHaveText('c') + await expect(file3).toHaveAttribute('aria-expanded', 'false') + const file4 = Locator('.TreeItem').nth(3) + await expect(file4).toHaveText('file1.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts b/packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts new file mode 100644 index 0000000..4acbecd --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts @@ -0,0 +1,16 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-folder-with-backslashes' + +export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/\\eee\\`) + + // act + await Workspace.setPath(tmpDir) + + // assert + const newFolder = Locator('.Explorer').locator('text=\\eee\\') + await expect(newFolder).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-create-folder.ts b/packages/e2e/src/viewlet.explorer-create-folder.ts new file mode 100644 index 0000000..abe76e5 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-create-folder.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-folder' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFolder() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('folder') + await Explorer.acceptEdit() + + // assert + const newFolder = Locator('.Explorer').locator('text=folder') + await expect(newFolder).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts new file mode 100644 index 0000000..00741d6 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts @@ -0,0 +1,33 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-cut-and-paste-file-error-already-exists' + +export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') + await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(2) + + // act + await Explorer.handleCut() + await Explorer.focusIndex(0) + await Explorer.handlePaste() + + // TODO should show error message that destination already exists + // assert + // const file1 = Locator('.TreeItem').nth(0) + // await expect(file1).toHaveText('a') + // await expect(file1).toHaveAttribute('aria-expanded', 'true') + // // TODO should be hidden + // const file2 = Locator('.TreeItem').nth(1) + // await expect(file2).toHaveText('b') + // await expect(file2).toHaveAttribute('aria-expanded', 'true') + // const file3 = Locator('.TreeItem').nth(2) + // await expect(file3).toHaveText('file.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts new file mode 100644 index 0000000..73bb696 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts @@ -0,0 +1,36 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-cut-and-paste-file' + +export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') + await FileSystem.mkdir(`${tmpDir}/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + + // act + await Explorer.handleCut() + await Explorer.focusIndex(2) + await Explorer.handlePaste() + + // TODO folder should expanded automatically + await Explorer.focusIndex(1) + await Explorer.expandRecursively() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + await expect(file1).toHaveAttribute('aria-expanded', 'true') + // TODO should be hidden + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('b') + await expect(file2).toHaveAttribute('aria-expanded', 'true') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).toHaveText('file.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts new file mode 100644 index 0000000..c8f09a2 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts @@ -0,0 +1,39 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-cut-and-paste-two-files' + +export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/file-1.txt`, 'content') + await FileSystem.writeFile(`${tmpDir}/a/file-2.txt`, 'content') + await FileSystem.mkdir(`${tmpDir}/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + + // act + await Explorer.selectIndices([1, 2]) + await Explorer.handleCut() + await Explorer.focusIndex(3) + await Explorer.handlePaste() + + // TODO folder should expanded automatically + await Explorer.focusIndex(1) + await Explorer.expandRecursively() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + await expect(file1).toHaveAttribute('aria-expanded', 'true') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('b') + await expect(file2).toHaveAttribute('aria-expanded', 'true') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).toHaveText('file-1.txt') + const file4 = Locator('.TreeItem').nth(3) + await expect(file4).toHaveText('file-2.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts new file mode 100644 index 0000000..7eff1d0 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts @@ -0,0 +1,39 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-cut-and-paste-two-folders' + +export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.mkdir(`${tmpDir}/a/c`) + await FileSystem.mkdir(`${tmpDir}/a/d`) + await FileSystem.mkdir(`${tmpDir}/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + + // act + await Explorer.selectIndices([1, 2]) + await Explorer.handleCut() + await Explorer.focusIndex(3) + await Explorer.handlePaste() + + // TODO folder should expanded automatically + await Explorer.focusIndex(1) + await Explorer.expandRecursively() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + await expect(file1).toHaveAttribute('aria-expanded', 'true') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('b') + await expect(file2).toHaveAttribute('aria-expanded', 'true') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).toHaveText('c') + const file4 = Locator('.TreeItem').nth(3) + await expect(file4).toHaveText('d') +} diff --git a/packages/e2e/src/viewlet.explorer-cut-cancel.ts b/packages/e2e/src/viewlet.explorer-cut-cancel.ts new file mode 100644 index 0000000..5e69d37 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-cut-cancel.ts @@ -0,0 +1,25 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-cut-cancel' + +export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + await ClipBoard.enableMemoryClipBoard() + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') + await FileSystem.mkdir(`${tmpDir}/b`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + await Explorer.focusIndex(1) + + // act + await Explorer.handleCut() + const treeItem = Locator('.TreeItem[data-index="1"]') + const treeItemLabel = treeItem.locator('.Label') + await expect(treeItemLabel).toHaveClass('LabelCut') + + await Explorer.handleEscape() + await expect(treeItemLabel).toHaveJSProperty('className', 'Label') +} diff --git a/packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts b/packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts new file mode 100644 index 0000000..07450a7 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-deeply-nested-folders' + +const depth = 1200 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + let currentPath = tmpDir + for (let i = 0; i < depth; i++) { + currentPath = `${currentPath}/a` + await FileSystem.mkdir(currentPath) + } + await FileSystem.writeFile(`${currentPath}/deep-file.txt`, 'deep') + + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + + // act + await Explorer.expandRecursively() + await Explorer.focusIndex(depth) + + // assert + const deepFile = Locator('.TreeItem', { hasText: 'deep-file.txt' }) + await expect(deepFile).toBeVisible() + await expect(deepFile).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts new file mode 100644 index 0000000..cbf69a0 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts @@ -0,0 +1,16 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-file-empty-workspace' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await Workspace.setPath(tmpDir) + + // act + await Explorer.removeDirent() + + // assert + const listItems = Locator('.Explorer .ListItems') + await expect(listItems).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-delete-file-error.ts b/packages/e2e/src/viewlet.explorer-delete-file-error.ts new file mode 100644 index 0000000..7f64cdb --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-file-error.ts @@ -0,0 +1,31 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-file-error' + +export const test: Test = async ({ Dialog, expect: _expect, Explorer, Extension, FileSystem, Locator: _Locator, Workspace }) => { + // arrange + // @ts-ignore + let _message: string = '' + // @ts-ignore + await Dialog.mockConfirm((message: string) => { + _message = message + return true + }) + const uri = import.meta.resolve('../fixtures/sample.file-system-provider-delete-file-error') + await Extension.addWebExtension(uri) + const prefix = 'extension-host://xyz://' + await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') + await Workspace.setPath(prefix) + await Explorer.focusFirst() + + // act + await Explorer.removeDirent() + + // assert + const expectedMessage = 'Error: Failed to execute file system provider: oops' + if (_message !== expectedMessage) { + throw new Error(`expected confirm message to be `) + } +} diff --git a/packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts b/packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts new file mode 100644 index 0000000..10b36b1 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts @@ -0,0 +1,21 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-file-no-focused-item' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') + await FileSystem.writeFile(`${tmpDir}/file-2.txt`, 'b') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(-1) + + // act + await Explorer.removeDirent() + + // assert + const file1 = Locator('.TreeItem', { hasText: 'file-1.txt' }) + const file2 = Locator('.TreeItem', { hasText: 'file-2.txt' }) + await expect(file1).toBeVisible() + await expect(file2).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-delete-file.ts b/packages/e2e/src/viewlet.explorer-delete-file.ts new file mode 100644 index 0000000..4f7a821 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-file.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-last-file' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + + // act + await Explorer.removeDirent() + + // assert + const file1 = Locator('text=file1.txt') + await expect(file1).toBeHidden() + const listItems = Locator('.Explorer .ListItems') + await expect(listItems).toBeFocused() + // TODO explorer should have focus outline +} diff --git a/packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts b/packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts new file mode 100644 index 0000000..cbcad40 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-folder-with-items' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/folder-1`) + await FileSystem.writeFile(`${tmpDir}/folder-1/a.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-1/b.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-1/c.txt`, '') + await FileSystem.mkdir(`${tmpDir}/folder-2`) + await FileSystem.mkdir(`${tmpDir}/folder-3`) + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + await Explorer.expandAll() + + // act + await Explorer.removeDirent() + + // assert + const fileA = Locator('text=a.txt') + const fileB = Locator('text=a.txt') + const fileC = Locator('text=a.txt') + await expect(fileA).toBeHidden() + await expect(fileB).toBeHidden() + await expect(fileC).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-delete-folder.ts b/packages/e2e/src/viewlet.explorer-delete-folder.ts new file mode 100644 index 0000000..b114e38 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-folder.ts @@ -0,0 +1,20 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-folder' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/folder-1`) + await FileSystem.mkdir(`${tmpDir}/folder-2`) + await FileSystem.mkdir(`${tmpDir}/folder-3`) + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusFirst() + await Explorer.removeDirent() + + // assert + const file1 = Locator('text=folder-1') + await expect(file1).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-delete-last-file.ts b/packages/e2e/src/viewlet.explorer-delete-last-file.ts new file mode 100644 index 0000000..ec3c7a3 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-last-file.ts @@ -0,0 +1,18 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-file' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + + // act + await Explorer.removeDirent() + + // assert + const file1 = Locator('text=file1.txt') + await expect(file1).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts b/packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts new file mode 100644 index 0000000..2d5d250 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-multiple-files' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + const explorer = Locator('.Explorer') + const file1 = explorer.locator('text=file1.txt') + const file2 = explorer.locator('text=file2.txt') + const file3 = explorer.locator('text=file3.txt') + await Explorer.focus() + await Explorer.selectIndices([0, 1]) + + // act + await Explorer.removeDirent() + + // assert + await expect(file1).toBeHidden() + await expect(file2).toBeHidden() + await expect(file3).toBeVisible() + + // TODO file3 should be focused +} diff --git a/packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts b/packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts new file mode 100644 index 0000000..5013812 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-multiple-files-focuses-remaining-item' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.selectIndices([0, 1]) + + const file1 = Locator('.TreeItem', { hasText: 'file1.txt' }) + const file2 = Locator('.TreeItem', { hasText: 'file2.txt' }) + const file3 = Locator('.TreeItem', { hasText: 'file3.txt' }) + + // act + await Explorer.removeDirent() + + // assert + await expect(file1).toBeHidden() + await expect(file2).toBeHidden() + await expect(file3).toBeVisible() + await expect(file3).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-delete-multiple-files.ts b/packages/e2e/src/viewlet.explorer-delete-multiple-files.ts new file mode 100644 index 0000000..52d05d9 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-multiple-files.ts @@ -0,0 +1,58 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-multiple-files' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + const explorer = Locator('.Explorer') + const file1 = explorer.locator('text=file1.txt') + const file2 = explorer.locator('text=file2.txt') + const file3 = explorer.locator('text=file3.txt') + + // act + await Explorer.focus() + + // assert + // TODO + // await expect(explorer).toHaveClass('FocusOutline') + // await expect(explorer).toBeFocused() + + // act + await Explorer.focusIndex(2) + + // assert + // TODO + // await expect(file3).toHaveClass('FocusOutline') + + // act + await Explorer.removeDirent() + + // assert + await expect(file3).toBeHidden() + // TODO + // await expect(file2).toHaveClass('FocusOutline') + + // act + await Explorer.removeDirent() + // await KeyBoard.press('Delete') + + // assert + await expect(file2).toBeHidden() + // TODO + // await expect(file1).toHaveClass('FocusOutline') + + // act + await Explorer.removeDirent() + + // assert + await expect(file1).toBeHidden() + // TODO + // await expect(explorer).toHaveClass('FocusOutline') +} diff --git a/packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts b/packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts new file mode 100644 index 0000000..4611872 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts @@ -0,0 +1,33 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-delete-nested-middle-folder' + +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a/b/c/d`) + await FileSystem.writeFile(`${tmpDir}/a/b/c/d/e.txt`, 'deep') + await Workspace.setPath(tmpDir) + + const topLevelFolder = Locator(`.TreeItem[title$="/a"]`) + const parentFolder = Locator(`.TreeItem[title$="/a/b"]`) + const deletedFolder = Locator(`.TreeItem[title$="/a/b/c"]`) + const deletedChildFolder = Locator(`.TreeItem[title$="/a/b/c/d"]`) + const deletedDescendantFile = Locator(`.TreeItem[title$="/a/b/c/d/e.txt"]`) + + await Explorer.focusFirst() + await Explorer.expandRecursively() + await Explorer.focusIndex(2) + + // act + await Explorer.removeDirent() + + // assert + await expect(topLevelFolder).toBeVisible() + await expect(parentFolder).toHaveId('TreeItemActive') + await expect(deletedFolder).toBeHidden() + await expect(deletedChildFolder).toBeHidden() + await expect(deletedDescendantFile).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts b/packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts new file mode 100644 index 0000000..1979825 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts @@ -0,0 +1,66 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drag-drop-error-scenarios' + +export const skip = 1 + +export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.mkdir(`${tmpDir}/readonly-dir`) + await Workspace.setPath(tmpDir) + + // Test 1: Drop file on read-only directory + await Command.execute('FileSystem.setReadOnly', `${tmpDir}/readonly-dir`, true) + + const directory = await navigator.storage.getDirectory() + const fileHandle = await directory.getFileHandle('test-file.txt', { create: true }) + const file = await fileHandle.getFile() + const fileList = [file] + const id = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) + + // Try to drop on read-only directory + await Explorer.handleDrop(2, 0, [id], fileList) + + // Should show error message + const errorMessage = Locator('.ErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('Permission denied') + + // Test 2: Drop with invalid file handle + const invalidId = 999_999 // Use number instead of string + await Explorer.handleDrop(0, 0, [invalidId], fileList) + + // Should handle invalid handle gracefully + await expect(errorMessage).toBeVisible() + + // Test 3: Drop file on itself (same location) + await Command.execute('FileSystem.setReadOnly', `${tmpDir}/readonly-dir`, false) + await Explorer.handleDrop(0, 0, [id], fileList) + + // Should handle or show appropriate message + const fileItem = Locator('.TreeItem', { hasText: 'test-file.txt' }) + await expect(fileItem).toBeVisible() + + // Test 4: Drop multiple files where one is invalid + const fileHandle2 = await directory.getFileHandle('test-file2.txt', { create: true }) + const file2 = await fileHandle2.getFile() + const fileList2 = [file, file2] + const id2 = await Command.execute('FileSystemHandle.addFileHandle', fileHandle2) + + // Delete one file after adding to handles to simulate error + await Command.execute('FileSystemHandle.removeFileHandle', id2) + + await Explorer.handleDrop(0, 0, [id, 999_999], fileList2) + + // Should handle partial failure gracefully + await expect(errorMessage).toBeVisible() + + // Test 5: Drop on non-existent target + await Explorer.handleDrop(999, 0, [id], fileList) + + // Should handle invalid target gracefully + await expect(errorMessage).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts b/packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts new file mode 100644 index 0000000..d93a471 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts @@ -0,0 +1,31 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drag-file-into-folder' + +export const skip = 1 + +export const test: Test = async ({ Explorer, FileSystem, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/new`) + await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(1) + await Explorer.handleDragOverIndex(1) + + // act + + // const opfsRoot = await navigator.storage.getDirectory() + // const fileHandle = await opfsRoot.getFileHandle('my first file', { + // create: true, + // }) + // console.log({ fileHandle }) + // const fileHandles = [fileHandle] + // const files = [] + // const paths = [] + // const index = 0 + // await Command.execute('Explorer.handleDropIndex', fileHandles, files, paths, index) + // await Explorer.handleDrop() + + // TODO drop file into folder and verify it is moved +} diff --git a/packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts new file mode 100644 index 0000000..c097c63 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts @@ -0,0 +1,18 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-empty-handles-empty-workspace' + +export const test: Test = async ({ expect, Explorer, Locator, Workspace }) => { + // arrange + await Workspace.setPath('') + const welcomeMessage = Locator('.Explorer .WelcomeMessage') + const treeItems = Locator('.TreeItem') + + // act + await Explorer.handleDrop(5000, 5000, [], []) + + // assert + await expect(welcomeMessage).toBeVisible() + await expect(welcomeMessage).toHaveText('You have not yet opened a folder.') + await expect(treeItems).toHaveCount(0) +} diff --git a/packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts new file mode 100644 index 0000000..a9b3509 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts @@ -0,0 +1,34 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-file-and-folder-empty-workspace' + +export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { + // arrange + await Workspace.setPath('') + const opfsRoot = await navigator.storage.getDirectory() + const fileHandle = await opfsRoot.getFileHandle('dropped-file.txt', { + create: true, + }) + const directoryHandle = await opfsRoot.getDirectoryHandle('mixed-dropped-workspace-folder', { + create: true, + }) + const nestedFileHandle = await directoryHandle.getFileHandle('folder-inside.txt', { + create: true, + }) + const writable = await nestedFileHandle.createWritable({ keepExistingData: false }) + await writable.write('folder') + await writable.close() + const fileId = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) + const directoryId = await Command.execute('FileSystemHandle.addFileHandle', directoryHandle) + const welcomeMessage = Locator('.Explorer .WelcomeMessage') + const nestedFile = Locator('.TreeItem[aria-label="folder-inside.txt"]') + const droppedFile = Locator('.TreeItem[aria-label="dropped-file.txt"]') + + // act + await Explorer.handleDrop(5000, 5000, [fileId, directoryId], []) + + // assert + await expect(welcomeMessage).toBeHidden() + await expect(nestedFile).toBeVisible() + await expect(droppedFile).toHaveCount(0) +} diff --git a/packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts new file mode 100644 index 0000000..6c57eaa --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-file-empty-workspace' + +export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { + // arrange + await Workspace.setPath('') + const opfsRoot = await navigator.storage.getDirectory() + const fileHandle = await opfsRoot.getFileHandle('dropped-file.txt', { + create: true, + }) + const id = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) + const welcomeMessage = Locator('.Explorer .WelcomeMessage') + const treeItems = Locator('.TreeItem') + + // act + await Explorer.handleDrop(5000, 5000, [id], []) + + // assert + await expect(welcomeMessage).toBeVisible() + await expect(welcomeMessage).toHaveText('You have not yet opened a folder.') + await expect(treeItems).toHaveCount(0) +} diff --git a/packages/e2e/src/viewlet.explorer-drop-file.ts b/packages/e2e/src/viewlet.explorer-drop-file.ts new file mode 100644 index 0000000..f7701b2 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-file.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-file' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/new`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.handleDragOverIndex(0) + const opfsRoot = await navigator.storage.getDirectory() + const fileHandle = await opfsRoot.getFileHandle('my first file', { + create: true, + }) + const fileHandles = [fileHandle] + const files = [] + const paths = [] + const index = 0 + + // act + await Explorer.handleDropIndex(fileHandles, files, paths, index) + + // assert + const newFile = Locator('.TreeItem[aria-label="my first file"]') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts new file mode 100644 index 0000000..4488442 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-folder-empty-workspace' + +export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { + // arrange + await Workspace.setPath('') + const opfsRoot = await navigator.storage.getDirectory() + const directoryHandle = await opfsRoot.getDirectoryHandle('dropped-workspace-folder', { + create: true, + }) + const nestedFileHandle = await directoryHandle.getFileHandle('inside.txt', { + create: true, + }) + const writable = await nestedFileHandle.createWritable({ keepExistingData: false }) + await writable.write('hello world') + await writable.close() + const id = await Command.execute('FileSystemHandle.addFileHandle', directoryHandle) + const welcomeMessage = Locator('.Explorer .WelcomeMessage') + + // act + await Explorer.handleDrop(5000, 5000, [id], []) + + // assert + await expect(welcomeMessage).toBeHidden() + const nestedFile = Locator('.TreeItem[aria-label="inside.txt"]') + await expect(nestedFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts b/packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts new file mode 100644 index 0000000..2b1f678 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts @@ -0,0 +1,35 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-folder-with-files' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/new`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.handleDragOverIndex(0) + const opfsRoot = await navigator.storage.getDirectory() + const directoryHandle = await opfsRoot.getDirectoryHandle('my first folder', { + create: true, + }) + const nestedFileHandle = await directoryHandle.getFileHandle('my first nested file', { create: true }) + const writable = await nestedFileHandle.createWritable({ keepExistingData: false }) + await writable.write('hello world') + await writable.close() + const fileHandles = [directoryHandle] + const files = [] + const paths = [] + const index = 0 + + // act + await Explorer.handleDropIndex(fileHandles, files, paths, index) + await Explorer.expandRecursively() + + // assert + const newFolder = Locator('.TreeItem[aria-label="my first folder"]') + await expect(newFolder).toBeVisible() + await expect(newFolder).toHaveAttribute('aria-expanded', 'true') + const newFile = Locator('.TreeItem[aria-label="my first nested file"]') + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-drop-folder.ts b/packages/e2e/src/viewlet.explorer-drop-folder.ts new file mode 100644 index 0000000..5a893b0 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-folder.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-file' + +export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/new`) + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + await Explorer.handleDragOverIndex(0) + + // act + const opfsRoot = await navigator.storage.getDirectory() + const directoryHandle = await opfsRoot.getDirectoryHandle('my first folder', { + create: true, + }) + const fileHandles = [directoryHandle] + const files = [] + const paths = [] + const index = 0 + await Command.execute('Explorer.handleDropIndex', fileHandles, files, paths, index) + + // assert + const newFolder = Locator('.TreeItem[aria-label="my first folder"]') + await expect(newFolder).toBeVisible() + await expect(newFolder).toHaveAttribute('aria-expanded', 'false') +} diff --git a/packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts new file mode 100644 index 0000000..6ab51fc --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts @@ -0,0 +1,40 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-drop-two-folders-empty-workspace' + +export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { + // arrange + await Workspace.setPath('') + const opfsRoot = await navigator.storage.getDirectory() + const firstDirectoryHandle = await opfsRoot.getDirectoryHandle('first-dropped-workspace-folder', { + create: true, + }) + const firstNestedFileHandle = await firstDirectoryHandle.getFileHandle('first-inside.txt', { + create: true, + }) + const firstWritable = await firstNestedFileHandle.createWritable({ keepExistingData: false }) + await firstWritable.write('first') + await firstWritable.close() + const secondDirectoryHandle = await opfsRoot.getDirectoryHandle('second-dropped-workspace-folder', { + create: true, + }) + const secondNestedFileHandle = await secondDirectoryHandle.getFileHandle('second-inside.txt', { + create: true, + }) + const secondWritable = await secondNestedFileHandle.createWritable({ keepExistingData: false }) + await secondWritable.write('second') + await secondWritable.close() + const firstId = await Command.execute('FileSystemHandle.addFileHandle', firstDirectoryHandle) + const secondId = await Command.execute('FileSystemHandle.addFileHandle', secondDirectoryHandle) + const welcomeMessage = Locator('.Explorer .WelcomeMessage') + const firstNestedFile = Locator('.TreeItem[aria-label="first-inside.txt"]') + const secondNestedFile = Locator('.TreeItem[aria-label="second-inside.txt"]') + + // act + await Explorer.handleDrop(5000, 5000, [firstId, secondId], []) + + // assert + await expect(welcomeMessage).toBeHidden() + await expect(firstNestedFile).toBeVisible() + await expect(secondNestedFile).toHaveCount(0) +} diff --git a/packages/e2e/src/viewlet.explorer-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-empty-workspace.ts new file mode 100644 index 0000000..9885ed9 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-empty-workspace.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-empty-workspace' + +export const test: Test = async ({ expect, Explorer, Locator, Workspace }) => { + // act + await Workspace.setPath('') + + // assert + const explorer = Locator('.Explorer') + await expect(explorer).toBeVisible() + const welcome = Locator('.Explorer .Welcome') + await expect(welcome).toBeVisible() + const welcomeMessage = Locator('.Explorer .WelcomeMessage') + await expect(welcomeMessage).toBeVisible() + await expect(welcomeMessage).toHaveText('You have not yet opened a folder.') + const openFolderButton = Locator('.Explorer .Button') + await expect(openFolderButton).toBeVisible() + await expect(openFolderButton).toHaveText('Open folder') + + await Explorer.handleDragOver(5000, 5000) + await expect(explorer).toHaveClass('DropTarget') +} diff --git a/packages/e2e/src/viewlet.explorer-expand-all.ts b/packages/e2e/src/viewlet.explorer-expand-all.ts new file mode 100644 index 0000000..f4fe9a5 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-all.ts @@ -0,0 +1,53 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-all' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/folder-1`) + await FileSystem.mkdir(`${tmpDir}/folder-2`) + await FileSystem.mkdir(`${tmpDir}/folder-3`) + await FileSystem.writeFile(`${tmpDir}/folder-1/a.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-1/b.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-1/c.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-2/a.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-2/b.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-2/c.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-3/a.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-3/b.txt`, '') + await FileSystem.writeFile(`${tmpDir}/folder-3/c.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + + // act + await Explorer.expandAll() + + // assert + const items = Locator('.TreeItem') + await expect(items).toHaveCount(12) + const itemOne = items.nth(0) + const itemTwo = items.nth(1) + const itemThree = items.nth(2) + const itemFour = items.nth(3) + const itemFive = items.nth(4) + const itemSix = items.nth(5) + const itemSeven = items.nth(6) + const itemEight = items.nth(7) + const itemNine = items.nth(8) + const itemTen = items.nth(9) + const itemEleven = items.nth(10) + const itemTwelve = items.nth(11) + await expect(itemOne).toHaveText('folder-1') + await expect(itemTwo).toHaveText('a.txt') + await expect(itemThree).toHaveText('b.txt') + await expect(itemFour).toHaveText('c.txt') + await expect(itemFive).toHaveText('folder-2') + await expect(itemSix).toHaveText('a.txt') + await expect(itemSeven).toHaveText('b.txt') + await expect(itemEight).toHaveText('c.txt') + await expect(itemNine).toHaveText('folder-3') + await expect(itemTen).toHaveText('a.txt') + await expect(itemEleven).toHaveText('b.txt') + await expect(itemTwelve).toHaveText('c.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts new file mode 100644 index 0000000..dd15fba --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts @@ -0,0 +1,35 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-folder-10-items' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/stress-folder`) + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00000.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00001.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00002.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00003.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00004.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00005.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00006.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00007.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00008.txt`, '') + await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00009.txt`, '') + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusFirst() + const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) + await expect(folder).toHaveId('TreeItemActive') + await Explorer.clickCurrent() + + // assert + await expect(folder).toHaveAttribute('aria-expanded', 'true') + const firstItem = Locator('.TreeItem', { hasText: 'item-00000.txt' }) + const lastItem = Locator('.TreeItem', { hasText: 'item-00009.txt' }) + await expect(firstItem).toBeVisible() + await Explorer.focusIndex(10) + await expect(lastItem).toBeVisible() + await expect(lastItem).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts new file mode 100644 index 0000000..59fba0b --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts @@ -0,0 +1,29 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-folder-100-items' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/stress-folder`) + for (let index = 0; index < 100; index++) { + const fileName = `item-${index.toString().padStart(5, '0')}.txt` + await FileSystem.writeFile(`${tmpDir}/stress-folder/${fileName}`, '') + } + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusFirst() + const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) + await expect(folder).toHaveId('TreeItemActive') + await Explorer.clickCurrent() + + // assert + await expect(folder).toHaveAttribute('aria-expanded', 'true') + const firstItem = Locator('.TreeItem', { hasText: 'item-00000.txt' }) + const lastItem = Locator('.TreeItem', { hasText: 'item-00099.txt' }) + await expect(firstItem).toBeVisible() + await Explorer.focusIndex(100) + await expect(lastItem).toBeVisible() + await expect(lastItem).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts new file mode 100644 index 0000000..8b3894f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts @@ -0,0 +1,38 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-folder-100k-items' + +export const skip = 1 + +const totalItems = 100_000 +const batchSize = 500 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/stress-folder`) + for (let start = 0; start < totalItems; start += batchSize) { + const end = Math.min(start + batchSize, totalItems) + await Promise.all( + Array.from({ length: end - start }, (_, index) => { + const number = start + index + const fileName = `item-${number.toString().padStart(6, '0')}.txt` + return FileSystem.writeFile(`${tmpDir}/stress-folder/${fileName}`, '') + }), + ) + } + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusFirst() + const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) + await expect(folder).toHaveId('TreeItemActive') + await Explorer.clickCurrent() + + // assert + await expect(folder).toHaveAttribute('aria-expanded', 'true') + const firstItem = Locator('.TreeItem', { hasText: 'item-000000.txt' }) + const secondItem = Locator('.TreeItem', { hasText: 'item-000001.txt' }) + await expect(firstItem).toBeVisible() + await expect(secondItem).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts new file mode 100644 index 0000000..0d3ca1e --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts @@ -0,0 +1,38 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-folder-10k-items' + +const totalItems = 10_000 +const batchSize = 500 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/stress-folder`) + for (let start = 0; start < totalItems; start += batchSize) { + const end = Math.min(start + batchSize, totalItems) + await Promise.all( + Array.from({ length: end - start }, (_, index) => { + const number = start + index + const fileName = `item-${number.toString().padStart(5, '0')}.txt` + return FileSystem.writeFile(`${tmpDir}/stress-folder/${fileName}`, '') + }), + ) + } + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusFirst() + const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) + await expect(folder).toHaveId('TreeItemActive') + await Explorer.clickCurrent() + + // assert + await expect(folder).toHaveAttribute('aria-expanded', 'true') + const firstItem = Locator('.TreeItem', { hasText: 'item-00000.txt' }) + const lastItem = Locator('.TreeItem', { hasText: 'item-09999.txt' }) + await expect(firstItem).toBeVisible() + await Explorer.focusIndex(10_000) + await expect(lastItem).toBeVisible() + await expect(lastItem).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts new file mode 100644 index 0000000..972bd84 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts @@ -0,0 +1,25 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-folder-10m-items' +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, Extension, Locator, Workspace }) => { + // arrange + const extensionUri = import.meta.resolve('../fixtures/sample.file-system-provider-expand-folder-10m-items') + await Extension.addWebExtension(extensionUri) + const workspacePath = 'extension-host://xyz://' + await Workspace.setPath(workspacePath) + + // act + await Explorer.focusFirst() + const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) + await expect(folder).toHaveId('TreeItemActive') + await Explorer.clickCurrent() + + // assert + await expect(folder).toHaveAttribute('aria-expanded', 'true') + const firstItem = Locator('.TreeItem', { hasText: 'item-00000000.txt' }) + const secondItem = Locator('.TreeItem', { hasText: 'item-00000001.txt' }) + await expect(firstItem).toBeVisible() + await expect(secondItem).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts new file mode 100644 index 0000000..a430ac6 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts @@ -0,0 +1,25 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-folder-1m-items' +export const skip = 1 + +export const test: Test = async ({ expect, Explorer, Extension, Locator, Workspace }) => { + // arrange + const extensionUri = import.meta.resolve('../fixtures/sample.file-system-provider-expand-folder-1m-items') + await Extension.addWebExtension(extensionUri) + const workspacePath = 'extension-host://xyz://' + await Workspace.setPath(workspacePath) + + // act + await Explorer.focusFirst() + const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) + await expect(folder).toHaveId('TreeItemActive') + await Explorer.clickCurrent() + + // assert + await expect(folder).toHaveAttribute('aria-expanded', 'true') + const firstItem = Locator('.TreeItem', { hasText: 'item-0000000.txt' }) + const secondItem = Locator('.TreeItem', { hasText: 'item-0000001.txt' }) + await expect(firstItem).toBeVisible() + await expect(secondItem).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-expand-recursively.ts b/packages/e2e/src/viewlet.explorer-expand-recursively.ts new file mode 100644 index 0000000..03847b2 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-expand-recursively.ts @@ -0,0 +1,30 @@ +// TODO maybe merge this test with the other explorer test, less end to end tests will run faster + +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-expand-recursively' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a/b`) + await FileSystem.writeFile(`${tmpDir}/a/b/c.txt`, 'ccccc') + await FileSystem.mkdir(`${tmpDir}/folder-1`) + await FileSystem.mkdir(`${tmpDir}/folder-2`) + await FileSystem.mkdir(`${tmpDir}/folder-3`) + await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + + // act + await Explorer.expandRecursively() + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + const secondTreeItem = treeItems.nth(1) + const thirdTreeItem = treeItems.nth(2) + await expect(firstTreeItem).toHaveText('a') + await expect(secondTreeItem).toHaveText('b') + await expect(thirdTreeItem).toHaveText('c.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-file-system-provider-error.ts b/packages/e2e/src/viewlet.explorer-file-system-provider-error.ts new file mode 100644 index 0000000..251052d --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-file-system-provider-error.ts @@ -0,0 +1,31 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-file-system-provider-error' +export const skip = 1 + +export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') + await Workspace.setPath(tmpDir) + + // Mock file system provider to throw an error + await Command.execute('FileSystemProvider.setError', true) + + // act & assert - Try to expand directory when provider throws error + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + + // Should show error state or handle gracefully + const errorMessage = Locator('.ErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('File system provider error') + + // Reset error state + await Command.execute('FileSystemProvider.setError', false) + + // Should recover and work normally + await Explorer.refresh() + const fileItem = Locator('.TreeItem', { hasText: 'file.txt' }) + await expect(fileItem).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts b/packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts new file mode 100644 index 0000000..7b0782e --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts @@ -0,0 +1,37 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-file-system-provider-invalid-data' +export const skip = 1 + +export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') + await Workspace.setPath(tmpDir) + + // Mock file system provider to return invalid data (null/undefined entries) + await Command.execute('FileSystemProvider.setInvalidData', true) + + // act & assert - Try to expand directory when provider returns invalid data + await Explorer.focusIndex(0) + await Explorer.expandRecursively() + + // Should handle invalid data gracefully and not crash + const treeItems = Locator('.TreeItem') + const firstItem = treeItems.first() + + // Should still show valid items, ignoring invalid ones + await expect(firstItem).toBeVisible() + + // Should not show broken UI elements + const brokenItems = Locator('.TreeItem[aria-label*="undefined"], .TreeItem[aria-label*="null"]') + await expect(brokenItems).toHaveCount(0) + + // Reset to normal data + await Command.execute('FileSystemProvider.setInvalidData', false) + await Explorer.refresh() + + // Should work normally after reset + const fileItem = Locator('.TreeItem', { hasText: 'file.txt' }) + await expect(fileItem).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts b/packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts new file mode 100644 index 0000000..1895a39 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts @@ -0,0 +1,18 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-copy-no-selection' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(-1) + + // act + await Explorer.handleCopy() + + // assert + const file1 = Locator('.TreeItem', { hasText: 'file-1.txt' }) + await expect(file1).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts b/packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts new file mode 100644 index 0000000..9bf002c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts @@ -0,0 +1,18 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-cut-no-selection' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(-1) + + // act + await Explorer.handleCut() + + // assert + const file1 = Locator('.TreeItem', { hasText: 'file-1.txt' }) + await expect(file1).toHaveClass('TreeItem') +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-leave.ts b/packages/e2e/src/viewlet.explorer-handle-drag-leave.ts new file mode 100644 index 0000000..327838a --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drag-leave.ts @@ -0,0 +1,25 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drag-leave' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.handleDragOver(5000, 5000) + + // assert + const explorer = Locator('.Explorer .ListItems') + await expect(explorer).toHaveClass('DropTarget') + + // act + await Explorer.handleDragLeave() + + // assert + // TODO +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts new file mode 100644 index 0000000..110833e --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts @@ -0,0 +1,19 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drag-over-all' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.handleDragOver(5000, 5000) + + // assert + const explorer = Locator('.Explorer .ListItems') + await expect(explorer).toHaveClass('DropTarget') +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts new file mode 100644 index 0000000..babc5ac --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drag-over-folder' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') + await FileSystem.writeFile(`${tmpDir}/a/c.txt`, '') + await FileSystem.writeFile(`${tmpDir}/a/d.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.expandRecursively() + + // act + await Explorer.handleDragOverIndex(2) + + // assert + const treeItems = Locator('.Explorer .TreeItem') + const treeItemOne = treeItems.nth(0) + await expect(treeItemOne).toHaveClass('DropTarget') + const treeItemTwo = treeItems.nth(1) + await expect(treeItemTwo).toHaveClass('DropTarget') + const treeItemThree = treeItems.nth(2) + await expect(treeItemThree).toHaveClass('DropTarget') + const treeItemFour = treeItems.nth(3) + await expect(treeItemFour).toHaveClass('DropTarget') +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts new file mode 100644 index 0000000..d37a8ec --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts @@ -0,0 +1,18 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drag-over-folder' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await Workspace.setPath(tmpDir) + + // act + await Explorer.handleDragOverIndex(0) + + // assert + const treeItems = Locator('.Explorer .TreeItem') + const treeItemOne = treeItems.nth(0) + await expect(treeItemOne).toHaveClass('DropTarget') +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts new file mode 100644 index 0000000..2a4cb8a --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts @@ -0,0 +1,17 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drag-over-index-out-of-range' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') + await Workspace.setPath(tmpDir) + + // act + await Explorer.handleDragOverIndex(999) + + // assert + const explorer = Locator('.Explorer .ListItems') + await expect(explorer).toHaveClass('DropTarget') +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts new file mode 100644 index 0000000..6075e74 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts @@ -0,0 +1,18 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drag-over-index-root' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') + await FileSystem.writeFile(`${tmpDir}/file-2.txt`, 'b') + await Workspace.setPath(tmpDir) + + // act + await Explorer.handleDragOverIndex(-1) + + // assert + const explorer = Locator('.Explorer .ListItems') + await expect(explorer).toHaveClass('DropTarget') +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over.ts new file mode 100644 index 0000000..3a82e49 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drag-over.ts @@ -0,0 +1,19 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drag-over' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.handleDragOver(5000, 5000) + + // assert + const explorer = Locator('.Explorer .ListItems') + await expect(explorer).toHaveClass('DropTarget') +} diff --git a/packages/e2e/src/viewlet.explorer-handle-drop.ts b/packages/e2e/src/viewlet.explorer-handle-drop.ts new file mode 100644 index 0000000..257cbe3 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-drop.ts @@ -0,0 +1,26 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-handle-drop' + +export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + const directory = await navigator.storage.getDirectory() + const fileHandle = await directory.getFileHandle('dropped-file.txt', { + create: true, + }) + const file = await fileHandle.getFile() + const fileList = [file] + const id = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) + + // act + await Explorer.handleDrop(0, 0, [id], fileList) + + // assert + const droppedFile = Locator('.TreeItem', { hasText: 'dropped-file.txt' }) + await expect(droppedFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts b/packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts new file mode 100644 index 0000000..922644b --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-icon-theme.change' + +export const skip = 1 + +export const test: Test = async ({ BaseUrl, expect, Extension, FileSystem, IconTheme, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/test.xyz`, 'test') + await FileSystem.mkdir(`${tmpDir}/test-folder`) + await Workspace.setPath(tmpDir) + const extensionUri = import.meta.resolve('../fixtures/sample.icon-theme') + await Extension.addWebExtension(extensionUri) + + // act + await IconTheme.setIconTheme('test-icon-theme') + + // assert + const iconFile = Locator('.TreeItem[aria-label="test.xyz"] .FileIcon') + const baseUrl = BaseUrl.getBaseUrl() + await expect(iconFile).toHaveAttribute('src', `${baseUrl}packages/extension-host-worker-tests/fixtures/sample.icon-theme/icons/default_file.svg`) +} diff --git a/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts b/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts new file mode 100644 index 0000000..0bcbf9f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-ignored-file-decoration-invalid-null' + +export const test: Test = async ({ expect, Extension, FileSystem, Locator, Settings, Workspace }) => { + // arrange + await Settings.update({ + 'explorer.sourceControlDecorations': true, + }) + const uri = import.meta.resolve('../fixtures/sample.source-control-decoration-invalid-null') + await Extension.addWebExtension(uri) + const tmpDir = 'extension-host://xyz://' + await FileSystem.writeFile(`${tmpDir}/a`, '') + await FileSystem.writeFile(`${tmpDir}/b`, '') + await FileSystem.writeFile(`${tmpDir}/.gitignore`, 'a') + + // act + await Workspace.setPath(tmpDir) + + // assert + const a = Locator('.TreeItem[aria-label="a"]') + await expect(a).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts b/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts new file mode 100644 index 0000000..1ff93ed --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-ignored-file-decoration-invalid-object' + +export const test: Test = async ({ expect, Extension, FileSystem, Locator, Settings, Workspace }) => { + // arrange + await Settings.update({ + 'explorer.sourceControlDecorations': true, + }) + const uri = import.meta.resolve('../fixtures/sample.source-control-decoration-invalid-object') + await Extension.addWebExtension(uri) + const tmpDir = 'extension-host://xyz://' + await FileSystem.writeFile(`${tmpDir}/a`, '') + await FileSystem.writeFile(`${tmpDir}/b`, '') + await FileSystem.writeFile(`${tmpDir}/.gitignore`, 'a') + + // act + await Workspace.setPath(tmpDir) + + // assert + const a = Locator('.TreeItem[aria-label="a"]') + await expect(a).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts b/packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts new file mode 100644 index 0000000..4653aa3 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts @@ -0,0 +1,26 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-ignored-file-decoration' + +export const skip = 1 + +export const test: Test = async ({ expect, Extension, FileSystem, Locator, Settings, Workspace }) => { + // arrange + await Settings.update({ + 'explorer.sourceControlDecorations': true, + }) + const uri = import.meta.resolve('../fixtures/sample.source-control-decoration') + await Extension.addWebExtension(uri) + const tmpDir = 'extension-host://xyz://' + await FileSystem.writeFile(`${tmpDir}/a`, '') + await FileSystem.writeFile(`${tmpDir}/b`, '') + await FileSystem.writeFile(`${tmpDir}/.gitignore`, 'a') + + // act + await Workspace.setPath(tmpDir) + + // assert + const a = Locator('.TreeItem[aria-label="a"]') + await expect(a).toBeVisible() + await expect(a).toHaveClass('decoration-ignored') +} diff --git a/packages/e2e/src/viewlet.explorer-keyboard-navigation.ts b/packages/e2e/src/viewlet.explorer-keyboard-navigation.ts new file mode 100644 index 0000000..507bf14 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-keyboard-navigation.ts @@ -0,0 +1,118 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-keyboard-navigation' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a/b`) + await FileSystem.writeFile(`${tmpDir}/a/b/c.txt`, 'ccccc') + await FileSystem.mkdir(`${tmpDir}/folder-1`) + await FileSystem.mkdir(`${tmpDir}/folder-2`) + await FileSystem.mkdir(`${tmpDir}/folder-3`) + await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(-1) + + // assert + // const explorer = Locator('.Explorer') + // await expect(explorer).toHaveClass('FocusOutline') + + // act + await Explorer.focusNext() + + // assert + const titleA = '/a' + const treeItemA = Locator(`.TreeItem[title$="${titleA}"]`) + await expect(treeItemA).toHaveId('TreeItemActive') + + // act + await Explorer.clickCurrent() + + // assert + const titleB = '/a/b' + const treeItemB = Locator(`.TreeItem[title$="${titleB}"]`) + await expect(treeItemB).toBeVisible() + await expect(treeItemA).toHaveId('TreeItemActive') + + // act + await Explorer.focusNext() + + // assert + await expect(treeItemB).toHaveId('TreeItemActive') + + // act + await Explorer.clickCurrent() + + // assert + const titleC = '/a/b/c.txt' + const treeItemC = Locator(`.TreeItem[title$="${titleC}"]`) + await expect(treeItemC).toBeVisible() + await expect(treeItemB).toHaveId('TreeItemActive') + + // act + await Explorer.focusNext() + + // assert + await expect(treeItemC).toHaveId('TreeItemActive') + + // act + await Explorer.clickCurrent() + + // assert + const editor = Locator('.Editor') + await expect(editor).toHaveText('ccccc') + + // act + await Explorer.handleArrowLeft() + + // assert + await expect(treeItemB).toHaveId('TreeItemActive') + await expect(treeItemC).toBeVisible() + + // act + await Explorer.handleArrowLeft() + + // assert + await expect(treeItemB).toHaveId('TreeItemActive') + await expect(treeItemC).toBeHidden() + + // act + await Explorer.handleArrowLeft() + + // assert + await expect(treeItemA).toHaveId('TreeItemActive') + await expect(treeItemB).toBeVisible() + + // act + await Explorer.handleArrowLeft() + + // assert + await expect(treeItemA).toHaveId('TreeItemActive') + await expect(treeItemB).toBeHidden() + + // act + await Explorer.focusLast() + + // assert + const titleTest = '/test.txt' + const treeItemTestTxt = Locator(`.TreeItem[title$="${titleTest}"]`) + await expect(treeItemTestTxt).toHaveId('TreeItemActive') + + // act + await Explorer.focusFirst() + + // assert + await expect(treeItemA).toHaveId('TreeItemActive') + + // act + await Explorer.removeDirent() + + // assert + await expect(treeItemA).toBeHidden() + const titleFolder1 = `/folder-1` + const treeItemFolder1 = Locator(`.TreeItem[title$="${titleFolder1}"]`) + await expect(treeItemFolder1).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-large-directory-performance.ts b/packages/e2e/src/viewlet.explorer-large-directory-performance.ts new file mode 100644 index 0000000..2d7afde --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-large-directory-performance.ts @@ -0,0 +1,52 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-large-directory-performance' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + + // Create 10,000 files in the directory + const numbers = Array.from(Array(10_000), (_, index) => index) + await Promise.all( + numbers.map((number) => { + return FileSystem.writeFile(`${tmpDir}/file${number.toString().padStart(4, '0')}.txt`, `content ${number}`) + }), + ) + + await Workspace.setPath(tmpDir) + + // Test 1: Initial load performance + await Explorer.focusIndex(0) + // await Explorer.expandRecursively() + + // Should load within reasonable time + + // Test 2: Verify items are loaded + const firstItem = Locator('.TreeItem').nth(0) + await expect(firstItem).toBeVisible() + + // Test 3: Navigation performance in large list + await Explorer.focusIndex(100) + await Explorer.focusIndex(1000) + await Explorer.focusIndex(5000) + + // Should navigate quickly + + // Test 4: Verify specific items exist + const midItem = Locator('.TreeItem', { hasText: 'file5000.txt' }) + await expect(midItem).toBeVisible() + + // Test 5: Test scrolling by focusing different items + await Explorer.focusIndex(9000) + await Explorer.focusIndex(100) + + // TODO need to autoscroll to those locations + // Test 6: Verify explorer is still responsive + // const lastItem = Locator('.TreeItem', { hasText: 'file9999.txt' }) + // await expect(lastItem).toBeVisible() + + // // Test 7: Test selection performance + // await Explorer.focusIndex(0) + // await Explorer.focusIndex(5000) +} diff --git a/packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts b/packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts new file mode 100644 index 0000000..539fb9f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts @@ -0,0 +1,21 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-long-file-name-500-emoji' + +export const test: Test = async ({ expect, Extension, FileSystem, Locator, Workspace }) => { + // arrange + const uri = import.meta.resolve('../fixtures/sample.file-system-provider-permission') + await Extension.addWebExtension(uri) + const prefix = 'extension-host://xyz://' + const fileName = `${'😀'.repeat(500)}.txt` + await FileSystem.writeFile(`${prefix}/${fileName}`, '') + + // act + await Workspace.setPath(`${prefix}/`) + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + await expect(treeItems).toHaveCount(1) + await expect(firstTreeItem).toContainText(fileName) +} diff --git a/packages/e2e/src/viewlet.explorer-long-file-name.ts b/packages/e2e/src/viewlet.explorer-long-file-name.ts new file mode 100644 index 0000000..20ac829 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-long-file-name.ts @@ -0,0 +1,17 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-long-file-name' + +export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + const fileName = `a`.repeat(100) + '.txt' + await FileSystem.writeFile(`${tmpDir}/${fileName}`, '') + + // act + await Workspace.setPath(tmpDir) + + // assert + const newFile = Locator(`text=${fileName}`) + await expect(newFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-many-files-20000.ts b/packages/e2e/src/viewlet.explorer-many-files-20000.ts new file mode 100644 index 0000000..09f9979 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-many-files-20000.ts @@ -0,0 +1,47 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-many-files-20000' + +const totalFiles = 20_000 +const batchSize = 500 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + for (let start = 0; start < totalFiles; start += batchSize) { + const end = Math.min(start + batchSize, totalFiles) + await Promise.all( + Array.from({ length: end - start }, (_, index) => { + const number = start + index + const fileName = `file-${number.toString().padStart(5, '0')}.txt` + return FileSystem.writeFile(`${tmpDir}/${fileName}`, `content ${number}`) + }), + ) + } + + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(0) + + // assert + const firstFile = Locator('.TreeItem', { hasText: 'file-00000.txt' }) + await expect(firstFile).toBeVisible() + await expect(firstFile).toHaveId('TreeItemActive') + + // act + await Explorer.focusIndex(10_000) + + // assert + const middleFile = Locator('.TreeItem', { hasText: 'file-10000.txt' }) + await expect(middleFile).toBeVisible() + await expect(middleFile).toHaveId('TreeItemActive') + + // act + await Explorer.focusIndex(19_999) + + // assert + const lastFile = Locator('.TreeItem', { hasText: 'file-19999.txt' }) + await expect(lastFile).toBeVisible() + await expect(lastFile).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts b/packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts new file mode 100644 index 0000000..177562f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts @@ -0,0 +1,32 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-many-files-repeated-focus-jumps' + +const totalFiles = 2000 +const batchSize = 250 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + for (let start = 0; start < totalFiles; start += batchSize) { + const end = Math.min(start + batchSize, totalFiles) + await Promise.all( + Array.from({ length: end - start }, (_, index) => { + const number = start + index + const fileName = `file-${number.toString().padStart(4, '0')}.txt` + return FileSystem.writeFile(`${tmpDir}/${fileName}`, `content ${number}`) + }), + ) + } + await Workspace.setPath(tmpDir) + + const indices = [0, 250, 1999, 125, 1500, 1, 1998] + + for (const index of indices) { + const fileName = `file-${index.toString().padStart(4, '0')}.txt` + const file = Locator('.TreeItem', { hasText: fileName }) + await Explorer.focusIndex(index) + await expect(file).toBeVisible() + await expect(file).toHaveId('TreeItemActive') + } +} diff --git a/packages/e2e/src/viewlet.explorer-many-folders-20000.ts b/packages/e2e/src/viewlet.explorer-many-folders-20000.ts new file mode 100644 index 0000000..2699100 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-many-folders-20000.ts @@ -0,0 +1,47 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-many-folders-20000' + +const totalFolders = 20_000 +const batchSize = 500 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + for (let start = 0; start < totalFolders; start += batchSize) { + const end = Math.min(start + batchSize, totalFolders) + await Promise.all( + Array.from({ length: end - start }, (_, index) => { + const number = start + index + const folderName = `folder-${number.toString().padStart(5, '0')}` + return FileSystem.mkdir(`${tmpDir}/${folderName}`) + }), + ) + } + + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(0) + + // assert + const firstFolder = Locator('.TreeItem', { hasText: 'folder-00000' }) + await expect(firstFolder).toBeVisible() + await expect(firstFolder).toHaveId('TreeItemActive') + + // act + await Explorer.focusIndex(10_000) + + // assert + const middleFolder = Locator('.TreeItem', { hasText: 'folder-10000' }) + await expect(middleFolder).toBeVisible() + await expect(middleFolder).toHaveId('TreeItemActive') + + // act + await Explorer.focusIndex(19_999) + + // assert + const lastFolder = Locator('.TreeItem', { hasText: 'folder-19999' }) + await expect(lastFolder).toBeVisible() + await expect(lastFolder).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-mouse-navigation.ts b/packages/e2e/src/viewlet.explorer-mouse-navigation.ts new file mode 100644 index 0000000..9434cba --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-mouse-navigation.ts @@ -0,0 +1,42 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-mouse-navigation' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a/b`) + await FileSystem.writeFile(`${tmpDir}/a/b/c.txt`, 'ccccc') + await FileSystem.mkdir(`${tmpDir}/folder-1`) + await FileSystem.mkdir(`${tmpDir}/folder-2`) + await FileSystem.mkdir(`${tmpDir}/folder-3`) + await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') + await Workspace.setPath(tmpDir) + + // act + await Explorer.handleClick(-1) + + // assert + // const explorer = Locator('.Explorer') + // await expect(explorer).toHaveClass('FocusOutline') + + // act + await Explorer.handleClick(0) + + // assert + const titleA = '/a' + const treeItemA = Locator(`.TreeItem[title$="${titleA}"]`) + await expect(treeItemA).toHaveId('TreeItemActive') + + // assert + const titleB = '/a/b' + const treeItemB = Locator(`.TreeItem[title$="${titleB}"]`) + await expect(treeItemB).toBeVisible() + await expect(treeItemA).toHaveId('TreeItemActive') + + // act + await Explorer.handleClick(1) + + // assert + await expect(treeItemB).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-new-file-called-twice.ts b/packages/e2e/src/viewlet.explorer-new-file-called-twice.ts new file mode 100644 index 0000000..5454fac --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-new-file-called-twice.ts @@ -0,0 +1,20 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-new-file-called-twice' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.newFile() + await Explorer.newFile() + + // assert + const treeItems = Locator('.TreeItem') + await expect(treeItems).toHaveCount(4) +} diff --git a/packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts b/packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts new file mode 100644 index 0000000..f359385 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts @@ -0,0 +1,25 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-open-folder-enoent-error' + +export const skip = 1 + +export const test: Test = async ({ Command, expect, FileSystem, Locator, SideBar, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + const missingFolder = `${tmpDir}/missing-folder` + await Workspace.setPath(missingFolder) + await SideBar.hide() + + // act + await Command.execute('Layout.showSideBar') + + // assert + const error = Locator('.Explorer .WelcomeMessage') + await expect(error).toBeVisible() + await expect(error).toHaveText(`Could not open "${missingFolder}" because the folder does not exist. It may have been moved or deleted.`) + + const openAnotherFolderButton = Locator('.Explorer .Button') + await expect(openAnotherFolderButton).toBeVisible() + await expect(openAnotherFolderButton).toHaveText('Open another folder') +} diff --git a/packages/e2e/src/viewlet.explorer-read-folder-error.ts b/packages/e2e/src/viewlet.explorer-read-folder-error.ts new file mode 100644 index 0000000..3f89e6f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-read-folder-error.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-read-folder-error' + +export const test: Test = async ({ expect, Extension, FileSystem, Layout, Locator, SideBar, Workspace }) => { + // arrange + const uri = import.meta.resolve('../fixtures/sample-file-system-provider-read-folder-error') + await Extension.addWebExtension(uri) + const prefix = 'extension-host://xyz://' + await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') + await Workspace.setPath(`${prefix}/`) + await SideBar.hide() + + // act + await Layout.showSideBar() + + // assert + const error = Locator('.Explorer .WelcomeMessage') + await expect(error).toBeVisible() + await expect(error).toHaveText(`Could not open folder due to Failed to execute file system provider: FileNotFoundError: File not found.`) +} diff --git a/packages/e2e/src/viewlet.explorer-refresh.ts b/packages/e2e/src/viewlet.explorer-refresh.ts new file mode 100644 index 0000000..d2e1792 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-refresh.ts @@ -0,0 +1,25 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-refresh' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + // act + await Workspace.setPath(tmpDir) + + // assert + const file1 = Locator('.TreeItem[aria-label="file1.txt"]') + await expect(file1).toBeVisible() + + // act + await FileSystem.remove(`${tmpDir}/file1.txt`) + await Explorer.refresh() + + // assert + await expect(file1).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-150-times.ts b/packages/e2e/src/viewlet.explorer-rename-file-150-times.ts new file mode 100644 index 0000000..92e76bd --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-150-times.ts @@ -0,0 +1,46 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file-150-times' + +const renameCount = 150 + +const getFileName = (index: number): string => { + return `file-${index.toString().padStart(3, '0')}.txt` +} + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/${getFileName(0)}`, 'content') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(0) + + const explorer = Locator('.Explorer') + const inputBox = explorer.locator('input') + + let currentFileName = getFileName(0) + + // act + for (let i = 1; i <= renameCount; i++) { + await Explorer.renameDirent() + await expect(inputBox).toHaveValue(currentFileName) + + const nextFileName = getFileName(i) + await Explorer.updateEditingValue(nextFileName) + await Explorer.acceptEdit() + + const renamedFile = Locator('.TreeItem', { hasText: nextFileName }) + await expect(renamedFile).toBeVisible() + await expect(renamedFile).toHaveId('TreeItemActive') + + currentFileName = nextFileName + } + + // assert + const finalFile = Locator('.TreeItem', { hasText: getFileName(renameCount) }) + const originalFile = Locator('.TreeItem', { hasText: getFileName(0) }) + await expect(inputBox).toBeHidden() + await expect(finalFile).toBeVisible() + await expect(finalFile).toHaveId('TreeItemActive') + await expect(originalFile).toBeHidden() +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts b/packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts new file mode 100644 index 0000000..1900dc6 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts @@ -0,0 +1,32 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file-cancel-150-times' + +const iterations = 150 + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + const explorer = Locator('.Explorer') + const inputBox = explorer.locator('input') + + // act + for (let index = 0; index < iterations; index++) { + await Explorer.focusIndex(1) + await Explorer.renameDirent() + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + await Explorer.cancelEdit() + await expect(inputBox).toBeHidden() + } + + // assert + const file2 = Locator('.TreeItem', { hasText: 'file2.txt' }) + await expect(file2).toBeVisible() + await expect(file2).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-cancel.ts b/packages/e2e/src/viewlet.explorer-rename-file-cancel.ts new file mode 100644 index 0000000..6c85602 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-cancel.ts @@ -0,0 +1,35 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file-cancel' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(1) + await Explorer.renameDirent() + + // assert + const explorer = Locator('.Explorer') + const inputBox = explorer.locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.cancelEdit() + + // assert + await expect(inputBox).toBeHidden() + + const file2 = Locator('.TreeItem', { hasText: 'file2.txt' }) + await expect(file2).toBeVisible() + + // TODO + // await expect(explorer).toBeFocused() + await expect(file2).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts b/packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts new file mode 100644 index 0000000..4407ab7 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts @@ -0,0 +1,32 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-create-file-error-no-name-provided' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(1) + await Explorer.renameDirent() + + // assert + const explorer = Locator('.Explorer') + const inputBox = explorer.locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('') + + // assert + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('A file or folder name must be provided.') +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts b/packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts new file mode 100644 index 0000000..266b5f3 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts @@ -0,0 +1,28 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file-error-permission-denied' + +export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { + // arrange + const uri = import.meta.resolve('../fixtures/sample.file-system-provider-permission') + await Extension.addWebExtension(uri) + + const prefix = 'extension-host://xyz://' + await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') + await Workspace.setPath(`${prefix}/`) + await Explorer.focusIndex(0) + + // act + await Explorer.rename() + await Explorer.updateEditingValue('file4.txt') + await Explorer.acceptEdit() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + await expect(inputBox).toHaveClass('InputValidationError') + const errorMessage = Locator('.ExplorerErrorMessage') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('Error: Failed to execute file system provider: Permission Denied') +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts b/packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts new file mode 100644 index 0000000..8a75a2c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts @@ -0,0 +1,75 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file-special-characters' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/original1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/original2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/original3.txt`, 'content 3') + await FileSystem.writeFile(`${tmpDir}/original4.txt`, 'content 4') + await FileSystem.writeFile(`${tmpDir}/original5.txt`, 'content 5') + + await Workspace.setPath(tmpDir) + + // Test 1: Rename file to include brackets and parentheses + const explorer1 = Locator('.Explorer') + await Explorer.focusIndex(0) + await Explorer.renameDirent() + const inputBox1 = explorer1.locator('input') + await expect(inputBox1).toBeVisible() + await expect(inputBox1).toBeFocused() + await Explorer.updateEditingValue('renamed[1](test).txt') + await Explorer.acceptEdit() + const renamedFile1 = Locator('text=renamed[1](test).txt') + await expect(renamedFile1).toBeVisible() + + // Test 2: Rename file to include special symbols + const explorer2 = Locator('.Explorer') + await Explorer.focusIndex(0) + await Explorer.renameDirent() + const inputBox2 = explorer2.locator('input') + await expect(inputBox2).toBeVisible() + await expect(inputBox2).toBeFocused() + await Explorer.updateEditingValue('special@#$%&.txt') + await Explorer.acceptEdit() + const renamedFile2 = Locator('text=special@#$%&.txt') + await expect(renamedFile2).toBeVisible() + + // Test 3: Rename file to include Unicode characters + const explorer3 = Locator('.Explorer') + await Explorer.focusIndex(0) + await Explorer.renameDirent() + const inputBox3 = explorer3.locator('input') + await expect(inputBox3).toBeVisible() + await expect(inputBox3).toBeFocused() + await Explorer.updateEditingValue('файл.txt') + await Explorer.acceptEdit() + const renamedFile3 = Locator('text=файл.txt') + await expect(renamedFile3).toBeVisible() + + // Test 4: Rename file to include emoji + const explorer4 = Locator('.Explorer') + await Explorer.focusIndex(0) + await Explorer.renameDirent() + const inputBox4 = explorer4.locator('input') + await expect(inputBox4).toBeVisible() + await expect(inputBox4).toBeFocused() + await Explorer.updateEditingValue('🎉 celebration.txt') + await Explorer.acceptEdit() + const renamedFile4 = Locator('text=🎉 celebration.txt') + await expect(renamedFile4).toBeVisible() + + // Test 5: Rename file to include mixed characters + const explorer5 = Locator('.Explorer') + await Explorer.focusIndex(0) + await Explorer.renameDirent() + const inputBox5 = explorer5.locator('input') + await expect(inputBox5).toBeVisible() + await expect(inputBox5).toBeFocused() + await Explorer.updateEditingValue('mixéd-🌟-file@123.txt') + await Explorer.acceptEdit() + const renamedFile5 = Locator('text=mixéd-🌟-file@123.txt') + await expect(renamedFile5).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-twice.ts b/packages/e2e/src/viewlet.explorer-rename-file-twice.ts new file mode 100644 index 0000000..d8504d9 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-twice.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file-twice' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(2) + + // act + await Explorer.renameDirent() + await Explorer.updateEditingValue('file4.txt') + await Explorer.acceptEdit() + await Explorer.renameDirent() + await Explorer.updateEditingValue('file3.txt') + await Explorer.acceptEdit() + + // assert + const file4 = Locator('.TreeItem', { hasText: 'file4.txt' }) + await expect(file4).toBeHidden() + const file3 = Locator('.TreeItem', { hasText: 'file3.txt' }) + await expect(file3).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts b/packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts new file mode 100644 index 0000000..6c5da0c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts @@ -0,0 +1,31 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file-whitespace' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/ `, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(0) + await Explorer.renameDirent() + + // assert + const explorer = Locator('.Explorer') + const inputBox = explorer.locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('file1.txt') + await Explorer.acceptEdit() + + // // assert + await expect(inputBox).toBeHidden() + const file1 = Locator('.TreeItem', { hasText: 'file1.txt' }) + await expect(file1).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-rename-file.ts b/packages/e2e/src/viewlet.explorer-rename-file.ts new file mode 100644 index 0000000..a18d9b2 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-file.ts @@ -0,0 +1,37 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-file' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(1) + await Explorer.renameDirent() + + // assert + const explorer = Locator('.Explorer') + const inputBox = explorer.locator('input') + await expect(inputBox).toHaveValue('file2.txt') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('file4.txt') + await Explorer.acceptEdit() + + // assert + await expect(inputBox).toBeHidden() + + const file4 = Locator('.TreeItem', { hasText: 'file4.txt' }) + await expect(file4).toBeVisible() + const listItems = explorer.locator('.ListItems') + await expect(listItems).toBeFocused() + await expect(file4).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-rename-folder-nested.ts b/packages/e2e/src/viewlet.explorer-rename-folder-nested.ts new file mode 100644 index 0000000..9852546 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-folder-nested.ts @@ -0,0 +1,39 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-folder-nested' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/a`) + await FileSystem.mkdir(`${tmpDir}/a/b`) + await FileSystem.mkdir(`${tmpDir}/a/b/c`) + await FileSystem.writeFile(`${tmpDir}/file1.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.expandRecursively() + + // act + await Explorer.focusIndex(1) + await Explorer.renameDirent() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(inputBox).toBeFocused() + + // act + await Explorer.updateEditingValue('d') + await Explorer.acceptEdit() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveText('a') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveText('d') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).toHaveText('c') + const file4 = Locator('.TreeItem').nth(3) + await expect(file4).toHaveText('file1.txt') + + // TODO folder d should be expanded +} diff --git a/packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts b/packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts new file mode 100644 index 0000000..89fed86 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts @@ -0,0 +1,34 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-rename-root-folder-no-indent-shift' + +export const test: Test = async ({ expect, Explorer, Extension, FileSystem, IconTheme, Locator, Settings, Workspace }) => { + // arrange + await Settings.update({ + 'explorer.useChevrons': true, + }) + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/folder-a`) + await FileSystem.writeFile(`${tmpDir}/file.txt`, '') + await Workspace.setPath(tmpDir) + const extensionUri = import.meta.resolve('../fixtures/sample.icon-theme') + await Extension.addWebExtension(extensionUri) + await IconTheme.setIconTheme('test-icon-theme') + + const folder = Locator('.TreeItem').nth(0) + await expect(folder).toHaveText('folder-a') + + // act + await Explorer.focusIndex(0) + + // assert + await expect(folder).toHaveJSProperty('className', 'TreeItem Indent-12 TreeItemActive') + + // act + await Explorer.renameDirent() + + // assert + const inputBox = Locator('input') + await expect(inputBox).toBeVisible() + await expect(folder).toHaveJSProperty('className', 'TreeItem Indent-12 TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts b/packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts new file mode 100644 index 0000000..95b0dc6 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts @@ -0,0 +1,36 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-reveal-from-tab-context-menu' + +export const skip = 1 + +export const test: Test = async ({ Command, ContextMenu, expect, Explorer, FileSystem, Locator, Main, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + const firstFile = `${tmpDir}/a.txt` + const secondFile = `${tmpDir}/b.txt` + await FileSystem.writeFile(firstFile, 'content 1') + await FileSystem.writeFile(secondFile, 'content 2') + await Workspace.setPath(tmpDir) + + const firstTreeItem = Locator('.TreeItem[aria-label="a.txt"]') + const secondTreeItem = Locator('.TreeItem[aria-label="b.txt"]') + await expect(firstTreeItem).toBeVisible() + await expect(secondTreeItem).toBeVisible() + + await Explorer.focusIndex(0) + await expect(firstTreeItem).toHaveId('TreeItemActive') + + await Main.openUri(secondFile) + const tab = Locator('.MainTab[title$="b.txt"]') + await expect(tab).toBeVisible() + + // act + await Command.execute('Main.handleTabContextMenu', 0, 0, 0) + const closeMenuItem = Locator('text=Close').first() + await expect(closeMenuItem).toBeVisible() + await ContextMenu.selectItem('Reveal in Explorer') + + // assert + await expect(secondTreeItem).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts b/packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts new file mode 100644 index 0000000..5477383 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts @@ -0,0 +1,34 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-reveal-non-existent-uri' + +export const skip = 1 + +export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await Workspace.setPath(tmpDir) + + await Explorer.newFile() + await Explorer.updateEditingValue('first.txt') + await Explorer.acceptEdit() + + await Explorer.newFile() + await Explorer.updateEditingValue('second.txt') + await Explorer.acceptEdit() + + const explorer = Locator('.Explorer') + const firstFile = Locator('.TreeItem[aria-label="first.txt"]') + const secondFile = Locator('.TreeItem[aria-label="second.txt"]') + await expect(explorer).toBeVisible() + await expect(firstFile).toBeVisible() + await expect(secondFile).toBeVisible() + + // act + await Command.execute('Explorer.reveal', 'non-existent:///some-file.txt') + + // assert + await expect(explorer).toBeVisible() + await expect(firstFile).toBeVisible() + await expect(secondFile).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer-scroll.ts b/packages/e2e/src/viewlet.explorer-scroll.ts new file mode 100644 index 0000000..e6be04a --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-scroll.ts @@ -0,0 +1,43 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-scroll' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + for (let i = 0; i < 100; i++) { + const fileName = `file-${i.toString().padStart(2, '0')}.txt` + await FileSystem.writeFile(`${tmpDir}/${fileName}`, '') + } + await Workspace.setPath(tmpDir) + const file00 = Locator('.TreeItem', { hasText: 'file-00.txt' }) + const file50 = Locator('.TreeItem', { hasText: 'file-50.txt' }) + const file99 = Locator('.TreeItem', { hasText: 'file-99.txt' }) + + // act + await Explorer.focusFirst() + + // assert + await expect(file00).toBeVisible() + await expect(file00).toHaveId('TreeItemActive') + + // act + await Explorer.focusIndex(50) + + // assert + await expect(file50).toBeVisible() + await expect(file50).toHaveId('TreeItemActive') + + // act + await Explorer.focusIndex(99) + + // assert + await expect(file99).toBeVisible() + await expect(file99).toHaveId('TreeItemActive') + + // act + await Explorer.focusFirst() + + // assert + await expect(file00).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts b/packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts new file mode 100644 index 0000000..98499d4 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts @@ -0,0 +1,21 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-select-all-then-delete-files' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + for (let index = 0; index < 10; index++) { + await FileSystem.writeFile(`${tmpDir}/file-${index}.txt`, `content ${index}`) + } + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(9) + + // act + await Explorer.selectAll() + await Explorer.removeDirent() + + // assert + const treeItems = Locator('.TreeItem') + await expect(treeItems).toHaveCount(0) +} diff --git a/packages/e2e/src/viewlet.explorer-select-all.ts b/packages/e2e/src/viewlet.explorer-select-all.ts new file mode 100644 index 0000000..9d098c5 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-select-all.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-select-all' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(2) + + // act + await Explorer.selectAll() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveClass('TreeItemActive') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveClass('TreeItemActive') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).not.toHaveClass('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-select-down.ts b/packages/e2e/src/viewlet.explorer-select-down.ts new file mode 100644 index 0000000..6847c36 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-select-down.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-select-down' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(1) + + // act + await Explorer.selectDown() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveClass('TreeItem') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveClass('TreeItemActive') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).not.toHaveClass('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts b/packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts new file mode 100644 index 0000000..6744bfb --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts @@ -0,0 +1,25 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-select-multiple-files-individually' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(2) + + // act + await Explorer.toggleIndividualSelection(1) + await Explorer.toggleIndividualSelection(2) + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveClass('TreeItem') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveClass('TreeItemActive') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).not.toHaveClass('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts b/packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts new file mode 100644 index 0000000..6460084 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-select-multiple-files-with-mouse' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + await Explorer.focusIndex(2) + + // act + await Explorer.handleClickAt(false, 0, false, true, 300, 0) + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveClass('TreeItemActive') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveClass('TreeItem') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).not.toHaveClass('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-select-multiple-files.ts b/packages/e2e/src/viewlet.explorer-select-multiple-files.ts new file mode 100644 index 0000000..ecf68d1 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-select-multiple-files.ts @@ -0,0 +1,23 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-select-multiple-files' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.selectIndices([0, 1]) + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveClass('TreeItemActive') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveClass('TreeItemActive') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).not.toHaveClass('TreeItem') +} diff --git a/packages/e2e/src/viewlet.explorer-select-up.ts b/packages/e2e/src/viewlet.explorer-select-up.ts new file mode 100644 index 0000000..80f68b2 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-select-up.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-select-up' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') + await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') + await Workspace.setPath(tmpDir) + + // act + await Explorer.focusIndex(1) + await Explorer.selectUp() + + // assert + const file1 = Locator('.TreeItem').nth(0) + await expect(file1).toHaveClass('TreeItemActive') + const file2 = Locator('.TreeItem').nth(1) + await expect(file2).toHaveClass('TreeItemActive') + const file3 = Locator('.TreeItem').nth(2) + await expect(file3).not.toHaveClass('TreeItem') +} diff --git a/packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts b/packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts new file mode 100644 index 0000000..dfbbff5 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts @@ -0,0 +1,27 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-set-delta-y-invalid-value' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + for (let i = 0; i < 30; i++) { + const fileName = `file-${i.toString().padStart(2, '0')}.txt` + await FileSystem.writeFile(`${tmpDir}/${fileName}`, '') + } + await Workspace.setPath(tmpDir) + const file00 = Locator('.TreeItem', { hasText: 'file-00.txt' }) + + // act + await Explorer.setDeltaY('invalid' as any) + + // assert + await expect(file00).toBeVisible() + + await Explorer.focusIndex(29) + + // assert + const file29 = Locator('.TreeItem', { hasText: 'file-29.txt' }) + await expect(file29).toBeVisible() + await expect(file29).toHaveId('TreeItemActive') +} diff --git a/packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts b/packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts new file mode 100644 index 0000000..33e3998 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts @@ -0,0 +1,24 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-sort-numeric-file-names' + +export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.mkdir(`${tmpDir}/file-1.txt`) + await FileSystem.mkdir(`${tmpDir}/file-10.txt`) + await FileSystem.mkdir(`${tmpDir}/file-2.txt`) + + // act + await Workspace.setPath(tmpDir) + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + const secondTreeItem = treeItems.nth(1) + const thirdTreeItem = treeItems.nth(2) + await expect(treeItems).toHaveCount(3) + await expect(firstTreeItem).toHaveText('file-1.txt') + await expect(secondTreeItem).toHaveText('file-2.txt') + await expect(thirdTreeItem).toHaveText('file-10.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-sorting-emojis.ts b/packages/e2e/src/viewlet.explorer-sorting-emojis.ts new file mode 100644 index 0000000..763cd1f --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-sorting-emojis.ts @@ -0,0 +1,45 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-sorting-emojis' + +export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/🚀 rocket.txt`, '') + await FileSystem.writeFile(`${tmpDir}/🌟 star.txt`, '') + await FileSystem.writeFile(`${tmpDir}/💎 diamond.txt`, '') + await FileSystem.writeFile(`${tmpDir}/🔥 fire.txt`, '') + await FileSystem.writeFile(`${tmpDir}/⚡ lightning.txt`, '') + await FileSystem.writeFile(`${tmpDir}/🌈 rainbow.txt`, '') + await FileSystem.writeFile(`${tmpDir}/🎯 target.txt`, '') + await FileSystem.writeFile(`${tmpDir}/💡 idea.txt`, '') + await FileSystem.writeFile(`${tmpDir}/🚀🚀 double-rocket.txt`, '') + await FileSystem.writeFile(`${tmpDir}/a-normal-file.txt`, '') + + // act + await Workspace.setPath(tmpDir) + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + const secondTreeItem = treeItems.nth(1) + const thirdTreeItem = treeItems.nth(2) + const fourthTreeItem = treeItems.nth(3) + const fifthTreeItem = treeItems.nth(4) + const sixthTreeItem = treeItems.nth(5) + const seventhTreeItem = treeItems.nth(6) + const eighthTreeItem = treeItems.nth(7) + const ninthTreeItem = treeItems.nth(8) + const tenthTreeItem = treeItems.nth(9) + await expect(treeItems).toHaveCount(10) + await expect(firstTreeItem).toHaveText('⚡ lightning.txt') + await expect(secondTreeItem).toHaveText('🌈 rainbow.txt') + await expect(thirdTreeItem).toHaveText('🌟 star.txt') + await expect(fourthTreeItem).toHaveText('🎯 target.txt') + await expect(fifthTreeItem).toHaveText('💎 diamond.txt') + await expect(sixthTreeItem).toHaveText('💡 idea.txt') + await expect(seventhTreeItem).toHaveText('🔥 fire.txt') + await expect(eighthTreeItem).toHaveText('🚀 rocket.txt') + await expect(ninthTreeItem).toHaveText('🚀🚀 double-rocket.txt') + await expect(tenthTreeItem).toHaveText('a-normal-file.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts b/packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts new file mode 100644 index 0000000..f553502 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts @@ -0,0 +1,45 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-sorting-mixed-alphanumeric-special' + +export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/1file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/a-file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/b_file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/file1.txt`, '') + await FileSystem.writeFile(`${tmpDir}/file2.txt`, '') + await FileSystem.writeFile(`${tmpDir}/file@10.txt`, '') + await FileSystem.writeFile(`${tmpDir}/file#2.txt`, '') + await FileSystem.writeFile(`${tmpDir}/file$3.txt`, '') + await FileSystem.writeFile(`${tmpDir}/z-file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/10file.txt`, '') + + // act + await Workspace.setPath(tmpDir) + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + const secondTreeItem = treeItems.nth(1) + const thirdTreeItem = treeItems.nth(2) + const fourthTreeItem = treeItems.nth(3) + const fifthTreeItem = treeItems.nth(4) + const sixthTreeItem = treeItems.nth(5) + const seventhTreeItem = treeItems.nth(6) + const eighthTreeItem = treeItems.nth(7) + const ninthTreeItem = treeItems.nth(8) + const tenthTreeItem = treeItems.nth(9) + await expect(treeItems).toHaveCount(10) + await expect(firstTreeItem).toHaveText('1file.txt') + await expect(secondTreeItem).toHaveText('10file.txt') + await expect(thirdTreeItem).toHaveText('a-file.txt') + await expect(fourthTreeItem).toHaveText('b_file.txt') + await expect(fifthTreeItem).toHaveText('file@10.txt') + await expect(sixthTreeItem).toHaveText('file#2.txt') + await expect(seventhTreeItem).toHaveText('file$3.txt') + await expect(eighthTreeItem).toHaveText('file1.txt') + await expect(ninthTreeItem).toHaveText('file2.txt') + await expect(tenthTreeItem).toHaveText('z-file.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-sorting-special-characters.ts b/packages/e2e/src/viewlet.explorer-sorting-special-characters.ts new file mode 100644 index 0000000..b8a25c2 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-sorting-special-characters.ts @@ -0,0 +1,45 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-sorting-special-characters' + +export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/-file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/!file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/(file).txt`, '') + await FileSystem.writeFile(`${tmpDir}/[file].txt`, '') + await FileSystem.writeFile(`${tmpDir}/{file}.txt`, '') + await FileSystem.writeFile(`${tmpDir}/@file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/&file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/#file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/+file.txt`, '') + await FileSystem.writeFile(`${tmpDir}/$file.txt`, '') + + // act + await Workspace.setPath(tmpDir) + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + const secondTreeItem = treeItems.nth(1) + const thirdTreeItem = treeItems.nth(2) + const fourthTreeItem = treeItems.nth(3) + const fifthTreeItem = treeItems.nth(4) + const sixthTreeItem = treeItems.nth(5) + const seventhTreeItem = treeItems.nth(6) + const eighthTreeItem = treeItems.nth(7) + const ninthTreeItem = treeItems.nth(8) + const tenthTreeItem = treeItems.nth(9) + await expect(treeItems).toHaveCount(10) + await expect(firstTreeItem).toHaveText('-file.txt') + await expect(secondTreeItem).toHaveText('!file.txt') + await expect(thirdTreeItem).toHaveText('(file).txt') + await expect(fourthTreeItem).toHaveText('[file].txt') + await expect(fifthTreeItem).toHaveText('{file}.txt') + await expect(sixthTreeItem).toHaveText('@file.txt') + await expect(seventhTreeItem).toHaveText('&file.txt') + await expect(eighthTreeItem).toHaveText('#file.txt') + await expect(ninthTreeItem).toHaveText('+file.txt') + await expect(tenthTreeItem).toHaveText('$file.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts b/packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts new file mode 100644 index 0000000..6af6920 --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts @@ -0,0 +1,45 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-sorting-unicode-characters' + +export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/café.txt`, '') + await FileSystem.writeFile(`${tmpDir}/naïve.txt`, '') + await FileSystem.writeFile(`${tmpDir}/résumé.txt`, '') + await FileSystem.writeFile(`${tmpDir}/piñata.txt`, '') + await FileSystem.writeFile(`${tmpDir}/jalapeño.txt`, '') + await FileSystem.writeFile(`${tmpDir}/façade.txt`, '') + await FileSystem.writeFile(`${tmpDir}/séance.txt`, '') + await FileSystem.writeFile(`${tmpDir}/déjà.txt`, '') + await FileSystem.writeFile(`${tmpDir}/château.txt`, '') + await FileSystem.writeFile(`${tmpDir}/soirée.txt`, '') + + // act + await Workspace.setPath(tmpDir) + + // assert + const treeItems = Locator('.TreeItem') + const firstTreeItem = treeItems.nth(0) + const secondTreeItem = treeItems.nth(1) + const thirdTreeItem = treeItems.nth(2) + const fourthTreeItem = treeItems.nth(3) + const fifthTreeItem = treeItems.nth(4) + const sixthTreeItem = treeItems.nth(5) + const seventhTreeItem = treeItems.nth(6) + const eighthTreeItem = treeItems.nth(7) + const ninthTreeItem = treeItems.nth(8) + const tenthTreeItem = treeItems.nth(9) + await expect(treeItems).toHaveCount(10) + await expect(firstTreeItem).toHaveText('café.txt') + await expect(secondTreeItem).toHaveText('château.txt') + await expect(thirdTreeItem).toHaveText('déjà.txt') + await expect(fourthTreeItem).toHaveText('façade.txt') + await expect(fifthTreeItem).toHaveText('jalapeño.txt') + await expect(sixthTreeItem).toHaveText('naïve.txt') + await expect(seventhTreeItem).toHaveText('piñata.txt') + await expect(eighthTreeItem).toHaveText('résumé.txt') + await expect(ninthTreeItem).toHaveText('séance.txt') + await expect(tenthTreeItem).toHaveText('soirée.txt') +} diff --git a/packages/e2e/src/viewlet.explorer-sorting.ts b/packages/e2e/src/viewlet.explorer-sorting.ts new file mode 100644 index 0000000..361251e --- /dev/null +++ b/packages/e2e/src/viewlet.explorer-sorting.ts @@ -0,0 +1,44 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'viewlet.explorer-sorting' + +export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/1.txt`, '') + await FileSystem.writeFile(`${tmpDir}/2.txt`, '') + await FileSystem.writeFile(`${tmpDir}/3.txt`, '') + await FileSystem.writeFile(`${tmpDir}/4.txt`, '') + await FileSystem.writeFile(`${tmpDir}/5.txt`, '') + await FileSystem.writeFile(`${tmpDir}/6.txt`, '') + await FileSystem.writeFile(`${tmpDir}/7.txt`, '') + await FileSystem.writeFile(`${tmpDir}/8.txt`, '') + await FileSystem.writeFile(`${tmpDir}/9.txt`, '') + await FileSystem.writeFile(`${tmpDir}/10.txt`, '') + await Workspace.setPath(tmpDir) + await Explorer.focusFirst() + + // assert + const items = Locator('.TreeItem') + await expect(items).toHaveCount(10) + const itemOne = items.nth(0) + const itemTwo = items.nth(1) + const itemThree = items.nth(2) + const itemFour = items.nth(3) + const itemFive = items.nth(4) + const itemSix = items.nth(5) + const itemSeven = items.nth(6) + const itemEight = items.nth(7) + const itemNine = items.nth(8) + const itemTen = items.nth(9) + await expect(itemOne).toHaveText('1.txt') + await expect(itemTwo).toHaveText('2.txt') + await expect(itemThree).toHaveText('3.txt') + await expect(itemFour).toHaveText('4.txt') + await expect(itemFive).toHaveText('5.txt') + await expect(itemSix).toHaveText('6.txt') + await expect(itemSeven).toHaveText('7.txt') + await expect(itemEight).toHaveText('8.txt') + await expect(itemNine).toHaveText('9.txt') + await expect(itemTen).toHaveText('10.txt') +} diff --git a/packages/e2e/src/viewlet.explorer.empty.ts b/packages/e2e/src/viewlet.explorer.empty.ts new file mode 100644 index 0000000..274258b --- /dev/null +++ b/packages/e2e/src/viewlet.explorer.empty.ts @@ -0,0 +1,16 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'explorer.empty' + +export const test: Test = async ({ expect, FileSystem, Locator, SideBar, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await Workspace.setPath(tmpDir) + + // act + await SideBar.open('Explorer') + + // assert + const explorer = Locator('.Explorer') + await expect(explorer).toBeVisible() +} diff --git a/packages/e2e/src/viewlet.explorer.open.ts b/packages/e2e/src/viewlet.explorer.open.ts new file mode 100644 index 0000000..c285f0c --- /dev/null +++ b/packages/e2e/src/viewlet.explorer.open.ts @@ -0,0 +1,19 @@ +import type { Test } from '@lvce-editor/test-with-playwright' + +export const name = 'explorer.open' + +export const test: Test = async ({ expect, FileSystem, Locator, SideBar, Workspace }) => { + // arrange + const tmpDir = await FileSystem.getTmpDir() + await FileSystem.writeFile(`${tmpDir}/test.css`, `abc`) + await Workspace.setPath(tmpDir) + + // act + await SideBar.open('Explorer') + + // assert + const explorer = Locator('.Explorer') + await expect(explorer).toBeVisible() + const file = explorer.locator('[aria-label="test.css"]') + await expect(file).toBeVisible() +} diff --git a/packages/e2e/tsconfig.json b/packages/e2e/tsconfig.json new file mode 100644 index 0000000..8b273ec --- /dev/null +++ b/packages/e2e/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "esnext", + "lib": ["esnext", "WebWorker"], + "checkJs": true, + "module": "nodenext", + "types": [], + "moduleResolution": "nodenext", + "rootDir": ".", + "skipLibCheck": true, + "noEmit": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "assumeChangesOnlyAffectDirectDependencies": true, + "strict": true, + "noImplicitAny": false, + "composite": true, + "noUnusedParameters": true, + "noUnusedLocals": true + }, + "include": ["src", "test"] +} diff --git a/packages/explorer-view/package-lock.json b/packages/explorer-view/package-lock.json new file mode 100644 index 0000000..233a29f --- /dev/null +++ b/packages/explorer-view/package-lock.json @@ -0,0 +1,4785 @@ +{ + "name": "@lvce-editor/explorer-view", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@lvce-editor/explorer-view", + "version": "0.0.0-dev", + "license": "MIT", + "devDependencies": { + "@jest/globals": "^30.4.1", + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/constants": "^5.14.0", + "@lvce-editor/i18n": "^2.1.0", + "@lvce-editor/list": "^1.7.0", + "@lvce-editor/rpc": "^6.4.0", + "@lvce-editor/rpc-registry": "^9.26.0", + "@lvce-editor/verror": "^1.7.0", + "@lvce-editor/viewlet-registry": "^4.1.0", + "@lvce-editor/virtual-dom-worker": "^9.13.0", + "jest": "^30.4.2", + "ts-jest": "^29.4.11" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.4.1.tgz", + "integrity": "sha512-v3bhyxUh9Hgmo5p6hAOXe14/R3ZxZDOsvHleh4B07z3m/x4/ngPUXEm9XwK4sF4u+f+P2ORb0Ge+MgpaqRMVDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.4.2.tgz", + "integrity": "sha512-TZJA6cPJUFxoWhxaLo8t0VX/MZX2wPWr0uIDvLSHIvN4gu9h02vSzqI2kBADG1ExqQlC+cY09xKMSreivvrChQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.4.1", + "@jest/pattern": "30.4.0", + "@jest/reporters": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.4.1", + "jest-config": "30.4.2", + "jest-haste-map": "30.4.1", + "jest-message-util": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-resolve-dependencies": "30.4.2", + "jest-runner": "30.4.2", + "jest-runtime": "30.4.2", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", + "jest-watcher": "30.4.1", + "pretty-format": "30.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.4.1.tgz", + "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "jest-mock": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-ginrj6TMgh2GshLUGCjO94Ptx9HhdZA/I6A9iUfyeLKFtdAjnKzHDgzgP9HYQgbxM1lbXScQ2eUBz2lGeVDPWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "30.4.1", + "jest-snapshot": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", + "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.4.1.tgz", + "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@sinonjs/fake-timers": "^15.4.0", + "@types/node": "*", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.4.1.tgz", + "integrity": "sha512-ZbuY4cmXC8DkxYjfvT2DbcHWL2T6vmsMhXCDcmTB2T0y0gaezBI77ufq5ZAIdcRkYZ7NEQEDg1xFeKbxUJ5v5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.1", + "@jest/expect": "30.4.1", + "@jest/types": "30.4.1", + "jest-mock": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", + "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.4.1.tgz", + "integrity": "sha512-/SnkPCzEQpUaBH81kjdEdDdo2WZl5hxw+BmLDGWjRkm8o7XlhjwsU36cqwe5PGBE5WYpBvDzRSdXx9rbGuJtNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "jest-worker": "30.4.1", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.4.1.tgz", + "integrity": "sha512-ObY4ljvQ95mt6iwKtVLetR/4yXiAgl3H4nJxhztr0MTjrN97TwDYrnCp/kF60Ec9HdhkWTHSu+Hg05aXfngpOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.4.1.tgz", + "integrity": "sha512-/ZG7pgEiOmmWkN9TplKbOu4id2N5lh7FHwRwlkgBVAzGdRH+OkkQ8wX/kIxg4zmd3ZQvAL1RwL2yWsvNYYECTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.4.1", + "@jest/types": "30.4.1", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.4.1.tgz", + "integrity": "sha512-PeYE+4td5rKjoRPxztObrXU+H8hsjZfxKMXOcmrr34JerSyB/ROOxbbicz8B7A5j9R9VayDnVPvBmedqCsFCdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.4.1", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.4.1.tgz", + "integrity": "sha512-Wz0LyktlTvRefoymh+n64hQ84KNXsRGcwdoZ8CSa0Ea+fgYcHZlnk+hDP7v2MS7il2bQ5uTEIxf4/NNfhMN4KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.4.1", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.1", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", + "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.4.0", + "@jest/schemas": "30.4.1", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lvce-editor/assert": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@lvce-editor/assert/-/assert-1.5.1.tgz", + "integrity": "sha512-euS3PuVVjZy06bPFbgTz1yjQ0mY5BgWeYEDb9eQL2ncqYeap0ADy1D57nddlps1VkhHxj1g2ifXkLeIKLkQYJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/command/-/command-2.0.0.tgz", + "integrity": "sha512-NZokXOACzuRoIpsHVHx+VhNQwM/QcQ4bl3wc8DgDM/+AxAVT2EU8S9cVQQedtJj94N35zmAB2To6Egm8aifOlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/constants": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/constants/-/constants-5.14.0.tgz", + "integrity": "sha512-eJvcdatVxKHYVtVhMOIULPo53uMNl6YCNztj65ejI4zVrP0qUspM2ymhpglyRoDnyZ+XtUVlMduCmSSq0fT6eQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/i18n": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/i18n/-/i18n-2.1.0.tgz", + "integrity": "sha512-LRtTevG7feHoUhaajgey8SlHRawFSAPS3SxM6n/QADEFaQFzQiTWYK5gOOq7oKp1MPIn1t/UXfFtGycACzvNeA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/ipc": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/ipc/-/ipc-15.0.0.tgz", + "integrity": "sha512-PY8HVhuShfGaTgTSgrsgwgv7Po3WPkgh9AlilgYull4yFPKYZphlGogMSudxq+IsdhKYjD7hdncUEoox+idXiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/verror": "^1.7.0", + "@lvce-editor/web-socket-server": "^2.1.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/json-rpc": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/json-rpc/-/json-rpc-8.0.0.tgz", + "integrity": "sha512-mjeSYYd0qJ0Jz3vpEucBnikdbIFsdmewDX/EkVLHw7obYh0WUXr9f3u528nVAHskrUpb8/IsZY4ynJ0Uaar9bA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/list": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/list/-/list-1.7.0.tgz", + "integrity": "sha512-5ED1ua0wU+7B4jV6T3xOTuUHWdriF+u8VU5vxoKx5PFwTPAGY3vpYRI72N/Mgp9oYRNX6WtXOIs6U/dCxblzlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.4.0" + } + }, + "node_modules/@lvce-editor/rpc": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/rpc/-/rpc-6.4.0.tgz", + "integrity": "sha512-AhIyFrPz9/9usLNSLNdMtHxSmrfYw4TfJXRMV19px/eYOv+Y20pEq3O31HtKejZaUVRUbPhhJ0EOa0z9YsGAcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/command": "^2.0.0", + "@lvce-editor/ipc": "^15.0.0", + "@lvce-editor/json-rpc": "^8.0.0" + } + }, + "node_modules/@lvce-editor/rpc-registry": { + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/rpc-registry/-/rpc-registry-9.26.0.tgz", + "integrity": "sha512-l34xcpyv94Z4Op82menHE1Gnb/tlNd7551WCaqMeOTb6X5G/5QLe4DxmIAj/Q6aUt5d0c4TiuIV05vxq6fFv6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/constants": "^5.14.0", + "@lvce-editor/rpc": "^6.4.0" + } + }, + "node_modules/@lvce-editor/verror": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/verror/-/verror-1.7.0.tgz", + "integrity": "sha512-+LGuAEIC2L7pbvkyAQVWM2Go0dAy+UWEui28g07zNtZsCBhm+gusBK8PNwLJLV5Jay+TyUYuwLIbJdjLLzqEBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/viewlet-registry": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/viewlet-registry/-/viewlet-registry-4.1.0.tgz", + "integrity": "sha512-B7IaJAb632LntuG6cezIi7sli1bDFETZYF0Ek6PqG8COZv5sBAQXoQrk9/lGMptUk6L4LveWp1n0PHpxkKQzHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/virtual-dom-worker": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/virtual-dom-worker/-/virtual-dom-worker-9.13.0.tgz", + "integrity": "sha512-U22G4jStIuHidFFeo2gTTJu411OF8hs3fWamTan2GUxH2xjEa7xaVcdioDUEs7nfyi/h2utTbGxhXyuUTA73yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lvce-editor/constants": "^5.13.0" + } + }, + "node_modules/@lvce-editor/web-socket-server": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/web-socket-server/-/web-socket-server-2.1.0.tgz", + "integrity": "sha512-Yldf6nJ4seaFaysYTkkLkOhuJQxkdyX/u01vk1X0dXi21882wMtQbDmYZoAg9rVGWbdBFDIdAJ99pFCAM8eUQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ws": "^8.18.2" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.4.1.tgz", + "integrity": "sha512-fATAbM8piYxkiXQp3RBXmZHxZVNJZAVXXfyeyCN2Tida3+qJ8ea9UxhiJ2y4fLO90ZImKt6k9FlcH2+rLkJGhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.4.1", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.4.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.4.0.tgz", + "integrity": "sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.4.0.tgz", + "integrity": "sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.4.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.372", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", + "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.4.1", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.4.2.tgz", + "integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.4.2", + "@jest/types": "30.4.1", + "import-local": "^3.2.0", + "jest-cli": "30.4.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.4.1.tgz", + "integrity": "sha512-IuctmYrxi21iOSOaIXpJWalHyPAsVv0GeBHKDn8C1CA4W5htHn7INL+wdnL4Bo0+olEndvAFkmb++tIQJG+vvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.4.1", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.4.2.tgz", + "integrity": "sha512-rvHH7VlY6LgbJXJTQ87GW62g1FntOtbhh0zT+v04kC+pgL6aBKyYINXxWukCpj3dcIBMw5/XUbtDS9dU9JTXeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.1", + "@jest/expect": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.4.1", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-runtime": "30.4.2", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", + "p-limit": "^3.1.0", + "pretty-format": "30.4.1", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.4.2.tgz", + "integrity": "sha512-jfA2ocvVHMXS2QijrJ0d31ektP+d/W0T5RpcTX2Pq+3sVqHlsXVCM2+FmwpL+bdY8OfHpIg9xMxLF17Zg0U49Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.4.2", + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.4.2", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.4.2.tgz", + "integrity": "sha512-rNHAShJQqQwFNoL0hbf3BphSBOWnpOUAKvidLS/AjNVLPfoj5mSf4jQMfW3cYOs6hXeZC7nF7mDHaBnbxELOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.4.0", + "@jest/test-sequencer": "30.4.1", + "@jest/types": "30.4.1", + "babel-jest": "30.4.1", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-circus": "30.4.2", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-runner": "30.4.2", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", + "parse-json": "^5.2.0", + "pretty-format": "30.4.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", + "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.4.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.4.0.tgz", + "integrity": "sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.4.1.tgz", + "integrity": "sha512-/8MJbH6fuj48TstjrMf+u/pd06Qezz5xOXvZA6442heNOWr8bdeoGZX2d9fCn028CoMgYmroH9//zky5GfyYmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.4.1", + "chalk": "^4.1.2", + "jest-util": "30.4.1", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.4.1.tgz", + "integrity": "sha512-4FZYVOk85hz2AyT6BbarKy9u37g6DbrDyCdFhsnDdXqyrueYQvB+0zO4f/kqLCRD0BsPRXPMNJeQwihKZV8naw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.1", + "@jest/fake-timers": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "jest-mock": "30.4.1", + "jest-util": "30.4.1", + "jest-validate": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.4.1.tgz", + "integrity": "sha512-rFrcONd8jeFsyw+Z9CrScJgglRf2+NFmNam8dKu7n+SoHqNYT47mn0DdEcVUZJpvh7Iz6/si7f7yUH7GJHVgnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.4.0", + "jest-util": "30.4.1", + "jest-worker": "30.4.1", + "picomatch": "^4.0.3", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.4.1.tgz", + "integrity": "sha512-IpmyiioeHxiWDhesHnUFmOxcTzwCwKpgACgWajtAP+nYQXiY7DakTxB6Bx9JFiRMljr0AX1PvnQdaU1KFoz6NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", + "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.4.1", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", + "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.4.1", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.4.1", + "picomatch": "^4.0.3", + "pretty-format": "30.4.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", + "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "jest-util": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", + "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.4.1.tgz", + "integrity": "sha512-Zry8Yq/yJcNAZ7dJ5F2heic8AheXvbFZ7XI5V+h28nrYZ7Qoyy4dItq8OodjnYD270mvX+ZudmrNV9cysqhW5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.1", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.4.1", + "jest-validate": "30.4.1", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.4.2.tgz", + "integrity": "sha512-gDiVh1I+GxYzz9oXlyw+1wv6VOYX1WYxMOfjsA3iGKePV2oxmbHhwxfkALxNxYy1ciw6APWwkW2zZONwP97aEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "30.4.0", + "jest-snapshot": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.4.2.tgz", + "integrity": "sha512-2dw0PslVYXxffXGpLo+Ejad+KcI1Qkjn7f4X4619gf21oCUmL+SPfjqIa/losUem3yEOvfNZe/F1HWUcNpODcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.4.1", + "@jest/environment": "30.4.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.4.0", + "jest-environment-node": "30.4.1", + "jest-haste-map": "30.4.1", + "jest-leak-detector": "30.4.1", + "jest-message-util": "30.4.1", + "jest-resolve": "30.4.1", + "jest-runtime": "30.4.2", + "jest-util": "30.4.1", + "jest-watcher": "30.4.1", + "jest-worker": "30.4.1", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.4.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.4.2.tgz", + "integrity": "sha512-3/5e8iPz2k/VLqlr8DgTftYyLUv8Su3FkCAO2/Od81UsUTpSxOrS6O5x5KkoQwyUjmpYyDJKeyAvg2T2nvpNkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.4.1", + "@jest/fake-timers": "30.4.1", + "@jest/globals": "30.4.1", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-regex-util": "30.4.0", + "jest-resolve": "30.4.1", + "jest-snapshot": "30.4.1", + "jest-util": "30.4.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.4.1.tgz", + "integrity": "sha512-tEOkkfOMppUyeiHwjZswOQ3lcnoTnws/q5FnGIaeIh/jmoU0ZlgMYRR8sTlTj+nNGCoJ0RDq6SfxGxCsyMTPmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.4.1", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.4.1", + "@jest/transform": "30.4.1", + "@jest/types": "30.4.1", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.4.1", + "graceful-fs": "^4.2.11", + "jest-diff": "30.4.1", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-util": "30.4.1", + "pretty-format": "30.4.1", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", + "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.4.1.tgz", + "integrity": "sha512-PDWi4SOwLnwqNDfHZjOcsEFyZ4fc/2W2gVL3DEoyqnB6jCQMLRtfBong8s6omIw3lI0HWOus12xfnFmQtjW3fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.4.1", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.4.1.tgz", + "integrity": "sha512-/l9UonmvCwjHH7d2h3iAwIloLc1H0S8mJZ/LNK3i86hqwPAz8otUJjP9MfYtz9Tt77Su5FD2xGjZn8d31IZHlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.4.1", + "@jest/types": "30.4.1", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.4.1", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.1.tgz", + "integrity": "sha512-SHynN/q/QD++iNyvMdy+WMmbCGk8jIsNcRxycXbWubSOhvo6T+j2afcfUSl+3hYsiBebOTo0cT7c2H7CXugu1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.4.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.4.1", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is-19": { + "name": "react-is", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", + "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.3.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ts-jest": { + "version": "29.4.11", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz", + "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.8.0", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/packages/explorer-view/package.json b/packages/explorer-view/package.json new file mode 100644 index 0000000..38b3093 --- /dev/null +++ b/packages/explorer-view/package.json @@ -0,0 +1,61 @@ +{ + "name": "@lvce-editor/explorer-view", + "version": "0.0.0-dev", + "description": "Explorer Worker", + "repository": { + "type": "git", + "url": "git+https://github.com/lvce-editor/explorer-view.git" + }, + "license": "MIT", + "author": "Lvce Editor", + "type": "module", + "main": "src/explorerViewWorkerMain.ts", + "scripts": { + "build:watch": "cd ../../ && npm run build:watch", + "dev": "cd ../../ && npm run dev", + "test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --detectOpenHandles --forceExit", + "test:watch": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --watch" + }, + "jest": { + "injectGlobals": false, + "extensionsToTreatAsEsm": [ + ".ts" + ], + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "transform": { + "^.+\\.tsx?$": [ + "ts-jest", + { + "useESM": true + } + ] + }, + "testMatch": [ + "**/test/**" + ], + "collectCoverage": true, + "coverageThreshold": { + "global": { + "branches": 70, + "functions": 85, + "lines": 80 + } + } + }, + "devDependencies": { + "@jest/globals": "^30.4.1", + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/constants": "^5.14.0", + "@lvce-editor/i18n": "^2.1.0", + "@lvce-editor/list": "^1.7.0", + "@lvce-editor/rpc": "^6.4.0", + "@lvce-editor/rpc-registry": "^9.26.0", + "@lvce-editor/verror": "^1.7.0", + "@lvce-editor/viewlet-registry": "^4.1.0", + "@lvce-editor/virtual-dom-worker": "^9.13.0", + "jest": "^30.4.2", + "ts-jest": "^29.4.11" + } +} diff --git a/packages/explorer-view/src/explorerViewWorkerMain.ts b/packages/explorer-view/src/explorerViewWorkerMain.ts new file mode 100644 index 0000000..abfaa99 --- /dev/null +++ b/packages/explorer-view/src/explorerViewWorkerMain.ts @@ -0,0 +1,3 @@ +import * as Main from './parts/Main/Main.ts' + +Main.main() diff --git a/packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts b/packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts new file mode 100644 index 0000000..117b074 --- /dev/null +++ b/packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts @@ -0,0 +1,68 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' +import { createTree } from '../CreateTree/CreateTree.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import * as GetFileOperationsCreate from '../GetFileOperationsCreate/GetFileOperationsCreate.ts' +import * as GetIndex from '../GetIndex/GetIndex.ts' +import { getParentFolder } from '../GetParentFolder/GetParentFolder.ts' +import { getPathParts } from '../GetPathParts/GetPathParts.ts' +import { getPathPartsChildren } from '../GetPathPartsChildren/GetPathPartsChildren.ts' +import { getSiblingFileNames } from '../GetSiblingFileNames/GetSiblingFileNames.ts' +import { mergeTrees } from '../MergeTrees/MergeTrees.ts' +import { openUri } from '../OpenUri/OpenUri.ts' +import { join2 } from '../Path/Path.ts' +import { refreshWorkspace } from '../RefreshWorkspace/RefreshWorkspace.ts' +import { treeToArray } from '../TreeToArray/TreeToArray.ts' +import * as ValidateFileName2 from '../ValidateFileName2/ValidateFileName2.ts' + +export const acceptCreate = async (state: ExplorerState, newDirentType: number): Promise => { + const { editingValue, focusedIndex, items, pathSeparator, root } = state + const newFileName = editingValue + const siblingFileNames = getSiblingFileNames(items, focusedIndex, root, pathSeparator) + const editingErrorMessage = ValidateFileName2.validateFileName2(newFileName, siblingFileNames) + if (editingErrorMessage) { + return { + ...state, + editingErrorMessage, + } + } + const parentFolder = getParentFolder(items, focusedIndex, root, pathSeparator) + const absolutePath = join2(parentFolder, newFileName) + const operations = GetFileOperationsCreate.getFileOperationsCreate(editingValue, newDirentType, pathSeparator, absolutePath, root) + const createErrorMessage = await ApplyFileOperations.applyFileOperations(operations) + if (createErrorMessage) { + return { + ...state, + editingErrorMessage: createErrorMessage, + } + } + + const pathPaths = getPathParts(root, absolutePath, pathSeparator) + const children = await getPathPartsChildren(pathPaths) + + const tree = createTree(items, root) + const childTree = createTree(children, root) + const merged = mergeTrees(tree, childTree) + + const newItems = treeToArray(merged, root) + + const dirents = newItems + const newFocusedIndex = GetIndex.getIndex(newItems, absolutePath) + + await refreshWorkspace() + + if (newDirentType === DirentType.File) { + await openUri(absolutePath, true) + } + + return { + ...state, + editingIndex: -1, + editingType: ExplorerEditingType.None, + focus: FocusId.List, + focusedIndex: newFocusedIndex, + items: dirents, + } +} diff --git a/packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts b/packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts new file mode 100644 index 0000000..eefc3e2 --- /dev/null +++ b/packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts @@ -0,0 +1,7 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { acceptCreate } from '../AcceptCreate/AcceptCreate.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const acceptCreateFile = async (state: ExplorerState): Promise => { + return acceptCreate(state, DirentType.File) +} diff --git a/packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts b/packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts new file mode 100644 index 0000000..a579b1d --- /dev/null +++ b/packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts @@ -0,0 +1,7 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { acceptCreate } from '../AcceptCreate/AcceptCreate.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const acceptCreateFolder = async (state: ExplorerState): Promise => { + return acceptCreate(state, DirentType.Directory) +} diff --git a/packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts b/packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts new file mode 100644 index 0000000..93aa374 --- /dev/null +++ b/packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts @@ -0,0 +1,19 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { acceptCreateFile } from '../AcceptCreateFile/AcceptCreateFile.ts' +import { acceptCreateFolder } from '../AcceptCreateFolder/AcceptCreateFolder.ts' +import { acceptRename } from '../AcceptRename/AcceptRename.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' + +export const acceptEdit = async (state: ExplorerState): Promise => { + const { editingType } = state + switch (editingType) { + case ExplorerEditingType.CreateFile: + return acceptCreateFile(state) + case ExplorerEditingType.CreateFolder: + return acceptCreateFolder(state) + case ExplorerEditingType.Rename: + return acceptRename(state) + default: + return state + } +} diff --git a/packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts b/packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts new file mode 100644 index 0000000..70b531d --- /dev/null +++ b/packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts @@ -0,0 +1,55 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' +import { computeExplorerRenamedDirentUpdate } from '../ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts' +import { createTree } from '../CreateTree/CreateTree.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' +import * as GetFileOperationsRename from '../GetFileOperationsRename/GetFileOperationsRename.ts' +import { getIndex } from '../GetIndex/GetIndex.ts' +import { dirname2, join2 } from '../Path/Path.ts' +import { treeToArray } from '../TreeToArray/TreeToArray.ts' +import { updateTree2 } from '../UpdateTree2/UpdateTree2.ts' +import * as ValidateFileName2 from '../ValidateFileName2/ValidateFileName2.ts' + +export const acceptRename = async (state: ExplorerState): Promise => { + const { editingIndex, editingValue, items, root } = state + const editingErrorMessage = ValidateFileName2.validateFileName2(editingValue) + if (editingErrorMessage) { + return { + ...state, + editingErrorMessage, + } + } + const renamedDirent = items[editingIndex] + const operations = GetFileOperationsRename.getFileOperationsRename(renamedDirent.path, editingValue) + const renameErrorMessage = await ApplyFileOperations.applyFileOperations(operations) + if (renameErrorMessage) { + return { + ...state, + editingErrorMessage: renameErrorMessage, + } + } + const oldUri = renamedDirent.path + const dirname = dirname2(oldUri) + const newUri = join2(dirname, editingValue) + const children = await getChildDirents('/', dirname, renamedDirent.depth - 1, []) + const tree = createTree(items, root) + const update = computeExplorerRenamedDirentUpdate(root, dirname, oldUri, children, tree, newUri) + const newTree = updateTree2(tree, update) + const newDirents = treeToArray(newTree, root) + const newFocusedIndex = getIndex(newDirents, newUri) + return { + ...state, + editingIcon: '', + editingIndex: -1, + editingSelectionEnd: 0, + editingSelectionStart: 0, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: true, + focusedIndex: newFocusedIndex, + items: newDirents, + } +} diff --git a/packages/explorer-view/src/parts/ActionType/ActionType.ts b/packages/explorer-view/src/parts/ActionType/ActionType.ts new file mode 100644 index 0000000..fb7182d --- /dev/null +++ b/packages/explorer-view/src/parts/ActionType/ActionType.ts @@ -0,0 +1 @@ +export const Button = 1 diff --git a/packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts b/packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts new file mode 100644 index 0000000..dd0338a --- /dev/null +++ b/packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts @@ -0,0 +1,17 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ScrollInto from '../ScrollInto/ScrollInto.ts' + +export const adjustScrollAfterPaste = (state: ExplorerState, focusedIndex: number): ExplorerState => { + const { itemHeight, maxLineY, minLineY } = state + const { newMaxLineY, newMinLineY } = ScrollInto.scrollInto(focusedIndex, minLineY, maxLineY) + const newDeltaY = newMinLineY * itemHeight + + return { + ...state, + deltaY: newDeltaY, + focused: true, + focusedIndex, + maxLineY: newMaxLineY, + minLineY: newMinLineY, + } +} diff --git a/packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts b/packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts new file mode 100644 index 0000000..b00b1e2 --- /dev/null +++ b/packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts @@ -0,0 +1,18 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' + +export const applyOperation = (operation: FileOperation): Promise => { + switch (operation.type) { + case FileOperationType.Copy: + return FileSystem.copy(operation.from || '', operation.path) + case FileOperationType.CreateFolder: + return FileSystem.mkdir(operation.path) + case FileOperationType.Remove: + return FileSystem.remove(operation.path) + case FileOperationType.Rename: + return FileSystem.rename(operation.from || '', operation.path) + default: + return FileSystem.writeFile(operation.path, operation.text) + } +} diff --git a/packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts b/packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts new file mode 100644 index 0000000..7a5e6b4 --- /dev/null +++ b/packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts @@ -0,0 +1,16 @@ +import { VError } from '@lvce-editor/verror' +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import { applyOperation as applyFileOperation } from '../ApplyFileOperation/ApplyFileOperation.ts' + +export const applyFileOperations = async (operations: readonly FileOperation[]): Promise => { + try { + // TODO run operations in parallel if possible + for (const operation of operations) { + await applyFileOperation(operation) + } + return '' + } catch (error) { + console.error(new VError(error, `Failed to apply file operations`)) + return `${error}` + } +} diff --git a/packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts b/packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts new file mode 100644 index 0000000..57531b8 --- /dev/null +++ b/packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts @@ -0,0 +1,14 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetRenderer from '../GetRenderer/GetRenderer.ts' + +export const applyRender = (oldState: ExplorerState, newState: ExplorerState, diffResult: readonly number[]): readonly any[] => { + const commands = [] + for (const item of diffResult) { + const fn = GetRenderer.getRenderer(item) + const result = fn(oldState, newState) + if (result.length > 0) { + commands.push(result) + } + } + return commands +} diff --git a/packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts b/packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts new file mode 100644 index 0000000..3b08ee9 --- /dev/null +++ b/packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts @@ -0,0 +1,4 @@ +export const None = 'none' +export const ToolBar = 'toolbar' +export const Tree = 'tree' +export const TreeItem = 'treeitem' diff --git a/packages/explorer-view/src/parts/Arrays/Arrays.ts b/packages/explorer-view/src/parts/Arrays/Arrays.ts new file mode 100644 index 0000000..f9a711a --- /dev/null +++ b/packages/explorer-view/src/parts/Arrays/Arrays.ts @@ -0,0 +1,11 @@ +export const lastIndex = (array: readonly any[]): number => { + return array.length - 1 +} + +export const fromAsync = async (asyncIterable: any): Promise => { + const children = [] + for await (const value of asyncIterable) { + children.push(value) + } + return children +} diff --git a/packages/explorer-view/src/parts/Assert/Assert.ts b/packages/explorer-view/src/parts/Assert/Assert.ts new file mode 100644 index 0000000..57950a9 --- /dev/null +++ b/packages/explorer-view/src/parts/Assert/Assert.ts @@ -0,0 +1 @@ +export * from '@lvce-editor/assert' diff --git a/packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts b/packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts new file mode 100644 index 0000000..c907b95 --- /dev/null +++ b/packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts @@ -0,0 +1,16 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const canBeDroppedInto = (dirent: ExplorerItem): boolean => { + if (!dirent) { + return false + } + switch (dirent.type) { + case DirentType.Directory: + case DirentType.DirectoryExpanded: + case DirentType.DirectoryExpanding: + return true + default: + return false + } +} diff --git a/packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts b/packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts new file mode 100644 index 0000000..e49a584 --- /dev/null +++ b/packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { cancelEditInternal } from '../CancelEditInternal/CancelEditInternal.ts' + +export const cancelEdit = async (state: ExplorerState): Promise => { + return cancelEditInternal(state, true) +} diff --git a/packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts b/packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts new file mode 100644 index 0000000..deb3fa2 --- /dev/null +++ b/packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts @@ -0,0 +1,22 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import { getFocusedIndexCancel } from '../GetFocusedIndexCancel/GetFocusedIndexCancel.ts' +import { isNormalItem } from '../IsNormalItem/IsNormalItem.ts' + +export const cancelEditCreate = async (state: ExplorerState, keepFocus: boolean): Promise => { + const { editingIndex, items } = state + const filteredItems = items.filter(isNormalItem) + const newFocusedIndex = getFocusedIndexCancel(filteredItems, editingIndex) + return { + ...state, + editingErrorMessage: '', + editingIndex: -1, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: keepFocus, + focusedIndex: newFocusedIndex, + items: filteredItems, + } +} diff --git a/packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts b/packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts new file mode 100644 index 0000000..013d262 --- /dev/null +++ b/packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts @@ -0,0 +1,12 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { cancelEditCreate } from '../CancelEditCreate/CancelEditCreate.ts' +import { cancelEditRename } from '../CancelEditRename/CancelEditRename.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' + +export const cancelEditInternal = async (state: ExplorerState, keepFocus: boolean): Promise => { + const { editingType } = state + if (editingType === ExplorerEditingType.Rename) { + return cancelEditRename(state, keepFocus) + } + return cancelEditCreate(state, keepFocus) +} diff --git a/packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts b/packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts new file mode 100644 index 0000000..21cd212 --- /dev/null +++ b/packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts @@ -0,0 +1,24 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import { getFocusedIndexCancel } from '../GetFocusedIndexCancel/GetFocusedIndexCancel.ts' +import { getNewDirentsForCancelRename } from '../GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts' + +export const cancelEditRename = (state: ExplorerState, keepFocus: boolean): ExplorerState => { + const { editingIndex, items } = state + const newItems = getNewDirentsForCancelRename(items, editingIndex) + const newFocusedIndex = getFocusedIndexCancel(items, editingIndex) + return { + ...state, + editingErrorMessage: '', + editingIndex: -1, + editingSelectionEnd: 0, + editingSelectionStart: 0, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: keepFocus, + focusedIndex: newFocusedIndex, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts b/packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts new file mode 100644 index 0000000..de9dc33 --- /dev/null +++ b/packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts @@ -0,0 +1,8 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const cancelTypeAhead = (state: ExplorerState): ExplorerState => { + return { + ...state, + focusWord: '', + } +} diff --git a/packages/explorer-view/src/parts/Character/Character.ts b/packages/explorer-view/src/parts/Character/Character.ts new file mode 100644 index 0000000..fd657d0 --- /dev/null +++ b/packages/explorer-view/src/parts/Character/Character.ts @@ -0,0 +1,4 @@ +export const EmptyString = '' +export const Slash = '/' +export const Dot = '.' +export const BackSlash = '\\' diff --git a/packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts b/packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts new file mode 100644 index 0000000..3fa3a25 --- /dev/null +++ b/packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts @@ -0,0 +1,10 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const chevronDownVirtualDom: VirtualDomNode = { + childCount: 0, + className: MergeClassNames.mergeClassNames(ClassNames.Chevron, ClassNames.MaskIconChevronDown), + type: VirtualDomElements.Div, +} diff --git a/packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts b/packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts new file mode 100644 index 0000000..25c3ac0 --- /dev/null +++ b/packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts @@ -0,0 +1,10 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const chevronRightVirtualDom: VirtualDomNode = { + childCount: 0, + className: MergeClassNames.mergeClassNames(ClassNames.Chevron, ClassNames.MaskIconChevronRight), + type: VirtualDomElements.Div, +} diff --git a/packages/explorer-view/src/parts/ChevronType/ChevronType.ts b/packages/explorer-view/src/parts/ChevronType/ChevronType.ts new file mode 100644 index 0000000..2525169 --- /dev/null +++ b/packages/explorer-view/src/parts/ChevronType/ChevronType.ts @@ -0,0 +1,3 @@ +export const None = 0 +export const Right = 1 +export const Down = 2 diff --git a/packages/explorer-view/src/parts/ClassNames/ClassNames.ts b/packages/explorer-view/src/parts/ClassNames/ClassNames.ts new file mode 100644 index 0000000..412a034 --- /dev/null +++ b/packages/explorer-view/src/parts/ClassNames/ClassNames.ts @@ -0,0 +1,40 @@ +// 0 = 'Button' +// 1 = 'IconButton' +// 2 = 'Button IconButton' +// it could make dom diffing faster, since for classname, +// once at start, send all classnames to renderer process +// only numbers are compared. it could also make rendering faster, +// representing the concatenated strings for example +// since less data is transferred to renderer process +// then, components uses numeric classname +// TODO add option to make classnames numeric +// when a component uses multiple classnames, it is a new number +export const Actions = 'Actions' +export const Button = 'Button' +export const ButtonNarrow = 'ButtonNarrow' +export const ButtonPrimary = 'ButtonPrimary' +export const ButtonWide = 'ButtonWide' +export const Chevron = 'Chevron' +export const Empty = '' +export const Explorer = 'Explorer' +export const ExplorerDropTarget = 'DropTarget' +export const ExplorerErrorMessage = 'ExplorerErrorMessage' +export const ExplorerInputBox = 'ExplorerInputBox' +export const FileIcon = 'FileIcon' +export const FocusOutline = 'FocusOutline' +export const IconButton = 'IconButton' +export const InputBox = 'InputBox' +export const InputValidationError = 'InputValidationError' +export const Label = 'Label' +export const LabelCut = 'LabelCut' +export const ListItems = 'ListItems' +export const MaskIconChevronDown = 'MaskIconChevronDown' +export const MaskIconChevronRight = 'MaskIconChevronRight' +export const ScrollBar = 'ScrollBar' +export const ScrollBarSmall = 'ScrollBarSmall' +export const ScrollBarThumb = 'ScrollBarThumb' +export const TreeItem = 'TreeItem' +export const TreeItemActive = 'TreeItemActive' +export const Viewlet = 'Viewlet' +export const Welcome = 'Welcome' +export const WelcomeMessage = 'WelcomeMessage' diff --git a/packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts b/packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts new file mode 100644 index 0000000..a39bc7e --- /dev/null +++ b/packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export interface ClickHandler { + (state: ExplorerState, dirent: ExplorerItem, index: number, keepFocus: boolean): Promise +} diff --git a/packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts b/packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts new file mode 100644 index 0000000..92664bc --- /dev/null +++ b/packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts @@ -0,0 +1,14 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' + +export const writeText = async (text: string): Promise => { + await RendererWorker.writeClipBoardText(text) +} + +export const readNativeFiles = async (): Promise => { + return RendererWorker.invoke('ClipBoard.readNativeFiles') +} + +export const writeNativeFiles = async (type: string, files: readonly string[]): Promise => { + return RendererWorker.invoke('ClipBoard.writeNativeFiles', type, files) +} diff --git a/packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts b/packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts new file mode 100644 index 0000000..cd711b2 --- /dev/null +++ b/packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as IsTopLevel from '../IsTopLevel/IsTopLevel.ts' +import * as ToCollapsedDirent from '../ToCollapsedDirent/ToCollapsedDirent.ts' + +export const collapseAll = async (state: ExplorerState): Promise => { + const { items } = state + const newDirents = items.filter(IsTopLevel.isTopLevel).map(ToCollapsedDirent.toCollapsedDirent) + return { + ...state, + focusedIndex: 0, + items: newDirents, + } +} diff --git a/packages/explorer-view/src/parts/CommandMap/CommandMap.ts b/packages/explorer-view/src/parts/CommandMap/CommandMap.ts new file mode 100644 index 0000000..07184f2 --- /dev/null +++ b/packages/explorer-view/src/parts/CommandMap/CommandMap.ts @@ -0,0 +1,176 @@ +import { terminate } from '@lvce-editor/viewlet-registry' +import * as AcceptEdit from '../AcceptEdit/AcceptEdit.ts' +import * as CancelEdit from '../CancelEdit/CancelEdit.ts' +import * as CancelTypeAhead from '../CancelTypeAhead/CancelTypeAhead.ts' +import * as CollapseAll from '../CollapseAll/CollapseAll.ts' +import * as CompareWithSelected from '../CompareWithSelected/CompareWithSelected.ts' +import * as CopyPath from '../CopyPath/CopyPath.ts' +import * as CopyRelativePath from '../CopyRelativePath/CopyRelativePath.ts' +import * as Create2 from '../Create2/Create2.ts' +import * as Create from '../Create/Create.ts' +import * as Diff2 from '../Diff2/Diff2.ts' +import * as ExpandAll from '../ExpandAll/ExpandAll.ts' +import * as ExpandRecursively from '../ExpandRecursively/ExpandRecursively.ts' +import * as WrapCommand from '../ExplorerStates/ExplorerStates.ts' +import * as Focus from '../Focus/Focus.ts' +import * as FocusFirst from '../FocusFirst/FocusFirst.ts' +import * as FocusIndex from '../FocusIndex/FocusIndex.ts' +import * as FocusLast from '../FocusLast/FocusLast.ts' +import * as FocusNext from '../FocusNext/FocusNext.ts' +import * as FocusNone from '../FocusNone/FocusNone.ts' +import * as FocusPrevious from '../FocusPrevious/FocusPrevious.ts' +import * as GetKeyBindings from '../GetKeyBindings/GetKeyBindings.ts' +import * as GetMenuEntries2 from '../GetMenuEntries2/GetMenuEntries2.ts' +import * as GetMenuEntries from '../GetMenuEntries/GetMenuEntries.ts' +import * as GetMouseActions from '../GetMouseActions/GetMouseActions.ts' +import * as HandleArrowLeft from '../HandleArrowLeft/HandleArrowLeft.ts' +import * as HandleArrowRight from '../HandleArrowRight/HandleArrowRight.ts' +import * as HandleBlur from '../HandleBlur/HandleBlur.ts' +import { handleButtonClick } from '../HandleButtonClick/HandleButtonClick.ts' +import * as HandleClick from '../HandleClick/HandleClick.ts' +import * as HandleClickAt from '../HandleClickAt/HandleClickAt.ts' +import * as HandleClickCurrent from '../HandleClickCurrent/HandleClickCurrent.ts' +import * as HandleClickCurrentButKeepFocus from '../HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts' +import * as HandleClickOpenFolder from '../HandleClickOpenFolder/HandleClickOpenFolder.ts' +import * as HandleContextMenu from '../HandleContextMenu/HandleContextMenu.ts' +import * as HandleContextMenuKeyboard from '../HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts' +import * as HandleContextMenuWelcome from '../HandleContextMenuWelcome/HandleContextMenuWelcome.ts' +import * as HandleCopy from '../HandleCopy/HandleCopy.ts' +import * as HandleCut from '../HandleCut/HandleCut.ts' +import { handleDoubleClick } from '../HandleDoubleClick/HandleDoubleClick.ts' +import { handleDragEnd } from '../HandleDragEnd/HandleDragEnd.ts' +import * as HandleDragLeave from '../HandleDragLeave/HandleDragLeave.ts' +import * as HandleDragOver from '../HandleDragOver/HandleDragOver.ts' +import * as HandleDragOverIndex from '../HandleDragOverIndex/HandleDragOverIndex.ts' +import * as HandleDragStart from '../HandleDragStart/HandleDragStart.ts' +import * as HandleDrop from '../HandleDrop/HandleDrop.ts' +import { handleDropIndex } from '../HandleDropIndex/HandleDropIndex.ts' +import { handleEscape } from '../HandleEscape/HandleEscape.ts' +import * as HandleFocus from '../HandleFocus/HandleFocus.ts' +import * as HandleIconThemeChange from '../HandleIconThemeChange/HandleIconThemeChange.ts' +import * as HandleInputBlur from '../HandleInputBlur/HandleInputBlur.ts' +import * as HandleInputClick from '../HandleInputClick/HandleInputClick.ts' +import * as HandleInputKeyDown from '../HandleInputKeyDown/HandleInputKeyDown.ts' +import * as HandleKeyDown from '../HandleKeyDown/HandleKeyDown.ts' +import * as HandlePaste from '../HandlePaste/HandlePaste.ts' +import * as HandlePointerDown from '../HandlePointerDown/HandlePointerDown.ts' +import * as HandleResize from '../HandleResize/HandleResize.ts' +import * as HandleUpload from '../HandleUpload/HandleUpload.ts' +import * as HandleWheel from '../HandleWheel/HandleWheel.ts' +import * as HandleWorkspaceChange from '../HandleWorkspaceChange/HandleWorkspaceChange.ts' +import { handleWorkspaceRefresh } from '../HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts' +import * as Initialize from '../Initialize/Initialize.ts' +import * as LoadContent from '../LoadContent/LoadContent.ts' +import * as NewFile from '../NewFile/NewFile.ts' +import * as NewFolder from '../NewFolder/NewFolder.ts' +import * as OpenContainingFolder from '../OpenContainingFolder/OpenContainingFolder.ts' +import * as Refresh from '../Refresh/Refresh.ts' +import * as RemoveDirent from '../RemoveDirent/RemoveDirent.ts' +import * as RenameDirent from '../RenameDirent/RenameDirent.ts' +import * as Render2 from '../Render2/Render2.ts' +import * as RenderActions2 from '../RenderActions2/RenderActions2.ts' +import * as RenderEventListeners from '../RenderEventListeners/RenderEventListeners.ts' +import * as RestoreState from '../RestoreState/RestoreState.ts' +import * as RevealItem from '../RevealItem/RevealItem.ts' +import * as SaveState from '../SaveState/SaveState.ts' +import * as SelectAll from '../SelectAll/SelectAll.ts' +import * as SelectDown from '../SelectDown/SelectDown.ts' +import * as SelectForCompare from '../SelectForCompare/SelectForCompare.ts' +import * as SelectIndices from '../SelectIndices/SelectIndices.ts' +import * as SelectUp from '../SelectUp/SelectUp.ts' +import * as SetDeltaY from '../SetDeltaY/SetDeltaY.ts' +import * as ToggleIndividualSelection from '../ToggleIndividualSelection/ToggleIndividualSelection.ts' +import * as UpdateEditingValue from '../UpdateEditingValue/UpdateEditingValue.ts' +import * as UpdateIcons from '../UpdateIcons/UpdateIcons.ts' + +export const commandMap = { + 'Explorer.acceptEdit': WrapCommand.wrapListItemCommand(AcceptEdit.acceptEdit), + 'Explorer.cancelEdit': WrapCommand.wrapListItemCommand(CancelEdit.cancelEdit), + 'Explorer.cancelTypeAhead': WrapCommand.wrapListItemCommand(CancelTypeAhead.cancelTypeAhead), + 'Explorer.collapseAll': WrapCommand.wrapListItemCommand(CollapseAll.collapseAll), + 'Explorer.compareWithSelected': WrapCommand.wrapListItemCommand(CompareWithSelected.compareWithSelected), + 'Explorer.copyPath': WrapCommand.wrapListItemCommand(CopyPath.copyPath), + 'Explorer.copyRelativePath': WrapCommand.wrapListItemCommand(CopyRelativePath.copyRelativePath), + 'Explorer.create': Create.create, + // not wrapped + 'Explorer.create2': Create2.create2, + 'Explorer.diff2': Diff2.diff2, + 'Explorer.expandAll': WrapCommand.wrapListItemCommand(ExpandAll.expandAll), + 'Explorer.expandRecursively': WrapCommand.wrapListItemCommand(ExpandRecursively.expandRecursively), + 'Explorer.focus': WrapCommand.wrapListItemCommand(Focus.focus), + 'Explorer.focusFirst': WrapCommand.wrapListItemCommand(FocusFirst.focusFirst), + 'Explorer.focusIndex': WrapCommand.wrapListItemCommand(FocusIndex.focusIndex), + 'Explorer.focusLast': WrapCommand.wrapListItemCommand(FocusLast.focusLast), + 'Explorer.focusNext': WrapCommand.wrapListItemCommand(FocusNext.focusNext), + 'Explorer.focusNone': WrapCommand.wrapListItemCommand(FocusNone.focusNone), + 'Explorer.focusPrevious': WrapCommand.wrapListItemCommand(FocusPrevious.focusPrevious), + 'Explorer.getCommandIds': WrapCommand.getCommandIds, + 'Explorer.getKeyBindings': GetKeyBindings.getKeyBindings, + 'Explorer.getMenuEntries': GetMenuEntries.getMenuEntries, + 'Explorer.getMenuEntries2': WrapCommand.wrapGetter(GetMenuEntries2.getMenuEntries2), + 'Explorer.getMouseActions': GetMouseActions.getMouseActions, + 'Explorer.handleArrowLeft': WrapCommand.wrapListItemCommand(HandleArrowLeft.handleArrowLeft), + 'Explorer.handleArrowRight': WrapCommand.wrapListItemCommand(HandleArrowRight.handleArrowRight), + 'Explorer.handleBlur': WrapCommand.wrapListItemCommand(HandleBlur.handleBlur), + 'Explorer.handleButtonClick': WrapCommand.wrapListItemCommand(handleButtonClick), + 'Explorer.handleClick': WrapCommand.wrapListItemCommand(HandleClick.handleClick), + 'Explorer.handleClickAt': WrapCommand.wrapListItemCommand(HandleClickAt.handleClickAt), + 'Explorer.handleClickCurrent': WrapCommand.wrapListItemCommand(HandleClickCurrent.handleClickCurrent), + 'Explorer.handleClickCurrentButKeepFocus': WrapCommand.wrapListItemCommand(HandleClickCurrentButKeepFocus.handleClickCurrentButKeepFocus), + 'Explorer.handleClickOpenFolder': WrapCommand.wrapListItemCommand(HandleClickOpenFolder.handleClickOpenFolder), + 'Explorer.handleContextMenu': WrapCommand.wrapListItemCommand(HandleContextMenu.handleContextMenu), + 'Explorer.handleContextMenuKeyboard': WrapCommand.wrapListItemCommand(HandleContextMenuKeyboard.handleContextMenuKeyboard), + 'Explorer.handleContextMenuWelcome': WrapCommand.wrapListItemCommand(HandleContextMenuWelcome.handleContextMenuWelcome), + 'Explorer.handleCopy': WrapCommand.wrapListItemCommand(HandleCopy.handleCopy), + 'Explorer.handleCut': WrapCommand.wrapListItemCommand(HandleCut.handleCut), + 'Explorer.handleDoubleClick': WrapCommand.wrapListItemCommand(handleDoubleClick), + 'Explorer.handleDragEnd': WrapCommand.wrapListItemCommand(handleDragEnd), + 'Explorer.handleDragLeave': WrapCommand.wrapListItemCommand(HandleDragLeave.handleDragLeave), + 'Explorer.handleDragOver': WrapCommand.wrapListItemCommand(HandleDragOver.handleDragOver), + 'Explorer.handleDragOverIndex': WrapCommand.wrapListItemCommand(HandleDragOverIndex.handleDragOverIndex), + 'Explorer.handleDragStart': WrapCommand.wrapListItemCommand(HandleDragStart.handleDragStart), + 'Explorer.handleDrop': WrapCommand.wrapListItemCommand(HandleDrop.handleDrop), + 'Explorer.handleDropIndex': WrapCommand.wrapListItemCommand(handleDropIndex), + 'Explorer.handleEscape': WrapCommand.wrapListItemCommand(handleEscape), + 'Explorer.handleFocus': WrapCommand.wrapListItemCommand(HandleFocus.handleFocus), + 'Explorer.handleIconThemeChange': WrapCommand.wrapListItemCommand(HandleIconThemeChange.handleIconThemeChange), + 'Explorer.handleInputBlur': WrapCommand.wrapListItemCommand(HandleInputBlur.handleInputBlur), + 'Explorer.handleInputClick': WrapCommand.wrapListItemCommand(HandleInputClick.handleInputClick), + 'Explorer.handleInputKeyDown': WrapCommand.wrapListItemCommand(HandleInputKeyDown.handleInputKeyDown), + 'Explorer.handleKeyDown': WrapCommand.wrapListItemCommand(HandleKeyDown.handleKeyDown), + 'Explorer.handlePaste': WrapCommand.wrapListItemCommand(HandlePaste.handlePaste), + 'Explorer.handlePointerDown': WrapCommand.wrapListItemCommand(HandlePointerDown.handlePointerDown), + 'Explorer.handleResize': WrapCommand.wrapListItemCommand(HandleResize.handleResize), + 'Explorer.handleUpload': WrapCommand.wrapListItemCommand(HandleUpload.handleUpload), + 'Explorer.handleWheel': WrapCommand.wrapListItemCommand(HandleWheel.handleWheel), + 'Explorer.handleWorkspaceChange': WrapCommand.wrapListItemCommand(HandleWorkspaceChange.handleWorkspaceChange), + 'Explorer.handleWorkspaceRefresh': WrapCommand.wrapListItemCommand(handleWorkspaceRefresh), + 'Explorer.initialize': Initialize.initialize, + 'Explorer.loadContent': WrapCommand.wrapListItemCommand(LoadContent.loadContent), + 'Explorer.newFile': WrapCommand.wrapListItemCommand(NewFile.newFile), + 'Explorer.newFolder': WrapCommand.wrapListItemCommand(NewFolder.newFolder), + 'Explorer.openContainingFolder': WrapCommand.wrapListItemCommand(OpenContainingFolder.openContainingFolder), + 'Explorer.refresh': WrapCommand.wrapListItemCommand(Refresh.refresh), + 'Explorer.removeDirent': WrapCommand.wrapListItemCommand(RemoveDirent.removeDirent), + 'Explorer.renameDirent': WrapCommand.wrapListItemCommand(RenameDirent.renameDirent), + 'Explorer.render2': Render2.render2, + 'Explorer.renderActions2': RenderActions2.renderActions, + 'Explorer.renderEventListeners': RenderEventListeners.renderEventListeners, + 'Explorer.restoreState': RestoreState.restoreState, + 'Explorer.reveal': WrapCommand.wrapListItemCommand(RevealItem.revealItem), + 'Explorer.revealItem': WrapCommand.wrapListItemCommand(RevealItem.revealItem), + + 'Explorer.saveState': WrapCommand.wrapGetter(SaveState.saveState), + 'Explorer.selectAll': WrapCommand.wrapListItemCommand(SelectAll.selectAll), + 'Explorer.selectDown': WrapCommand.wrapListItemCommand(SelectDown.selectDown), + 'Explorer.selectForCompare': WrapCommand.wrapListItemCommand(SelectForCompare.selectForCompare), + 'Explorer.selectIndices': WrapCommand.wrapListItemCommand(SelectIndices.setSelectedIndices), + 'Explorer.selectUp': WrapCommand.wrapListItemCommand(SelectUp.selectUp), + 'Explorer.setDeltaY': WrapCommand.wrapListItemCommand(SetDeltaY.setDeltaY), + 'Explorer.setSelectedIndices': WrapCommand.wrapListItemCommand(SelectIndices.setSelectedIndices), + 'Explorer.terminate': terminate, + 'Explorer.toggleIndividualSelection': WrapCommand.wrapListItemCommand(ToggleIndividualSelection.toggleIndividualSelection), + 'Explorer.updateEditingValue': WrapCommand.wrapListItemCommand(UpdateEditingValue.updateEditingValue), + + 'Explorer.updateIcons': WrapCommand.wrapListItemCommand(UpdateIcons.updateIcons), +} diff --git a/packages/explorer-view/src/parts/Compare/Compare.ts b/packages/explorer-view/src/parts/Compare/Compare.ts new file mode 100644 index 0000000..4ca33ca --- /dev/null +++ b/packages/explorer-view/src/parts/Compare/Compare.ts @@ -0,0 +1,8 @@ +const RE_CHARACTERS = /^[a-zA-Z.-]+$/ + +export const compareStringNumeric = (a: string, b: string): number => { + if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) { + return a < b ? -1 : 1 + } + return a.localeCompare(b, 'en', { numeric: true }) +} diff --git a/packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts b/packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts new file mode 100644 index 0000000..83c3ee3 --- /dev/null +++ b/packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts @@ -0,0 +1,24 @@ +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as Compare from '../Compare/Compare.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +const priorityMapFoldersFirst: Record = { + [DirentType.Directory]: 1, + [DirentType.File]: 0, + [DirentType.Socket]: 0, + [DirentType.SymLinkFile]: 0, + [DirentType.SymLinkFolder]: 1, + [DirentType.Unknown]: 0, +} + +const compareDirentType = (direntA: RawDirent, direntB: RawDirent): number => { + return priorityMapFoldersFirst[direntB.type] - priorityMapFoldersFirst[direntA.type] +} + +const compareDirentName = (direntA: RawDirent, direntB: RawDirent): number => { + return Compare.compareStringNumeric(direntA.name, direntB.name) +} + +export const compareDirent = (direntA: RawDirent, direntB: RawDirent): number => { + return compareDirentType(direntA, direntB) || compareDirentName(direntA, direntB) +} diff --git a/packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts b/packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts new file mode 100644 index 0000000..c0f5b5e --- /dev/null +++ b/packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts @@ -0,0 +1,18 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetFocusedFile from '../GetFocusedFile/GetFocusedFile.ts' +import * as OpenDiff from '../OpenDiff/OpenDiff.ts' + +export const compareWithSelected = async (state: ExplorerState): Promise => { + const focusedFile = GetFocusedFile.getFocusedFile(state) + if (!focusedFile) { + return state + } + if (!state.compareSourceUri || state.compareSourceUri === focusedFile.path) { + return state + } + await OpenDiff.openDiff(state.compareSourceUri, focusedFile.path, true) + return { + ...state, + compareSourceUri: '', + } +} diff --git a/packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts b/packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts new file mode 100644 index 0000000..2d25dd1 --- /dev/null +++ b/packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts @@ -0,0 +1,28 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { Tree } from '../Tree/Tree.ts' +import type { TreeUpdate } from '../TreeUpdate/TreeUpdate.ts' + +export const computeExplorerRenamedDirentUpdate = ( + root: string, + parentPath: string, + oldUri: string, + children: readonly ExplorerItem[], + tree: Tree, + newUri: string, +): TreeUpdate => { + const rootLength = root.length + const relativeDirname = parentPath.slice(rootLength) + const relativeOldPath = oldUri.slice(rootLength) + const relativeNewUri = newUri.slice(rootLength) + const update: TreeUpdate = Object.create(null) + update[relativeDirname] = children + const oldItems = tree[relativeOldPath] || [] + update[relativeNewUri] = oldItems + for (const [key, value] of Object.entries(tree)) { + if (key.startsWith(`${relativeOldPath}/`)) { + const newKey = `${relativeNewUri}` + key.slice(relativeOldPath.length) + update[newKey] = value + } + } + return update +} diff --git a/packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts b/packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts new file mode 100644 index 0000000..ac4e728 --- /dev/null +++ b/packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts @@ -0,0 +1,8 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const confirmDelete = async (paths: readonly string[]): Promise => { + // TODO use i18n string + const message = paths.length === 1 ? `Are you sure you want to delete "${paths[0]}"?` : `Are you sure you want to delete ${paths.length} items?` + const result = await RendererWorker.confirm(message) + return result === true +} diff --git a/packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts b/packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts new file mode 100644 index 0000000..52ca7c7 --- /dev/null +++ b/packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts @@ -0,0 +1,7 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' + +export const confirmPaste = async (): Promise => { + const result = await RendererWorker.confirm(ExplorerStrings.pasteConfirmation()) + return result === true +} diff --git a/packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts b/packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts new file mode 100644 index 0000000..40c7ab7 --- /dev/null +++ b/packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts @@ -0,0 +1,12 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ContextMenuProps } from '../ContextMenuProps/ContextMenuProps.ts' + +export const show2 = async ( + uid: number, + menuId: ContextMenuProps['menuId'], + x: number, + y: number, + args: ContextMenuProps, +): Promise => { + await RendererWorker.showContextMenu2(uid, menuId, x, y, args) +} diff --git a/packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts b/packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts new file mode 100644 index 0000000..2ab40c0 --- /dev/null +++ b/packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export interface ContextMenuHandler { + (state: ExplorerState, x: number, y: number): Promise +} diff --git a/packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts b/packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts new file mode 100644 index 0000000..08f5e6f --- /dev/null +++ b/packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts @@ -0,0 +1,11 @@ +import type { MenuEntryId } from '@lvce-editor/constants' + +export interface ContextMenuPropsBase { + readonly menuId: number +} + +export interface ContextMenuPropsExplorer extends ContextMenuPropsBase { + readonly menuId: typeof MenuEntryId.Explorer +} + +export type ContextMenuProps = ContextMenuPropsExplorer diff --git a/packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts b/packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts new file mode 100644 index 0000000..f59019d --- /dev/null +++ b/packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts @@ -0,0 +1,11 @@ +import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' +import { applyFileOperations } from '../ApplyFileOperations/ApplyFileOperations.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' +import { getFileOperationsElectron } from '../GetFileOperationsElectron/GetFileOperationsElectron.ts' + +// TODO copy files in parallel +export const copyFilesElectron = async (root: string, fileHandles: DroppedArgs, files: readonly File[], paths: readonly string[]): Promise => { + const pathSeparator = await FileSystem.getPathSeparator(root) + const operations = await getFileOperationsElectron(root, paths, fileHandles, pathSeparator) + await applyFileOperations(operations) +} diff --git a/packages/explorer-view/src/parts/CopyPath/CopyPath.ts b/packages/explorer-view/src/parts/CopyPath/CopyPath.ts new file mode 100644 index 0000000..e7272fe --- /dev/null +++ b/packages/explorer-view/src/parts/CopyPath/CopyPath.ts @@ -0,0 +1,12 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetFocusedDirent from '../GetFocusedDirent/GetFocusedDirent.ts' + +export const copyPath = async (state: ExplorerState): Promise => { + const dirent = GetFocusedDirent.getFocusedDirent(state) + // TODO windows paths + // TODO handle error + const path = dirent ? dirent.path : state.root + await RendererWorker.writeClipBoardText(path) + return state +} diff --git a/packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts b/packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts new file mode 100644 index 0000000..f8cec66 --- /dev/null +++ b/packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts @@ -0,0 +1,28 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ClipBoard from '../ClipBoard/ClipBoard.ts' +import * as GetFocusedDirent from '../GetFocusedDirent/GetFocusedDirent.ts' + +const getRelativePath = (root: string, pathSeparator: string, path: string): string => { + if (root && path.startsWith(root)) { + const relativePath = path.slice(root.length) + if (relativePath.startsWith(pathSeparator)) { + return relativePath.slice(pathSeparator.length) + } + return relativePath + } + if (path.startsWith(pathSeparator)) { + return path.slice(pathSeparator.length) + } + return path +} + +export const copyRelativePath = async (state: ExplorerState): Promise => { + const dirent = GetFocusedDirent.getFocusedDirent(state) + if (!dirent) { + return state + } + const relativePath = getRelativePath(state.root, state.pathSeparator, dirent.path) + // TODO handle error + await ClipBoard.writeText(relativePath) + return state +} diff --git a/packages/explorer-view/src/parts/CountInRange/CountInRange.ts b/packages/explorer-view/src/parts/CountInRange/CountInRange.ts new file mode 100644 index 0000000..f8c48df --- /dev/null +++ b/packages/explorer-view/src/parts/CountInRange/CountInRange.ts @@ -0,0 +1,7 @@ +export const countInRange = (start: number, end: number): readonly number[] => { + const items: number[] = [] + for (let i = start; i <= end; i++) { + items.push(i) + } + return items +} diff --git a/packages/explorer-view/src/parts/Create/Create.ts b/packages/explorer-view/src/parts/Create/Create.ts new file mode 100644 index 0000000..7d3dc29 --- /dev/null +++ b/packages/explorer-view/src/parts/Create/Create.ts @@ -0,0 +1,82 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' +import * as Height from '../Height/Height.ts' +import * as PathSeparatorType from '../PathSeparatorType/PathSeparatorType.ts' + +// TODO parentUid might ot be needed +export const create = ( + id: number, + uri: string, + x: number, + y: number, + width: number, + height: number, + args: any, + parentUid: any, + platform: number = 0, + assetDir: string = '', +): any => { + const state: ExplorerState = { + assetDir, + compareSourceUri: '', + confirmDelete: false, + confirmPaste: false, + cutItems: [], + decorations: [], + deltaY: 0, + dropTargets: [], + editingErrorMessage: '', + editingIcon: '', + editingIndex: -1, + editingSelectionEnd: 0, + editingSelectionStart: 0, + editingType: ExplorerEditingType.None, + editingValue: '', + errorCode: '', + errorMessage: '', + errorMessageLeft: 0, + errorMessageTop: 0, + errorMessageWidth: 0, + excluded: [], + fileIconCache: Object.create(null), + finalDeltaY: 0, + focus: 0, + focused: false, + focusedIndex: -1, + focusWord: '', + focusWordTimeout: 800, + handleOffset: 0, + hasError: false, + height, + hoverIndex: -1, + icons: [], + initial: true, + inputSource: 0, + isPointerDown: false, + itemHeight: Height.ListItem, + items: [], + maxIndent: 0, + maxLineY: 0, + minLineY: 0, + parentUid, + pasteShouldMove: false, + pathSeparator: PathSeparatorType.Slash, + platform, + pointerDownIndex: -1, + root: '', + scrollBarActive: false, + scrollBarHeight: 0, + sourceControlDecorations: false, + sourceControlIgnoredUris: [], + uid: id, + useChevrons: false, + version: 0, + visibleExplorerItems: [], + width, + x, + y, + } + ExplorerStates.set(state.uid, state, state) + return state +} diff --git a/packages/explorer-view/src/parts/Create2/Create2.ts b/packages/explorer-view/src/parts/Create2/Create2.ts new file mode 100644 index 0000000..97dc62b --- /dev/null +++ b/packages/explorer-view/src/parts/Create2/Create2.ts @@ -0,0 +1,17 @@ +import { create } from '../Create/Create.ts' + +// TODO parentUid might ot be needed +export const create2 = ( + uid: number, + uri: string, + x: number, + y: number, + width: number, + height: number, + args: any, + parentUid: any, + platform: number = 0, + assetDir: string = '', +): void => { + return create(uid, uri, x, y, width, height, args, parentUid, platform, assetDir) +} diff --git a/packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts b/packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts new file mode 100644 index 0000000..0228b59 --- /dev/null +++ b/packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts @@ -0,0 +1,10 @@ +import { ensureUri } from '../EnsureUris/EnsureUris.ts' + +export const createDecorationMap = (decorations: readonly any[]): Record => { + const map: Record = Object.create(null) + for (const decoration of decorations) { + const uri = ensureUri(decoration.uri) + map[uri] = decoration.decoration + } + return map +} diff --git a/packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts b/packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts new file mode 100644 index 0000000..ec6deb7 --- /dev/null +++ b/packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts @@ -0,0 +1,62 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const createDefaultState = (): ExplorerState => ({ + assetDir: '', + compareSourceUri: '', + confirmDelete: false, + confirmPaste: false, + cutItems: [], + decorations: [], + deltaY: 0, + dropTargets: [], + editingErrorMessage: '', + editingIcon: '', + editingIndex: -1, + editingSelectionEnd: 0, + editingSelectionStart: 0, + editingType: 0, + editingValue: '', + errorCode: '', + errorMessage: '', + errorMessageLeft: 0, + errorMessageTop: 0, + errorMessageWidth: 0, + excluded: [], + fileIconCache: {}, + finalDeltaY: 0, + focus: 0, + focused: true, + focusedIndex: 0, + focusWord: '', + focusWordTimeout: 1000, + handleOffset: 0, + hasError: false, + height: 100, + hoverIndex: 0, + icons: [], + initial: false, + inputSource: 0, + isPointerDown: false, + itemHeight: 20, + items: [], + maxIndent: 0, + maxLineY: 0, + minLineY: 0, + parentUid: 0, + pasteShouldMove: false, + pathSeparator: '/', + platform: 0, + pointerDownIndex: -1, + root: '/', + scrollBarActive: false, + scrollBarHeight: 0, + sourceControlDecorations: false, + sourceControlIgnoredUris: [], + uid: 1, + useChevrons: false, + version: 1, + visibleExplorerItems: [], + width: 100, + x: 0, + y: 0, +}) diff --git a/packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts b/packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts new file mode 100644 index 0000000..829144d --- /dev/null +++ b/packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts @@ -0,0 +1,15 @@ +import { type Rpc, LazyTransferMessagePortRpcParent } from '@lvce-editor/rpc' +import { VError } from '@lvce-editor/verror' +import * as SendMessagePortToFileSystemWorker from '../SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts' + +export const createFileSystemWorkerRpc = async (): Promise => { + try { + const rpc = await LazyTransferMessagePortRpcParent.create({ + commandMap: {}, + send: SendMessagePortToFileSystemWorker.sendMessagePortToFileSystemWorker, + }) + return rpc + } catch (error) { + throw new VError(error, `Failed to create file system worker rpc`) + } +} diff --git a/packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts b/packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts new file mode 100644 index 0000000..b62b62e --- /dev/null +++ b/packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts @@ -0,0 +1,19 @@ +import { type Rpc, LazyTransferMessagePortRpcParent } from '@lvce-editor/rpc' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { VError } from '@lvce-editor/verror' + +const send = (port: MessagePort): Promise => { + return RendererWorker.sendMessagePortToIconThemeWorker(port, 0) +} + +export const createIconThemeWorkerRpc = async (): Promise => { + try { + const rpc = await LazyTransferMessagePortRpcParent.create({ + commandMap: {}, + send, + }) + return rpc + } catch (error) { + throw new VError(error, `Failed to create icon theme worker rpc`) + } +} diff --git a/packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts b/packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts new file mode 100644 index 0000000..d7de3bf --- /dev/null +++ b/packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts @@ -0,0 +1,18 @@ +import * as FileSystem from '../FileSystem/FileSystem.ts' + +export const createNestedPath = async (root: string, path: string, pathSeparator: string): Promise => { + const parts = path.slice(root.length).split(pathSeparator) + let currentPath = '' + for (const part of parts) { + if (!part) continue + currentPath = currentPath ? `${currentPath}${pathSeparator}${part}` : part + try { + await FileSystem.mkdir(`${root}${currentPath}`) + } catch (error) { + // Ignore error if directory already exists + if (!(error instanceof Error && error.message.includes('already exists'))) { + throw error + } + } + } +} diff --git a/packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts b/packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts new file mode 100644 index 0000000..513b5fd --- /dev/null +++ b/packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts @@ -0,0 +1,20 @@ +import { type Rpc, LazyTransferMessagePortRpcParent } from '@lvce-editor/rpc' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { VError } from '@lvce-editor/verror' + +const send = (port: MessagePort): Promise => { + // @ts-ignore + return RendererWorker.sendMessagePortToSourceControlWorker(port, 0) +} + +export const createSourceControlWorkerRpc = async (): Promise => { + try { + const rpc = await LazyTransferMessagePortRpcParent.create({ + commandMap: {}, + send, + }) + return rpc + } catch (error) { + throw new VError(error, `Failed to create source control worker rpc`) + } +} diff --git a/packages/explorer-view/src/parts/CreateTree/CreateTree.ts b/packages/explorer-view/src/parts/CreateTree/CreateTree.ts new file mode 100644 index 0000000..7529c35 --- /dev/null +++ b/packages/explorer-view/src/parts/CreateTree/CreateTree.ts @@ -0,0 +1,33 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { Tree } from '../Tree/Tree.ts' +import type { TreeItem } from '../TreeItem/TreeItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as Path from '../Path/Path.ts' + +const getActualType = (type: number, expanded: boolean): number => { + const actualType = type === DirentType.Directory && expanded ? DirentType.DirectoryExpanded : type + return actualType +} + +export const createTree = (items: readonly ExplorerItem[], root: string): Tree => { + const tree: Record = Object.create(null) + const rootLength = root.length + const paths = items.map((item) => { + const relativePath = item.path.slice(rootLength) + const dirname = Path.dirname2(relativePath) + return dirname + }) + for (const item of items) { + const { name, path, type } = item + const relativePath = path.slice(rootLength) + const dirname = Path.dirname2(relativePath) + const isExpanded = paths.includes(relativePath) + const actualType = getActualType(type, isExpanded) + tree[dirname] ||= [] + tree[dirname].push({ + name, + type: actualType, + }) + } + return tree +} diff --git a/packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts b/packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts new file mode 100644 index 0000000..7cadf87 --- /dev/null +++ b/packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts @@ -0,0 +1,22 @@ +import { getChildHandles } from '../GetChildHandles/GetChildHandles.ts' +import { getFileHandleText } from '../GetFileHandleText/GetFileHandleText.ts' +import { isDirectoryHandle } from '../IsDirectoryHandle/IsDirectoryHandle.ts' +import { isFileHandle } from '../IsFileHandle/IsFileHandle.ts' + +export const createUploadTree = async (root: string, fileHandles: readonly FileSystemHandle[]): Promise => { + const uploadTree = Object.create(null) + const normalized = fileHandles.filter(Boolean) + for (const fileHandle of normalized) { + const { name } = fileHandle + if (isDirectoryHandle(fileHandle)) { + const children = await getChildHandles(fileHandle) + const childTree = await createUploadTree(name, children) + uploadTree[name] = childTree + } else if (isFileHandle(fileHandle)) { + // TODO maybe save blob and use filesystem.writeblob + const text = await getFileHandleText(fileHandle) + uploadTree[name] = text + } + } + return uploadTree +} diff --git a/packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts b/packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts new file mode 100644 index 0000000..fcbcc6d --- /dev/null +++ b/packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts @@ -0,0 +1 @@ +export const DELTA_EDITING = 100 diff --git a/packages/explorer-view/src/parts/Diff/Diff.ts b/packages/explorer-view/src/parts/Diff/Diff.ts new file mode 100644 index 0000000..d85bc2f --- /dev/null +++ b/packages/explorer-view/src/parts/Diff/Diff.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DiffModules from '../DiffModules/DiffModules.ts' + +export const diff = (oldState: ExplorerState, newState: ExplorerState): readonly number[] => { + const diffResult: number[] = [] + for (let i = 0; i < DiffModules.modules.length; i++) { + const fn = DiffModules.modules[i] + if (!fn(oldState, newState)) { + diffResult.push(DiffModules.numbers[i]) + } + } + return diffResult +} diff --git a/packages/explorer-view/src/parts/Diff2/Diff2.ts b/packages/explorer-view/src/parts/Diff2/Diff2.ts new file mode 100644 index 0000000..988bc96 --- /dev/null +++ b/packages/explorer-view/src/parts/Diff2/Diff2.ts @@ -0,0 +1,8 @@ +import * as Diff from '../Diff/Diff.ts' +import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' + +export const diff2 = (uid: number): readonly number[] => { + const { newState, oldState } = ExplorerStates.get(uid) + const result = Diff.diff(oldState, newState) + return result +} diff --git a/packages/explorer-view/src/parts/DiffCss/DiffCss.ts b/packages/explorer-view/src/parts/DiffCss/DiffCss.ts new file mode 100644 index 0000000..490681d --- /dev/null +++ b/packages/explorer-view/src/parts/DiffCss/DiffCss.ts @@ -0,0 +1,21 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { + // TODO compute css more optimized + // maybe only when items change, and even then not + // always, but only when it affects the css + return ( + oldState.deltaY === newState.deltaY && + oldState.editingErrorMessage === newState.editingErrorMessage && + oldState.hasError === newState.hasError && + oldState.errorMessage === newState.errorMessage && + oldState.errorCode === newState.errorCode && + oldState.errorMessageLeft === newState.errorMessageLeft && + oldState.errorMessageTop === newState.errorMessageTop && + oldState.maxIndent === newState.maxIndent && + oldState.scrollBarActive === newState.scrollBarActive && + oldState.scrollBarHeight === newState.scrollBarHeight && + oldState.visibleExplorerItems === newState.visibleExplorerItems && + oldState.width === newState.width + ) +} diff --git a/packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts b/packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts new file mode 100644 index 0000000..85ec20e --- /dev/null +++ b/packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { + return oldState.isPointerDown || !newState.isPointerDown +} diff --git a/packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts b/packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts new file mode 100644 index 0000000..19083a6 --- /dev/null +++ b/packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts @@ -0,0 +1,10 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { Selection } from '../Selection/Selection.ts' + +export const diffEditingSelection = (state: ExplorerState, start: number, end: number): Selection | undefined => { + const { editingSelectionEnd, editingSelectionStart } = state + if (editingSelectionStart === start && editingSelectionEnd === end) { + return undefined + } + return { end, start } +} diff --git a/packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts b/packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts new file mode 100644 index 0000000..dd68b49 --- /dev/null +++ b/packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { + return oldState.focused === newState.focused && oldState.focus === newState.focus +} diff --git a/packages/explorer-view/src/parts/DiffItems/DiffItems.ts b/packages/explorer-view/src/parts/DiffItems/DiffItems.ts new file mode 100644 index 0000000..37e3e58 --- /dev/null +++ b/packages/explorer-view/src/parts/DiffItems/DiffItems.ts @@ -0,0 +1,23 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { + return ( + oldState.items === newState.items && + oldState.minLineY === newState.minLineY && + oldState.maxLineY === newState.maxLineY && + oldState.focusedIndex === newState.focusedIndex && + oldState.editingIndex === newState.editingIndex && + oldState.editingType === newState.editingType && + oldState.editingValue === newState.editingValue && + oldState.editingErrorMessage === newState.editingErrorMessage && + oldState.hasError === newState.hasError && + oldState.errorMessage === newState.errorMessage && + oldState.errorCode === newState.errorCode && + oldState.width === newState.width && + oldState.focused === newState.focused && + oldState.dropTargets === newState.dropTargets && + oldState.icons === newState.icons && + oldState.cutItems === newState.cutItems && + oldState.visibleExplorerItems === newState.visibleExplorerItems + ) +} diff --git a/packages/explorer-view/src/parts/DiffModules/DiffModules.ts b/packages/explorer-view/src/parts/DiffModules/DiffModules.ts new file mode 100644 index 0000000..499e2c3 --- /dev/null +++ b/packages/explorer-view/src/parts/DiffModules/DiffModules.ts @@ -0,0 +1,27 @@ +import * as DiffCss from '../DiffCss/DiffCss.ts' +import * as DiffDragData from '../DiffDragData/DiffDragData.ts' +import * as DiffFocus from '../DiffFocus/DiffFocus.ts' +import * as DiffItems from '../DiffItems/DiffItems.ts' +import * as DiffSelection from '../DiffSelection/DiffSelection.ts' +import * as DiffType from '../DiffType/DiffType.ts' +import * as DiffValue from '../DiffValue/DiffValue.ts' + +export const modules = [ + DiffItems.isEqual, + DiffFocus.isEqual, + DiffFocus.isEqual, + DiffValue.isEqual, + DiffSelection.isEqual, + DiffDragData.isEqual, + DiffCss.isEqual, +] + +export const numbers = [ + DiffType.RenderIncremental, + DiffType.RenderFocus, + DiffType.RenderFocusContext, + DiffType.RenderValue, + DiffType.RenderSelection, + DiffType.RenderDragData, + DiffType.RenderCss, +] diff --git a/packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts b/packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts new file mode 100644 index 0000000..ac1c39a --- /dev/null +++ b/packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { + return oldState.editingSelectionStart === newState.editingSelectionStart && oldState.editingSelectionEnd === newState.editingSelectionEnd +} diff --git a/packages/explorer-view/src/parts/DiffType/DiffType.ts b/packages/explorer-view/src/parts/DiffType/DiffType.ts new file mode 100644 index 0000000..898bd08 --- /dev/null +++ b/packages/explorer-view/src/parts/DiffType/DiffType.ts @@ -0,0 +1,9 @@ +export const RenderItems = 4 +export const RenderEditingIndex = 5 +export const RenderFocus = 6 +export const RenderFocusContext = 7 +export const RenderValue = 8 +export const RenderSelection = 9 +export const RenderDragData = 10 +export const RenderCss = 11 +export const RenderIncremental = 12 diff --git a/packages/explorer-view/src/parts/DiffValue/DiffValue.ts b/packages/explorer-view/src/parts/DiffValue/DiffValue.ts new file mode 100644 index 0000000..86cc483 --- /dev/null +++ b/packages/explorer-view/src/parts/DiffValue/DiffValue.ts @@ -0,0 +1,9 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusId from '../FocusId/FocusId.ts' + +export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { + if (newState.focus !== FocusId.Input) { + return true + } + return oldState.focus === FocusId.Input && newState.focus === FocusId.Input && oldState.editingValue === newState.editingValue +} diff --git a/packages/explorer-view/src/parts/DirentType/DirentType.ts b/packages/explorer-view/src/parts/DirentType/DirentType.ts new file mode 100644 index 0000000..98b34c3 --- /dev/null +++ b/packages/explorer-view/src/parts/DirentType/DirentType.ts @@ -0,0 +1,21 @@ +import { DELTA_EDITING } from '../DeltaEditing/DeltaEditing.ts' + +export const BlockDevice = 1 +export const CharacterDevice = 2 +export const Directory = 3 +export const DirectoryExpanded = 4 +export const DirectoryExpanding = 5 +export const File = 7 +export const Socket = 8 +export const Symlink = 9 +export const SymLinkFile = 10 +export const SymLinkFolder = 11 +export const Unknown = 12 + +export const EditingFile = File + DELTA_EDITING +export const EditingFolder = Directory + DELTA_EDITING +export const EditingDirectoryExpanded = DirectoryExpanded + DELTA_EDITING +export const EditingUnknown = Unknown + DELTA_EDITING +export const EditingSymLinkFile = SymLinkFile + DELTA_EDITING +export const EditingSymLinkFolder = SymLinkFolder + DELTA_EDITING +export const EditingSymLinkUnknown = Symlink + DELTA_EDITING diff --git a/packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts b/packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts new file mode 100644 index 0000000..7c7ca5a --- /dev/null +++ b/packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts @@ -0,0 +1,7 @@ +export interface DomEventListener { + readonly name: string | number + readonly params: readonly string[] + readonly passive?: boolean + readonly preventDefault?: boolean + readonly stopPropagation?: boolean +} diff --git a/packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts b/packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts new file mode 100644 index 0000000..5301d5d --- /dev/null +++ b/packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts @@ -0,0 +1,18 @@ +export const HandleButtonClick = 18 +export const HandleClick = 1 +export const HandleClickOpenFolder = 2 +export const HandleContextMenu = 3 +export const HandleContextMenuWelcome = 20 +export const HandleDragEnd = 19 +export const HandleDragLeave = 4 +export const HandleDragOver = 5 +export const HandleDragStart = 17 +export const HandleDrop = 6 +export const HandleEditingInput = 7 +export const HandleInputBlur = 8 +export const HandleInputClick = 9 +export const HandleListBlur = 11 +export const HandleListFocus = 12 +export const HandlePointerDown = 14 +export const HandleWheel = 15 +export const HandleDoubleClick = 16 diff --git a/packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts b/packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts new file mode 100644 index 0000000..0dd2ddc --- /dev/null +++ b/packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts @@ -0,0 +1,4 @@ +export interface DragDataItem { + readonly data: string + readonly type: string +} diff --git a/packages/explorer-view/src/parts/DropHandler/DropHandler.ts b/packages/explorer-view/src/parts/DropHandler/DropHandler.ts new file mode 100644 index 0000000..c055948 --- /dev/null +++ b/packages/explorer-view/src/parts/DropHandler/DropHandler.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' + +export interface DropHandler { + (state: ExplorerState, fileHandles: DroppedArgs, files: readonly File[], paths: readonly string[], index: number): Promise +} diff --git a/packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts b/packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts new file mode 100644 index 0000000..9d94738 --- /dev/null +++ b/packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts @@ -0,0 +1 @@ +export const dropTargetFull = [-1] diff --git a/packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts b/packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts new file mode 100644 index 0000000..657b3a6 --- /dev/null +++ b/packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts @@ -0,0 +1,10 @@ +export const ensureUri = (item: string): string => { + if (item.startsWith('/')) { + return `file://` + item + } + return item +} + +export const ensureUris = (maybeUris: readonly string[]): readonly string[] => { + return maybeUris.map(ensureUri) +} diff --git a/packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts b/packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts new file mode 100644 index 0000000..0e4fc54 --- /dev/null +++ b/packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts @@ -0,0 +1 @@ +export const ENOENT = 'ENOENT' diff --git a/packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts b/packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts new file mode 100644 index 0000000..86d9987 --- /dev/null +++ b/packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts @@ -0,0 +1,38 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' + +export const expandAll = async (state: ExplorerState): Promise => { + const { focusedIndex, items, pathSeparator } = state + if (focusedIndex === -1) { + return state + } + const dirent = items[focusedIndex] + const { depth } = dirent + const newDirents = [...items] + // TODO fetch child dirents in parallel + for (const dirent of newDirents) { + if (dirent.depth === depth && dirent.type === DirentType.Directory) { + // TODO expand + // TODO avoid mutating state here + // @ts-ignore + dirent.type = DirentType.DirectoryExpanding + // TODO handle error + // TODO race condition + const childDirents = await GetChildDirents.getChildDirents(pathSeparator, dirent.path, dirent.depth) + const newIndex = newDirents.indexOf(dirent) + if (newIndex === -1) { + continue + } + newDirents.splice(newIndex + 1, 0, ...childDirents) + // TODO avoid mutating state here + // @ts-ignore + dirent.type = DirentType.DirectoryExpanded + // await expand(state, dirent.index) + } + } + return { + ...state, + items: newDirents, + } +} diff --git a/packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts b/packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts new file mode 100644 index 0000000..bf80a58 --- /dev/null +++ b/packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts @@ -0,0 +1,38 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as GetChildDirentsRecursively from '../GetChildDirentsRecursively/GetChildDirentsRecursively.ts' +import * as GetParentEndIndex from '../GetParentEndIndex/GetParentEndIndex.ts' + +export const expandRecursively = async (state: ExplorerState): Promise => { + const { focusedIndex, items, pathSeparator, root } = state + const dirent = + focusedIndex < 0 + ? { + depth: 0, + path: root, + type: DirentType.Directory, + } + : items[focusedIndex] + if (dirent.type !== DirentType.Directory && dirent.type !== DirentType.DirectoryExpanding && dirent.type !== DirentType.DirectoryExpanded) { + return state + } + // TODO race condition: what if folder is being collapse while it is recursively expanding? + // TODO race condition: what if folder is being deleted while it is recursively expanding? + // TODO race condition: what if a new file/folder is created while the folder is recursively expanding? + // @ts-ignore + const childDirents = await GetChildDirentsRecursively.getChildDirentsRecursively(dirent, pathSeparator) + const startIndex = focusedIndex + if (focusedIndex >= 0) { + const endIndex = GetParentEndIndex.getParentEndIndex(items, focusedIndex) + const newDirents = [...items.slice(0, startIndex), ...childDirents, ...items.slice(endIndex)] + return { + ...state, + items: newDirents, + } + } + const newDirents = childDirents.slice(1) + return { + ...state, + items: newDirents, + } +} diff --git a/packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts b/packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts new file mode 100644 index 0000000..dcf2e7e --- /dev/null +++ b/packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts @@ -0,0 +1,3 @@ +export const None = 0 +export const Expanded = 1 +export const Collapsed = 2 diff --git a/packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts b/packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts new file mode 100644 index 0000000..29966d2 --- /dev/null +++ b/packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts @@ -0,0 +1,7 @@ +export const None = 0 + +export const CreateFile = 1 + +export const CreateFolder = 2 + +export const Rename = 3 diff --git a/packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts b/packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts new file mode 100644 index 0000000..a888eba --- /dev/null +++ b/packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts @@ -0,0 +1,6 @@ +export class ExplorerError extends Error { + constructor(message: string) { + super(message) + this.name = 'ExplorerError' + } +} diff --git a/packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts b/packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts new file mode 100644 index 0000000..f239a38 --- /dev/null +++ b/packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts @@ -0,0 +1,10 @@ +export interface ExplorerItem { + readonly depth: number + readonly icon?: string + readonly name: string + readonly path: string + readonly posInSet?: number + readonly selected: boolean + readonly setSize?: number + readonly type: number +} diff --git a/packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts b/packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts new file mode 100644 index 0000000..060af6e --- /dev/null +++ b/packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts @@ -0,0 +1,65 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' +import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' +import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' + +export interface ExplorerState { + readonly assetDir: string + readonly compareSourceUri: string + readonly confirmDelete: boolean + readonly confirmPaste: boolean + readonly cutItems: readonly string[] + readonly decorations: readonly FileDecoration[] + readonly deltaY: number + readonly dropTargets: readonly number[] + readonly editingErrorMessage: string + readonly editingIcon: string + readonly editingIndex: number + readonly editingSelectionEnd: number + readonly editingSelectionStart: number + readonly editingType: number + readonly editingValue: string + readonly errorCode: string + readonly errorMessage: string + readonly errorMessageLeft: number + readonly errorMessageTop: number + readonly errorMessageWidth: number + readonly excluded: readonly any[] + readonly fileIconCache: FileIconCache + readonly finalDeltaY: number + readonly focus: number + readonly focused: boolean + readonly focusedIndex: number + readonly focusWord: string + readonly focusWordTimeout: number + readonly handleOffset: number + readonly hasError: boolean + readonly height: number + readonly hoverIndex: number + readonly icons: readonly string[] + readonly initial: boolean + readonly inputSource: number + readonly isPointerDown: boolean + readonly itemHeight: number + readonly items: readonly ExplorerItem[] + readonly maxIndent: number + readonly maxLineY: number + readonly minLineY: number + readonly parentUid: number + readonly pasteShouldMove: boolean + readonly pathSeparator: string + readonly platform: number + readonly pointerDownIndex: number + readonly root: string + readonly scrollBarActive: boolean + readonly scrollBarHeight: number + readonly sourceControlDecorations: boolean + readonly sourceControlIgnoredUris: readonly string[] + readonly uid: number + readonly useChevrons: boolean + readonly version: number + readonly visibleExplorerItems: readonly VisibleExplorerItem[] + readonly width: number + readonly x: number + readonly y: number +} diff --git a/packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts b/packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts new file mode 100644 index 0000000..38cbb41 --- /dev/null +++ b/packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts @@ -0,0 +1,81 @@ +import * as ViewletRegistry from '@lvce-editor//viewlet-registry' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetFileIcons from '../GetFileIcons/GetFileIcons.ts' +import * as GetExplorerMaxLineY from '../GetMaxLineY/GetMaxLineY.ts' +import * as GetVisibleExplorerItems from '../GetVisibleExplorerItems/GetVisibleExplorerItems.ts' + +export const { get, getCommandIds, registerCommands, set, wrapGetter } = ViewletRegistry.create() + +interface Fn { + (state: ExplorerState, ...args: T): ExplorerState | Promise +} + +export const wrapListItemCommand = (fn: Fn): ((id: number, ...args: T) => Promise) => { + const wrappedCommand = async (id: number, ...args: T): Promise => { + const { newState } = get(id) + const updatedState = await fn(newState, ...args) + if (newState === updatedState) { + return + } + const { + cutItems, + decorations, + dropTargets, + editingErrorMessage, + editingIcon, + editingIndex, + fileIconCache, + focusedIndex, + height, + itemHeight, + items, + minLineY, + sourceControlIgnoredUris, + useChevrons, + } = updatedState + const intermediate = get(id) + set(id, intermediate.oldState, updatedState) + const maxLineY = GetExplorerMaxLineY.getExplorerMaxLineY(minLineY, height, itemHeight, items.length) + if ( + items === intermediate.newState.items && + minLineY === intermediate.newState.minLineY && + height === intermediate.newState.height && + itemHeight === intermediate.newState.itemHeight && + editingIcon === intermediate.newState.editingIcon && + cutItems === intermediate.newState.cutItems && + editingErrorMessage === intermediate.newState.editingErrorMessage && + dropTargets === intermediate.newState.dropTargets && + fileIconCache === intermediate.newState.fileIconCache && + decorations === intermediate.newState.decorations + ) { + return + } + const visible = items.slice(minLineY, maxLineY) + const { icons, newFileIconCache } = await GetFileIcons.getFileIcons(visible, fileIconCache) + const visibleExplorerItems = GetVisibleExplorerItems.getVisibleExplorerItems( + items, + minLineY, + maxLineY, + focusedIndex, + editingIndex, + editingErrorMessage, + icons, + useChevrons, + dropTargets, + editingIcon, + cutItems, + sourceControlIgnoredUris, + decorations, + ) + const finalState: ExplorerState = { + ...updatedState, + fileIconCache: newFileIconCache, + icons, + maxLineY, + visibleExplorerItems, + } + const intermediate2 = get(id) + set(id, intermediate2.oldState, finalState) + } + return wrappedCommand +} diff --git a/packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts b/packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts new file mode 100644 index 0000000..17a6e94 --- /dev/null +++ b/packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts @@ -0,0 +1,140 @@ +import * as I18nString from '../I18NString/I18NString.ts' +import * as UiStrings from '../UiStrings/UiStrings.ts' + +export const newFile = (): string => { + return I18nString.i18nString(UiStrings.NewFile) +} + +export const newFolder = (): string => { + return I18nString.i18nString(UiStrings.NewFolder) +} + +export const openContainingFolder = (): string => { + return I18nString.i18nString(UiStrings.OpenContainingFolder) +} + +export const openInIntegratedTerminal = (): string => { + return I18nString.i18nString(UiStrings.OpenInIntegratedTerminal) +} + +export const cut = (): string => { + return I18nString.i18nString(UiStrings.Cut) +} + +export const copy = (): string => { + return I18nString.i18nString(UiStrings.Copy) +} + +export const paste = (): string => { + return I18nString.i18nString(UiStrings.Paste) +} + +export const pasteConfirmation = (): string => { + return I18nString.i18nString(UiStrings.PasteConfirmation) +} + +export const copyPath = (): string => { + return I18nString.i18nString(UiStrings.CopyPath) +} + +export const copyRelativePath = (): string => { + return I18nString.i18nString(UiStrings.CopyRelativePath) +} + +export const compareWithSelected = (): string => { + return I18nString.i18nString(UiStrings.CompareWithSelected) +} + +export const selectForCompare = (): string => { + return I18nString.i18nString(UiStrings.SelectForCompare) +} + +export const rename = (): string => { + return I18nString.i18nString(UiStrings.Rename) +} + +export const deleteItem = (): string => { + return I18nString.i18nString(UiStrings.Delete) +} + +export const deleteConfirmationSingle = (path: string): string => { + return I18nString.i18nString(UiStrings.DeleteConfirmationSingle, [path]) +} + +export const deleteConfirmationMultiple = (count: number): string => { + return I18nString.i18nString(UiStrings.DeleteConfirmationMultiple, [count.toString()]) +} + +export const refresh = (): string => { + return I18nString.i18nString(UiStrings.RefreshExplorer) +} + +export const removeFolderFromWorkspace = (): string => { + return I18nString.i18nString(UiStrings.RemoveFolderFromWorkspace) +} + +export const collapseAll = (): string => { + return I18nString.i18nString(UiStrings.CollapseAllFoldersInExplorer) +} + +export const explorer = (): string => { + return I18nString.i18nString(UiStrings.Explorer) +} + +export const filesExplorer = (): string => { + return I18nString.i18nString(UiStrings.FilesExplorer) +} + +export const youHaveNotYetOpenedAFolder = (): string => { + return I18nString.i18nString(UiStrings.YouHaveNotYetOpenedAFolder) +} + +export const openFolder = (): string => { + return I18nString.i18nString(UiStrings.OpenFolder) +} + +export const openAnotherFolder = (): string => { + return I18nString.i18nString(UiStrings.OpenAnotherFolder) +} + +export const noFolderOpen = (): string => { + return I18nString.i18nString(UiStrings.NoFolderOpen) +} + +export const fileOrFolderNameMustBeProvided = (): string => { + return I18nString.i18nString(UiStrings.FileOrFolderNameMustBeProvider) +} + +export const fileCannotStartWithSlash = (): string => { + return I18nString.i18nString(UiStrings.FileNameCannotStartWithSlash) +} + +export const fileCannotStartWithDot = (): string => { + return I18nString.i18nString(UiStrings.FileCannotStartWithDot) +} + +export const fileCannotStartWithBackSlash = (): string => { + return I18nString.i18nString(UiStrings.FileCannotStartWithBackSlash) +} + +export const typeAFileName = (): string => { + return I18nString.i18nString(UiStrings.TypeAFileName) +} + +export const fileNameCannotStartWithSlash = (): string => { + return I18nString.i18nString(UiStrings.FileNameCannotStartWithSlash) +} + +export const fileOrFolderAlreadyExists = (name: string): string => { + return I18nString.i18nString(UiStrings.FileOrFolderAlreadyExists, { + PH1: name, + }) +} + +export const theNameIsNotValid = (): string => { + return I18nString.i18nString(UiStrings.TheNameIsNotValid) +} + +export const leadingOrTrailingWhitespaceDetected = (): string => { + return I18nString.i18nString(UiStrings.LeadingOrTrailingWhitespaceDetected) +} diff --git a/packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts b/packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts new file mode 100644 index 0000000..8b96bf3 --- /dev/null +++ b/packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts @@ -0,0 +1,4 @@ +export interface FileDecoration { + readonly decoration: string + readonly uri: string +} diff --git a/packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts b/packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts new file mode 100644 index 0000000..0af9114 --- /dev/null +++ b/packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts @@ -0,0 +1,3 @@ +export interface FileIconCache { + readonly [key: string]: string +} diff --git a/packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts b/packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts new file mode 100644 index 0000000..c90f913 --- /dev/null +++ b/packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts @@ -0,0 +1,6 @@ +import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' + +export interface FileIconsResult { + readonly icons: readonly string[] + readonly newFileIconCache: FileIconCache +} diff --git a/packages/explorer-view/src/parts/FileOperation/FileOperation.ts b/packages/explorer-view/src/parts/FileOperation/FileOperation.ts new file mode 100644 index 0000000..8af40f1 --- /dev/null +++ b/packages/explorer-view/src/parts/FileOperation/FileOperation.ts @@ -0,0 +1,35 @@ +import type { Copy, CreateFile, CreateFolder, Remove, Rename } from '../FileOperationType/FileOperationType.ts' + +export interface FileOperationBase { + readonly type: number +} + +export interface FileOperationCreateFile extends FileOperationBase { + readonly path: string + readonly text: string + readonly type: typeof CreateFile +} + +export interface FileOperationCreateFolder extends FileOperationBase { + readonly path: string + readonly type: typeof CreateFolder +} + +export interface FileOperationCopy extends FileOperationBase { + readonly from: string + readonly path: string + readonly type: typeof Copy +} + +export interface FileOperationRename extends FileOperationBase { + readonly from: string + readonly path: string + readonly type: typeof Rename +} + +export interface FileOperationRemove extends FileOperationBase { + readonly path: string + readonly type: typeof Remove +} + +export type FileOperation = FileOperationCopy | FileOperationCreateFile | FileOperationCreateFolder | FileOperationRename | FileOperationRemove diff --git a/packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts b/packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts new file mode 100644 index 0000000..5554459 --- /dev/null +++ b/packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts @@ -0,0 +1,5 @@ +export const CreateFolder = 1 +export const CreateFile = 2 +export const Copy = 3 +export const Rename = 4 +export const Remove = 5 diff --git a/packages/explorer-view/src/parts/FileSystem/FileSystem.ts b/packages/explorer-view/src/parts/FileSystem/FileSystem.ts new file mode 100644 index 0000000..f968218 --- /dev/null +++ b/packages/explorer-view/src/parts/FileSystem/FileSystem.ts @@ -0,0 +1,41 @@ +import * as FileSystemWorker from '../FileSystemWorker/FileSystemWorker.ts' + +export const remove = async (dirent: string): Promise => { + return FileSystemWorker.invoke('FileSystem.remove', dirent) +} + +export const readDirWithFileTypes = async (uri: string): Promise => { + return FileSystemWorker.invoke('FileSystem.readDirWithFileTypes', uri) +} + +export const getPathSeparator = async (root: string): Promise => { + return FileSystemWorker.invoke('FileSystem.getPathSeparator', root) +} + +export const getRealPath = async (path: string): Promise => { + return FileSystemWorker.invoke('FileSystem.getRealPath', path) +} + +export const stat = async (dirent: string): Promise => { + return FileSystemWorker.invoke('FileSystem.stat', dirent) +} + +export const createFile = async (uri: string): Promise => { + return FileSystemWorker.invoke('FileSystem.writeFile', uri, '') +} + +export const writeFile = async (uri: string, content: string): Promise => { + return FileSystemWorker.invoke('FileSystem.writeFile', uri, content) +} + +export const mkdir = async (uri: string): Promise => { + return FileSystemWorker.invoke('FileSystem.mkdir', uri) +} + +export const rename = async (oldUri: string, newUri: string): Promise => { + return FileSystemWorker.invoke('FileSystem.rename', oldUri, newUri) +} + +export const copy = async (oldUri: string, newUri: string): Promise => { + return FileSystemWorker.invoke('FileSystem.copy', oldUri, newUri) +} diff --git a/packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts b/packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts new file mode 100644 index 0000000..81608cc --- /dev/null +++ b/packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts @@ -0,0 +1,8 @@ +import { FileSystemWorker, RendererWorker } from '@lvce-editor/rpc-registry' + +// TODO use direct connection +export const invoke = async (method: string, ...params: readonly unknown[]): Promise => { + return RendererWorker.invoke(method, ...params) +} + +export const { set } = FileSystemWorker diff --git a/packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts b/packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts new file mode 100644 index 0000000..8886653 --- /dev/null +++ b/packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts @@ -0,0 +1,25 @@ +export const filterByFocusWord = (items: readonly string[], focusedIndex: number, focusWord: string): number => { + if (items.length === 0) { + return -1 + } + + const matches: number[] = [] + for (let i = 0; i < items.length; i++) { + if (items[i].toLowerCase().includes(focusWord)) { + matches.push(i) + } + } + + if (matches.length === 0) { + return -1 + } + + // Find the next match after the current focus + let nextIndex = matches.findIndex((index) => index > focusedIndex) + if (nextIndex === -1) { + // If no match found after current focus, wrap around to the first match + nextIndex = 0 + } + + return matches[nextIndex] +} diff --git a/packages/explorer-view/src/parts/Focus/Focus.ts b/packages/explorer-view/src/parts/Focus/Focus.ts new file mode 100644 index 0000000..65e6d14 --- /dev/null +++ b/packages/explorer-view/src/parts/Focus/Focus.ts @@ -0,0 +1,12 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusId from '../FocusId/FocusId.ts' + +export const focus = (state: ExplorerState): ExplorerState => { + if (state.focus) { + return state + } + return { + ...state, + focus: FocusId.List, + } +} diff --git a/packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts b/packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts new file mode 100644 index 0000000..3159108 --- /dev/null +++ b/packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts @@ -0,0 +1,10 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { focusIndex } from '../FocusIndex/FocusIndex.ts' + +export const focusFirst = (state: ExplorerState): ExplorerState => { + const { focusedIndex, items } = state + if (items.length === 0 || focusedIndex === 0) { + return state + } + return focusIndex(state, 0) +} diff --git a/packages/explorer-view/src/parts/FocusId/FocusId.ts b/packages/explorer-view/src/parts/FocusId/FocusId.ts new file mode 100644 index 0000000..a291d8e --- /dev/null +++ b/packages/explorer-view/src/parts/FocusId/FocusId.ts @@ -0,0 +1,3 @@ +export const None = 0 +export const List = 1 +export const Input = 2 diff --git a/packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts b/packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts new file mode 100644 index 0000000..f276402 --- /dev/null +++ b/packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts @@ -0,0 +1,45 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const focusIndex = (state: ExplorerState, index: number): ExplorerState => { + const { items, maxLineY, minLineY } = state + const newItems = items.map((item, i) => ({ + ...item, + selected: i === index ? false : false, + })) + if (index < minLineY) { + if (index < 0) { + return { + ...state, + focused: true, + focusedIndex: index, + items: newItems, + } + } + const diff = maxLineY - minLineY + return { + ...state, + focused: true, + focusedIndex: index, + items: newItems, + maxLineY: index + diff, + minLineY: index, + } + } + if (index >= maxLineY) { + const diff = maxLineY - minLineY + return { + ...state, + focused: true, + focusedIndex: index, + items: newItems, + maxLineY: index + 1, + minLineY: index + 1 - diff, + } + } + return { + ...state, + focused: true, + focusedIndex: index, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/FocusKey/FocusKey.ts b/packages/explorer-view/src/parts/FocusKey/FocusKey.ts new file mode 100644 index 0000000..a8b4139 --- /dev/null +++ b/packages/explorer-view/src/parts/FocusKey/FocusKey.ts @@ -0,0 +1,3 @@ +import { WhenExpression } from '@lvce-editor/constants' + +export const ExplorerEditBox = WhenExpression.FocusExplorerEditBox diff --git a/packages/explorer-view/src/parts/FocusLast/FocusLast.ts b/packages/explorer-view/src/parts/FocusLast/FocusLast.ts new file mode 100644 index 0000000..b5ce9ae --- /dev/null +++ b/packages/explorer-view/src/parts/FocusLast/FocusLast.ts @@ -0,0 +1,12 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as Arrays from '../Arrays/Arrays.ts' +import { focusIndex } from '../FocusIndex/FocusIndex.ts' + +export const focusLast = (state: ExplorerState): ExplorerState => { + const { focusedIndex, items } = state + const lastIndex = Arrays.lastIndex(items) + if (items.length === 0 || focusedIndex === lastIndex) { + return state + } + return focusIndex(state, lastIndex) +} diff --git a/packages/explorer-view/src/parts/FocusNext/FocusNext.ts b/packages/explorer-view/src/parts/FocusNext/FocusNext.ts new file mode 100644 index 0000000..3116321 --- /dev/null +++ b/packages/explorer-view/src/parts/FocusNext/FocusNext.ts @@ -0,0 +1,11 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as Arrays from '../Arrays/Arrays.ts' +import { focusIndex } from '../FocusIndex/FocusIndex.ts' + +export const focusNext = (state: ExplorerState): ExplorerState => { + const { focusedIndex, items } = state + if (focusedIndex === Arrays.lastIndex(items)) { + return state + } + return focusIndex(state, focusedIndex + 1) +} diff --git a/packages/explorer-view/src/parts/FocusNone/FocusNone.ts b/packages/explorer-view/src/parts/FocusNone/FocusNone.ts new file mode 100644 index 0000000..9dbdd6e --- /dev/null +++ b/packages/explorer-view/src/parts/FocusNone/FocusNone.ts @@ -0,0 +1,10 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { focusIndex } from '../FocusIndex/FocusIndex.ts' + +export const focusNone = (state: ExplorerState): ExplorerState => { + const { focusedIndex } = state + if (focusedIndex === -1) { + return state + } + return focusIndex(state, -1) +} diff --git a/packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts b/packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts new file mode 100644 index 0000000..af9e01a --- /dev/null +++ b/packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts @@ -0,0 +1,11 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusIndex from '../FocusIndex/FocusIndex.ts' +import * as GetParentStartIndex from '../GetParentStartIndex/GetParentStartIndex.ts' + +export const focusParentFolder = (state: ExplorerState): ExplorerState => { + const parentStartIndex = GetParentStartIndex.getParentStartIndex(state.items, state.focusedIndex) + if (parentStartIndex === -1) { + return state + } + return FocusIndex.focusIndex(state, parentStartIndex) +} diff --git a/packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts b/packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts new file mode 100644 index 0000000..cdf070a --- /dev/null +++ b/packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts @@ -0,0 +1,18 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as Arrays from '../Arrays/Arrays.ts' +import { focusIndex } from '../FocusIndex/FocusIndex.ts' + +export const focusPrevious = (state: ExplorerState): ExplorerState => { + const { focusedIndex, items } = state + switch (focusedIndex) { + case -1: + if (items.length === 0) { + return state + } + return focusIndex(state, Arrays.lastIndex(items)) + case 0: + return state + default: + return focusIndex(state, focusedIndex - 1) + } +} diff --git a/packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts b/packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts new file mode 100644 index 0000000..ab26d33 --- /dev/null +++ b/packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts @@ -0,0 +1,42 @@ +import * as Path from '../Path/Path.ts' + +export const generateUniqueName = (baseName: string, existingPaths: readonly string[], root: string): string => { + // Handle files with extensions + const lastDotIndex = baseName.lastIndexOf('.') + const hasExtension = lastDotIndex !== -1 && lastDotIndex !== 0 && lastDotIndex !== baseName.length - 1 + + let nameWithoutExtension: string + let extension: string + + if (hasExtension) { + nameWithoutExtension = baseName.slice(0, lastDotIndex) + extension = baseName.slice(lastDotIndex) + } else { + nameWithoutExtension = baseName + extension = '' + } + + // Check if original name exists + const originalPath = Path.join2(root, baseName) + if (!existingPaths.includes(originalPath)) { + return baseName + } + + // Try "original copy" + const copyName = `${nameWithoutExtension} copy${extension}` + const copyPath = Path.join2(root, copyName) + if (!existingPaths.includes(copyPath)) { + return copyName + } + + // Try "original copy 1", "original copy 2", etc. + let counter = 1 + while (true) { + const numberedCopyName = `${nameWithoutExtension} copy ${counter}${extension}` + const numberedCopyPath = Path.join2(root, numberedCopyName) + if (!existingPaths.includes(numberedCopyPath)) { + return numberedCopyName + } + counter++ + } +} diff --git a/packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts b/packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts new file mode 100644 index 0000000..32bd161 --- /dev/null +++ b/packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts @@ -0,0 +1,19 @@ +import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as GetIconVirtualDom from '../GetIconVirtualDom/GetIconVirtualDom.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const getActionButtonVirtualDom = (action: ViewletAction): readonly VirtualDomNode[] => { + const { icon, id, name } = action + return [ + { + childCount: 1, + className: ClassNames.IconButton, + name, + title: id, + type: VirtualDomElements.Button, + }, + GetIconVirtualDom.getIconVirtualDom(icon || ''), + ] +} diff --git a/packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts b/packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts new file mode 100644 index 0000000..51464aa --- /dev/null +++ b/packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts @@ -0,0 +1,13 @@ +import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ActionType from '../ActionType/ActionType.ts' +import * as GetActionButtonVirtualDom from '../GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts' + +export const getActionVirtualDom = (action: ViewletAction): readonly VirtualDomNode[] => { + switch (action.type) { + case ActionType.Button: + return GetActionButtonVirtualDom.getActionButtonVirtualDom(action) + default: + return [] + } +} diff --git a/packages/explorer-view/src/parts/GetActions/GetActions.ts b/packages/explorer-view/src/parts/GetActions/GetActions.ts new file mode 100644 index 0000000..c05294b --- /dev/null +++ b/packages/explorer-view/src/parts/GetActions/GetActions.ts @@ -0,0 +1,41 @@ +import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' +import * as ActionType from '../ActionType/ActionType.ts' +import * as ViewletExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' +import * as InputName from '../InputName/InputName.ts' +import * as MaskIcon from '../MaskIcon/MaskIcon.ts' + +export const getActions = (root: string): readonly ViewletAction[] => { + if (!root) { + return [] + } + return [ + { + command: 'newFile', + icon: MaskIcon.NewFile, + id: ViewletExplorerStrings.newFile(), + name: InputName.NewFile, + type: ActionType.Button, + }, + { + command: 'newFolder', + icon: MaskIcon.NewFolder, + id: ViewletExplorerStrings.newFolder(), + name: InputName.NewFolder, + type: ActionType.Button, + }, + { + command: 'refresh', + icon: MaskIcon.Refresh, + id: ViewletExplorerStrings.refresh(), + name: InputName.Refresh, + type: ActionType.Button, + }, + { + command: 'collapseAll', + icon: MaskIcon.CollapseAll, + id: ViewletExplorerStrings.collapseAll(), + name: InputName.CollapseAll, + type: ActionType.Button, + }, + ] +} diff --git a/packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts b/packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts new file mode 100644 index 0000000..098bbd4 --- /dev/null +++ b/packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts @@ -0,0 +1,20 @@ +import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as AriaRoles from '../AriaRoles/AriaRoles.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' +import * as GetActionVirtualDom from '../GetActionVirtualDom/GetActionVirtualDom.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const getActionsVirtualDom = (actions: readonly ViewletAction[]): readonly VirtualDomNode[] => { + return [ + { + childCount: actions.length, + className: ClassNames.Actions, + onClick: DomEventListenerFunctions.HandleButtonClick, + role: AriaRoles.ToolBar, + type: VirtualDomElements.Div, + }, + ...actions.flatMap(GetActionVirtualDom.getActionVirtualDom), + ] +} diff --git a/packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts b/packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts new file mode 100644 index 0000000..c671a8b --- /dev/null +++ b/packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts @@ -0,0 +1,17 @@ +import * as ChevronType from '../ChevronType/ChevronType.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const getChevronType = (type: number, useChevrons: boolean): number => { + if (!useChevrons) { + return ChevronType.None + } + switch (type) { + case DirentType.Directory: + return ChevronType.Right + case DirentType.DirectoryExpanded: + case DirentType.DirectoryExpanding: + return ChevronType.Down + default: + return ChevronType.None + } +} diff --git a/packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts b/packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts new file mode 100644 index 0000000..6cd51e7 --- /dev/null +++ b/packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts @@ -0,0 +1,13 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ChevronDownVirtualDom from '../ChevronDownVirtualDom/ChevronDownVirtualDom.ts' +import * as ChevronRightVirtualDom from '../ChevronRightVirtualDom/ChevronRightVirtualDom.ts' + +const chevronDomNodes: readonly (readonly VirtualDomNode[])[] = [ + [], + [ChevronRightVirtualDom.chevronRightVirtualDom], + [ChevronDownVirtualDom.chevronDownVirtualDom], +] + +export const getChevronVirtualDom = (chevronType: number): readonly VirtualDomNode[] => { + return chevronDomNodes[chevronType] +} diff --git a/packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts b/packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts new file mode 100644 index 0000000..62a0239 --- /dev/null +++ b/packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts @@ -0,0 +1,22 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as Assert from '../Assert/Assert.ts' +import { getChildDirentsRaw } from '../GetChildDirentsRaw/GetChildDirentsRaw.ts' +import * as ToDisplayDirents from '../ToDisplayDirents/ToDisplayDirents.ts' + +export const getChildDirents = async ( + pathSeparator: string, + parentDirentPath: string, + parentDirentDepth: number, + excluded: readonly string[] = [], +): Promise => { + Assert.string(pathSeparator) + // TODO use event/actor based code instead, this is impossible to cancel right now + // also cancel updating when opening new folder + // const dispose = state => state.pendingRequests.forEach(cancelRequest) + // TODO should use FileSystem directly in this case because it is globally available anyway + // and more typesafe than Command.execute + // and more performant + const rawDirents = await getChildDirentsRaw(parentDirentPath) + const displayDirents = ToDisplayDirents.toDisplayDirents(pathSeparator, rawDirents, parentDirentPath, parentDirentDepth, excluded) + return displayDirents +} diff --git a/packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts b/packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts new file mode 100644 index 0000000..2248376 --- /dev/null +++ b/packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts @@ -0,0 +1,14 @@ +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as Assert from '../Assert/Assert.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' +import { hasSymbolicLinks } from '../HasSymbolicLink/HasSymbolicLink.ts' +import * as ResolveSymbolicLinks from '../ResolveSymbolicLinks/ResolveSymbolicLinks.ts' + +export const getChildDirentsRaw = async (uri: string): Promise => { + const rawDirents = await FileSystem.readDirWithFileTypes(uri) + Assert.array(rawDirents) + if (hasSymbolicLinks(rawDirents)) { + return ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + } + return rawDirents +} diff --git a/packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts b/packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts new file mode 100644 index 0000000..8df1ee1 --- /dev/null +++ b/packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts @@ -0,0 +1,24 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' +import * as MakeExpanded from '../MakeExpanded/MakeExpanded.ts' + +// TODO this is very inefficient +export const getChildDirentsRecursively = async (dirent: ExplorerItem, pathSeparator: string): Promise => { + switch (dirent.type) { + case DirentType.Directory: + case DirentType.DirectoryExpanded: + case DirentType.DirectoryExpanding: + const childDirents = await GetChildDirents.getChildDirents(pathSeparator, dirent.path, dirent.depth) + const all = [MakeExpanded.makeExpanded(dirent)] + for (const childDirent of childDirents) { + const childAll = await getChildDirentsRecursively(childDirent, pathSeparator) + all.push(...childAll) + } + return all + case DirentType.File: + return [dirent] + default: + return [] + } +} diff --git a/packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts b/packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts new file mode 100644 index 0000000..d89f4f0 --- /dev/null +++ b/packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts @@ -0,0 +1,8 @@ +import * as Arrays from '../Arrays/Arrays.ts' + +export const getChildHandles = async (fileHandle: FileSystemDirectoryHandle): Promise => { + // @ts-ignore + const values = fileHandle.values() + const children = await Arrays.fromAsync(values) + return children +} diff --git a/packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts b/packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts new file mode 100644 index 0000000..7393a61 --- /dev/null +++ b/packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts @@ -0,0 +1,49 @@ +import type { ClickHandler } from '../ClickHandler/ClickHandler.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import { ExplorerError } from '../ExplorerError/ExplorerError.ts' +import * as HandleClickDirectory from '../HandleClickDirectory/HandleClickDirectory.ts' +import * as HandleClickDirectoryExpanded from '../HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' +import * as HandleClickDirectoryExpanding from '../HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts' +import * as HandleClickFile from '../HandleClickFile/HandleClickFile.ts' +import * as HandleClickSymlink from '../HandleClickSymlink/HandleClickSymlink.ts' +// TODO viewlet should only have create and refresh functions +// every thing else can be in a separate module .lazy.js +// and .ipc.js + +// viewlet: creating | refreshing | done | disposed +// TODO recycle viewlets (maybe) + +// TODO instead of root string, there should be a root dirent + +// TODO rename dirents to items, then can use virtual list component directly + +// TODO support multiselection and removing multiple dirents + +// TODO use posInSet and setSize properties to compute more effectively + +// TODO much shared logic with newFolder + +export const getClickFn = (direntType: number): ClickHandler => { + switch (direntType) { + case DirentType.Directory: + case DirentType.SymLinkFolder: + return HandleClickDirectory.handleClickDirectory + case DirentType.DirectoryExpanded: + return HandleClickDirectoryExpanded.handleClickDirectoryExpanded + case DirentType.DirectoryExpanding: + return HandleClickDirectoryExpanding.handleClickDirectoryExpanding + case DirentType.File: + case DirentType.SymLinkFile: + return HandleClickFile.handleClickFile + case DirentType.Symlink: + return HandleClickSymlink.handleClickSymLink + case DirentType.CharacterDevice: + throw new ExplorerError('Cannot open character device files') + case DirentType.BlockDevice: + throw new ExplorerError('Cannot open block device files') + case DirentType.Socket: + throw new ExplorerError('Cannot open socket files') + default: + throw new ExplorerError(`unsupported dirent type ${direntType}`) + } +} diff --git a/packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts b/packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts new file mode 100644 index 0000000..b21a5cf --- /dev/null +++ b/packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts @@ -0,0 +1,10 @@ +export const getContainingFolder = (root: string, dirents: readonly any[], focusedIndex: number, pathSeparator: string): string => { + if (focusedIndex < 0) { + return root + } + const dirent = dirents[focusedIndex] + const direntPath = dirent.path + const direntParentPath = direntPath.slice(0, -(dirent.name.length + 1)) + const path = `${direntParentPath}` + return path +} diff --git a/packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts b/packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts new file mode 100644 index 0000000..29bd9ed --- /dev/null +++ b/packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts @@ -0,0 +1,13 @@ +import type { ContextMenuHandler } from '../ContextMenuHandler/ContextMenuHandler.ts' +import * as ViewletExplorerHandleContextMenuKeyBoard from '../HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts' +import * as ViewletExplorerHandleContextMenuMouseAt from '../HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts' +import * as MouseEventType from '../MouseEventType/MouseEventType.ts' + +export const getContextMenuHandler = (button: number): ContextMenuHandler => { + switch (button) { + case MouseEventType.Keyboard: + return ViewletExplorerHandleContextMenuKeyBoard.handleContextMenuKeyboard + default: + return ViewletExplorerHandleContextMenuMouseAt.handleContextMenuMouseAt + } +} diff --git a/packages/explorer-view/src/parts/GetCss/GetCss.ts b/packages/explorer-view/src/parts/GetCss/GetCss.ts new file mode 100644 index 0000000..2caddb5 --- /dev/null +++ b/packages/explorer-view/src/parts/GetCss/GetCss.ts @@ -0,0 +1,27 @@ +import { getIndentRule } from '../GetIndentRule/GetIndentRule.ts' + +export const getCss = ( + scrollBarHeight: number, + scrollBarTop: number, + uniqueIndents: readonly number[], + errorMessageLeft: number, + errorMessageTop: number, + errorMessageWidth: number, +): string => { + const rules = [ + `.Explorer { + --ScrollBarThumbHeight: ${scrollBarHeight}px; + --ScrollBarThumbTop: ${scrollBarTop}px; + --ErrorMessageTop: ${errorMessageTop}px; + --ErrorMessageLeft: ${errorMessageLeft}px; + --ErrorMessageWidth: ${errorMessageWidth}px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +}`, + ...uniqueIndents.map(getIndentRule), + ] + const css = rules.join('\n') + return css +} diff --git a/packages/explorer-view/src/parts/GetDragData/GetDragData.ts b/packages/explorer-view/src/parts/GetDragData/GetDragData.ts new file mode 100644 index 0000000..cbfcef7 --- /dev/null +++ b/packages/explorer-view/src/parts/GetDragData/GetDragData.ts @@ -0,0 +1,36 @@ +import { getDragLabel } from '../GetDragLabel/GetDragLabel.ts' + +const toUri = (path: string): string => { + if (path.startsWith('file://')) { + return path + } + return 'file://' + path +} + +export interface DragInfoItem { + readonly data: string + readonly type: string +} + +export interface IDragInfoNew { + readonly items: readonly DragInfoItem[] + readonly label?: string +} + +export const getDragData = (urls: readonly string[]): IDragInfoNew => { + const data = urls.map(toUri).join('\n') + const dragData: readonly DragInfoItem[] = [ + { + data, + type: 'text/uri-list', + }, + { + data, + type: 'text/plain', + }, + ] + return { + items: dragData, + label: getDragLabel(urls), + } +} diff --git a/packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts b/packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts new file mode 100644 index 0000000..abd961b --- /dev/null +++ b/packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts @@ -0,0 +1,8 @@ +import { getBaseName } from '../Path/Path.ts' + +export const getDragLabel = (urls: readonly string[]): string => { + if (urls.length === 1) { + return getBaseName('/', urls[0]) + } + return `${urls.length}` +} diff --git a/packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts b/packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts new file mode 100644 index 0000000..7d93aec --- /dev/null +++ b/packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts @@ -0,0 +1,12 @@ +import type { DropHandler } from '../DropHandler/DropHandler.ts' +import * as HandleDropIndex from '../HandleDropIndex/HandleDropIndex.ts' +import * as HandleDropRoot from '../HandleDropRoot/HandleDropRoot.ts' + +export const getDropHandler = (index: number): DropHandler => { + switch (index) { + case -1: + return HandleDropRoot.handleDropRoot + default: + return HandleDropIndex.handleDropIndex + } +} diff --git a/packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts b/packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts new file mode 100644 index 0000000..4902674 --- /dev/null +++ b/packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts @@ -0,0 +1,21 @@ +import { RendererWorker as Rpc } from '@lvce-editor/rpc-registry' +import * as DirentType from '../DirentType/DirentType.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' + +export const getEditingIcon = async (editingType: number, value: string, direntType?: number): Promise => { + if (editingType === ExplorerEditingType.CreateFile) { + return Rpc.invoke('IconTheme.getFileIcon', { name: value }) + } + if (editingType === ExplorerEditingType.Rename) { + if (direntType === DirentType.File || direntType === DirentType.EditingFile) { + return Rpc.invoke('IconTheme.getFileIcon', { name: value }) + } + if (direntType === DirentType.Directory || direntType === DirentType.EditingFolder || direntType === DirentType.EditingDirectoryExpanded) { + return Rpc.invoke('IconTheme.getFolderIcon', { name: value }) + } + } + if (editingType === ExplorerEditingType.CreateFolder) { + return Rpc.invoke('IconTheme.getFolderIcon', { name: value }) + } + return '' +} diff --git a/packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts b/packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts new file mode 100644 index 0000000..f5bd518 --- /dev/null +++ b/packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts @@ -0,0 +1,8 @@ +import { DELTA_EDITING } from '../DeltaEditing/DeltaEditing.ts' + +export const getEditingType = (direntType: number): number => { + if (direntType < DELTA_EDITING) { + return direntType + DELTA_EDITING + } + return direntType +} diff --git a/packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts b/packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts new file mode 100644 index 0000000..220d232 --- /dev/null +++ b/packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts @@ -0,0 +1,6 @@ +export const getErrorCode = (error: unknown): string => { + if (error && typeof error === 'object' && 'code' in error && typeof error.code === 'string') { + return error.code + } + return '' +} diff --git a/packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts b/packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts new file mode 100644 index 0000000..5dbaf15 --- /dev/null +++ b/packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts @@ -0,0 +1,9 @@ +export const getErrorMessage = (error: unknown): string => { + if (error instanceof Error) { + return error.message + } + if (typeof error === 'string') { + return error + } + return 'Unknown error' +} diff --git a/packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts b/packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts new file mode 100644 index 0000000..88382ff --- /dev/null +++ b/packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts @@ -0,0 +1,19 @@ +import { type VirtualDomNode, text } from '@lvce-editor/virtual-dom-worker' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const getErrorMessageDom = (errorMessage: string): readonly VirtualDomNode[] => { + if (!errorMessage) { + return [] + } + + return [ + { + childCount: 1, + className: MergeClassNames.mergeClassNames(ClassNames.ExplorerErrorMessage), + type: VirtualDomElements.Div, + }, + text(errorMessage), + ] +} diff --git a/packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts b/packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts new file mode 100644 index 0000000..4c6caa5 --- /dev/null +++ b/packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts @@ -0,0 +1,25 @@ +export interface Position { + readonly errorMessageWidth: number + readonly left: number + readonly top: number +} + +export const getErrorMessagePosition = ( + itemHeight: number, + focusedIndex: number, + minLineY: number, + depth: number, + indent: number, + fileIconWidth: number, + padding: number, + width: number, +): Position => { + const top = itemHeight * (focusedIndex - minLineY + 1) + const left = depth * indent + fileIconWidth + padding + const errorMessageWidth = width - left + return { + errorMessageWidth, + left, + top, + } +} diff --git a/packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts b/packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts new file mode 100644 index 0000000..5da0cca --- /dev/null +++ b/packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts @@ -0,0 +1,10 @@ +export const getExcluded = (): string[] => { + const excludedObject = {} + const excluded = [] + for (const [key, value] of Object.entries(excludedObject)) { + if (value) { + excluded.push(key) + } + } + return excluded +} diff --git a/packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts b/packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts new file mode 100644 index 0000000..c6b7e90 --- /dev/null +++ b/packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import { isExpanded } from '../IsExpanded/IsExpanded.ts' + +export const getExpandedDirents = (items: readonly ExplorerItem[]): readonly ExplorerItem[] => { + return items.filter(isExpanded) +} diff --git a/packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts b/packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts new file mode 100644 index 0000000..f29acd1 --- /dev/null +++ b/packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts @@ -0,0 +1,14 @@ +import * as DirentType from '../DirentType/DirentType.ts' +import * as ExpandedType from '../ExpandedType/ExpandedType.ts' + +export const getExpandedType = (type: number): number => { + switch (type) { + case DirentType.Directory: + return ExpandedType.Collapsed + case DirentType.DirectoryExpanded: + case DirentType.DirectoryExpanding: + return ExpandedType.Expanded + default: + return ExpandedType.None + } +} diff --git a/packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts b/packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts new file mode 100644 index 0000000..ca4f967 --- /dev/null +++ b/packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts @@ -0,0 +1,43 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' +import * as AriaRoles from '../AriaRoles/AriaRoles.ts' +import * as GetChevronVirtualDom from '../GetChevronVirtualDom/GetChevronVirtualDom.ts' +import * as GetFileIconVirtualDom from '../GetFileIconVirtualDom/GetFileIconVirtualDom.ts' +import * as GetInputDom from '../GetInputDom/GetInputDom.ts' +import * as GetLabelDom from '../GetLabelDom/GetLabelDom.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +const getTitle = (path: string): string => { + if (path.startsWith('file://')) { + return path.slice('file://'.length) + } + return path +} + +export const getExplorerItemVirtualDom = (item: VisibleExplorerItem): readonly VirtualDomNode[] => { + const { ariaExpanded, chevron, className, depth, hasEditingError, icon, id, index, isCut, isEditing, isIgnored, name, path, posInSet, setSize } = + item + const chevronDom = GetChevronVirtualDom.getChevronVirtualDom(chevron) + return [ + { + ariaDescription: '', + ariaExpanded, + ariaLabel: name, + ariaLevel: depth, + ariaPosInSet: posInSet, + ariaSetSize: setSize, + childCount: 2 + chevronDom.length, + className, + 'data-index': index, + draggable: true, + id, + role: AriaRoles.TreeItem, + title: getTitle(path), + type: VirtualDomElements.Div, + }, + ...chevronDom, + GetFileIconVirtualDom.getFileIconVirtualDom(icon), + ...GetInputDom.getInputDom(isEditing, hasEditingError), + ...GetLabelDom.getLabelDom(isEditing, name, isCut || isIgnored), + ] +} diff --git a/packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts b/packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts new file mode 100644 index 0000000..0e368fd --- /dev/null +++ b/packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts @@ -0,0 +1,65 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' +import * as AriaRoles from '../AriaRoles/AriaRoles.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as GetErrorMessageDom from '../GetErrorMessageDom/GetErrorMessageDom.ts' +import * as GetExplorerWelcomeVirtualDom from '../GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts' +import * as GetListItemsVirtualDom from '../GetListItemsVirtualDom/GetListItemsVirtualDom.ts' +import * as GetLoadErrorVirtualDom from '../GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts' +import * as GetScrollBarSize from '../GetScrollBarSize/GetScrollBarSize.ts' +import * as GetScrollBarVirtualDom from '../GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +const getParentNode = (childCount: number): VirtualDomNode => { + return { + childCount, + className: MergeClassNames.mergeClassNames(ClassNames.Viewlet, ClassNames.Explorer), + role: AriaRoles.None, + type: VirtualDomElements.Div, + } +} + +const getChildCount = (scrollBarDomLength: number, errorDomLength: number): number => { + let childCount = 1 + if (scrollBarDomLength > 0) { + childCount++ + } + if (errorDomLength > 0) { + childCount++ + } + return childCount +} + +export const getExplorerVirtualDom = ( + visibleItems: readonly VisibleExplorerItem[], + focusedIndex: number, + root: string, + isWide: boolean, + focused: boolean, + dropTargets: readonly number[], + height: number, + contentHeight: number, + editingErrorMessage: string, + loadErrorMessage: string, + showOpenAnotherFolderButton: boolean, +): readonly VirtualDomNode[] => { + if (!root) { + return GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(isWide, dropTargets) + } + if (loadErrorMessage) { + return GetLoadErrorVirtualDom.getLoadErrorVirtualDom(loadErrorMessage, isWide, showOpenAnotherFolderButton) + } + const scrollBarHeight = GetScrollBarSize.getScrollBarSize(height, contentHeight, 20) + const scrollBarDom = GetScrollBarVirtualDom.getScrollBarVirtualDom(scrollBarHeight) + const errorDom = GetErrorMessageDom.getErrorMessageDom(editingErrorMessage) + const childCount = getChildCount(scrollBarDom.length, errorDom.length) + const parentNode = getParentNode(childCount) + const dom: readonly VirtualDomNode[] = [ + parentNode, + ...GetListItemsVirtualDom.getListItemsVirtualDom(visibleItems, focusedIndex, focused, dropTargets), + ...scrollBarDom, + ...errorDom, + ] + return dom +} diff --git a/packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts b/packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts new file mode 100644 index 0000000..a00b454 --- /dev/null +++ b/packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts @@ -0,0 +1,52 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' +import { dropTargetFull } from '../DropTargetFull/DropTargetFull.ts' +import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' +import * as InputName from '../InputName/InputName.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' +import { text } from '../VirtualDomHelpers/VirtualDomHelpers.ts' + +const getClassName = (dropTargets: readonly number[]): string => { + const extraClassName = dropTargets === dropTargetFull ? ClassNames.ExplorerDropTarget : ClassNames.Empty + return MergeClassNames.mergeClassNames(ClassNames.Viewlet, ClassNames.Explorer, extraClassName) +} + +export const getExplorerWelcomeVirtualDom = (isWide: boolean, dropTargets: readonly number[]): readonly VirtualDomNode[] => { + return [ + { + childCount: 1, + className: getClassName(dropTargets), + onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, + onDragLeave: DomEventListenerFunctions.HandleDragLeave, + onDragOver: DomEventListenerFunctions.HandleDragOver, + onDrop: DomEventListenerFunctions.HandleDrop, + tabIndex: 0, + type: VirtualDomElements.Div, + }, + { + childCount: 2, + className: ClassNames.Welcome, + type: VirtualDomElements.Div, + }, + { + childCount: 1, + className: ClassNames.WelcomeMessage, + type: VirtualDomElements.P, + }, + text(ExplorerStrings.youHaveNotYetOpenedAFolder()), + { + childCount: 1, + className: MergeClassNames.mergeClassNames( + ClassNames.Button, + ClassNames.ButtonPrimary, + isWide ? ClassNames.ButtonWide : ClassNames.ButtonNarrow, + ), + name: InputName.OpenFolder, + onClick: DomEventListenerFunctions.HandleClickOpenFolder, + type: VirtualDomElements.Button, + }, + text(ExplorerStrings.openFolder()), + ] +} diff --git a/packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts b/packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts new file mode 100644 index 0000000..585c602 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts @@ -0,0 +1,5 @@ +export const getFileArray = (fileList: FileList): readonly File[] => { + // @ts-ignore + const files = [...fileList] + return files +} diff --git a/packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts b/packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts new file mode 100644 index 0000000..e8865be --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts @@ -0,0 +1,32 @@ +import { SourceControlWorker } from '@lvce-editor/rpc-registry' +import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' +import { ensureUris } from '../EnsureUris/EnsureUris.ts' +import { normalizeDecorations } from '../NormalizeDecorations/NormalizeDecorations.ts' + +export const getFileDecorations = async ( + scheme: string, + root: string, + maybeUris: readonly string[], + decorationsEnabled: boolean, + assetDir: string, + platform: number, +): Promise => { + try { + if (!decorationsEnabled) { + return [] + } + const providerIds = await SourceControlWorker.invoke('SourceControl.getEnabledProviderIds', scheme, root, assetDir, platform) + if (providerIds.length === 0) { + return [] + } + // TODO how to handle multiple providers? + const providerId = providerIds.at(-1) + const uris = ensureUris(maybeUris) + const decorations = await SourceControlWorker.invoke('SourceControl.getFileDecorations', providerId, uris, assetDir, platform) + const normalized = normalizeDecorations(decorations) + return normalized + } catch (error) { + console.error(error) + return [] + } +} diff --git a/packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts b/packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts new file mode 100644 index 0000000..8091ace --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts @@ -0,0 +1,5 @@ +export const getFileHandleText = async (fileHandle: FileSystemFileHandle): Promise => { + const file = await fileHandle.getFile() + const text = await file.text() + return text +} diff --git a/packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts b/packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts new file mode 100644 index 0000000..845820c --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts @@ -0,0 +1,10 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' + +export const getFileHandles = async (fileIds: readonly number[]): Promise => { + if (fileIds.length === 0) { + return [] + } + const files = await RendererWorker.getFileHandles(fileIds) + return files +} diff --git a/packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts b/packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts new file mode 100644 index 0000000..22c27dc --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts @@ -0,0 +1,14 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as AriaRoles from '../AriaRoles/AriaRoles.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const getFileIconVirtualDom = (icon: string): VirtualDomNode => { + return { + childCount: 0, + className: ClassNames.FileIcon, + role: AriaRoles.None, + src: icon, + type: VirtualDomElements.Img, + } +} diff --git a/packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts b/packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts new file mode 100644 index 0000000..817176b --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts @@ -0,0 +1,20 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' +import type { FileIconsResult } from '../FileIconsRequest/FileIconsResult.ts' +import * as GetFileIconsCached from '../GetFileIconsCached/GetFileIconsCached.ts' +import * as GetMissingIconRequests from '../GetMissingIconRequests/GetMissingIconRequests.ts' +import { getPaths } from '../GetPaths/GetPaths.ts' +import * as RequestFileIcons from '../RequestFileIcons/RequestFileIcons.ts' +import * as UpdateIconCache from '../UpdateIconCache/UpdateIconCache.ts' + +export const getFileIcons = async (dirents: readonly ExplorerItem[], fileIconCache: FileIconCache): Promise => { + const missingRequests = GetMissingIconRequests.getMissingIconRequests(dirents, fileIconCache) + const newIcons = await RequestFileIcons.requestFileIcons(missingRequests) + const newFileIconCache = UpdateIconCache.updateIconCache(fileIconCache, missingRequests, newIcons) + const paths = getPaths(dirents) + const icons = GetFileIconsCached.getIconsCached(paths, newFileIconCache) + return { + icons, + newFileIconCache, + } +} diff --git a/packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts b/packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts new file mode 100644 index 0000000..ae83b79 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts @@ -0,0 +1,5 @@ +import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' + +export const getIconsCached = (dirents: readonly string[], fileIconCache: FileIconCache): string[] => { + return dirents.map((dirent) => fileIconCache[dirent]) +} diff --git a/packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts b/packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts new file mode 100644 index 0000000..e77b96a --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts @@ -0,0 +1,22 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import { join2 } from '../Path/Path.ts' + +export const getFileOperations = (root: string, uploadTree: any): readonly FileOperation[] => { + const operations: FileOperation[] = [] + + const processTree = (tree: any, currentPath: string): void => { + for (const [path, value] of Object.entries(tree)) { + const fullPath = currentPath ? join2(currentPath, path) : path + if (typeof value === 'object') { + operations.push({ path: join2(root, fullPath), type: FileOperationType.CreateFolder }) + processTree(value, fullPath) + } else if (typeof value === 'string') { + operations.push({ path: join2(root, fullPath), text: value, type: FileOperationType.CreateFile }) + } + } + } + + processTree(uploadTree, '') + return operations +} diff --git a/packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts b/packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts new file mode 100644 index 0000000..5861737 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts @@ -0,0 +1,33 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import { generateUniqueName } from '../GenerateUniqueName/GenerateUniqueName.ts' +import * as Path from '../Path/Path.ts' + +export const getFileOperationsCopy = ( + root: string, + existingUris: readonly string[], + files: readonly string[], + focusedUri: string, +): readonly FileOperation[] => { + const operations: FileOperation[] = [] + + for (const file of files) { + const baseName = Path.getBaseName('/', file) + if (existingUris.includes(file)) { + operations.push({ + from: file, + path: Path.join2(focusedUri, baseName), + type: FileOperationType.Rename, + }) + } else { + const uniqueName = generateUniqueName(baseName, existingUris, root) + const newUri = Path.join2(root, uniqueName) + operations.push({ + from: file, // TODO ensure file is uri + path: newUri, + type: FileOperationType.Copy, + }) + } + } + return operations +} diff --git a/packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts b/packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts new file mode 100644 index 0000000..bfe5187 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts @@ -0,0 +1,47 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import * as Path from '../Path/Path.ts' + +const getFileOperationsNestedPath = (path: string, root: string, pathSeparator: string): readonly FileOperation[] => { + const parts = path.slice(root.length).split(pathSeparator) + const operations: FileOperation[] = [] + let currentPath = '' + for (const part of parts) { + if (!part) continue + currentPath = Path.join2(currentPath, part) + operations.push({ + path: Path.join2(root, currentPath), + type: FileOperationType.CreateFolder, + }) + } + return operations +} + +export const getFileOperationsCreate = ( + newFileName: string, + newDirentType: number, + pathSeparator: string, + absolutePath: string, + root: string, +): readonly FileOperation[] => { + const operations: FileOperation[] = [] + const parentPath = Path.dirname(pathSeparator, absolutePath) + + operations.push(...getFileOperationsNestedPath(parentPath, root, pathSeparator)) + + if (newDirentType === DirentType.File) { + operations.push({ + path: absolutePath, + text: '', + type: FileOperationType.CreateFile, + }) + } else if (newDirentType === DirentType.Directory) { + operations.push({ + path: absolutePath, + type: FileOperationType.CreateFolder, + }) + } + + return operations +} diff --git a/packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts b/packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts new file mode 100644 index 0000000..aaa881c --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts @@ -0,0 +1,20 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import { generateUniqueName } from '../GenerateUniqueName/GenerateUniqueName.ts' +import * as Path from '../Path/Path.ts' + +export const getFileOperationsCut = (root: string, existingUris: readonly string[], files: readonly string[]): readonly FileOperation[] => { + const operations: FileOperation[] = [] + + for (const file of files) { + const baseName = Path.getBaseName('/', file) + const uniqueName = generateUniqueName(baseName, existingUris, root) + const newUri = Path.join2(root, uniqueName) + operations.push({ + from: file, // TODO ensure file is uri + path: newUri, + type: FileOperationType.Copy, + }) + } + return operations +} diff --git a/packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts b/packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts new file mode 100644 index 0000000..aeee343 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts @@ -0,0 +1,24 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import { join } from '../Path/Path.ts' +import { getDroppedName, type DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' + +export const getFileOperationsElectron = async ( + root: string, + paths: readonly string[], + fileHandles: DroppedArgs, + pathSeparator: string, +): Promise => { + const operations: FileOperation[] = [] + for (let i = 0; i < paths.length; i++) { + const fileHandle = fileHandles[i] + const name = getDroppedName(fileHandle) + const path = paths[i] + operations.push({ + from: path, + path: join(pathSeparator, root, name), + type: FileOperationType.Copy, + }) + } + return operations +} diff --git a/packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts b/packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts new file mode 100644 index 0000000..9a299d3 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts @@ -0,0 +1,16 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import * as Path from '../Path/Path.ts' + +export const getFileOperationsRename = (oldAbsolutePath: string, newFileName: string): readonly FileOperation[] => { + const operations: FileOperation[] = [] + const oldParentPath = Path.dirname2(oldAbsolutePath) + const newAbsolutePath = Path.join2(oldParentPath, newFileName) + operations.push({ + from: oldAbsolutePath, + path: newAbsolutePath, + type: FileOperationType.Rename, + }) + + return operations +} diff --git a/packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts b/packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts new file mode 100644 index 0000000..7b512ff --- /dev/null +++ b/packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const getFilePathElectron = async (file: File): Promise => { + return RendererWorker.invoke('FileSystemHandle.getFilePathElectron', file) +} diff --git a/packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts b/packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts new file mode 100644 index 0000000..2cb19d0 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts @@ -0,0 +1,15 @@ +import * as GetFilePathElectron from '../GetFilePathElectron/GetFilePathElectron.ts' +import * as PlatformType from '../PlatformType/PlatformType.ts' + +const getFilepath = async (file: File): Promise => { + return GetFilePathElectron.getFilePathElectron(file) +} + +export const getFilePaths = async (files: readonly File[], platform: number): Promise => { + if (platform !== PlatformType.Electron) { + return files.map((file) => '') + } + const promises = files.map(getFilepath) + const paths = await Promise.all(promises) + return paths +} diff --git a/packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts b/packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts new file mode 100644 index 0000000..fd21ba7 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts @@ -0,0 +1,16 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +const isFolder = (direntType: number): boolean => { + return direntType === DirentType.Directory || direntType === DirentType.DirectoryExpanded || direntType === DirentType.SymLinkFolder +} + +export const getFittingIndex = (dirents: readonly ExplorerItem[], startIndex: number): number => { + for (let i = startIndex; i >= 0; i--) { + const dirent = dirents[i] + if (dirent && isFolder(dirent.type)) { + return i + } + } + return -1 +} diff --git a/packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts b/packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts new file mode 100644 index 0000000..e25cf8e --- /dev/null +++ b/packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts @@ -0,0 +1,8 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const getFocusedDirent = (state: ExplorerState): ExplorerItem | undefined => { + const { focusedIndex, items, minLineY } = state + const dirent = items[focusedIndex + minLineY] + return dirent +} diff --git a/packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts b/packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts new file mode 100644 index 0000000..da505d6 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts @@ -0,0 +1,14 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const getFocusedFile = (state: ExplorerState): ExplorerItem | undefined => { + if (state.focusedIndex < 0 || state.focusedIndex >= state.items.length) { + return undefined + } + const item = state.items[state.focusedIndex] + if (item.type !== DirentType.File) { + return undefined + } + return item +} diff --git a/packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts b/packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts new file mode 100644 index 0000000..9b534e9 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const getFocusedIndexCancel = (items: readonly ExplorerItem[], editingIndex: number): number => { + const newFocusedIndex = editingIndex >= items.length ? items.length - 1 : editingIndex + return newFocusedIndex +} diff --git a/packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts b/packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts new file mode 100644 index 0000000..379f0c1 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts @@ -0,0 +1,5 @@ +import { RendererWorker as Rpc } from '@lvce-editor/rpc-registry' + +export const getFolderIcon = async (name: string): Promise => { + return Rpc.invoke('IconTheme.getFolderIcon', { name }) +} diff --git a/packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts b/packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts new file mode 100644 index 0000000..ec47294 --- /dev/null +++ b/packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts @@ -0,0 +1,15 @@ +export const getFriendlyErrorMessage = (errorMessage: string, errorCode: string): string => { + switch (errorCode) { + case 'EACCES': + case 'EPERM': + return 'permission was denied' + case 'EBUSY': + return 'the folder is currently in use' + case 'ENOENT': + return 'the folder does not exist' + case 'ENOTDIR': + return 'the path is not a folder' + default: + return errorMessage || 'an unexpected error occurred' + } +} diff --git a/packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts b/packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts new file mode 100644 index 0000000..9036f5c --- /dev/null +++ b/packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts @@ -0,0 +1,12 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as AriaRoles from '../AriaRoles/AriaRoles.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const getIconVirtualDom = (icon: string, type = VirtualDomElements.Div): VirtualDomNode => { + return { + childCount: 0, + className: `MaskIcon MaskIcon${icon}`, + role: AriaRoles.None, + type, + } +} diff --git a/packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts b/packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts new file mode 100644 index 0000000..ab8ac4e --- /dev/null +++ b/packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts @@ -0,0 +1,5 @@ +export const getIndentRule = (indent: number): string => { + return `.Indent-${indent} { + padding-left: ${indent}px; +}` +} diff --git a/packages/explorer-view/src/parts/GetIndex/GetIndex.ts b/packages/explorer-view/src/parts/GetIndex/GetIndex.ts new file mode 100644 index 0000000..6898e27 --- /dev/null +++ b/packages/explorer-view/src/parts/GetIndex/GetIndex.ts @@ -0,0 +1,11 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const getIndex = (dirents: readonly ExplorerItem[], uri: string): number => { + for (let i = 0; i < dirents.length; i++) { + const dirent = dirents[i] + if (dirent.path === uri) { + return i + } + } + return -1 +} diff --git a/packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts b/packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts new file mode 100644 index 0000000..9078506 --- /dev/null +++ b/packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const getIndexFromPosition = (state: ExplorerState, eventX: number, eventY: number): number => { + const { itemHeight, items, minLineY, y } = state + const index = Math.floor((eventY - y) / itemHeight) + if (index < 0) { + return 0 + } + if (index >= items.length) { + return -1 + } + return index + minLineY +} diff --git a/packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts b/packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts new file mode 100644 index 0000000..3ec7175 --- /dev/null +++ b/packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts @@ -0,0 +1,9 @@ +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' + +export const getInputClassName = (hasEditingError: boolean): string => { + if (hasEditingError) { + return MergeClassNames.mergeClassNames(ClassNames.ExplorerInputBox, ClassNames.InputValidationError) + } + return ClassNames.ExplorerInputBox +} diff --git a/packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts b/packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts new file mode 100644 index 0000000..2af52ec --- /dev/null +++ b/packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts @@ -0,0 +1,30 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' +import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' +import { getInputClassName } from '../GetInputClassName/GetInputClassName.ts' +import * as InputName from '../InputName/InputName.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const getInputDom = (isEditing: boolean, hasEditingError: boolean): readonly VirtualDomNode[] => { + if (!isEditing) { + return [] + } + const ariaLabel = ExplorerStrings.typeAFileName() + return [ + { + ariaLabel: ariaLabel, + autocapitalize: 'off', + autocomplete: 'off', + autocorrect: 'off', + childCount: 0, + className: getInputClassName(hasEditingError), + id: 'ExplorerInput', + name: InputName.ExplorerInput, + onBlur: DomEventListenerFunctions.HandleInputBlur, + onClick: DomEventListenerFunctions.HandleInputClick, + onInput: DomEventListenerFunctions.HandleEditingInput, + spellcheck: 'false', + type: VirtualDomElements.Input, + }, + ] +} diff --git a/packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts b/packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts new file mode 100644 index 0000000..ad77cbd --- /dev/null +++ b/packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts @@ -0,0 +1,123 @@ +import { WhenExpression } from '@lvce-editor/constants' +import { KeyCode, KeyModifier } from '@lvce-editor/virtual-dom-worker' +import type { KeyBinding } from '../KeyBinding/KeyBinding.ts' + +export const getKeyBindings = (): readonly KeyBinding[] => { + return [ + { + command: 'Explorer.selectUp', + key: KeyModifier.Shift | KeyCode.UpArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.selectDown', + key: KeyModifier.Shift | KeyCode.DownArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handleArrowRight', + key: KeyCode.RightArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handleArrowLeft', + key: KeyCode.LeftArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.focusFirst', + key: KeyCode.Home, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.focusLast', + key: KeyCode.End, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.focusPrevious', + key: KeyCode.UpArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.focusNext', + key: KeyCode.DownArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.expandAll', + key: KeyModifier.CtrlCmd | KeyCode.Star, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.expandRecursively', + key: KeyModifier.Alt | KeyCode.RightArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.collapseAll', + key: KeyModifier.CtrlCmd | KeyCode.LeftArrow, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handlePaste', + key: KeyModifier.CtrlCmd | KeyCode.KeyV, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handleCopy', + key: KeyModifier.CtrlCmd | KeyCode.KeyC, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handleCut', + key: KeyModifier.CtrlCmd | KeyCode.KeyX, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.renameDirent', + key: KeyCode.F2, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.cancelEdit', + key: KeyCode.Escape, + when: WhenExpression.FocusExplorerEditBox, + }, + { + command: 'Explorer.acceptEdit', + key: KeyCode.Enter, + when: WhenExpression.FocusExplorerEditBox, + }, + { + command: 'Explorer.removeDirent', + key: KeyCode.Delete, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.focusNone', + key: KeyCode.Escape, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handleClickCurrentButKeepFocus', + key: KeyCode.Space, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handleClickCurrent', + key: KeyCode.Enter, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.handleEscape', + key: KeyCode.Escape, + when: WhenExpression.FocusExplorer, + }, + { + command: 'Explorer.selectAll', + key: KeyModifier.CtrlCmd | KeyCode.KeyA, + when: WhenExpression.FocusExplorer, + }, + ] +} diff --git a/packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts b/packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts new file mode 100644 index 0000000..aa1b0bd --- /dev/null +++ b/packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts @@ -0,0 +1,28 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' +import { text } from '../VirtualDomHelpers/VirtualDomHelpers.ts' + +const label: VirtualDomNode = { + childCount: 1, + className: ClassNames.Label, + type: VirtualDomElements.Div, +} + +export const getLabelDom = (isEditing: boolean, name: string, isDimmed: boolean): readonly VirtualDomNode[] => { + if (isEditing) { + return [] + } + if (isDimmed) { + return [ + { + childCount: 1, + className: MergeClassNames.mergeClassNames(ClassNames.Label, ClassNames.LabelCut), + type: VirtualDomElements.Div, + }, + text(name), + ] + } + return [label, text(name)] +} diff --git a/packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts b/packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts new file mode 100644 index 0000000..bf5cb77 --- /dev/null +++ b/packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts @@ -0,0 +1,58 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' +import * as AriaRoles from '../AriaRoles/AriaRoles.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' +import { dropTargetFull } from '../DropTargetFull/DropTargetFull.ts' +import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' +import * as GetExplorerItemVirtualDom from '../GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +const getActiveDescendant = (focusedIndex: number): string | undefined => { + if (focusedIndex >= 0) { + return 'TreeItemActive' + } + return undefined +} + +const getClassName = (focused: boolean, focusedIndex: number, dropTarget: readonly number[]): string => { + const extraClass1 = focused && focusedIndex === -1 ? ClassNames.FocusOutline : ClassNames.Empty + const extraClass2 = dropTarget === dropTargetFull ? ClassNames.ExplorerDropTarget : ClassNames.Empty + const className = MergeClassNames.mergeClassNames(ClassNames.ListItems, extraClass1, extraClass2) + return className +} + +export const getListItemsVirtualDom = ( + visibleItems: readonly VisibleExplorerItem[], + focusedIndex: number, + focused: boolean, + dropTargets: readonly number[], +): readonly VirtualDomNode[] => { + const dom: readonly VirtualDomNode[] = [ + { + ariaActiveDescendant: getActiveDescendant(focusedIndex), + ariaLabel: ExplorerStrings.filesExplorer(), + childCount: visibleItems.length, + className: getClassName(focused, focusedIndex, dropTargets), + onBlur: DomEventListenerFunctions.HandleListBlur, + onClick: DomEventListenerFunctions.HandleClick, + onContextMenu: DomEventListenerFunctions.HandleContextMenu, + onDblClick: DomEventListenerFunctions.HandleDoubleClick, + onDragEnd: DomEventListenerFunctions.HandleDragEnd, + onDragLeave: DomEventListenerFunctions.HandleDragLeave, + onDragOver: DomEventListenerFunctions.HandleDragOver, + onDragStart: DomEventListenerFunctions.HandleDragStart, + onDrop: DomEventListenerFunctions.HandleDrop, + onFocus: DomEventListenerFunctions.HandleListFocus, + onPointerDown: DomEventListenerFunctions.HandlePointerDown, + onWheel: DomEventListenerFunctions.HandleWheel, + role: AriaRoles.Tree, + tabIndex: 0, + type: VirtualDomElements.Div, + // onKeyDown: DomEventListenerFunctions.HandleListKeyDown, + }, + ...visibleItems.flatMap(GetExplorerItemVirtualDom.getExplorerItemVirtualDom), + ] + return dom +} diff --git a/packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts b/packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts new file mode 100644 index 0000000..95dc156 --- /dev/null +++ b/packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts @@ -0,0 +1,24 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +const getMissingFolderMessage = (root: string): string => { + if (root) { + return `Could not open "${root}" because the folder does not exist. It may have been moved or deleted.` + } + return 'Could not open folder because the folder does not exist. It may have been moved or deleted.' +} + +export const getLoadErrorMessage = (state: ExplorerState): string => { + if (state.hasError) { + if (state.errorCode === 'ENOENT') { + return getMissingFolderMessage(state.root) + } + const code = state.errorCode ? ` (error code: ${state.errorCode})` : '' + const reason = state.errorMessage || 'an unexpected error occurred' + return `Could not open folder due to ${reason}${code}.` + } + return '' +} + +export const shouldShowOpenAnotherFolderButton = (state: ExplorerState): boolean => { + return state.hasError && state.errorCode === 'ENOENT' +} diff --git a/packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts b/packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts new file mode 100644 index 0000000..45e9963 --- /dev/null +++ b/packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts @@ -0,0 +1,57 @@ +import { text } from '@lvce-editor/virtual-dom-worker' +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as AriaRoles from '../AriaRoles/AriaRoles.ts' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' +import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' +import * as InputName from '../InputName/InputName.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +const getParentNode = (childCount: number): VirtualDomNode => { + return { + childCount, + className: MergeClassNames.mergeClassNames(ClassNames.Viewlet, ClassNames.Explorer), + role: AriaRoles.None, + type: VirtualDomElements.Div, + } +} + +export const getLoadErrorVirtualDom = ( + loadErrorMessage: string, + isWide: boolean, + showOpenAnotherFolderButton: boolean, +): readonly VirtualDomNode[] => { + const childCount = showOpenAnotherFolderButton ? 2 : 1 + const errorDom: readonly VirtualDomNode[] = [ + { + childCount, + className: ClassNames.Welcome, + type: VirtualDomElements.Div, + }, + { + childCount: 1, + className: ClassNames.WelcomeMessage, + type: VirtualDomElements.P, + }, + text(loadErrorMessage), + ] + const buttonDom = showOpenAnotherFolderButton + ? [ + { + childCount: 1, + className: MergeClassNames.mergeClassNames( + ClassNames.Button, + ClassNames.ButtonPrimary, + isWide ? ClassNames.ButtonWide : ClassNames.ButtonNarrow, + ), + name: InputName.OpenFolder, + onClick: DomEventListenerFunctions.HandleClickOpenFolder, + type: VirtualDomElements.Button, + }, + text(ExplorerStrings.openAnotherFolder()), + ] + : [] + const parentNode = getParentNode(1) + return [parentNode, ...errorDom, ...buttonDom] +} diff --git a/packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts b/packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts new file mode 100644 index 0000000..9bb1d3b --- /dev/null +++ b/packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts @@ -0,0 +1,6 @@ +import * as GetNumberOfVisibleItems from '../GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts' + +export const getExplorerMaxLineY = (minLineY: number, height: number, itemHeight: number, direntsLength: number): number => { + const maxLineY = minLineY + Math.min(GetNumberOfVisibleItems.getNumberOfVisibleItems(height, itemHeight), direntsLength) + return maxLineY +} diff --git a/packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts b/packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts new file mode 100644 index 0000000..34eabc7 --- /dev/null +++ b/packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts @@ -0,0 +1,214 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { MenuEntry } from '../MenuEntry/MenuEntry.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as ViewletExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' +import * as MenuEntrySeparator from '../MenuEntrySeparator/MenuEntrySeparator.ts' +import * as MenuItemFlags from '../MenuItemFlags/MenuItemFlags.ts' + +const menuEntryNewFile: MenuEntry = { + command: 'Explorer.newFile', + flags: MenuItemFlags.None, + id: 'newFile', + label: ViewletExplorerStrings.newFile(), +} + +const menuEntryNewFolder: MenuEntry = { + command: 'Explorer.newFolder', + flags: MenuItemFlags.None, + id: 'newFolder', + label: ViewletExplorerStrings.newFolder(), +} + +const menuEntryOpenContainingFolder: MenuEntry = { + command: 'Explorer.openContainingFolder', + flags: MenuItemFlags.RestoreFocus, + id: 'openContainingFolder', + label: ViewletExplorerStrings.openContainingFolder(), +} + +const menuEntryOpenInIntegratedTerminal: MenuEntry = { + command: /* TODO */ '-1', + flags: MenuItemFlags.None, + id: 'openInIntegratedTerminal', + label: ViewletExplorerStrings.openInIntegratedTerminal(), +} + +const menuEntryCut: MenuEntry = { + command: 'Explorer.handleCut', + flags: MenuItemFlags.RestoreFocus, + id: 'cut', + label: ViewletExplorerStrings.cut(), +} + +const menuEntryCopy: MenuEntry = { + command: 'Explorer.handleCopy', + flags: MenuItemFlags.RestoreFocus, + id: 'copy', + label: ViewletExplorerStrings.copy(), +} + +const menuEntryPaste: MenuEntry = { + command: 'Explorer.handlePaste', + flags: MenuItemFlags.None, + id: 'paste', + label: ViewletExplorerStrings.paste(), +} + +const menuEntryCopyPath: MenuEntry = { + command: 'Explorer.copyPath', + flags: MenuItemFlags.RestoreFocus, + id: 'copyPath', + label: ViewletExplorerStrings.copyPath(), +} + +const menuEntryCopyRelativePath: MenuEntry = { + command: 'Explorer.copyRelativePath', + flags: MenuItemFlags.RestoreFocus, + id: 'copyRelativePath', + label: ViewletExplorerStrings.copyRelativePath(), +} + +const menuEntrySelectForCompare: MenuEntry = { + command: 'Explorer.selectForCompare', + flags: MenuItemFlags.RestoreFocus, + id: 'selectForCompare', + label: ViewletExplorerStrings.selectForCompare(), +} + +const menuEntryCompareWithSelected: MenuEntry = { + command: 'Explorer.compareWithSelected', + flags: MenuItemFlags.RestoreFocus, + id: 'compareWithSelected', + label: ViewletExplorerStrings.compareWithSelected(), +} + +const menuEntryRename: MenuEntry = { + command: 'Explorer.renameDirent', + flags: MenuItemFlags.None, + id: 'rename', + label: ViewletExplorerStrings.rename(), +} + +const menuEntryDelete: MenuEntry = { + command: 'Explorer.removeDirent', + flags: MenuItemFlags.None, + id: 'delete', + label: ViewletExplorerStrings.deleteItem(), +} + +const menuEntryRemoveFolderFromWorkspace: MenuEntry = { + command: 'Workspace.close', + flags: MenuItemFlags.None, + id: 'removeFolderFromWorkspace', + label: ViewletExplorerStrings.removeFolderFromWorkspace(), +} + +const ALL_ENTRIES: readonly MenuEntry[] = [ + menuEntryNewFile, + menuEntryNewFolder, + menuEntryOpenContainingFolder, + menuEntryOpenInIntegratedTerminal, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCut, + menuEntryCopy, + menuEntryPaste, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCopyPath, + menuEntryCopyRelativePath, + MenuEntrySeparator.menuEntrySeparator, + menuEntryRename, + menuEntryDelete, +] + +// TODO there are two possible ways of getting the focused dirent of explorer +// 1. directly access state of explorer (bad because it directly accesses state of another component) +// 2. expose getFocusedDirent method in explorer (bad because explorer code should not know about for menuEntriesExplorer, which needs that method) +const getFocusedDirent = (explorerState: ExplorerState): ExplorerItem | undefined => { + if (!explorerState || explorerState.focusedIndex < 0) { + return undefined + } + return explorerState.items[explorerState.focusedIndex] +} + +const getMenuEntriesDirectory = (): readonly MenuEntry[] => { + return ALL_ENTRIES +} + +const getMenuEntriesFile = (): readonly MenuEntry[] => { + return [ + menuEntryOpenContainingFolder, + menuEntryOpenInIntegratedTerminal, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCut, + menuEntryCopy, + menuEntryPaste, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCopyPath, + menuEntryCopyRelativePath, + MenuEntrySeparator.menuEntrySeparator, + menuEntrySelectForCompare, + MenuEntrySeparator.menuEntrySeparator, + menuEntryRename, + menuEntryDelete, + ] +} + +const getMenuEntriesFileCompareWithSelected = (): readonly MenuEntry[] => { + return [ + menuEntryOpenContainingFolder, + menuEntryOpenInIntegratedTerminal, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCut, + menuEntryCopy, + menuEntryPaste, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCopyPath, + menuEntryCopyRelativePath, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCompareWithSelected, + MenuEntrySeparator.menuEntrySeparator, + menuEntryRename, + menuEntryDelete, + ] +} + +const getMenuEntriesDefault = (): readonly MenuEntry[] => { + return ALL_ENTRIES +} + +const getMenuEntriesRoot = (root: string): readonly MenuEntry[] => { + const entries: MenuEntry[] = [ + menuEntryNewFile, + menuEntryNewFolder, + menuEntryOpenContainingFolder, + menuEntryOpenInIntegratedTerminal, + MenuEntrySeparator.menuEntrySeparator, + menuEntryPaste, + MenuEntrySeparator.menuEntrySeparator, + menuEntryCopyPath, + menuEntryCopyRelativePath, + ] + if (root) { + entries.push(MenuEntrySeparator.menuEntrySeparator, menuEntryRemoveFolderFromWorkspace) + } + return entries +} + +export const getMenuEntries = (state: ExplorerState): readonly MenuEntry[] => { + const focusedDirent = getFocusedDirent(state) + if (!focusedDirent) { + return getMenuEntriesRoot(state.root) + } + switch (focusedDirent.type) { + case DirentType.Directory: + return getMenuEntriesDirectory() + case DirentType.File: + if (state.compareSourceUri && state.compareSourceUri !== focusedDirent.path) { + return getMenuEntriesFileCompareWithSelected() + } + return getMenuEntriesFile() + default: + return getMenuEntriesDefault() + } +} diff --git a/packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts b/packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts new file mode 100644 index 0000000..69dd8c6 --- /dev/null +++ b/packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts @@ -0,0 +1,7 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { MenuEntry } from '../MenuEntry/MenuEntry.ts' +import { getMenuEntries } from '../GetMenuEntries/GetMenuEntries.ts' + +export const getMenuEntries2 = (state: ExplorerState): readonly MenuEntry[] => { + return getMenuEntries(state) +} diff --git a/packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts b/packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts new file mode 100644 index 0000000..fe65b4e --- /dev/null +++ b/packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts @@ -0,0 +1,27 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' +import type { IconRequest } from '../IconRequest/IconRequest.ts' + +const getMissingDirents = (dirents: readonly ExplorerItem[], fileIconCache: FileIconCache): readonly ExplorerItem[] => { + const missingDirents: ExplorerItem[] = [] + for (const dirent of dirents) { + if (!(dirent.path in fileIconCache)) { + missingDirents.push(dirent) + } + } + return missingDirents +} + +const toIconRequest = (dirent: ExplorerItem): IconRequest => { + return { + name: dirent.name, + path: dirent.path, + type: dirent.type, + } +} + +export const getMissingIconRequests = (dirents: readonly ExplorerItem[], fileIconCache: FileIconCache): readonly IconRequest[] => { + const missingRequests = getMissingDirents(dirents, fileIconCache) + const iconRequests = missingRequests.map(toIconRequest) + return iconRequests +} diff --git a/packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts b/packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts new file mode 100644 index 0000000..8514c54 --- /dev/null +++ b/packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const getMouseAction = (uid: number, button: number, modifiers: any): Promise => { + return RendererWorker.invoke('MouseActions.get', uid, button, modifiers) +} diff --git a/packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts b/packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts new file mode 100644 index 0000000..c451c72 --- /dev/null +++ b/packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts @@ -0,0 +1,33 @@ +import { WhenExpression } from '@lvce-editor/constants' +import type { MouseAction } from '../MouseAction/MouseAction.ts' +import * as MouseEventType from '../MouseEventType/MouseEventType.ts' + +export const getMouseActions = (): readonly MouseAction[] => { + return [ + { + button: MouseEventType.LeftClick, + command: 'Explorer.openFile', + description: 'Open file on click', + modifiers: {}, + when: WhenExpression.FocusExplorer, + }, + { + button: MouseEventType.LeftClick, + command: 'Explorer.toggleSelection', + description: 'Toggle selection with Ctrl+Click', + modifiers: { + ctrl: true, + }, + when: WhenExpression.FocusExplorer, + }, + { + button: MouseEventType.LeftClick, + command: 'Explorer.rangeSelection', + description: 'Select range with Shift+Click', + modifiers: { + shift: true, + }, + when: WhenExpression.FocusExplorer, + }, + ] +} diff --git a/packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts b/packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts new file mode 100644 index 0000000..384f689 --- /dev/null +++ b/packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts @@ -0,0 +1,43 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' +import { join2 } from '../Path/Path.ts' + +export const getNewChildDirentsForNewDirent = async ( + items: readonly ExplorerItem[], + depth: number, + parentPath: string, + direntType: number, +): Promise => { + // Get existing children or query them if they don't exist + let existingChildren = items.filter((item) => item.depth === depth && item.path.startsWith(parentPath)) + if (existingChildren.length === 0) { + const childDirents = await FileSystem.readDirWithFileTypes(parentPath) + existingChildren = childDirents.map((dirent: { name: string; type: number }, index: number) => ({ + depth, + icon: '', + name: dirent.name, + path: join2(parentPath, dirent.name), + posInSet: index + 1, + selected: false, + setSize: childDirents.length, + type: dirent.type, + })) + } + const updatedChildren = existingChildren.map((child, index) => ({ + ...child, + posInSet: index + 1, + setSize: existingChildren.length + 2, + })) + const newDirent: ExplorerItem = { + depth, + icon: '', + name: '', + path: parentPath, + posInSet: updatedChildren.length + 1, + selected: false, + setSize: existingChildren.length + 2, + type: direntType, + } + const allChildDirents = [...updatedChildren, newDirent] + return allChildDirents +} diff --git a/packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts b/packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts new file mode 100644 index 0000000..b18bfe4 --- /dev/null +++ b/packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts @@ -0,0 +1,13 @@ +import * as DirentType from '../DirentType/DirentType.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' + +export const getNewDirentType = (editingType: number): number => { + switch (editingType) { + case ExplorerEditingType.CreateFile: + return DirentType.EditingFile + case ExplorerEditingType.CreateFolder: + return DirentType.EditingFolder + default: + return DirentType.File + } +} diff --git a/packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts b/packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts new file mode 100644 index 0000000..0f43185 --- /dev/null +++ b/packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts @@ -0,0 +1,72 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { NewDirentsAcceptResult } from '../NewDirentsAcceptResult/NewDirentsAcceptResult.ts' +import * as CompareDirent from '../CompareDirent/CompareDirent.ts' +import { getParentFolder } from '../GetParentFolder/GetParentFolder.ts' + +export const getNewDirentsAccept = ( + items: readonly ExplorerItem[], + focusedIndex: number, + editingValue: string, + root: string, + pathSeparator: string, + newDirentType: number, +): NewDirentsAcceptResult => { + const newFileName = editingValue + const parentFolder = getParentFolder(items, focusedIndex, root, pathSeparator) + const absolutePath = [parentFolder, newFileName].join(pathSeparator) + + const parentDirent = + focusedIndex >= 0 + ? items[focusedIndex] + : { + depth: 0, + path: root, + } + const depth = parentDirent.depth + 1 + const newDirent: ExplorerItem = { + depth, + icon: '', + name: newFileName, + path: absolutePath, + posInSet: -1, + selected: false, + setSize: 1, + type: newDirentType, + } + // @ts-ignore + newDirent.icon = '' + let insertIndex = focusedIndex + let posInSet = 1 + let setSize = 1 + let i = Math.max(focusedIndex, -1) + 1 + // TODO update posinset and setsize of all affected dirents + for (; i < items.length; i++) { + const dirent = items[i] + if (dirent.depth !== depth) { + break + } + const compareResult = CompareDirent.compareDirent(dirent, newDirent) + if (compareResult === 1) { + insertIndex = i - 1 + break + } else { + // @ts-ignore + posInSet = dirent.posInSet + 1 + // @ts-ignore + setSize = dirent.setSize + 1 + insertIndex = i + } + // @ts-ignore + dirent.setSize++ + } + // @ts-ignore + newDirent.setSize = setSize + // @ts-ignore + newDirent.posInSet = posInSet + const newItems = [...items] + newItems.splice(insertIndex + 1, 0, newDirent) + return { + dirents: newItems, + newFocusedIndex: insertIndex + 1, + } +} diff --git a/packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts b/packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts new file mode 100644 index 0000000..1361691 --- /dev/null +++ b/packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts @@ -0,0 +1,12 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import { normalizeDirentType } from '../NormalizeDirentType/NormalizeDirentType.ts' + +export const getNewDirentsForCancelRename = (items: readonly ExplorerItem[], editingIndex: number): readonly ExplorerItem[] => { + const item = items[editingIndex] + const newItems = [...items] + newItems[editingIndex] = { + ...item, + type: normalizeDirentType(item.type), + } + return newItems +} diff --git a/packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts b/packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts new file mode 100644 index 0000000..b475ee6 --- /dev/null +++ b/packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts @@ -0,0 +1,50 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import { getNewChildDirentsForNewDirent } from '../GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts' + +export const getNewDirentsForNewDirent = async ( + items: readonly ExplorerItem[], + focusedIndex: number, + type: number, + root: string, +): Promise => { + if (items.length === 0 || focusedIndex === -1) { + const newDirent: ExplorerItem = { + depth: 0, + icon: '', + name: '', + path: root, + posInSet: 1, + selected: false, + setSize: 1, + type, + } + return [...items, newDirent] + } + + const focusedItem = items[focusedIndex] + if (!focusedItem) { + return items + } + const parentPath = focusedItem.path + const depth = focusedItem.depth + 1 + + const updatedChildren = await getNewChildDirentsForNewDirent(items, depth, parentPath, type) + + // Create new array with updated items + const parentIndex = focusedIndex + const itemsBeforeParent = items.slice(0, parentIndex) + const itemsAfterChildren = items.slice(parentIndex + updatedChildren.length) + + let updatedParent = { + ...items[parentIndex], + setSize: (items[parentIndex]?.setSize || 0) + 1, + } + + // If the parent is a closed Directory, expand it + if (updatedParent.type === DirentType.Directory) { + updatedParent = { ...updatedParent, type: DirentType.DirectoryExpanded } + } + + return [...itemsBeforeParent, updatedParent, ...updatedChildren, ...itemsAfterChildren] +} diff --git a/packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts b/packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts new file mode 100644 index 0000000..6d28838 --- /dev/null +++ b/packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts @@ -0,0 +1,15 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as GetEditingType from '../GetEditingType/GetEditingType.ts' + +export const getNewDirentsForRename = (items: readonly ExplorerItem[], focusedIndex: number): readonly ExplorerItem[] => { + const item = items[focusedIndex] + const editingType = GetEditingType.getEditingType(item.type) + return [ + ...items.slice(0, focusedIndex), + { + ...item, + type: editingType, + }, + ...items.slice(focusedIndex + 1), + ] +} diff --git a/packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts b/packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts new file mode 100644 index 0000000..286b39e --- /dev/null +++ b/packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts @@ -0,0 +1,24 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as CanBeDroppedInto from '../CanBeDroppedInto/CanBeDroppedInto.ts' +import { countInRange } from '../CountInRange/CountInRange.ts' +import { dropTargetFull } from '../DropTargetFull/DropTargetFull.ts' +import { getParentEndIndex } from '../GetParentEndIndex/GetParentEndIndex.ts' +import { getParentStartIndex } from '../GetParentStartIndex/GetParentStartIndex.ts' + +export const getNewDropTargets = (state: ExplorerState, index: number): readonly number[] => { + const { items } = state + if (index === -1) { + return dropTargetFull + } + const item = items[index] + if (!item) { + return dropTargetFull + } + if (!CanBeDroppedInto.canBeDroppedInto(item)) { + const startIndex = getParentStartIndex(items, index) + const endIndex = getParentEndIndex(items, index) + return countInRange(startIndex, endIndex) + } + const newDropTargets = [index] + return newDropTargets +} diff --git a/packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts b/packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts new file mode 100644 index 0000000..e51d3f2 --- /dev/null +++ b/packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts @@ -0,0 +1,9 @@ +// TODO optimize this function to return the minimum number +// of visible items needed, e.g. when not scrolled 5 items with +// 20px fill 100px but when scrolled 6 items are needed +export const getNumberOfVisibleItems = (listHeight: number, itemHeight: number): number => { + if (listHeight <= 0 || itemHeight <= 0) { + return 0 + } + return Math.ceil(listHeight / itemHeight) + 1 +} diff --git a/packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts b/packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts new file mode 100644 index 0000000..53b44f2 --- /dev/null +++ b/packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts @@ -0,0 +1,11 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const getParentEndIndex = (dirents: readonly ExplorerItem[], index: number): number => { + const dirent = dirents[index] + const { depth } = dirent + let endIndex = index + 1 + while (endIndex < dirents.length && dirents[endIndex].depth > depth) { + endIndex++ + } + return endIndex +} diff --git a/packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts b/packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts new file mode 100644 index 0000000..0b1bbaa --- /dev/null +++ b/packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts @@ -0,0 +1,22 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import { dirname } from '../Path/Path.ts' + +const isFileLike = (type: number): boolean => { + return type === DirentType.File || type === DirentType.SymLinkFile +} + +export const getParentFolder = (dirents: readonly ExplorerItem[], index: number, root: string, pathSeparator: string): string => { + if (index < 0) { + return root + } + const item = dirents[index] + if (!item) { + return root + } + if (isFileLike(item.type)) { + const parentFolder = dirname(pathSeparator, item.path) + return parentFolder || root + } + return item.path +} diff --git a/packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts b/packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts new file mode 100644 index 0000000..9af0262 --- /dev/null +++ b/packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts @@ -0,0 +1,10 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const getParentStartIndex = (dirents: readonly ExplorerItem[], index: number): number => { + const dirent = dirents[index] + let startIndex = index - 1 + while (startIndex >= 0 && dirents[startIndex].depth >= dirent.depth) { + startIndex-- + } + return startIndex +} diff --git a/packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts b/packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts new file mode 100644 index 0000000..99857da --- /dev/null +++ b/packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts @@ -0,0 +1,18 @@ +import type { PasteHandler } from '../PasteHandler/PasteHandler.ts' +import * as HandlePasteCopy from '../HandlePasteCopy/HandlePasteCopy.ts' +import * as HandlePasteCut from '../HandlePasteCut/HandlePasteCut.ts' +import * as HandlePasteNone from '../HandlePasteNone/HandlePasteNone.ts' +import * as NativeFileTypes from '../NativeFileTypes/NativeFileTypes.ts' + +export const getPasteHandler = (type: string): PasteHandler => { + switch (type) { + case NativeFileTypes.Copy: + return HandlePasteCopy.handlePasteCopy + case NativeFileTypes.Cut: + return HandlePasteCut.handlePasteCut + case NativeFileTypes.None: + return HandlePasteNone.handlePasteNone + default: + throw new Error(`unexpected native paste type: ${type}`) + } +} diff --git a/packages/explorer-view/src/parts/GetPath/GetPath.ts b/packages/explorer-view/src/parts/GetPath/GetPath.ts new file mode 100644 index 0000000..769968b --- /dev/null +++ b/packages/explorer-view/src/parts/GetPath/GetPath.ts @@ -0,0 +1,5 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const getPath = (item: ExplorerItem): string => { + return item.path +} diff --git a/packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts b/packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts new file mode 100644 index 0000000..1d1544c --- /dev/null +++ b/packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts @@ -0,0 +1,17 @@ +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' + +export const getPathDirentsMap = async (allPaths: readonly string[]): Promise> => { + const pathToDirents: Record = Object.create(null) + await Promise.all( + allPaths.map(async (path) => { + try { + const dirents = await FileSystem.readDirWithFileTypes(path) + pathToDirents[path] = dirents + } catch { + // ignore + } + }), + ) + return pathToDirents +} diff --git a/packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts b/packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts new file mode 100644 index 0000000..25bdc2c --- /dev/null +++ b/packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts @@ -0,0 +1,18 @@ +import type { PathPart } from '../PathPart/PathPart.ts' + +export const getPathParts = (root: string, uri: string, pathSeparator: string): readonly PathPart[] => { + const parts: PathPart[] = [] + let index = root.length - 1 + let depth = 0 + while ((index = uri.indexOf(pathSeparator, index + 1)) !== -1) { + const partUri = uri.slice(0, index) + parts.push({ + depth: depth++, + expanded: true, + path: partUri, + pathSeparator, + root, + }) + } + return parts +} diff --git a/packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts b/packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts new file mode 100644 index 0000000..129aef2 --- /dev/null +++ b/packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts @@ -0,0 +1,16 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { PathPart } from '../PathPart/PathPart.ts' +import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' +import { orderDirents } from '../OrderDirents/OrderDirents.ts' + +const getPathPartChildren = async (pathPart: PathPart): Promise => { + const children = await getChildDirents(pathPart.pathSeparator, pathPart.path, pathPart.depth) + return children +} + +export const getPathPartsChildren = async (pathparts: readonly PathPart[]): Promise => { + const pathPartsChildren = await Promise.all(pathparts.map(getPathPartChildren)) + const pathPartsChildrenFlat = pathPartsChildren.flat() + const orderedPathParts = orderDirents(pathPartsChildrenFlat) + return orderedPathParts +} diff --git a/packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts b/packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts new file mode 100644 index 0000000..947fa03 --- /dev/null +++ b/packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts @@ -0,0 +1,20 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import * as Path from '../Path/Path.ts' + +const getPathPartUpdate = (operation: FileOperation): string => { + switch (operation.type) { + case FileOperationType.CreateFile: + return Path.dirname2(operation.path) + case FileOperationType.CreateFolder: + return Path.dirname2(operation.path) + case FileOperationType.Rename: + return Path.dirname2(operation.path) + default: + return '' + } +} + +export const getPathPartsFromFileOperations = (operations: readonly FileOperation[]): readonly string[] => { + return operations.map(getPathPartUpdate).filter(Boolean) +} diff --git a/packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts b/packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts new file mode 100644 index 0000000..36c8354 --- /dev/null +++ b/packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts @@ -0,0 +1,15 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { PathPart } from '../PathPart/PathPart.ts' +import { getIndex } from '../GetIndex/GetIndex.ts' + +export const getPathPartsToReveal = (root: string, pathParts: readonly PathPart[], dirents: readonly ExplorerItem[]): readonly PathPart[] => { + for (let i = 0; i < pathParts.length; i++) { + const pathPart = pathParts[i] + const index = getIndex(dirents, pathPart.path) + if (index === -1) { + continue + } + return pathParts.slice(i) + } + return pathParts +} diff --git a/packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts b/packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts new file mode 100644 index 0000000..e63932d --- /dev/null +++ b/packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts @@ -0,0 +1,5 @@ +import * as FileSystem from '../FileSystem/FileSystem.ts' + +export const getPathSeparator = async (root: string): Promise => { + return FileSystem.getPathSeparator(root) +} diff --git a/packages/explorer-view/src/parts/GetPaths/GetPaths.ts b/packages/explorer-view/src/parts/GetPaths/GetPaths.ts new file mode 100644 index 0000000..b3d8288 --- /dev/null +++ b/packages/explorer-view/src/parts/GetPaths/GetPaths.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import { getPath } from '../GetPath/GetPath.ts' + +export const getPaths = (items: readonly ExplorerItem[]): readonly string[] => { + return items.map(getPath) +} diff --git a/packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts b/packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts new file mode 100644 index 0000000..5ad91ea --- /dev/null +++ b/packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts @@ -0,0 +1,11 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import { getProtoMapInternal } from '../GetProtoMapInternal/GetProtoMapInternal.ts' + +export const getProtoMap = ( + root: string, + pathToDirents: Record, + expandedPaths: readonly string[], +): readonly ExplorerItem[] => { + return getProtoMapInternal(root, pathToDirents, expandedPaths, 1) +} diff --git a/packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts b/packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts new file mode 100644 index 0000000..e6aca27 --- /dev/null +++ b/packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts @@ -0,0 +1,34 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import { join2 } from '../Path/Path.ts' +import { restoreDirentType } from '../RestoreDirentType/RestoreDirentType.ts' + +export const getProtoMapInternal = ( + root: string, + pathToDirents: Record, + expandedPaths: readonly string[], + depth: number, +): readonly ExplorerItem[] => { + if (!(root in pathToDirents)) { + return [] + } + const items = pathToDirents[root] || [] + const protoMap: ExplorerItem[] = [] + for (let i = 0; i < items.length; i++) { + const item = items[i] + const path = join2(root, item.name) + const displayDirent: ExplorerItem = { + depth, + icon: '', + name: item.name, + path, + posInSet: i + 1, + selected: false, + setSize: items.length, + type: restoreDirentType(item.type, path, expandedPaths), + } + const children = getProtoMapInternal(path, pathToDirents, expandedPaths, depth + 1) + protoMap.push(displayDirent, ...children) + } + return protoMap +} diff --git a/packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts b/packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts new file mode 100644 index 0000000..9de6d33 --- /dev/null +++ b/packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts @@ -0,0 +1,15 @@ +import type { Selection } from '../Selection/Selection.ts' + +export const getRenameSelectionRange = (name: string): Selection => { + const dotIndex = name.lastIndexOf('.') + if (dotIndex === -1) { + return { + end: name.length, + start: 0, + } + } + return { + end: dotIndex, + start: 0, + } +} diff --git a/packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts b/packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts new file mode 100644 index 0000000..35d6a3d --- /dev/null +++ b/packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts @@ -0,0 +1,33 @@ +import type { Renderer } from '../Renderer/Renderer.ts' +import * as DiffType from '../DiffType/DiffType.ts' +import { renderCss } from '../RenderCss/RenderCss.ts' +import * as RenderDragData from '../RenderDragData/RenderDragData.ts' +import * as RenderEditingSelection from '../RenderEditingSelection/RenderEditingSelection.ts' +import * as RenderFocus from '../RenderFocus/RenderFocus.ts' +import * as RenderFocusContext from '../RenderFocusContext/RenderFocusContext.ts' +import { renderIncremental } from '../RenderIncremental/RenderIncremental.ts' +import * as RenderItems from '../RenderItems/RenderItems.ts' +import * as RenderValue from '../RenderValue/RenderValue.ts' + +export const getRenderer = (diffType: number): Renderer => { + switch (diffType) { + case DiffType.RenderCss: + return renderCss + case DiffType.RenderDragData: + return RenderDragData.renderDragData + case DiffType.RenderFocus: + return RenderFocus.renderFocus + case DiffType.RenderFocusContext: + return RenderFocusContext.renderFocusContext + case DiffType.RenderIncremental: + return renderIncremental + case DiffType.RenderItems: + return RenderItems.renderItems + case DiffType.RenderSelection: + return RenderEditingSelection.renderEditingSelection + case DiffType.RenderValue: + return RenderValue.renderValue + default: + throw new Error('unknown renderer') + } +} diff --git a/packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts b/packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts new file mode 100644 index 0000000..61280e7 --- /dev/null +++ b/packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts @@ -0,0 +1,6 @@ +export const getRestoredDeltaY = (savedState: any): number => { + if (savedState && typeof savedState.deltaY === 'number') { + return savedState.deltaY + } + return 0 +} diff --git a/packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts b/packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts new file mode 100644 index 0000000..4ab91bd --- /dev/null +++ b/packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts @@ -0,0 +1,48 @@ +import * as DirentType from '../DirentType/DirentType.ts' +import * as SortExplorerItems from '../SortExplorerItems/SortExplorerItems.ts' + +export const getSavedChildDirents = (map: any, path: any, depth: any, excluded: any, pathSeparator: any): readonly any[] => { + let children = map[path] + if (!children) { + return [] + } + const dirents = [] + children = SortExplorerItems.sortExplorerItems(children) + const visible = [] + const displayRoot = path.endsWith(pathSeparator) ? path : path + pathSeparator + for (const child of children) { + if (excluded.includes(child.name)) { + continue + } + visible.push(child) + } + const visibleLength = visible.length + for (let i = 0; i < visibleLength; i++) { + const child = visible[i] + const { name, type } = child + const childPath = displayRoot + name + if ((child.type === DirentType.Directory || child.type === DirentType.SymLinkFolder) && childPath in map) { + dirents.push({ + depth, + icon: '', + name, + path: childPath, + posInSet: i + 1, + setSize: visibleLength, + type: DirentType.DirectoryExpanded, + }) + dirents.push(...getSavedChildDirents(map, childPath, depth + 1, excluded, pathSeparator)) + } else { + dirents.push({ + depth, + icon: '', + name, + path: childPath, + posInSet: i + 1, + setSize: visibleLength, + type, + }) + } + } + return dirents +} diff --git a/packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts b/packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts new file mode 100644 index 0000000..a85dde0 --- /dev/null +++ b/packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts @@ -0,0 +1,3 @@ +export const getSavedRoot = (savedState: any, workspacePath: string): string => { + return workspacePath +} diff --git a/packages/explorer-view/src/parts/GetScheme/GetScheme.ts b/packages/explorer-view/src/parts/GetScheme/GetScheme.ts new file mode 100644 index 0000000..199fefa --- /dev/null +++ b/packages/explorer-view/src/parts/GetScheme/GetScheme.ts @@ -0,0 +1,9 @@ +const RE_PROTOCOL = /^[a-z+]:\/\// + +export const getScheme = (uri: string): string => { + const match = uri.match(RE_PROTOCOL) + if (!match) { + return '' + } + return match[0] +} diff --git a/packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts b/packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts new file mode 100644 index 0000000..de2c610 --- /dev/null +++ b/packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts @@ -0,0 +1,6 @@ +export const getScrollBarSize = (size: number, contentSize: number, minimumSliderSize: number): number => { + if (size >= contentSize) { + return 0 + } + return Math.max(Math.round(size ** 2 / contentSize), minimumSliderSize) +} diff --git a/packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts b/packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts new file mode 100644 index 0000000..16fa46b --- /dev/null +++ b/packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts @@ -0,0 +1,10 @@ +export const getScrollBarTop = (height: number, contentHeight: number, scrollTop: number): number => { + if (contentHeight <= 0 || !Number.isFinite(contentHeight)) { + return 0 + } + const scrollBarTop = Math.round((scrollTop / contentHeight) * height) + if (!Number.isFinite(scrollBarTop)) { + return 0 + } + return scrollBarTop +} diff --git a/packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts b/packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts new file mode 100644 index 0000000..9c77e66 --- /dev/null +++ b/packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts @@ -0,0 +1,23 @@ +import type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker' +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' +import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' + +export const getScrollBarVirtualDom = (scrollBarHeight: number): readonly VirtualDomNode[] => { + const shouldShowScrollbar = scrollBarHeight > 0 + if (!shouldShowScrollbar) { + return [] + } + return [ + { + childCount: 1, + className: MergeClassNames.mergeClassNames(ClassNames.ScrollBar, ClassNames.ScrollBarSmall), + type: VirtualDomElements.Div, + }, + { + childCount: 0, + className: ClassNames.ScrollBarThumb, + type: VirtualDomElements.Div, + }, + ] +} diff --git a/packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts b/packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts new file mode 100644 index 0000000..fe3b270 --- /dev/null +++ b/packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts @@ -0,0 +1,7 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const getSelectedItems = (items: readonly ExplorerItem[], focusedIndex: number): readonly ExplorerItem[] => { + const dirent = items[focusedIndex] + const selectedItems = items.filter((item) => item.selected || item === dirent) + return selectedItems +} diff --git a/packages/explorer-view/src/parts/GetSettings/GetSettings.ts b/packages/explorer-view/src/parts/GetSettings/GetSettings.ts new file mode 100644 index 0000000..9c93461 --- /dev/null +++ b/packages/explorer-view/src/parts/GetSettings/GetSettings.ts @@ -0,0 +1,21 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { Settings } from '../Settings/Settings.ts' + +export const getSettings = async (): Promise => { + // TODO don't return false always + // TODO get all settings at once + const useChevronsRaw = await RendererWorker.invoke('Preferences.get', 'explorer.useChevrons') + const useChevrons = useChevronsRaw === false ? false : true + const confirmDeleteRaw = await RendererWorker.invoke('Preferences.get', 'explorer.confirmdelete') + const confirmDelete = confirmDeleteRaw === false ? false : false + const confirmPasteRaw = await RendererWorker.invoke('Preferences.get', 'explorer.confirmpaste') + const confirmPaste = confirmPasteRaw === false ? false : false + const sourceControlDecorationsRaw = await RendererWorker.invoke('Preferences.get', 'explorer.sourceControlDecorations') + const sourceControlDecorations = sourceControlDecorationsRaw === false ? false : true + return { + confirmDelete, + confirmPaste, + sourceControlDecorations, + useChevrons, + } +} diff --git a/packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts b/packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts new file mode 100644 index 0000000..b2b0e1f --- /dev/null +++ b/packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts @@ -0,0 +1,20 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const getSiblingFileNames = (items: readonly ExplorerItem[], focusedIndex: number, root: string, pathSeparator: string): readonly string[] => { + if (focusedIndex < 0 || focusedIndex >= items.length) { + // If no focused item or invalid index, get root level items + return items.filter((item) => item.depth === 0).map((item) => item.name) + } + + const focusedItem = items[focusedIndex] + const nameLength = focusedItem.name ? focusedItem.name.length + 1 : 0 + const focusedItemParentPath = focusedItem.path.slice(0, -nameLength) + + // Find all items that are direct children of the same parent as the focused item + const siblingItems = items.filter((item) => { + const itemParentPath = item.path.slice(0, -nameLength) + return itemParentPath === focusedItemParentPath + }) + + return siblingItems.map((item) => item.name) +} diff --git a/packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts b/packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts new file mode 100644 index 0000000..2335cab --- /dev/null +++ b/packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts @@ -0,0 +1,13 @@ +import * as DirentType from '../DirentType/DirentType.ts' + +export const getSimpleIconRequestType = (direntType: number): 1 | 2 => { + if ( + direntType === DirentType.Directory || + direntType === DirentType.DirectoryExpanded || + direntType === DirentType.EditingDirectoryExpanded || + direntType === DirentType.EditingFolder + ) { + return 2 + } + return 1 +} diff --git a/packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts b/packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts new file mode 100644 index 0000000..1444024 --- /dev/null +++ b/packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts @@ -0,0 +1,12 @@ +import * as DirentType from '../DirentType/DirentType.ts' + +export const getSymlinkType = (type: number): number => { + switch (type) { + case DirentType.Directory: + return DirentType.SymLinkFolder + case DirentType.File: + return DirentType.SymLinkFile + default: + return DirentType.Symlink + } +} diff --git a/packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts b/packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts new file mode 100644 index 0000000..e61d775 --- /dev/null +++ b/packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts @@ -0,0 +1,8 @@ +import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' + +export const getTopLevelDirents = (root: string, pathSeparator: string, excluded: any[]): any => { + if (!root) { + return [] + } + return getChildDirents(pathSeparator, root, 0, excluded) +} diff --git a/packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts b/packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts new file mode 100644 index 0000000..b6db63a --- /dev/null +++ b/packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts @@ -0,0 +1,24 @@ +import * as ClassNames from '../ClassNames/ClassNames.ts' +import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' + +export const getTreeItemClassName = ( + isSelected: boolean, + isFocused: boolean, + isDropping: boolean, + useChevrons: boolean, + indent: number, + decoration: string, +): string => { + let className = ClassNames.TreeItem + className = MergeClassNames.mergeClassNames(className, `Indent-${indent}`) + if (isSelected || isFocused) { + className = MergeClassNames.mergeClassNames(className, ClassNames.TreeItemActive) + } + if (isDropping) { + className = MergeClassNames.mergeClassNames(className, 'DropTarget') + } + if (decoration) { + className = MergeClassNames.mergeClassNames(className, `decoration-${decoration}`) + } + return className +} diff --git a/packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts b/packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts new file mode 100644 index 0000000..27b8c79 --- /dev/null +++ b/packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts @@ -0,0 +1,5 @@ +const defaultIndent = 12 + +export const getTreeItemIndent = (depth: number): number => { + return depth * defaultIndent +} diff --git a/packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts b/packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts new file mode 100644 index 0000000..012821a --- /dev/null +++ b/packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts @@ -0,0 +1,13 @@ +// TODO make all of these variable configurable +const defaultPaddingLeft = 4 + +const defaultIndent = 8 + +// TODO make chevron size configurable +const chevronSize = 22 + +export const getTreeItemIndentWithChevron = (depth: number, chevron: number): number => { + // TODO use numeric value here, convert to string value in renderer process + const extraSpace = chevron ? 0 : chevronSize + return depth * defaultIndent + extraSpace + defaultPaddingLeft +} diff --git a/packages/explorer-view/src/parts/GetUnique/GetUnique.ts b/packages/explorer-view/src/parts/GetUnique/GetUnique.ts new file mode 100644 index 0000000..4074d44 --- /dev/null +++ b/packages/explorer-view/src/parts/GetUnique/GetUnique.ts @@ -0,0 +1,9 @@ +export const getUnique = (items: readonly number[]): readonly number[] => { + const seens: number[] = [] + for (const item of items) { + if (!seens.includes(item)) { + seens.push(item) + } + } + return seens +} diff --git a/packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts b/packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts new file mode 100644 index 0000000..fbf57f4 --- /dev/null +++ b/packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts @@ -0,0 +1,10 @@ +import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' +import { getUnique } from '../GetUnique/GetUnique.ts' + +const getIndent = (item: VisibleExplorerItem): number => item.indent + +export const getUniqueIndents = (items: readonly VisibleExplorerItem[]): readonly number[] => { + const indents = items.map(getIndent) + const uniqueIndents = getUnique(indents) + return uniqueIndents +} diff --git a/packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts b/packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts new file mode 100644 index 0000000..589cb85 --- /dev/null +++ b/packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts @@ -0,0 +1,84 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' +import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' +import * as ChevronType from '../ChevronType/ChevronType.ts' +import { createDecorationMap } from '../CreateDecorationMap/CreateDecorationMap.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as GetChevronType from '../GetChevronType/GetChevronType.ts' +import * as GetExpandedType from '../GetExpandedType/GetExpandedType.ts' +import { getTreeItemClassName } from '../GetTreeItemClassName/GetTreeItemClassName.ts' +import * as GetTreeItemIndent from '../GetTreeItemIndent/GetTreeItemIndent.ts' +import * as GetTreeItemIndentWithChevron from '../GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts' + +const ariaExpandedValues: (string | undefined)[] = [undefined, 'true', 'false'] + +const getEditingChevron = (direntType: number): number => { + switch (direntType) { + case DirentType.EditingDirectoryExpanded: + return ChevronType.Down + case DirentType.EditingFolder: + return ChevronType.Right + default: + return ChevronType.None + } +} + +export const getVisibleExplorerItems = ( + items: readonly ExplorerItem[], + minLineY: number, + maxLineY: number, + focusedIndex: number, + editingIndex: number, + editingErrorMessage: string, + icons: readonly string[], + useChevrons: boolean, + dropTargets: readonly number[], + editingIcon: string, + cutItems: readonly string[], + sourceControlIgnoredUris: readonly string[] = [], + decorations: readonly FileDecoration[], +): readonly VisibleExplorerItem[] => { + const decorationMap = createDecorationMap(decorations) + const visible: VisibleExplorerItem[] = [] + const indentFn = useChevrons ? GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron : GetTreeItemIndent.getTreeItemIndent + let iconIndex = 0 + for (let i = minLineY; i < Math.min(maxLineY, items.length); i++) { + const item = items[i] + let chevron = GetChevronType.getChevronType(item.type, useChevrons) + const isEditing = i === editingIndex + let icon = icons[iconIndex++] + if (isEditing) { + icon = editingIcon + chevron = getEditingChevron(item.type) + } + const isFocused = i === focusedIndex + const id = isFocused ? 'TreeItemActive' : undefined + const isSelected = item.selected + const isCut = cutItems.includes(item.path) + const isDropping = dropTargets.includes(i) + const isIgnored = sourceControlIgnoredUris.includes(item.path) + const indent = indentFn(item.depth, chevron) + const decoration = decorationMap[item.path] || '' + const className = getTreeItemClassName(isSelected, isFocused, isDropping, useChevrons, indent, decoration) + const expanded = GetExpandedType.getExpandedType(item.type) + const ariaExpanded = ariaExpandedValues[expanded] + visible.push({ + ...item, + ariaExpanded, + chevron, + className, + decoration, + hasEditingError: isEditing && Boolean(editingErrorMessage), + icon, + id, + indent, + index: i, + isCut, + isEditing: isEditing, + isIgnored, + posInSet: item.posInSet ?? i + 1, + setSize: item.setSize ?? items.length, + }) + } + return visible +} diff --git a/packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts b/packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts new file mode 100644 index 0000000..8acd6e7 --- /dev/null +++ b/packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts @@ -0,0 +1,5 @@ +import { RendererWorker as Rpc } from '@lvce-editor/rpc-registry' + +export const getWorkspacePath = (): Promise => { + return Rpc.invoke('Workspace.getPath') +} diff --git a/packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts b/packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts new file mode 100644 index 0000000..bb923f8 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts @@ -0,0 +1,23 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as FocusParentFolder from '../FocusParentFolder/FocusParentFolder.ts' +import * as HandleClickDirectoryExpanded from '../HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' + +export const handleArrowLeft = (state: ExplorerState): ExplorerState | Promise => { + const { focusedIndex, items } = state + if (focusedIndex === -1) { + return state + } + const dirent = items[focusedIndex] + switch (dirent.type) { + case DirentType.Directory: + case DirentType.File: + case DirentType.SymLinkFile: + return FocusParentFolder.focusParentFolder(state) + case DirentType.DirectoryExpanded: + return HandleClickDirectoryExpanded.handleClickDirectoryExpanded(state, dirent, focusedIndex, true) + default: + // TODO handle expanding directory and cancel file system call to read child dirents + return state + } +} diff --git a/packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts b/packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts new file mode 100644 index 0000000..28e9fa9 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts @@ -0,0 +1,28 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as HandleArrowRightDirectoryExpanded from '../HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts' +import * as HandleClickDirectory from '../HandleClickDirectory/HandleClickDirectory.ts' +import * as HandleClickSymlink from '../HandleClickSymlink/HandleClickSymlink.ts' + +export const handleArrowRight = async (state: ExplorerState): Promise => { + const { focusedIndex, items } = state + if (focusedIndex === -1) { + return state + } + const dirent = items[focusedIndex] + switch (dirent.type) { + case DirentType.Directory: + case DirentType.SymLinkFolder: + // @ts-ignore + return HandleClickDirectory.handleClickDirectory(state, dirent, focusedIndex) + case DirentType.DirectoryExpanded: + return HandleArrowRightDirectoryExpanded.handleArrowRightDirectoryExpanded(state, dirent) + case DirentType.File: + case DirentType.SymLinkFile: + return state + case DirentType.Symlink: + return HandleClickSymlink.handleClickSymLink(state, dirent, focusedIndex) + default: + throw new Error(`unsupported file type ${dirent.type}`) + } +} diff --git a/packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts b/packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts new file mode 100644 index 0000000..115545a --- /dev/null +++ b/packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts @@ -0,0 +1,14 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusIndex from '../FocusIndex/FocusIndex.ts' + +export const handleArrowRightDirectoryExpanded = (state: ExplorerState, dirent: any): ExplorerState => { + const { focusedIndex, items } = state + if (focusedIndex === items.length - 1) { + return state + } + const nextDirent = items[focusedIndex + 1] + if (nextDirent.depth === dirent.depth + 1) { + return FocusIndex.focusIndex(state, focusedIndex + 1) + } + return state +} diff --git a/packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts b/packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts new file mode 100644 index 0000000..db76f3a --- /dev/null +++ b/packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts @@ -0,0 +1,18 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleBlur = async (state: ExplorerState): Promise => { + // TODO when blur event occurs because of context menu, focused index should stay the same + // but focus outline should be removed + const { items } = state + const newItems = items.map((item) => { + return { + ...item, + selected: false, + } + }) + return { + ...state, + focused: false, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts b/packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts new file mode 100644 index 0000000..bf4acdf --- /dev/null +++ b/packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts @@ -0,0 +1,21 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { collapseAll } from '../CollapseAll/CollapseAll.ts' +import * as InputName from '../InputName/InputName.ts' +import { newFile } from '../NewFile/NewFile.ts' +import { newFolder } from '../NewFolder/NewFolder.ts' +import { refresh } from '../Refresh/Refresh.ts' + +export const handleButtonClick = async (state: ExplorerState, name: string): Promise => { + switch (name) { + case InputName.CollapseAll: + return collapseAll(state) + case InputName.NewFile: + return newFile(state) + case InputName.NewFolder: + return newFolder(state) + case InputName.Refresh: + return refresh(state) + default: + return state + } +} diff --git a/packages/explorer-view/src/parts/HandleClick/HandleClick.ts b/packages/explorer-view/src/parts/HandleClick/HandleClick.ts new file mode 100644 index 0000000..83df8e7 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClick/HandleClick.ts @@ -0,0 +1,49 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusIndex from '../FocusIndex/FocusIndex.ts' +import * as GetClickFn from '../GetClickFn/GetClickFn.ts' +import { normalizeDirentType } from '../NormalizeDirentType/NormalizeDirentType.ts' +import { resetEditing } from '../ResetEditing/ResetEditing.ts' +// TODO viewlet should only have create and refresh functions +// every thing else can be in a separate module .lazy.js +// and .ipc.js + +// viewlet: creating | refreshing | done | disposed +// TODO recycle viewlets (maybe) + +// TODO instead of root string, there should be a root dirent + +// TODO rename dirents to items, then can use virtual list component directly + +// TODO use posInSet and setSize properties to compute more effectively + +// TODO much shared logic with newFolder + +export const handleClick = async (state: ExplorerState, index: number, keepFocus = false): Promise => { + const { items } = state + if (index === -1) { + return FocusIndex.focusIndex(state, -1) + } + const actualIndex = index + const dirent = items[actualIndex] + if (!dirent) { + console.warn(`[explorer] dirent at index ${actualIndex} not found`, state) + return state + } + const normalizedType = normalizeDirentType(dirent.type) + const clickFn = GetClickFn.getClickFn(normalizedType) + const newState = await clickFn(state, dirent, actualIndex, keepFocus) + if (newState.editingIndex === -1) { + return newState + } + return { + ...newState, + ...resetEditing, + } +} + +// export const handleBlur=()=>{} + +// TODO what happens when mouse leave and anther mouse enter event occur? +// should update preview instead of closing and reopening + +// TODO maybe just insert items into explorer and refresh whole explorer diff --git a/packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts b/packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts new file mode 100644 index 0000000..ef63190 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts @@ -0,0 +1,32 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusIndex from '../FocusIndex/FocusIndex.ts' +import * as GetIndexFromPosition from '../GetIndexFromPosition/GetIndexFromPosition.ts' +import * as HandleClick from '../HandleClick/HandleClick.ts' +import * as HandleClickAtRangeSelection from '../HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts' +import * as MouseEventType from '../MouseEventType/MouseEventType.ts' +import { toggleIndividualSelection } from '../ToggleIndividualSelection/ToggleIndividualSelection.ts' + +export const handleClickAt = async ( + state: ExplorerState, + defaultPrevented: boolean, + button: number, + ctrlKey: boolean, + shiftKey: boolean, + eventX: number, + eventY: number, +): Promise => { + if (defaultPrevented || button !== MouseEventType.LeftClick) { + return state + } + const index = GetIndexFromPosition.getIndexFromPosition(state, eventX, eventY) + if (index === -1 || index >= state.items.length) { + return FocusIndex.focusIndex(state, -1) + } + if (shiftKey) { + return HandleClickAtRangeSelection.handleClickAtRangeSelection(state, index) + } + if (ctrlKey) { + return toggleIndividualSelection(state, index) + } + return HandleClick.handleClick(state, index) +} diff --git a/packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts b/packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts new file mode 100644 index 0000000..9cceeda --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as HandleRangeSelection from '../HandleRangeSelection/HandleRangeSelection.ts' + +export const handleClickAtRangeSelection = async (state: ExplorerState, index: number): Promise => { + const { items } = state + const firstSelectedIndex = items.findIndex((item) => item.selected) + if (firstSelectedIndex === -1) { + return HandleRangeSelection.handleRangeSelection(state, index, index) + } + const min = Math.min(firstSelectedIndex, index) + const max = Math.min(firstSelectedIndex, index) + return HandleRangeSelection.handleRangeSelection(state, min, max) +} diff --git a/packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts b/packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts new file mode 100644 index 0000000..1d22e5b --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as HandleClick from '../HandleClick/HandleClick.ts' + +export const handleClickCurrent = (state: ExplorerState): Promise => { + return HandleClick.handleClick(state, state.focusedIndex - state.minLineY, /* keepFocus */ false) +} diff --git a/packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts b/packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts new file mode 100644 index 0000000..07afc99 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as HandleClick from '../HandleClick/HandleClick.ts' + +export const handleClickCurrentButKeepFocus = (state: ExplorerState): Promise => { + return HandleClick.handleClick(state, state.focusedIndex - state.minLineY, /* keepFocus */ true) +} diff --git a/packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts b/packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts new file mode 100644 index 0000000..a0fd062 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts @@ -0,0 +1,37 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' + +export const handleClickDirectory = async (state: ExplorerState, dirent: ExplorerItem, index: number, keepFocus: boolean): Promise => { + // @ts-ignore + dirent.type = DirentType.DirectoryExpanding + // TODO handle error + const dirents = await GetChildDirents.getChildDirents(state.pathSeparator, dirent.path, dirent.depth) + const state2 = state + if (!state2) { + return state + } + // TODO use Viewlet.getState here and check if it exists + const newIndex = state2.items.indexOf(dirent) + // TODO if viewlet is disposed or root has changed, return + if (newIndex === -1) { + return state + } + const newDirents = [...state2.items] + newDirents.splice(newIndex + 1, 0, ...dirents) + // @ts-ignore + dirent.type = DirentType.DirectoryExpanded + // @ts-ignore + dirent.icon = '' + // TODO when focused index has changed while expanding, don't update it + + return { + ...state, + focus: FocusId.List, + focused: keepFocus, + focusedIndex: newIndex, + items: newDirents, + } +} diff --git a/packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts b/packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts new file mode 100644 index 0000000..80e5ee1 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts @@ -0,0 +1,44 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as GetParentEndIndex from '../GetParentEndIndex/GetParentEndIndex.ts' + +export const handleClickDirectoryExpanded = async ( + state: ExplorerState, + dirent: ExplorerItem, + index: number, + keepFocus: boolean, +): Promise => { + const { itemHeight, items, maxLineY, minLineY } = state + // @ts-ignore + dirent.type = DirentType.Directory + // @ts-ignore + dirent.icon = '' + const endIndex = GetParentEndIndex.getParentEndIndex(items, index) + const removeCount = endIndex - index - 1 + // TODO race conditions and side effects are everywhere + const newDirents = [...items] + newDirents.splice(index + 1, removeCount) + const newTotal = newDirents.length + if (newTotal < maxLineY) { + const visibleItems = Math.min(maxLineY - minLineY, newTotal) + const newMaxLineY = Math.min(maxLineY, newTotal) + const newMinLineY = newMaxLineY - visibleItems + const deltaY = newMinLineY * itemHeight + return { + ...state, + deltaY, + focused: keepFocus, + focusedIndex: index, + items: newDirents, + maxLineY: newMaxLineY, + minLineY: newMinLineY, + } + } + return { + ...state, + focused: keepFocus, + focusedIndex: index, + items: newDirents, + } +} diff --git a/packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts b/packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts new file mode 100644 index 0000000..96af48e --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts @@ -0,0 +1,20 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const handleClickDirectoryExpanding = async ( + state: ExplorerState, + dirent: ExplorerItem, + index: number, + keepFocus: boolean, +): Promise => { + // @ts-ignore + dirent.type = DirentType.Directory + // @ts-ignore + dirent.icon = '' + return { + ...state, + focused: keepFocus, + focusedIndex: index, + } +} diff --git a/packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts b/packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts new file mode 100644 index 0000000..1d57818 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts @@ -0,0 +1,12 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as OpenUri from '../OpenUri/OpenUri.ts' + +export const handleClickFile = async (state: ExplorerState, dirent: ExplorerItem, index: number, keepFocus = false): Promise => { + await OpenUri.openUri(dirent.path, !keepFocus) + return { + ...state, + focused: keepFocus, + focusedIndex: index, + } +} diff --git a/packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts b/packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts new file mode 100644 index 0000000..39af422 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts @@ -0,0 +1,7 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as OpenFolder from '../OpenFolder/OpenFolder.ts' + +export const handleClickOpenFolder = async (state: ExplorerState): Promise => { + await OpenFolder.openFolder() + return state +} diff --git a/packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts b/packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts new file mode 100644 index 0000000..a89e4b4 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts @@ -0,0 +1,16 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' +import * as HandleClickFile from '../HandleClickFile/HandleClickFile.ts' + +export const handleClickSymLink = async (state: ExplorerState, dirent: ExplorerItem, index: number): Promise => { + const realPath = await FileSystem.getRealPath(dirent.path) + const type = await FileSystem.stat(realPath) + switch (type) { + case DirentType.File: + return HandleClickFile.handleClickFile(state, dirent, index) + default: + throw new Error(`unsupported file type ${type}`) + } +} diff --git a/packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts b/packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts new file mode 100644 index 0000000..e97155d --- /dev/null +++ b/packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts @@ -0,0 +1,8 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetContextMenuHandler from '../GetContextMenuHandler/GetContextMenuHandler.ts' + +export const handleContextMenu = async (state: ExplorerState, button: number, x: number, y: number): Promise => { + const fn = GetContextMenuHandler.getContextMenuHandler(button) + const newState = await fn(state, x, y) + return newState +} diff --git a/packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts b/packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts new file mode 100644 index 0000000..f9a20e0 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts @@ -0,0 +1,21 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as Assert from '../Assert/Assert.ts' +import * as ContextMenu from '../ContextMenu/ContextMenu.ts' +import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' +import * as MenuEntryId from '../MenuEntryId/MenuEntryId.ts' + +export const handleContextMenuAtIndex = async (state: ExplorerState, index: number, x: number, y: number): Promise => { + Assert.number(x) + Assert.number(y) + const { uid } = state + const newState: ExplorerState = { + ...state, + focused: false, + focusedIndex: index, + } + ExplorerStates.set(uid, state, newState) + await ContextMenu.show2(uid, MenuEntryId.Explorer, x, y, { + menuId: MenuEntryId.Explorer, + }) + return newState +} diff --git a/packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts b/packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts new file mode 100644 index 0000000..5a4ba29 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts @@ -0,0 +1,9 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { handleContextMenuAtIndex } from '../HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts' + +export const handleContextMenuKeyboard = async (state: ExplorerState, index: number = state.focusedIndex): Promise => { + const { itemHeight, minLineY, x, y } = state + const menuX = x + const menuY = y + (index - minLineY + 1) * itemHeight + return handleContextMenuAtIndex(state, index, menuX, menuY) +} diff --git a/packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts b/packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts new file mode 100644 index 0000000..f56b534 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts @@ -0,0 +1,11 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as Assert from '../Assert/Assert.ts' +import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' +import { handleContextMenuAtIndex } from '../HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts' + +export const handleContextMenuMouseAt = async (state: ExplorerState, x: number, y: number): Promise => { + Assert.number(x) + Assert.number(y) + const focusedIndex = getIndexFromPosition(state, x, y) + return handleContextMenuAtIndex(state, focusedIndex, x, y) +} diff --git a/packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts b/packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts new file mode 100644 index 0000000..5ba6917 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleContextMenuWelcome = (state: ExplorerState): ExplorerState => { + return state +} diff --git a/packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts b/packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts new file mode 100644 index 0000000..0e06e63 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts @@ -0,0 +1,21 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ClipBoard from '../ClipBoard/ClipBoard.ts' +import * as GetFocusedDirent from '../GetFocusedDirent/GetFocusedDirent.ts' + +export const handleCopy = async (state: ExplorerState): Promise => { + // TODO handle multiple files + // TODO if not file is selected, what happens? + const dirent = GetFocusedDirent.getFocusedDirent(state) + if (!dirent) { + console.error('[ViewletExplorer/handleCopy] no dirent selected') + return state + } + const absolutePath = dirent.path + // TODO handle copy error gracefully + const files = [absolutePath] + await ClipBoard.writeNativeFiles('copy', files) + return { + ...state, + pasteShouldMove: false, + } +} diff --git a/packages/explorer-view/src/parts/HandleCut/HandleCut.ts b/packages/explorer-view/src/parts/HandleCut/HandleCut.ts new file mode 100644 index 0000000..68e60f9 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleCut/HandleCut.ts @@ -0,0 +1,20 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ClipBoard from '../ClipBoard/ClipBoard.ts' +import { getSelectedItems } from '../GetSelectedItems/GetSelectedItems.ts' + +export const handleCut = async (state: ExplorerState): Promise => { + // TODO handle multiple files + // TODO if not file is selected, what happens? + const { focusedIndex, items } = state + const dirents = getSelectedItems(items, focusedIndex) + if (dirents.length === 0) { + return state + } + const files = dirents.map((dirent) => dirent.path) + await ClipBoard.writeNativeFiles('cut', files) + return { + ...state, + cutItems: files, + pasteShouldMove: true, + } +} diff --git a/packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts b/packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts new file mode 100644 index 0000000..2f86f3f --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts @@ -0,0 +1,11 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' +import { newFile } from '../NewFile/NewFile.ts' + +export const handleDoubleClick = async (state: ExplorerState, eventX: number, eventY: number): Promise => { + const index = getIndexFromPosition(state, eventX, eventY) + if (index !== -1) { + return state + } + return newFile(state) +} diff --git a/packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts b/packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts new file mode 100644 index 0000000..02c99fa --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts @@ -0,0 +1,8 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleDragEnd = (state: ExplorerState): ExplorerState => { + return { + ...state, + dropTargets: [], + } +} diff --git a/packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts b/packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts new file mode 100644 index 0000000..ce4a8f6 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleDragLeave = (state: ExplorerState): ExplorerState => { + return state +} diff --git a/packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts b/packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts new file mode 100644 index 0000000..d30d628 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts @@ -0,0 +1,11 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as Assert from '../Assert/Assert.ts' +import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' +import { handleDragOverIndex } from '../HandleDragOverIndex/HandleDragOverIndex.ts' + +export const handleDragOver = (state: ExplorerState, x: number, y: number): ExplorerState => { + Assert.number(x) + Assert.number(y) + const index = getIndexFromPosition(state, x, y) + return handleDragOverIndex(state, index) +} diff --git a/packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts b/packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts new file mode 100644 index 0000000..20a4f29 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts @@ -0,0 +1,15 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetNewDropTargets from '../GetNewDropTargets/GetNewDropTargets.ts' +import * as IsEqual from '../IsEqual/IsEqual.ts' + +export const handleDragOverIndex = (state: ExplorerState, index: number): ExplorerState => { + const { dropTargets } = state + const newDropTargets = GetNewDropTargets.getNewDropTargets(state, index) + if (IsEqual.isEqual(dropTargets, newDropTargets)) { + return state + } + return { + ...state, + dropTargets: newDropTargets, + } +} diff --git a/packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts b/packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts new file mode 100644 index 0000000..f551e03 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleDragStart = (state: ExplorerState): ExplorerState => { + return state +} diff --git a/packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts b/packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts new file mode 100644 index 0000000..54f9d29 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts @@ -0,0 +1,28 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getDropHandler } from '../GetDropHandler/GetDropHandler.ts' +import * as GetFileArray from '../GetFileArray/GetFileArray.ts' +import { getFileHandles } from '../GetFileHandles/GetFileHandles.ts' +import { getFilePaths } from '../GetFilePaths/GetFilePaths.ts' +import * as GetIndexFromPosition from '../GetIndexFromPosition/GetIndexFromPosition.ts' +import { VError } from '../VError/VError.ts' + +export const handleDrop = async ( + state: ExplorerState, + x: number, + y: number, + fileIds: readonly number[], + fileList: FileList, +): Promise => { + try { + const { platform } = state + const files = GetFileArray.getFileArray(fileList) + const fileHandles = await getFileHandles(fileIds) + const paths = await getFilePaths(files, platform) + const index = GetIndexFromPosition.getIndexFromPosition(state, x, y) + const fn = getDropHandler(index) + const result = await fn(state, fileHandles, files, paths, index) + return result + } catch (error) { + throw new VError(error, 'Failed to drop files') + } +} diff --git a/packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts b/packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts new file mode 100644 index 0000000..88d0391 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts @@ -0,0 +1,90 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' +import * as GetParentStartIndex from '../GetParentStartIndex/GetParentStartIndex.ts' +import * as HandleDropRoot from '../HandleDropRoot/HandleDropRoot.ts' +import { uploadFileSystemHandles } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' + +const getEndIndex = (items: readonly ExplorerItem[], index: number, dirent: ExplorerItem): number => { + for (let i = index + 1; i < items.length; i++) { + if (items[i].depth === dirent.depth) { + return i + } + } + return items.length +} + +const getMergedDirents = ( + items: readonly ExplorerItem[], + index: number, + dirent: ExplorerItem, + childDirents: readonly ExplorerItem[], +): readonly ExplorerItem[] => { + const startIndex = index + const endIndex = getEndIndex(items, index, dirent) + const mergedDirents = [...items.slice(0, startIndex), { ...dirent, type: DirentType.DirectoryExpanded }, ...childDirents, ...items.slice(endIndex)] + return mergedDirents +} + +const handleDropIntoFolder = async ( + state: ExplorerState, + dirent: ExplorerItem, + index: number, + fileHandles: DroppedArgs, + files: readonly File[], + paths: readonly string[], +): Promise => { + const { items, pathSeparator } = state + + await uploadFileSystemHandles(dirent.path, '/', fileHandles) + + const childDirents = await GetChildDirents.getChildDirents(pathSeparator, dirent.path, dirent.depth) + const mergedDirents = getMergedDirents(items, index, dirent, childDirents) + // TODO update maxlineY + return { + ...state, + dropTargets: [], + items: mergedDirents, + } +} + +const handleDropIntoFile = ( + state: ExplorerState, + dirent: ExplorerItem, + index: number, + fileHandles: DroppedArgs, + files: readonly File[], + paths: readonly string[], +): Promise => { + const { items } = state + const parentIndex = GetParentStartIndex.getParentStartIndex(items, index) + if (parentIndex === -1) { + return HandleDropRoot.handleDropRoot(state, fileHandles, files, paths) + } + return handleDropIndex(state, fileHandles, files, paths, parentIndex) +} + +export const handleDropIndex = async ( + state: ExplorerState, + fileHandles: DroppedArgs, + files: readonly File[], + paths: readonly string[], + index: number, +): Promise => { + const { items } = state + const dirent = items[index] + // TODO if it is a file, drop into the folder of the file + // TODO if it is a folder, drop into the folder + // TODO if it is a symlink, read symlink and determine if file can be dropped + switch (dirent.type) { + case DirentType.Directory: + case DirentType.DirectoryExpanded: + return handleDropIntoFolder(state, dirent, index, fileHandles, files, paths) + case DirentType.File: + return handleDropIntoFile(state, dirent, index, fileHandles, files, paths) + default: + return state + } +} diff --git a/packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts b/packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts new file mode 100644 index 0000000..df85c0b --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts @@ -0,0 +1,27 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' +import * as HandleDropRootDefault from '../HandleDropRootDefault/HandleDropRootDefault.ts' +import * as HandleDropRootElectron from '../HandleDropRootElectron/HandleDropRootElectron.ts' +import * as PlatformType from '../PlatformType/PlatformType.ts' + +interface DropHandler { + (state: ExplorerState, fileHandles: DroppedArgs, files: readonly File[], paths: readonly string[]): Promise +} + +const getModule = (isElectron: boolean): DropHandler => { + if (isElectron) { + return HandleDropRootElectron.handleDrop + } + return HandleDropRootDefault.handleDrop +} + +export const handleDropRoot = async ( + state: ExplorerState, + fileHandles: DroppedArgs, + files: readonly File[], + paths: readonly string[], +): Promise => { + const isElectron = state.platform === PlatformType.Electron + const fn = getModule(isElectron) + return fn(state, fileHandles, files, paths) +} diff --git a/packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts b/packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts new file mode 100644 index 0000000..a677aff --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts @@ -0,0 +1,79 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' +import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' +import { isDirectoryHandle } from '../IsDirectoryHandle/IsDirectoryHandle.ts' +import * as LoadContent from '../LoadContent/LoadContent.ts' +import * as Refresh from '../Refresh/Refresh.ts' +import * as UploadFileSystemHandles from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' + +const mergeDirents = (oldDirents: readonly any[], newDirents: readonly any[]): readonly any[] => { + return newDirents +} + +const getMergedDirents = async (root: string, pathSeparator: string, dirents: readonly any[]): Promise => { + const childDirents = await getChildDirents(pathSeparator, root, 0) + const mergedDirents = mergeDirents(dirents, childDirents) + return mergedDirents +} + +const getDroppedDirectoryWorkspacePath = (fileHandle: FileSystemDirectoryHandle): string => { + return `html://${fileHandle.name}` +} + +const openDroppedDirectoryAsWorkspace = async (state: ExplorerState, fileHandle: FileSystemDirectoryHandle): Promise => { + const path = getDroppedDirectoryWorkspacePath(fileHandle) + await RendererWorker.invoke('PersistentFileHandle.addHandle', fileHandle.name, fileHandle) + await RendererWorker.invoke('Workspace.setPath', path) + const updated = await LoadContent.loadContent(state, undefined) + return { + ...updated, + dropTargets: [], + } +} + +const getFirstDroppedDirectory = (state: ExplorerState, fileHandles: DroppedArgs): FileSystemDirectoryHandle | undefined => { + if (state.root !== '') { + return undefined + } + for (const item of fileHandles) { + const fileHandle = UploadFileSystemHandles.getFileSystemHandle(item) + if (isDirectoryHandle(fileHandle)) { + return fileHandle + } + } + return undefined +} + +export const handleDrop = async ( + state: ExplorerState, + fileHandles: DroppedArgs, + files: readonly File[], + paths: readonly string[], +): Promise => { + const { items, pathSeparator, root } = state + const droppedDirectory = getFirstDroppedDirectory(state, fileHandles) + if (droppedDirectory) { + return openDroppedDirectoryAsWorkspace(state, droppedDirectory) + } + if (root === '') { + return { + ...state, + dropTargets: [], + } + } + const handled = await UploadFileSystemHandles.uploadFileSystemHandles(root, pathSeparator, fileHandles) + if (handled) { + const updated = await Refresh.refresh(state) + return { + ...updated, + dropTargets: [], + } + } + const mergedDirents = await getMergedDirents(root, pathSeparator, items) + return { + ...state, + dropTargets: [], + items: mergedDirents, + } +} diff --git a/packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts b/packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts new file mode 100644 index 0000000..f140f97 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts @@ -0,0 +1,67 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' +import { copyFilesElectron } from '../CopyFilesElectron/CopyFilesElectron.ts' +import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' +import { isDirectoryHandle } from '../IsDirectoryHandle/IsDirectoryHandle.ts' +import * as LoadContent from '../LoadContent/LoadContent.ts' +import { getFileSystemHandle } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' + +const mergeDirents = (oldDirents: readonly ExplorerItem[], newDirents: readonly ExplorerItem[]): any => { + return newDirents +} + +const getMergedDirents = async (root: any, pathSeparator: any, dirents: any): Promise => { + const childDirents = await GetChildDirents.getChildDirents(pathSeparator, root, 0) + const mergedDirents = mergeDirents(dirents, childDirents) + return mergedDirents +} + +const openDroppedDirectoryAsWorkspace = async (state: ExplorerState, path: string): Promise => { + await RendererWorker.invoke('Workspace.setPath', path) + const updated = await LoadContent.loadContent(state, undefined) + return { + ...updated, + dropTargets: [], + } +} + +const getFirstDroppedDirectoryPath = (state: ExplorerState, fileHandles: DroppedArgs, paths: readonly string[]): string | undefined => { + if (state.root !== '') { + return undefined + } + for (let i = 0; i < fileHandles.length; i++) { + const fileHandle = getFileSystemHandle(fileHandles[i]) + if (isDirectoryHandle(fileHandle)) { + return paths[i] + } + } + return undefined +} + +export const handleDrop = async ( + state: ExplorerState, + fileHandles: DroppedArgs, + files: readonly File[], + paths: readonly string[], +): Promise => { + const { items, pathSeparator, root } = state + const droppedDirectoryPath = getFirstDroppedDirectoryPath(state, fileHandles, paths) + if (droppedDirectoryPath) { + return openDroppedDirectoryAsWorkspace(state, droppedDirectoryPath) + } + if (root === '') { + return { + ...state, + dropTargets: [], + } + } + await copyFilesElectron(root, fileHandles, files, paths) + const mergedDirents = await getMergedDirents(root, pathSeparator, items) + return { + ...state, + dropTargets: [], + items: mergedDirents, + } +} diff --git a/packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts b/packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts new file mode 100644 index 0000000..5738b03 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts @@ -0,0 +1,8 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleEscape = async (state: ExplorerState): Promise => { + return { + ...state, + cutItems: [], + } +} diff --git a/packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts b/packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts new file mode 100644 index 0000000..3ece137 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts @@ -0,0 +1,12 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusId from '../FocusId/FocusId.ts' + +export const handleFocus = async (state: ExplorerState): Promise => { + if (state.editingIndex !== -1) { + return state + } + return { + ...state, + focus: FocusId.List, + } +} diff --git a/packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts b/packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts new file mode 100644 index 0000000..5535947 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as UpdateIcons from '../UpdateIcons/UpdateIcons.ts' + +export const handleIconThemeChange = (state: ExplorerState): Promise => { + return UpdateIcons.updateIcons(state) +} diff --git a/packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts b/packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts new file mode 100644 index 0000000..b941dfa --- /dev/null +++ b/packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts @@ -0,0 +1,14 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { acceptEdit } from '../AcceptEdit/AcceptEdit.ts' +import { cancelEditInternal } from '../CancelEditInternal/CancelEditInternal.ts' + +export const handleInputBlur = async (state: ExplorerState): Promise => { + const { editingErrorMessage, editingIndex, editingValue } = state + if (editingIndex === -1) { + return state + } + if (editingErrorMessage || !editingValue) { + return cancelEditInternal(state, false) + } + return acceptEdit(state) +} diff --git a/packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts b/packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts new file mode 100644 index 0000000..695af6f --- /dev/null +++ b/packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleInputClick = (state: ExplorerState): ExplorerState => { + return state +} diff --git a/packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts b/packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts new file mode 100644 index 0000000..5d4a687 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleInputKeyDown = (state: ExplorerState, key: string): ExplorerState => { + return state +} diff --git a/packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts b/packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts new file mode 100644 index 0000000..d9dc44d --- /dev/null +++ b/packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts @@ -0,0 +1,42 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { cancelTypeAhead } from '../CancelTypeAhead/CancelTypeAhead.ts' +import { filterByFocusWord } from '../FilterByFocusWord/FilterByFocusWord.ts' +import { isAscii } from '../IsAscii/IsAscii.ts' + +let timeout: number | undefined + +export const handleKeyDown = (state: ExplorerState, key: string): ExplorerState => { + const { focusedIndex, focusWord, focusWordTimeout, items } = state + if (focusWord && key === '') { + return cancelTypeAhead(state) + } + if (!isAscii(key)) { + return state + } + + const newFocusWord = focusWord + key.toLowerCase() + const itemNames = items.map((item) => item.name) + const matchingIndex = filterByFocusWord(itemNames, focusedIndex, newFocusWord) + + if (timeout) { + clearTimeout(timeout) + } + + timeout = setTimeout(async () => { + await RendererWorker.invoke('Explorer.cancelTypeAhead') + }, focusWordTimeout) + + if (matchingIndex === -1) { + return { + ...state, + focusWord: newFocusWord, + } + } + + return { + ...state, + focusedIndex: matchingIndex, + focusWord: newFocusWord, + } +} diff --git a/packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts b/packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts new file mode 100644 index 0000000..09781ad --- /dev/null +++ b/packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts @@ -0,0 +1,35 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ClipBoard from '../ClipBoard/ClipBoard.ts' +import * as HandlePasteCopy from '../HandlePasteCopy/HandlePasteCopy.ts' +import * as HandlePasteCut from '../HandlePasteCut/HandlePasteCut.ts' +import * as NativeFileTypes from '../NativeFileTypes/NativeFileTypes.ts' + +export const handlePaste = async (state: ExplorerState): Promise => { + const nativeFiles = await ClipBoard.readNativeFiles() + if (!nativeFiles) { + return state + } + // TODO detect cut/paste event, not sure if that is possible + // TODO check that pasted folder is not a parent folder of opened folder + // TODO support pasting multiple paths + // TODO what happens when pasting multiple paths, but some of them error? + // how many error messages should be shown? Should the operation be undone? + // TODO what if it is a large folder and takes a long time to copy? Should show progress + // TODO what if there is a permission error? Probably should show a modal to ask for permission + // TODO if error is EEXISTS, just rename the copy (e.g. file-copy-1.txt, file-copy-2.txt) + // TODO actual target should be selected folder + // TODO but what if a file is currently selected? Then maybe the parent folder + // TODO but will it work if the folder is a symlink? + // TODO handle error gracefully when copy fails + + // If no files to paste, return original state unchanged + if (nativeFiles.type === NativeFileTypes.None) { + return state + } + + // Use the pasteShouldMove flag to determine whether to cut or copy + if (state.pasteShouldMove) { + return HandlePasteCut.handlePasteCut(state, nativeFiles) + } + return HandlePasteCopy.handlePasteCopy(state, nativeFiles) +} diff --git a/packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts b/packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts new file mode 100644 index 0000000..8e5dfc5 --- /dev/null +++ b/packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts @@ -0,0 +1,53 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' +import * as AdjustScrollAfterPaste from '../AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts' +import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' +import { getFileOperationsCopy } from '../GetFileOperationsCopy/GetFileOperationsCopy.ts' +import { getIndex } from '../GetIndex/GetIndex.ts' +import { refresh } from '../Refresh/Refresh.ts' + +export const handlePasteCopy = async (state: ExplorerState, nativeFiles: NativeFilesResult): Promise => { + // TODO handle pasting files into nested folder + // TODO handle pasting files into symlink + // TODO handle pasting files into broken symlink + // TODO handle pasting files into hardlink + // TODO what if folder is big and it takes a long time + + // TODO use file operations and bulk edit + const { focusedIndex, items, root } = state + const focusedUri = items[focusedIndex]?.path || root + const existingUris = items.map((item) => item.path) + const operations = getFileOperationsCopy(root, existingUris, nativeFiles.files, focusedUri) + // TODO handle error? + await ApplyFileOperations.applyFileOperations(operations) + + // TODO use refreshExplorer with the paths that have been affected by file operations + // TODO only update folder at which level it changed + const latestState = await refresh(state) + + // Focus on the first newly created file and adjust scroll position + const newFilePaths = operations.map((operation) => operation.path) + if (newFilePaths.length > 0) { + const firstNewFilePath = newFilePaths[0] + const newFileIndex = getIndex(latestState.items, firstNewFilePath) + if (newFileIndex !== -1) { + const adjustedState = AdjustScrollAfterPaste.adjustScrollAfterPaste(latestState, newFileIndex) + return { + ...adjustedState, + pasteShouldMove: false, + } + } + } + // If there are no items, ensure focusedIndex is 0 + if (latestState.items.length === 0) { + return { + ...latestState, + focusedIndex: 0, + pasteShouldMove: false, + } + } + return { + ...latestState, + pasteShouldMove: false, + } +} diff --git a/packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts b/packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts new file mode 100644 index 0000000..6fa7261 --- /dev/null +++ b/packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts @@ -0,0 +1,63 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' +import * as AdjustScrollAfterPaste from '../AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts' +import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import { getIndex } from '../GetIndex/GetIndex.ts' +import { getBaseName, join2 } from '../Path/Path.ts' +import { refresh } from '../Refresh/Refresh.ts' + +const getOperations = (toUri: string, files: readonly string[]): readonly FileOperation[] => { + const operations: FileOperation[] = [] + for (const file of files) { + const baseName = getBaseName('/', file) + const newUri = join2(toUri, baseName) + operations.push({ + from: file, + path: newUri, + type: FileOperationType.Rename, + }) + } + return operations +} + +const getTargetUri = (root: string, items: readonly ExplorerItem[], index: number): string => { + if (index === -1) { + return root + } + return items[index].path +} + +export const handlePasteCut = async (state: ExplorerState, nativeFiles: NativeFilesResult): Promise => { + const { focusedIndex, items, pathSeparator, root } = state + // TODO root is not necessrily target uri + const targetUri = getTargetUri(root, items, focusedIndex) + const operations = getOperations(targetUri, nativeFiles.files) + await ApplyFileOperations.applyFileOperations(operations) + + // Refresh the state after cut operations + const latestState = await refresh(state) + + // Focus on the first pasted file and adjust scroll position + if (nativeFiles.files.length > 0) { + const firstPastedFile = nativeFiles.files[0] + const targetPath = `${root}${pathSeparator}${getBaseName(pathSeparator, firstPastedFile)}` + const pastedFileIndex = getIndex(latestState.items, targetPath) + if (pastedFileIndex !== -1) { + const adjustedState = AdjustScrollAfterPaste.adjustScrollAfterPaste(latestState, pastedFileIndex) + return { + ...adjustedState, + cutItems: [], + pasteShouldMove: false, + } + } + } + + return { + ...latestState, + cutItems: [], + pasteShouldMove: false, + } +} diff --git a/packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts b/packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts new file mode 100644 index 0000000..96f5496 --- /dev/null +++ b/packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts @@ -0,0 +1,7 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' + +export const handlePasteNone = async (state: ExplorerState, nativeFiles: NativeFilesResult): Promise => { + console.error('[ViewletExplorer/handlePaste] no paths detected') + return state +} diff --git a/packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts b/packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts new file mode 100644 index 0000000..2013dcd --- /dev/null +++ b/packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts @@ -0,0 +1,17 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' +import * as MouseEventType from '../MouseEventType/MouseEventType.ts' + +export const handlePointerDown = (state: ExplorerState, button: number, x: number, y: number): ExplorerState => { + const index = getIndexFromPosition(state, x, y) + if (button === MouseEventType.LeftClick && index === -1) { + return { + ...state, + focus: FocusId.List, + focused: true, + focusedIndex: -1, + } + } + return state +} diff --git a/packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts b/packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts new file mode 100644 index 0000000..297399f --- /dev/null +++ b/packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts @@ -0,0 +1,24 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +/** + * Handles range selection in the explorer. + * @param state The current explorer state + * @param startIndex The starting index of the range (must be ≤ endIndex) + * @param endIndex The ending index of the range (must be ≥ startIndex) + * @throws Error if startIndex > endIndex + */ +export const handleRangeSelection = (state: ExplorerState, startIndex: number, endIndex: number): ExplorerState => { + if (startIndex > endIndex) { + throw new Error('startIndex must be less than or equal to endIndex') + } + + const { items } = state + const newItems = items.map((item, i) => ({ + ...item, + selected: i >= startIndex && i <= endIndex ? true : item.selected, + })) + return { + ...state, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/HandleResize/HandleResize.ts b/packages/explorer-view/src/parts/HandleResize/HandleResize.ts new file mode 100644 index 0000000..f4f9d9e --- /dev/null +++ b/packages/explorer-view/src/parts/HandleResize/HandleResize.ts @@ -0,0 +1,43 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetExplorerMaxLineY from '../GetMaxLineY/GetMaxLineY.ts' +import * as GetScrollBarSize from '../GetScrollBarSize/GetScrollBarSize.ts' + +export interface Dimensions { + readonly height: number + readonly width: number +} + +export const handleResize = (state: ExplorerState, dimensions: Dimensions): ExplorerState => { + const { height: rawHeight, width: rawWidth } = dimensions + if (!Number.isFinite(rawHeight) || !Number.isFinite(rawWidth)) { + return state + } + const height = Math.max(0, rawHeight) + const width = Math.max(0, rawWidth) + const { deltaY, itemHeight, items } = state + const contentHeight = items.length * itemHeight + const maxDeltaY = Math.max(contentHeight - height, 0) + const newDeltaY = Math.min(Math.max(deltaY, 0), maxDeltaY) + const minLineY = Math.round(newDeltaY / itemHeight) + const maxLineY = GetExplorerMaxLineY.getExplorerMaxLineY(minLineY, height, itemHeight, items.length) + const scrollBarHeight = GetScrollBarSize.getScrollBarSize(height, contentHeight, 20) + if ( + state.height === height && + state.width === width && + state.deltaY === newDeltaY && + state.minLineY === minLineY && + state.maxLineY === maxLineY && + state.scrollBarHeight === scrollBarHeight + ) { + return state + } + return { + ...state, + deltaY: newDeltaY, + height, + maxLineY, + minLineY, + scrollBarHeight, + width, + } +} diff --git a/packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts b/packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts new file mode 100644 index 0000000..7c78e23 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const handleSelection = (state: ExplorerState, index: number): ExplorerState => { + const { items } = state + const newItems = items.map((item, i) => ({ + ...item, + selected: i === index ? !item.selected : item.selected, + })) + return { + ...state, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts b/packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts new file mode 100644 index 0000000..aa49edd --- /dev/null +++ b/packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts @@ -0,0 +1,18 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' + +export const handleUpload = async (state: ExplorerState, dirents: readonly any[]): Promise => { + const { pathSeparator, root } = state + for (const dirent of dirents) { + // TODO switch + // TODO symlink might not be possible to be copied + // TODO create folder if type is 2 + if (dirent.type === /* File */ 1) { + // TODO reading text might be inefficient for binary files + // but not sure how else to send them via jsonrpc + const content = await dirent.file.text() + const absolutePath = [root, dirent.file.name].join(pathSeparator) + await FileSystem.writeFile(absolutePath, content) + } + } +} diff --git a/packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts b/packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts new file mode 100644 index 0000000..f8cb052 --- /dev/null +++ b/packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as SetDeltaY from '../SetDeltaY/SetDeltaY.ts' + +export const handleWheel = (state: ExplorerState, deltaMode: number, deltaY: number): Promise => { + return SetDeltaY.setDeltaY(state, state.deltaY + deltaY) +} diff --git a/packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts b/packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts new file mode 100644 index 0000000..f80e13e --- /dev/null +++ b/packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts @@ -0,0 +1,10 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetWorkspacePath from '../GetWorkspacePath/GetWorkspacePath.ts' +import * as LoadContent from '../LoadContent/LoadContent.ts' + +export const handleWorkspaceChange = async (state: ExplorerState): Promise => { + const newRoot = await GetWorkspacePath.getWorkspacePath() + const state1 = { ...state, root: newRoot } + const newState = await LoadContent.loadContent(state1, undefined) + return newState +} diff --git a/packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts b/packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts new file mode 100644 index 0000000..22fcf4a --- /dev/null +++ b/packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { refresh } from '../Refresh/Refresh.ts' + +export const handleWorkspaceRefresh = async (state: ExplorerState): Promise => { + return refresh(state) +} diff --git a/packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts b/packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts new file mode 100644 index 0000000..4696965 --- /dev/null +++ b/packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts @@ -0,0 +1,5 @@ +const RE_WHITESPACE = /^\s|\s$/ + +export const hasLeadingOrTrailingWhitespace = (text: string): boolean => { + return RE_WHITESPACE.test(text) +} diff --git a/packages/explorer-view/src/parts/HasProperty/HasProperty.ts b/packages/explorer-view/src/parts/HasProperty/HasProperty.ts new file mode 100644 index 0000000..ed57d2d --- /dev/null +++ b/packages/explorer-view/src/parts/HasProperty/HasProperty.ts @@ -0,0 +1,7 @@ +type ObjectWithProperty = { + [key in Options]: unknown +} + +export const hasProperty = (object: unknown, key: K): object is ObjectWithProperty => { + return !!object && typeof object === 'object' && key in object +} diff --git a/packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts b/packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts new file mode 100644 index 0000000..e92784c --- /dev/null +++ b/packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts @@ -0,0 +1,6 @@ +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as IsSymbolicLink from '../IsSymbolicLink/IsSymbolicLink.ts' + +export const hasSymbolicLinks = (rawDirents: readonly RawDirent[]): boolean => { + return rawDirents.some(IsSymbolicLink.isSymbolicLink) +} diff --git a/packages/explorer-view/src/parts/Height/Height.ts b/packages/explorer-view/src/parts/Height/Height.ts new file mode 100644 index 0000000..0cdee25 --- /dev/null +++ b/packages/explorer-view/src/parts/Height/Height.ts @@ -0,0 +1 @@ +export const ListItem = 22 diff --git a/packages/explorer-view/src/parts/I18NString/I18NString.ts b/packages/explorer-view/src/parts/I18NString/I18NString.ts new file mode 100644 index 0000000..288e81d --- /dev/null +++ b/packages/explorer-view/src/parts/I18NString/I18NString.ts @@ -0,0 +1 @@ +export * from '@lvce-editor/i18n' diff --git a/packages/explorer-view/src/parts/IconRequest/IconRequest.ts b/packages/explorer-view/src/parts/IconRequest/IconRequest.ts new file mode 100644 index 0000000..85f7d37 --- /dev/null +++ b/packages/explorer-view/src/parts/IconRequest/IconRequest.ts @@ -0,0 +1,5 @@ +export interface IconRequest { + readonly name: string + readonly path: string + readonly type: number +} diff --git a/packages/explorer-view/src/parts/IconTheme/IconTheme.ts b/packages/explorer-view/src/parts/IconTheme/IconTheme.ts new file mode 100644 index 0000000..56a3bcd --- /dev/null +++ b/packages/explorer-view/src/parts/IconTheme/IconTheme.ts @@ -0,0 +1,23 @@ +/** + * @deprecated + */ +export const getFileIcon = ({ name }: { readonly name: string }): string => { + console.warn('do not use') + return '' +} + +/** + * @deprecated + */ +export const getIcon = (dirent: any): string => { + console.warn('do not use') + return '' +} + +/** + * @deprecated + */ +export const getFolderIcon = (dirent: any): string => { + console.warn('do not use') + return '' +} diff --git a/packages/explorer-view/src/parts/Initialize/Initialize.ts b/packages/explorer-view/src/parts/Initialize/Initialize.ts new file mode 100644 index 0000000..adc9f35 --- /dev/null +++ b/packages/explorer-view/src/parts/Initialize/Initialize.ts @@ -0,0 +1,3 @@ +export const initialize = async (): Promise => { + // this function is not needed anymore +} diff --git a/packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts b/packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts new file mode 100644 index 0000000..1337d84 --- /dev/null +++ b/packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts @@ -0,0 +1,7 @@ +import { createFileSystemWorkerRpc } from '../CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts' +import * as FileSystemWorker from '../FileSystemWorker/FileSystemWorker.ts' + +export const initializeFileSystemWorker = async (): Promise => { + const rpc = await createFileSystemWorkerRpc() + FileSystemWorker.set(rpc) +} diff --git a/packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts b/packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts new file mode 100644 index 0000000..f9aa597 --- /dev/null +++ b/packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts @@ -0,0 +1,7 @@ +import { IconThemeWorker } from '@lvce-editor/rpc-registry' +import { createIconThemeWorkerRpc } from '../CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts' + +export const initializeIconThemeWorker = async (): Promise => { + const rpc = await createIconThemeWorkerRpc() + IconThemeWorker.set(rpc) +} diff --git a/packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts b/packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts new file mode 100644 index 0000000..9541469 --- /dev/null +++ b/packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts @@ -0,0 +1,10 @@ +import { WebWorkerRpcClient } from '@lvce-editor/rpc' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as CommandMap from '../CommandMap/CommandMap.ts' + +export const initializeRendererWorker = async (): Promise => { + const rpc = await WebWorkerRpcClient.create({ + commandMap: CommandMap.commandMap, + }) + RendererWorker.set(rpc) +} diff --git a/packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts b/packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts new file mode 100644 index 0000000..9f03e42 --- /dev/null +++ b/packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts @@ -0,0 +1,12 @@ +import { SourceControlWorker } from '@lvce-editor/rpc-registry' +import { createSourceControlWorkerRpc } from '../CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts' + +export const initializeSourceControlWorker = async (): Promise => { + try { + const rpc = await createSourceControlWorkerRpc() + // TODO + SourceControlWorker.set(rpc) + } catch { + // ignore + } +} diff --git a/packages/explorer-view/src/parts/InputName/InputName.ts b/packages/explorer-view/src/parts/InputName/InputName.ts new file mode 100644 index 0000000..87652a0 --- /dev/null +++ b/packages/explorer-view/src/parts/InputName/InputName.ts @@ -0,0 +1,6 @@ +export const CollapseAll = 'CollapseAll' +export const ExplorerInput = 'ExplorerInput' +export const NewFile = 'NewFile' +export const NewFolder = 'NewFolder' +export const OpenFolder = 'OpenFolder' +export const Refresh = 'Refresh' diff --git a/packages/explorer-view/src/parts/InputSource/InputSource.ts b/packages/explorer-view/src/parts/InputSource/InputSource.ts new file mode 100644 index 0000000..603f27e --- /dev/null +++ b/packages/explorer-view/src/parts/InputSource/InputSource.ts @@ -0,0 +1,2 @@ +export const User = 1 +export const Script = 2 diff --git a/packages/explorer-view/src/parts/IsAscii/IsAscii.ts b/packages/explorer-view/src/parts/IsAscii/IsAscii.ts new file mode 100644 index 0000000..a31eec2 --- /dev/null +++ b/packages/explorer-view/src/parts/IsAscii/IsAscii.ts @@ -0,0 +1,5 @@ +const RE_ASCII = /^[a-z]$/ + +export const isAscii = (key: string): boolean => { + return RE_ASCII.test(key) +} diff --git a/packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts b/packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts new file mode 100644 index 0000000..e7d1003 --- /dev/null +++ b/packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts @@ -0,0 +1,3 @@ +export const isDirectoryHandle = (fileHandle: FileSystemHandle): fileHandle is FileSystemDirectoryHandle => { + return fileHandle.kind === 'directory' +} diff --git a/packages/explorer-view/src/parts/IsEqual/IsEqual.ts b/packages/explorer-view/src/parts/IsEqual/IsEqual.ts new file mode 100644 index 0000000..e0578d1 --- /dev/null +++ b/packages/explorer-view/src/parts/IsEqual/IsEqual.ts @@ -0,0 +1,12 @@ +export const isEqual = (a: readonly any[], b: readonly any[]): boolean => { + if (a.length !== b.length) { + return false + } + const { length } = a + for (let i = 0; i < length; i++) { + if (a[i] !== b[i]) { + return false + } + } + return true +} diff --git a/packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts b/packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts new file mode 100644 index 0000000..9a12a9b --- /dev/null +++ b/packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const isExpanded = (item: ExplorerItem): boolean => { + return item.type === DirentType.DirectoryExpanded || item.type === DirentType.DirectoryExpanding +} diff --git a/packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts b/packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts new file mode 100644 index 0000000..6fc56de --- /dev/null +++ b/packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const isExpandedDirectory = (dirent: ExplorerItem): boolean => { + return dirent.type === DirentType.DirectoryExpanded +} diff --git a/packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts b/packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts new file mode 100644 index 0000000..98becbf --- /dev/null +++ b/packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts @@ -0,0 +1,3 @@ +export const isFileHandle = (fileHandle: FileSystemHandle): fileHandle is FileSystemFileHandle => { + return fileHandle.kind === 'file' +} diff --git a/packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts b/packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts new file mode 100644 index 0000000..5fc95f5 --- /dev/null +++ b/packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const isNormalItem = (item: ExplorerItem): boolean => { + return item.type !== DirentType.EditingFile && item.type !== DirentType.EditingFolder +} diff --git a/packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts b/packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts new file mode 100644 index 0000000..f58b26a --- /dev/null +++ b/packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts @@ -0,0 +1,6 @@ +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const isSymbolicLink = (dirent: RawDirent): boolean => { + return dirent.type === DirentType.Symlink +} diff --git a/packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts b/packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts new file mode 100644 index 0000000..8765086 --- /dev/null +++ b/packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts @@ -0,0 +1,5 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const isTopLevel = (dirent: ExplorerItem): boolean => { + return dirent.depth === 1 +} diff --git a/packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts b/packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts new file mode 100644 index 0000000..89d2862 --- /dev/null +++ b/packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts @@ -0,0 +1,7 @@ +export const isUriWithinRoot = (root: string, uri: string, pathSeparator: string): boolean => { + if (uri === root) { + return true + } + const rootWithSeparator = root.endsWith(pathSeparator) ? root : `${root}${pathSeparator}` + return uri.startsWith(rootWithSeparator) +} diff --git a/packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts b/packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts new file mode 100644 index 0000000..9045dcd --- /dev/null +++ b/packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts @@ -0,0 +1,47 @@ +/* eslint-disable no-useless-escape */ + +// copied from https://github.com/microsoft/vscode/blob/6b924c51528e663dda5091a1493229a361676aca/src/vs/base/common/extpath.ts by Microsoft (License MIT) + +// Reference: https://en.wikipedia.org/wiki/Filename +const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g +const UNIX_INVALID_FILE_CHARS = /\//g +const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt\d|com\d)(\.(.*?))?$/i + +export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean): boolean { + const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS + + if (!name || name.length === 0 || /^\s+$/.test(name)) { + return false // require a name that is not just whitespace + } + + invalidFileChars.lastIndex = 0 // the holy grail of software development + if (invalidFileChars.test(name)) { + return false // check for certain invalid file characters + } + + if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) { + return false // check for certain invalid file names + } + + if (name === '.' || name === '..' || name === '...') { + return false // check for reserved values + } + + if (name.startsWith('../')) { + return false // check for names starting with ../ + } + + if (isWindowsOS && name.at(-1) === '.') { + return false // Windows: file cannot end with a "." + } + + if (isWindowsOS && name.length !== name.trim().length) { + return false // Windows: file cannot end with a whitespace + } + + if (name.length > 255) { + return false // most file systems do not allow files > 255 length + } + + return true +} diff --git a/packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts b/packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts new file mode 100644 index 0000000..b01afe0 --- /dev/null +++ b/packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts @@ -0,0 +1,5 @@ +export interface KeyBinding { + readonly command: string + readonly key: number + readonly when: number +} diff --git a/packages/explorer-view/src/parts/KeyCode/KeyCode.ts b/packages/explorer-view/src/parts/KeyCode/KeyCode.ts new file mode 100644 index 0000000..bb3bf08 --- /dev/null +++ b/packages/explorer-view/src/parts/KeyCode/KeyCode.ts @@ -0,0 +1,18 @@ +export const Enter = 3 +export const Escape = 8 +export const Space = 9 +export const End = 255 +export const Home = 12 +export const LeftArrow = 13 +export const UpArrow = 14 +export const RightArrow = 15 +export const DownArrow = 16 +export const Delete = 18 + +export const KeyA = 29 +export const KeyC = 31 +export const KeyV = 50 + +export const F2 = 58 + +export const Star = 131 diff --git a/packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts b/packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts new file mode 100644 index 0000000..ebce747 --- /dev/null +++ b/packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts @@ -0,0 +1,4 @@ +export const CtrlCmd = (1 << 11) >>> 0 +export const Shift = (1 << 10) >>> 0 +export const Alt = (1 << 9) >>> 0 +export const WinCtrl = (1 << 8) >>> 0 diff --git a/packages/explorer-view/src/parts/Listen/Listen.ts b/packages/explorer-view/src/parts/Listen/Listen.ts new file mode 100644 index 0000000..c0f1aa9 --- /dev/null +++ b/packages/explorer-view/src/parts/Listen/Listen.ts @@ -0,0 +1,11 @@ +import * as CommandMap from '../CommandMap/CommandMap.ts' +import { registerCommands } from '../ExplorerStates/ExplorerStates.ts' +import { initializeFileSystemWorker } from '../InitializeFileSystemWorker/InitializeFileSystemWorker.ts' +import { initializeIconThemeWorker } from '../InitializeIconThemeWorker/InitializeIconThemeWorker.ts' +import { initializeRendererWorker } from '../InitializeRendererWorker/initializeRendereWorker.ts' +import { initializeSourceControlWorker } from '../InitializeSourceControlWorker/InitializeSourceControlWorker.ts' + +export const listen = async (): Promise => { + registerCommands(CommandMap.commandMap) + await Promise.all([initializeRendererWorker(), initializeFileSystemWorker(), initializeIconThemeWorker(), initializeSourceControlWorker()]) +} diff --git a/packages/explorer-view/src/parts/LoadContent/LoadContent.ts b/packages/explorer-view/src/parts/LoadContent/LoadContent.ts new file mode 100644 index 0000000..db49b66 --- /dev/null +++ b/packages/explorer-view/src/parts/LoadContent/LoadContent.ts @@ -0,0 +1,71 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetErrorCode from '../GetErrorCode/GetErrorCode.ts' +import * as GetErrorMessage from '../GetErrorMessage/GetErrorMessage.ts' +import * as GetExcluded from '../GetExcluded/GetExcluded.ts' +import * as GetFileDecorations from '../GetFileDecorations/GetFileDecorations.ts' +import * as GetFriendlyErrorMessage from '../GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts' +import * as GetPathSeparator from '../GetPathSeparator/GetPathSeparator.ts' +import * as GetRestoredDeltaY from '../GetRestoredDeltaY/GetRestoredDeltaY.ts' +import * as GetSavedRoot from '../GetSavedRoot/GetSavedRoot.ts' +import { getScheme } from '../GetScheme/GetScheme.ts' +import * as GetSettings from '../GetSettings/GetSettings.ts' +import * as GetWorkspacePath from '../GetWorkspacePath/GetWorkspacePath.ts' +import * as RestoreExpandedState from '../RestoreExpandedState/RestoreExpandedState.ts' + +export const loadContent = async (state: ExplorerState, savedState: any): Promise => { + const { assetDir, height, itemHeight, platform } = state + const { confirmDelete, sourceControlDecorations, useChevrons } = await GetSettings.getSettings() + const workspacePath = await GetWorkspacePath.getWorkspacePath() + const root = GetSavedRoot.getSavedRoot(savedState, workspacePath) + try { + // TODO path separator could be restored from saved state + const pathSeparator = await GetPathSeparator.getPathSeparator(root) // TODO only load path separator once + const excluded = GetExcluded.getExcluded() + const restoredDirents = await RestoreExpandedState.restoreExpandedState(savedState, root, pathSeparator, excluded) + const rawDeltaY = GetRestoredDeltaY.getRestoredDeltaY(savedState) + const maxDeltaY = Math.max(restoredDirents.length * itemHeight - height, 0) + const deltaY = Math.min(Math.max(rawDeltaY, 0), maxDeltaY) + const minLineY = Math.round(deltaY / itemHeight) + + const scheme = getScheme(root) + const decorations = await GetFileDecorations.getFileDecorations( + scheme, + root, + restoredDirents.filter((item: any) => item.depth === 1).map((item: any) => item.path), + sourceControlDecorations, + assetDir, + platform, + ) + return { + ...state, + confirmDelete, + decorations, + deltaY, + errorCode: '', + errorMessage: '', + excluded, + hasError: false, + initial: false, + items: restoredDirents, + maxIndent: 10, + minLineY, + pathSeparator, + root, + useChevrons, + } + } catch (error) { + const errorCode = GetErrorCode.getErrorCode(error) + const errorMessage = GetFriendlyErrorMessage.getFriendlyErrorMessage(GetErrorMessage.getErrorMessage(error), errorCode) + return { + ...state, + confirmDelete, + errorCode, + errorMessage, + hasError: true, + initial: false, + items: [], + root, + useChevrons, + } + } +} diff --git a/packages/explorer-view/src/parts/Main/Main.ts b/packages/explorer-view/src/parts/Main/Main.ts new file mode 100644 index 0000000..fbe7842 --- /dev/null +++ b/packages/explorer-view/src/parts/Main/Main.ts @@ -0,0 +1,5 @@ +import * as Listen from '../Listen/Listen.ts' + +export const main = async (): Promise => { + await Listen.listen() +} diff --git a/packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts b/packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts new file mode 100644 index 0000000..4c338e0 --- /dev/null +++ b/packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts @@ -0,0 +1,12 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const makeExpanded = (dirent: ExplorerItem): ExplorerItem => { + if (dirent.type === DirentType.Directory) { + return { + ...dirent, + type: DirentType.DirectoryExpanded, + } + } + return dirent +} diff --git a/packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts b/packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts new file mode 100644 index 0000000..f702e27 --- /dev/null +++ b/packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts @@ -0,0 +1,4 @@ +export const CollapseAll = 'CollapseAll' +export const NewFile = 'NewFile' +export const NewFolder = 'NewFolder' +export const Refresh = 'Refresh' diff --git a/packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts b/packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts new file mode 100644 index 0000000..b7bf9de --- /dev/null +++ b/packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts @@ -0,0 +1,6 @@ +export interface MenuEntry { + readonly command: string + readonly flags: number + readonly id: string + readonly label: string +} diff --git a/packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts b/packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts new file mode 100644 index 0000000..26765f4 --- /dev/null +++ b/packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts @@ -0,0 +1 @@ +export const Explorer = 4 diff --git a/packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts b/packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts new file mode 100644 index 0000000..620506d --- /dev/null +++ b/packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts @@ -0,0 +1,8 @@ +import * as MenuItemFlags from '../MenuItemFlags/MenuItemFlags.ts' + +export const menuEntrySeparator = { + command: '', + flags: MenuItemFlags.Separator, + id: 'separator', + label: '', +} diff --git a/packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts b/packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts new file mode 100644 index 0000000..3ce7396 --- /dev/null +++ b/packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts @@ -0,0 +1,5 @@ +export const Separator = 1 + +export const None = 0 + +export const RestoreFocus = 6 diff --git a/packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts b/packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts new file mode 100644 index 0000000..653e3b1 --- /dev/null +++ b/packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts @@ -0,0 +1 @@ +export { mergeClassNames } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts b/packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts new file mode 100644 index 0000000..c3eefc7 --- /dev/null +++ b/packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts @@ -0,0 +1,17 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const mergeDirents = (oldDirents: readonly ExplorerItem[], newDirents: readonly ExplorerItem[]): readonly ExplorerItem[] => { + const merged: ExplorerItem[] = [] + let oldIndex = 0 + for (const newDirent of newDirents) { + merged.push(newDirent) + for (let i = oldIndex; i < oldDirents.length; i++) { + if (oldDirents[i].path === newDirent.path) { + // TOOD copy children of old dirent + oldIndex = i + break + } + } + } + return merged +} diff --git a/packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts b/packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts new file mode 100644 index 0000000..d9b507b --- /dev/null +++ b/packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts @@ -0,0 +1,8 @@ +import type { Tree } from '../Tree/Tree.ts' + +export const mergeTrees = (a: Tree, b: Tree): Tree => { + return { + ...a, + ...b, + } +} diff --git a/packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts b/packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts new file mode 100644 index 0000000..a60e478 --- /dev/null +++ b/packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts @@ -0,0 +1,15 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const mergeVisibleWithHiddenItems = (visibleItems: readonly ExplorerItem[], hiddenItems: readonly ExplorerItem[]): readonly ExplorerItem[] => { + const merged = [...visibleItems, ...hiddenItems] + const seen = Object.create(null) + const unique = [] + for (const item of merged) { + if (seen[item.path]) { + continue + } + seen[item.path] = true + unique.push(item) + } + return unique +} diff --git a/packages/explorer-view/src/parts/MouseAction/MouseAction.ts b/packages/explorer-view/src/parts/MouseAction/MouseAction.ts new file mode 100644 index 0000000..67bad55 --- /dev/null +++ b/packages/explorer-view/src/parts/MouseAction/MouseAction.ts @@ -0,0 +1,12 @@ +export interface MouseAction { + readonly button: number + readonly command: string + readonly description: string + readonly modifiers: { + readonly ctrl?: boolean + readonly shift?: boolean + readonly alt?: boolean + readonly meta?: boolean + } + readonly when?: number +} diff --git a/packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts b/packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts new file mode 100644 index 0000000..ee59861 --- /dev/null +++ b/packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts @@ -0,0 +1,3 @@ +export const Keyboard = -1 + +export const LeftClick = 0 diff --git a/packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts b/packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts new file mode 100644 index 0000000..7d92318 --- /dev/null +++ b/packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts @@ -0,0 +1,3 @@ +export const None = 'none' +export const Copy = 'copy' +export const Cut = 'cut' diff --git a/packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts b/packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts new file mode 100644 index 0000000..ebd73eb --- /dev/null +++ b/packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts @@ -0,0 +1,5 @@ +export interface NativeFilesResult { + readonly files: readonly string[] + readonly source: 'gnomeCopiedFiles' + readonly type: 'none' | 'copy' | 'cut' +} diff --git a/packages/explorer-view/src/parts/NewDirent/NewDirent.ts b/packages/explorer-view/src/parts/NewDirent/NewDirent.ts new file mode 100644 index 0000000..58aa3d3 --- /dev/null +++ b/packages/explorer-view/src/parts/NewDirent/NewDirent.ts @@ -0,0 +1,27 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import * as GetFittingIndex from '../GetFittingIndex/GetFittingIndex.ts' +import * as GetNewDirentsForNewDirent from '../GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts' +import * as GetNewDirentType from '../GetNewDirentType/GetNewDirentType.ts' + +export const newDirent = async (state: ExplorerState, editingType: number): Promise => { + // TODO do it like vscode, select position between folders and files + const { editingIndex, focusedIndex, items, root } = state + if (editingIndex !== -1) { + return state + } + const index = GetFittingIndex.getFittingIndex(items, focusedIndex) + const direntType = GetNewDirentType.getNewDirentType(editingType) + const newDirents = await GetNewDirentsForNewDirent.getNewDirentsForNewDirent(items, index, direntType, root) + const newEditingIndex = newDirents.findIndex((item) => item.type === DirentType.EditingFile || item.type === DirentType.EditingFolder) + return { + ...state, + editingIndex: newEditingIndex, + editingType, + editingValue: '', + focus: FocusId.Input, + focusedIndex: newEditingIndex, + items: newDirents, + } +} diff --git a/packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts b/packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts new file mode 100644 index 0000000..179b167 --- /dev/null +++ b/packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts @@ -0,0 +1,6 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export interface NewDirentsAcceptResult { + readonly dirents: readonly ExplorerItem[] + readonly newFocusedIndex: number +} diff --git a/packages/explorer-view/src/parts/NewFile/NewFile.ts b/packages/explorer-view/src/parts/NewFile/NewFile.ts new file mode 100644 index 0000000..2c155a3 --- /dev/null +++ b/packages/explorer-view/src/parts/NewFile/NewFile.ts @@ -0,0 +1,8 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as NewDirent from '../NewDirent/NewDirent.ts' + +// TODO much shared logic with newFolder +export const newFile = (state: ExplorerState): Promise => { + return NewDirent.newDirent(state, ExplorerEditingType.CreateFile) +} diff --git a/packages/explorer-view/src/parts/NewFolder/NewFolder.ts b/packages/explorer-view/src/parts/NewFolder/NewFolder.ts new file mode 100644 index 0000000..6999e55 --- /dev/null +++ b/packages/explorer-view/src/parts/NewFolder/NewFolder.ts @@ -0,0 +1,7 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as NewDirent from '../NewDirent/NewDirent.ts' + +export const newFolder = (state: ExplorerState): Promise => { + return NewDirent.newDirent(state, ExplorerEditingType.CreateFolder) +} diff --git a/packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts b/packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts new file mode 100644 index 0000000..2301642 --- /dev/null +++ b/packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts @@ -0,0 +1,12 @@ +import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' + +const isValid = (decoration: FileDecoration): boolean => { + return decoration && typeof decoration.decoration === 'string' && typeof decoration.uri === 'string' +} + +export const normalizeDecorations = (decorations: readonly FileDecoration[]): readonly FileDecoration[] => { + if (!decorations || !Array.isArray(decorations)) { + return [] + } + return decorations.filter(isValid) +} diff --git a/packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts b/packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts new file mode 100644 index 0000000..4a17326 --- /dev/null +++ b/packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts @@ -0,0 +1,8 @@ +import { DELTA_EDITING } from '../DeltaEditing/DeltaEditing.ts' + +export const normalizeDirentType = (direntType: number): number => { + if (direntType > DELTA_EDITING) { + return direntType - DELTA_EDITING + } + return direntType +} diff --git a/packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts b/packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts new file mode 100644 index 0000000..63b424f --- /dev/null +++ b/packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts @@ -0,0 +1,10 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getContainingFolder } from '../GetContainingFolder/GetContainingFolder.ts' +import { openNativeFolder } from '../OpenNativeFolder/OpenNativeFolder.ts' + +export const openContainingFolder = async (state: ExplorerState): Promise => { + const { focusedIndex, items, pathSeparator, root } = state + const path = getContainingFolder(root, items, focusedIndex, pathSeparator) + await openNativeFolder(path) + return state +} diff --git a/packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts b/packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts new file mode 100644 index 0000000..c3cb011 --- /dev/null +++ b/packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const openDiff = async (leftUri: string, rightUri: string, focus: boolean): Promise => { + await RendererWorker.openUri(`diff://${leftUri}<->${rightUri}`, focus) +} diff --git a/packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts b/packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts new file mode 100644 index 0000000..aed078f --- /dev/null +++ b/packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const openFolder = async (): Promise => { + await RendererWorker.invoke(`Dialog.openFolder`) +} diff --git a/packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts b/packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts new file mode 100644 index 0000000..2be83fa --- /dev/null +++ b/packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const openNativeFolder = async (path: string): Promise => { + await RendererWorker.invoke('OpenNativeFolder.openNativeFolder', /* path */ path) +} diff --git a/packages/explorer-view/src/parts/OpenUri/OpenUri.ts b/packages/explorer-view/src/parts/OpenUri/OpenUri.ts new file mode 100644 index 0000000..3c67189 --- /dev/null +++ b/packages/explorer-view/src/parts/OpenUri/OpenUri.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const openUri = async (uri: string, focus: boolean): Promise => { + await RendererWorker.openUri(uri, /* focus */ focus) +} diff --git a/packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts b/packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts new file mode 100644 index 0000000..f10a24b --- /dev/null +++ b/packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts @@ -0,0 +1,28 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import { isTopLevel } from '../IsTopLevel/IsTopLevel.ts' + +export const orderDirents = (dirents: readonly ExplorerItem[]): readonly ExplorerItem[] => { + if (dirents.length === 0) { + return dirents + } + + const withDeepChildren = (parent: ExplorerItem, processed: Set): ExplorerItem[] => { + if (processed.has(parent.path)) { + return [] + } + processed.add(parent.path) + + const children = [] + for (const dirent of dirents) { + if (dirent.depth === parent.depth + 1 && dirent.path.startsWith(parent.path)) { + children.push(...withDeepChildren(dirent, processed)) + } + } + return [parent, ...children] + } + + const topLevelDirents = dirents.filter(isTopLevel) + const processed = new Set() + const ordered = topLevelDirents.flatMap((dirent) => withDeepChildren(dirent, processed)) + return ordered +} diff --git a/packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts b/packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts new file mode 100644 index 0000000..876b473 --- /dev/null +++ b/packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts @@ -0,0 +1,6 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' + +export interface PasteHandler { + (state: ExplorerState, nativeFiles: NativeFilesResult): Promise +} diff --git a/packages/explorer-view/src/parts/Path/Path.ts b/packages/explorer-view/src/parts/Path/Path.ts new file mode 100644 index 0000000..435a6d3 --- /dev/null +++ b/packages/explorer-view/src/parts/Path/Path.ts @@ -0,0 +1,26 @@ +export const dirname = (pathSeparator: string, path: string): string => { + const index = path.lastIndexOf(pathSeparator) + if (index === -1) { + return path + } + return path.slice(0, index) +} + +export const dirname2 = (path: string): string => { + return dirname('/', path) +} + +export const join = (pathSeparator: string, ...parts: readonly string[]): string => { + return parts.join(pathSeparator) +} + +export const getBaseName = (pathSeparator: string, path: string): string => { + return path.slice(path.lastIndexOf(pathSeparator) + 1) +} + +export const join2 = (path: string, childPath: string): string => { + if (path.endsWith('/') || childPath.startsWith('/')) { + return `${path}${childPath}` + } + return `${path}/${childPath}` +} diff --git a/packages/explorer-view/src/parts/PathPart/PathPart.ts b/packages/explorer-view/src/parts/PathPart/PathPart.ts new file mode 100644 index 0000000..2edfea0 --- /dev/null +++ b/packages/explorer-view/src/parts/PathPart/PathPart.ts @@ -0,0 +1,7 @@ +export interface PathPart { + readonly depth: number + readonly expanded?: boolean + readonly path: string + readonly pathSeparator: string + readonly root: string +} diff --git a/packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts b/packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts new file mode 100644 index 0000000..af10cfd --- /dev/null +++ b/packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts @@ -0,0 +1 @@ +export const Slash = '/' diff --git a/packages/explorer-view/src/parts/PlatformType/PlatformType.ts b/packages/explorer-view/src/parts/PlatformType/PlatformType.ts new file mode 100644 index 0000000..a38fa00 --- /dev/null +++ b/packages/explorer-view/src/parts/PlatformType/PlatformType.ts @@ -0,0 +1,7 @@ +export const Web = 1 + +export const Electron = 2 + +export const Remote = 3 + +export const Test = 4 diff --git a/packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts b/packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts new file mode 100644 index 0000000..082383d --- /dev/null +++ b/packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts @@ -0,0 +1,3 @@ +export const Fulfilled = 'fulfilled' + +export const Rejected = 'rejected' diff --git a/packages/explorer-view/src/parts/Px/Px.ts b/packages/explorer-view/src/parts/Px/Px.ts new file mode 100644 index 0000000..a7dc278 --- /dev/null +++ b/packages/explorer-view/src/parts/Px/Px.ts @@ -0,0 +1 @@ +export { px, position } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/RawDirent/RawDirent.ts b/packages/explorer-view/src/parts/RawDirent/RawDirent.ts new file mode 100644 index 0000000..fb6836f --- /dev/null +++ b/packages/explorer-view/src/parts/RawDirent/RawDirent.ts @@ -0,0 +1,4 @@ +export interface RawDirent { + readonly name: string + readonly type: number +} diff --git a/packages/explorer-view/src/parts/Refresh/Refresh.ts b/packages/explorer-view/src/parts/Refresh/Refresh.ts new file mode 100644 index 0000000..23316ce --- /dev/null +++ b/packages/explorer-view/src/parts/Refresh/Refresh.ts @@ -0,0 +1,25 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getExpandedDirents } from '../GetExpandedDirents/GetExpandedDirents.ts' +import { getPathDirentsMap } from '../GetPathDirentsMap/GetPathDirentsMap.ts' +import { getPaths } from '../GetPaths/GetPaths.ts' +import { getProtoMap } from '../GetProtoMap/GetProtoMap.ts' +import { sortPathDirentsMap } from '../SortPathDirentsMap/SortPathDirentsMap.ts' + +export const refresh = async (state: ExplorerState): Promise => { + const { focusedIndex, items, root } = state + const expandedDirents = getExpandedDirents(items) + const expandedPaths = getPaths(expandedDirents) + const allPaths = [root, ...expandedPaths] + const pathToDirents = await getPathDirentsMap(allPaths) + const sortedPathDirents = sortPathDirentsMap(pathToDirents) + const newItems = getProtoMap(root, sortedPathDirents, expandedPaths) + let newFocusedIndex = focusedIndex + if (focusedIndex >= newItems.length) { + newFocusedIndex = newItems.length - 1 + } + return { + ...state, + focusedIndex: newFocusedIndex, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts b/packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts new file mode 100644 index 0000000..8422b04 --- /dev/null +++ b/packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts @@ -0,0 +1,46 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' + +export const refreshChildDirent = async ( + folder: ExplorerItem, + dirent: any, + pathSeparator: string, + expandedFolders: readonly string[], +): Promise => { + const path = folder.path.endsWith(pathSeparator) ? `${folder.path}${dirent.name}` : `${folder.path}${pathSeparator}${dirent.name}` + const isExpandedFolder = expandedFolders.includes(path) + let type = DirentType.File + if (dirent.type === 'directory') { + type = isExpandedFolder ? DirentType.DirectoryExpanded : DirentType.Directory + } + + const item: ExplorerItem = { + depth: folder.depth + 1, + name: dirent.name, + path, + selected: false, + type, + } + + if (isExpandedFolder && dirent.type === 'directory') { + const nestedItems = await refreshChildDirents(item, pathSeparator, expandedFolders) + return [item, ...nestedItems] + } + + return [item] +} + +export const refreshChildDirents = async ( + folder: ExplorerItem, + pathSeparator: string, + expandedFolders: readonly string[], +): Promise => { + const childDirents = await FileSystem.readDirWithFileTypes(folder.path) + const childItems = await Promise.all( + childDirents.map(async (dirent) => { + return refreshChildDirent(folder, dirent, pathSeparator, expandedFolders) + }), + ) + return childItems.flat() +} diff --git a/packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts b/packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts new file mode 100644 index 0000000..7a58e39 --- /dev/null +++ b/packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts @@ -0,0 +1,10 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const refreshWorkspace = async (): Promise => { + // TODO maybe pass an application id to this? + try { + await RendererWorker.invoke('Layout.handleWorkspaceRefresh') + } catch { + // ignore + } +} diff --git a/packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts b/packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts new file mode 100644 index 0000000..aa39ca6 --- /dev/null +++ b/packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts @@ -0,0 +1,44 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' +import * as ConfirmDelete from '../ConfirmDelete/ConfirmDelete.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import { getPaths } from '../GetPaths/GetPaths.ts' +import { getSelectedItems } from '../GetSelectedItems/GetSelectedItems.ts' +import * as Refresh from '../Refresh/Refresh.ts' +import { showErrorAlert } from '../ShowErrorAlert/ShowErrorAlert.ts' + +export const removeDirent = async (state: ExplorerState): Promise => { + const { confirmDelete, focusedIndex, items } = state + const selectedItems = getSelectedItems(items, focusedIndex) + if (selectedItems.length === 0) { + return state + } + const toRemove = getPaths(selectedItems) + + if (confirmDelete) { + const confirmed = await ConfirmDelete.confirmDelete(toRemove) + if (!confirmed) { + return state + } + } + const fileOperations: readonly FileOperation[] = toRemove.map((item) => { + return { + path: item, + type: FileOperationType.Remove, + } + }) + // TODO use bulk edit and explorer refresh + const errorMessage = await ApplyFileOperations.applyFileOperations(fileOperations) + if (errorMessage) { + await showErrorAlert(errorMessage) + return state + } + const newState = await Refresh.refresh(state) + return { + ...newState, + focus: FocusId.List, + focused: true, + } +} diff --git a/packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts b/packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts new file mode 100644 index 0000000..aeb3a12 --- /dev/null +++ b/packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts @@ -0,0 +1,28 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import { getNewDirentsForRename } from '../GetNewDirentsForRename/GetNewDirentsForRename.ts' +import { getRenameSelectionRange } from '../GetRenameSelectionRange/GetRenameSelectionRange.ts' +import * as InputSource from '../InputSource/InputSource.ts' + +export const renameDirent = async (state: ExplorerState): Promise => { + const { focusedIndex, icons, items, minLineY } = state + if (items.length === 0) { + return state + } + const item = items[focusedIndex] + const newItems = getNewDirentsForRename(items, focusedIndex) + const { end, start } = getRenameSelectionRange(item.name) + return { + ...state, + editingIcon: icons[focusedIndex - minLineY], + editingIndex: focusedIndex, + editingSelectionEnd: end, + editingSelectionStart: start, + editingType: ExplorerEditingType.Rename, + editingValue: item.name, + focus: FocusId.Input, + inputSource: InputSource.Script, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/Render2/Render2.ts b/packages/explorer-view/src/parts/Render2/Render2.ts new file mode 100644 index 0000000..436e2fe --- /dev/null +++ b/packages/explorer-view/src/parts/Render2/Render2.ts @@ -0,0 +1,9 @@ +import * as ApplyRender from '../ApplyRender/ApplyRender.ts' +import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' + +export const render2 = (uid: number, diffResult: readonly number[]): readonly any[] => { + const { newState, oldState } = ExplorerStates.get(uid) + ExplorerStates.set(uid, newState, newState) + const commands = ApplyRender.applyRender(oldState, newState, diffResult) + return commands +} diff --git a/packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts b/packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts new file mode 100644 index 0000000..607ca80 --- /dev/null +++ b/packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts @@ -0,0 +1,11 @@ +import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' +import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' +import * as ViewletExplorerActions from '../GetActions/GetActions.ts' +import * as GetActionsVirtualDom from '../GetActionsVirtualDom/GetActionsVirtualDom.ts' + +export const renderActions = (uid: number): readonly VirtualDomNode[] => { + const { newState } = ExplorerStates.get(uid) + const actions = ViewletExplorerActions.getActions(newState.root) + const dom = GetActionsVirtualDom.getActionsVirtualDom(actions) + return dom +} diff --git a/packages/explorer-view/src/parts/RenderCss/RenderCss.ts b/packages/explorer-view/src/parts/RenderCss/RenderCss.ts new file mode 100644 index 0000000..983e3df --- /dev/null +++ b/packages/explorer-view/src/parts/RenderCss/RenderCss.ts @@ -0,0 +1,33 @@ +import { ViewletCommand } from '@lvce-editor/constants' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getCss } from '../GetCss/GetCss.ts' +import * as GetErrorMessagePosition from '../GetErrorMessagePosition/GetErrorMessagePosition.ts' +import { getScrollBarSize } from '../GetScrollBarSize/GetScrollBarSize.ts' +import { getScrollBarTop } from '../GetScrollBarTop/GetScrollBarTop.ts' +import { getUniqueIndents } from '../GetUniqueIndents/GetUniqueIndents.ts' + +export const renderCss = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { + const { deltaY, focusedIndex, height, itemHeight, items, minLineY, uid, visibleExplorerItems, width } = newState + const uniqueIndents = getUniqueIndents(visibleExplorerItems) + const contentHeight = items.length * itemHeight + const scrollBarTop = getScrollBarTop(height, contentHeight, deltaY) + const scrollBarHeight = getScrollBarSize(height, contentHeight, 20) + const indent = 8 + const padding = 10 + const fileIconWidth = 16 + const defaultPaddingLeft = 0 + const chevronSpace = 22 + const depth = items[focusedIndex]?.depth || 0 + const { errorMessageWidth, left, top } = GetErrorMessagePosition.getErrorMessagePosition( + itemHeight, + focusedIndex, + minLineY, + depth, + indent, + fileIconWidth, + padding + defaultPaddingLeft + chevronSpace, + width, + ) + const css = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, left, top, errorMessageWidth) + return [ViewletCommand.SetCss, uid, css] +} diff --git a/packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts b/packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts new file mode 100644 index 0000000..70f05fa --- /dev/null +++ b/packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts @@ -0,0 +1,10 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getDragData } from '../GetDragData/GetDragData.ts' + +export const renderDragData = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { + const { focusedIndex, items, uid } = newState + const selected = items.filter((item, index) => item.selected || index === focusedIndex) + const urls = selected.map((item) => item.path) + const dragData = getDragData(urls) + return ['Viewlet.setDragData', uid, dragData] +} diff --git a/packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts b/packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts new file mode 100644 index 0000000..ad84631 --- /dev/null +++ b/packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts @@ -0,0 +1,8 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { Renderer } from '../Renderer/Renderer.ts' +import * as InputName from '../InputName/InputName.ts' + +export const renderEditingSelection: Renderer = (oldState: ExplorerState, newState: ExplorerState): any => { + const { editingSelectionEnd, editingSelectionStart, uid } = newState + return ['Viewlet.setSelectionByName', uid, InputName.ExplorerInput, editingSelectionStart, editingSelectionEnd] +} diff --git a/packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts b/packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts new file mode 100644 index 0000000..69558ad --- /dev/null +++ b/packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts @@ -0,0 +1,98 @@ +import { EventExpression } from '@lvce-editor/constants' +import type { DomEventListener } from '../DomEventListener/DomEventListener.ts' +import * as DomEventListenersFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' + +export const renderEventListeners = (): readonly DomEventListener[] => { + return [ + { + name: DomEventListenersFunctions.HandleInputBlur, + params: ['handleInputBlur'], + }, + { + name: DomEventListenersFunctions.HandleListFocus, + params: ['handleFocus', EventExpression.IsTrusted, EventExpression.EventTargetClassName], + }, + { + name: DomEventListenersFunctions.HandleListBlur, + params: ['handleBlur'], + }, + { + name: DomEventListenersFunctions.HandleClick, + params: [ + 'handleClickAt', + EventExpression.DefaultPrevented, + EventExpression.Button, + EventExpression.CtrlKey, + EventExpression.ShiftKey, + EventExpression.ClientX, + EventExpression.ClientY, + ], + preventDefault: true, + }, + { + name: DomEventListenersFunctions.HandleInputClick, + params: ['handleInputClick'], + preventDefault: true, + }, + { + name: DomEventListenersFunctions.HandleClickOpenFolder, + params: ['handleClickOpenFolder'], + preventDefault: true, + }, + { + name: DomEventListenersFunctions.HandlePointerDown, + params: ['handlePointerDown', EventExpression.Button, EventExpression.ClientX, EventExpression.ClientY], + }, + { + name: DomEventListenersFunctions.HandleDoubleClick, + params: ['handleDoubleClick', EventExpression.ClientX, EventExpression.ClientY], + }, + { + name: DomEventListenersFunctions.HandleEditingInput, + params: ['updateEditingValue', EventExpression.TargetValue], + }, + { + name: DomEventListenersFunctions.HandleContextMenu, + params: ['handleContextMenu', EventExpression.Button, EventExpression.ClientX, EventExpression.ClientY], + preventDefault: true, + }, + { + name: DomEventListenersFunctions.HandleContextMenuWelcome, + params: ['handleContextMenuWelcome'], + preventDefault: true, + }, + { + name: DomEventListenersFunctions.HandleWheel, + params: ['handleWheel', EventExpression.DeltaMode, EventExpression.DeltaY], + passive: true, + }, + { + name: DomEventListenersFunctions.HandleDragOver, + params: ['handleDragOver', EventExpression.ClientX, EventExpression.ClientY], + preventDefault: true, + }, + { + name: DomEventListenersFunctions.HandleDrop, + params: ['handleDrop', EventExpression.ClientX, EventExpression.ClientY, EventExpression.DataTransferFiles2, EventExpression.DataTransferFiles], + preventDefault: true, + }, + { + name: DomEventListenersFunctions.HandleDragLeave, + params: ['handleDragLeave'], + }, + { + name: DomEventListenersFunctions.HandleButtonClick, + params: ['handleButtonClick', EventExpression.TargetName], + }, + { + name: DomEventListenersFunctions.HandleDragEnd, + params: ['handleDragEnd'], + }, + { + // @ts-ignore + dragEffect: 'copyMove', + name: DomEventListenersFunctions.HandleDragStart, + params: ['handleDragStart'], + }, + ] +} diff --git a/packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts b/packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts new file mode 100644 index 0000000..a3d89f3 --- /dev/null +++ b/packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts @@ -0,0 +1,21 @@ +import { ViewletCommand } from '@lvce-editor/constants' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import * as InputName from '../InputName/InputName.ts' +import * as InputSource from '../InputSource/InputSource.ts' + +export const renderFocus = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { + if (newState.inputSource === InputSource.User) { + return [] + } + if (newState.focus === FocusId.Input) { + return [ViewletCommand.FocusElementByName, InputName.ExplorerInput] + } + if (newState.focus === FocusId.List) { + return [ViewletCommand.FocusSelector, '.ListItems'] + } + // TODO + // 1. when focused, focus the outer list element + // 2. when focused, set focus context in renderer worker + return [] +} diff --git a/packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts b/packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts new file mode 100644 index 0000000..c7ef35f --- /dev/null +++ b/packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts @@ -0,0 +1,14 @@ +import { ViewletCommand, WhenExpression } from '@lvce-editor/constants' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusId from '../FocusId/FocusId.ts' + +export const renderFocusContext = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { + const { uid } = newState + if (newState.focus === FocusId.Input) { + return [ViewletCommand.SetFocusContext, uid, WhenExpression.FocusExplorerEditBox] + } + if (newState.focus === FocusId.List) { + return [ViewletCommand.SetFocusContext, uid, WhenExpression.FocusExplorer] + } + return [] +} diff --git a/packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts b/packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts new file mode 100644 index 0000000..f84c899 --- /dev/null +++ b/packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts @@ -0,0 +1,11 @@ +import { ViewletCommand } from '@lvce-editor/constants' +import { diffTree } from '@lvce-editor/virtual-dom-worker' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { renderItems } from '../RenderItems/RenderItems.ts' + +export const renderIncremental = (oldState: ExplorerState, newState: ExplorerState): any => { + const oldDom = renderItems(oldState, oldState)[2] + const newDom = renderItems(newState, newState)[2] + const patches = diffTree(oldDom, newDom) + return [ViewletCommand.SetPatches, newState.uid, patches] +} diff --git a/packages/explorer-view/src/parts/RenderItems/RenderItems.ts b/packages/explorer-view/src/parts/RenderItems/RenderItems.ts new file mode 100644 index 0000000..0d9a085 --- /dev/null +++ b/packages/explorer-view/src/parts/RenderItems/RenderItems.ts @@ -0,0 +1,30 @@ +import { ViewletCommand } from '@lvce-editor/constants' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetExplorerVirtualDom from '../GetExplorerVirtualDom/GetExplorerVirtualDom.ts' +import * as GetLoadErrorMessage from '../GetLoadErrorMessage/GetLoadErrorMessage.ts' + +export const renderItems = (oldState: ExplorerState, newState: ExplorerState): any => { + const { dropTargets, editingErrorMessage, focused, focusedIndex, height, initial, itemHeight, items, root, width } = newState + const visibleDirents = newState.visibleExplorerItems + const isWide = width > 450 + const contentHeight = items.length * itemHeight + const loadErrorMessage = GetLoadErrorMessage.getLoadErrorMessage(newState) + const showOpenAnotherFolderButton = GetLoadErrorMessage.shouldShowOpenAnotherFolderButton(newState) + if (initial) { + return [ViewletCommand.SetDom2, newState.uid, []] + } + const dom = GetExplorerVirtualDom.getExplorerVirtualDom( + visibleDirents, + focusedIndex, + root, + isWide, + focused, + dropTargets, + height, + contentHeight, + editingErrorMessage, + loadErrorMessage, + showOpenAnotherFolderButton, + ) + return [ViewletCommand.SetDom2, newState.uid, dom] +} diff --git a/packages/explorer-view/src/parts/RenderValue/RenderValue.ts b/packages/explorer-view/src/parts/RenderValue/RenderValue.ts new file mode 100644 index 0000000..42a5007 --- /dev/null +++ b/packages/explorer-view/src/parts/RenderValue/RenderValue.ts @@ -0,0 +1,14 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as FocusId from '../FocusId/FocusId.ts' +import * as InputName from '../InputName/InputName.ts' +import * as InputSource from '../InputSource/InputSource.ts' + +export const renderValue = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { + if (newState.inputSource === InputSource.User) { + return [] + } + if (newState.focus === FocusId.Input) { + return ['Viewlet.setValueByName', InputName.ExplorerInput, newState.editingValue] + } + return [] +} diff --git a/packages/explorer-view/src/parts/Renderer/Renderer.ts b/packages/explorer-view/src/parts/Renderer/Renderer.ts new file mode 100644 index 0000000..d67e331 --- /dev/null +++ b/packages/explorer-view/src/parts/Renderer/Renderer.ts @@ -0,0 +1,5 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export interface Renderer { + (oldState: ExplorerState, newState: ExplorerState): readonly any[] +} diff --git a/packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts b/packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts new file mode 100644 index 0000000..7b5f6ca --- /dev/null +++ b/packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts @@ -0,0 +1,12 @@ +import { IconThemeWorker } from '@lvce-editor/rpc-registry' +import type { IconRequest } from '../IconRequest/IconRequest.ts' +import { toSimpleIconRequest } from '../ToSimpleIconRequest/ToSimpleIconRequest.ts' + +export const requestFileIcons = async (requests: readonly IconRequest[]): Promise => { + if (requests.length === 0) { + return [] + } + const simpleRequests = requests.map(toSimpleIconRequest) + const icons = await IconThemeWorker.getIcons(simpleRequests) + return icons +} diff --git a/packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts b/packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts new file mode 100644 index 0000000..26129f0 --- /dev/null +++ b/packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts @@ -0,0 +1,13 @@ +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' + +export const resetEditing = { + editingErrorMessage: '', + editingIcon: '', + editingIndex: -1, + editingSelection: { + end: 0, + start: 0, + }, + editingType: ExplorerEditingType.None, + editingValue: '', +} diff --git a/packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts b/packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts new file mode 100644 index 0000000..767ee6f --- /dev/null +++ b/packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts @@ -0,0 +1,44 @@ +import * as DirentType from '../DirentType/DirentType.ts' +import * as ErrorCodes from '../ErrorCodes/ErrorCodes.ts' +import * as FileSystem from '../FileSystem/FileSystem.ts' +import * as GetSymlinkType from '../GetSymlinkType/GetSymlinkType.ts' +import * as IsSymbolicLink from '../IsSymbolicLink/IsSymbolicLink.ts' + +// TODO maybe resolving of symbolic links should happen in shared process? +// so that there is less code and less work in the frontend +const resolveSymbolicLink = async (uri: string, rawDirent: any): Promise => { + try { + // TODO support windows paths + const absolutePath = uri + '/' + rawDirent.name + const type = await FileSystem.stat(absolutePath) + const symLinkType = GetSymlinkType.getSymlinkType(type) + return { + name: rawDirent.name, + type: symLinkType, + } + } catch (error) { + // @ts-ignore + if (error && error.code === ErrorCodes.ENOENT) { + return { + name: rawDirent.name, + type: DirentType.SymLinkFile, + } + } + console.error(`Failed to resolve symbolic link for ${rawDirent.name}: ${error}`) + return rawDirent + } +} + +export const resolveSymbolicLinks = async (uri: string, rawDirents: readonly any[]): Promise => { + const promises = [] + for (const rawDirent of rawDirents) { + if (IsSymbolicLink.isSymbolicLink(rawDirent)) { + const resolvedDirent = resolveSymbolicLink(uri, rawDirent) + promises.push(resolvedDirent) + } else { + promises.push(rawDirent) + } + } + const resolvedDirents = await Promise.all(promises) + return resolvedDirents +} diff --git a/packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts b/packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts new file mode 100644 index 0000000..39c061a --- /dev/null +++ b/packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts @@ -0,0 +1,8 @@ +import * as DirentType from '../DirentType/DirentType.ts' + +export const restoreDirentType = (rawDirentType: number, path: string, expandedPaths: readonly string[]): number => { + if (rawDirentType === DirentType.Directory && expandedPaths.includes(path)) { + return DirentType.DirectoryExpanded + } + return rawDirentType +} diff --git a/packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts b/packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts new file mode 100644 index 0000000..b0265b7 --- /dev/null +++ b/packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts @@ -0,0 +1,53 @@ +import * as Character from '../Character/Character.ts' +import { getChildDirentsRaw } from '../GetChildDirentsRaw/GetChildDirentsRaw.ts' +import { getSavedChildDirents } from '../GetSavedChildDirents/GetSavedChildDirents.ts' +import * as PromiseStatus from '../PromiseStatus/PromiseStatus.ts' + +const createDirents = ( + root: string, + expandedDirentPaths: readonly string[], + expandedDirentChildren: any, + excluded: readonly string[], + pathSeparator: string, +): readonly any[] => { + const dirents = [] + const map = Object.create(null) + for (let i = 0; i < expandedDirentPaths.length; i++) { + const path = expandedDirentPaths[i] + const children = expandedDirentChildren[i] + if (children.status === PromiseStatus.Fulfilled) { + map[path] = children.value + } + } + dirents.push(...getSavedChildDirents(map, root, 1, excluded, pathSeparator)) + return dirents +} + +const getSavedExpandedPaths = (savedState: any, root: string): any => { + if (savedState && savedState.root !== root) { + return [] + } + if (savedState && savedState.expandedPaths && Array.isArray(savedState.expandedPaths)) { + return savedState.expandedPaths + } + return [] +} + +export const restoreExpandedState = async (savedState: any, root: any, pathSeparator: any, excluded: any): Promise => { + // TODO read all opened folders in parallel + // ignore ENOENT errors + // ignore ENOTDIR errors + // merge all dirents + // restore scroll location + const expandedPaths = getSavedExpandedPaths(savedState, root) + if (root === Character.EmptyString) { + return [] + } + const expandedDirentPaths = [root, ...expandedPaths] + const expandedDirentChildren = await Promise.allSettled(expandedDirentPaths.map(getChildDirentsRaw)) + if (expandedDirentChildren[0].status === PromiseStatus.Rejected) { + throw expandedDirentChildren[0].reason + } + const dirents = createDirents(root, expandedDirentPaths, expandedDirentChildren, excluded, pathSeparator) + return dirents +} diff --git a/packages/explorer-view/src/parts/RestoreState/RestoreState.ts b/packages/explorer-view/src/parts/RestoreState/RestoreState.ts new file mode 100644 index 0000000..a7c7fde --- /dev/null +++ b/packages/explorer-view/src/parts/RestoreState/RestoreState.ts @@ -0,0 +1,41 @@ +import type { RestoredState } from '../RestoredState/RestoredState.ts' +import { hasProperty } from '../HasProperty/HasProperty.ts' + +const getSavedMinLineY = (savedState: unknown): number => { + if (hasProperty(savedState, 'minLineY') && typeof savedState.minLineY === 'number') { + return savedState.minLineY + } + return 0 +} +const getSavedDeltaY = (savedState: unknown): number => { + if (hasProperty(savedState, 'deltaY') && typeof savedState.deltaY === 'number') { + return savedState.deltaY + } + return 0 +} + +const getSavedWorkspacePath = (savedState: unknown): string => { + if (hasProperty(savedState, 'workspacePath') && typeof savedState.workspacePath === 'string') { + return savedState.workspacePath + } + return '' +} + +export const restoreState = (savedState: unknown): RestoredState => { + if (!savedState) { + return { + deltaY: 0, + minLineY: 0, + root: '', + } + } + + const root = getSavedWorkspacePath(savedState) + const minLineY = getSavedMinLineY(savedState) + const deltaY = getSavedDeltaY(savedState) + return { + deltaY, + minLineY, + root, + } +} diff --git a/packages/explorer-view/src/parts/RestoredState/RestoredState.ts b/packages/explorer-view/src/parts/RestoredState/RestoredState.ts new file mode 100644 index 0000000..48d0137 --- /dev/null +++ b/packages/explorer-view/src/parts/RestoredState/RestoredState.ts @@ -0,0 +1,5 @@ +export interface RestoredState { + readonly deltaY: number + readonly minLineY: number + readonly root: string +} diff --git a/packages/explorer-view/src/parts/RevealItem/RevealItem.ts b/packages/explorer-view/src/parts/RevealItem/RevealItem.ts new file mode 100644 index 0000000..f93b797 --- /dev/null +++ b/packages/explorer-view/src/parts/RevealItem/RevealItem.ts @@ -0,0 +1,20 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as Assert from '../Assert/Assert.ts' +import * as GetIndex from '../GetIndex/GetIndex.ts' +import * as IsUriWithinRoot from '../IsUriWithinRoot/IsUriWithinRoot.ts' +import * as RevealItemHidden from '../RevealItemHidden/RevealItemHidden.ts' +import * as RevealItemVisible from '../RevealItemVisible/RevealItemVisible.ts' + +export const revealItem = async (state: ExplorerState, uri: string): Promise => { + Assert.object(state) + Assert.string(uri) + const { items, pathSeparator, root } = state + if (!IsUriWithinRoot.isUriWithinRoot(root, uri, pathSeparator)) { + return state + } + const index = GetIndex.getIndex(items, uri) + if (index === -1) { + return RevealItemHidden.revealItemHidden(state, uri) + } + return RevealItemVisible.revealItemVisible(state, index) +} diff --git a/packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts b/packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts new file mode 100644 index 0000000..49885b7 --- /dev/null +++ b/packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts @@ -0,0 +1,35 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getIndex } from '../GetIndex/GetIndex.ts' +import { getPathParts } from '../GetPathParts/GetPathParts.ts' +import { getPathPartsChildren } from '../GetPathPartsChildren/GetPathPartsChildren.ts' +import { getPathPartsToReveal } from '../GetPathPartsToReveal/GetPathPartsToReveal.ts' +import { mergeVisibleWithHiddenItems } from '../MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts' +import { orderDirents } from '../OrderDirents/OrderDirents.ts' +import { scrollInto } from '../ScrollInto/ScrollInto.ts' + +// TODO maybe just insert items into explorer and refresh whole explorer +export const revealItemHidden = async (state: ExplorerState, uri: string): Promise => { + const { items, maxLineY, minLineY, pathSeparator, root } = state + const pathParts = getPathParts(root, uri, pathSeparator) + if (pathParts.length === 0) { + return state + } + const pathPartsToReveal = getPathPartsToReveal(root, pathParts, items) + const pathPartsChildren = await getPathPartsChildren(pathPartsToReveal) + const pathPartsChildrenFlat = pathPartsChildren.flat() + const orderedPathParts = orderDirents(pathPartsChildrenFlat) + const mergedDirents = mergeVisibleWithHiddenItems(items, orderedPathParts) + const index = getIndex(mergedDirents, uri) + if (index === -1) { + throw new Error(`File not found in explorer ${uri}`) + } + const { newMaxLineY, newMinLineY } = scrollInto(index, minLineY, maxLineY) + return { + ...state, + focused: true, + focusedIndex: index, + items: mergedDirents, + maxLineY: newMaxLineY, + minLineY: newMinLineY, + } +} diff --git a/packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts b/packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts new file mode 100644 index 0000000..b4e8641 --- /dev/null +++ b/packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts @@ -0,0 +1,14 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ScrollInto from '../ScrollInto/ScrollInto.ts' + +export const revealItemVisible = (state: ExplorerState, index: number): ExplorerState => { + const { maxLineY, minLineY } = state + const { newMaxLineY, newMinLineY } = ScrollInto.scrollInto(index, minLineY, maxLineY) + return { + ...state, + focused: true, + focusedIndex: index, + maxLineY: newMaxLineY, + minLineY: newMinLineY, + } +} diff --git a/packages/explorer-view/src/parts/RpcId/RpcId.ts b/packages/explorer-view/src/parts/RpcId/RpcId.ts new file mode 100644 index 0000000..e6e564a --- /dev/null +++ b/packages/explorer-view/src/parts/RpcId/RpcId.ts @@ -0,0 +1 @@ +export const RendererWorker = 1 diff --git a/packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts b/packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts new file mode 100644 index 0000000..260ee61 --- /dev/null +++ b/packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts @@ -0,0 +1 @@ +export * from '@lvce-editor/rpc-registry' diff --git a/packages/explorer-view/src/parts/SaveState/SaveState.ts b/packages/explorer-view/src/parts/SaveState/SaveState.ts new file mode 100644 index 0000000..bf9c2eb --- /dev/null +++ b/packages/explorer-view/src/parts/SaveState/SaveState.ts @@ -0,0 +1,16 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { SavedState } from '../SavedState/SavedState.ts' +import * as GetPath from '../GetPath/GetPath.ts' +import * as IsExpandedDirectory from '../IsExpandedDirectory/IsExpandedDirectory.ts' + +export const saveState = (state: ExplorerState): SavedState => { + const { deltaY, items, maxLineY, minLineY, root } = state + const expandedPaths = items.filter(IsExpandedDirectory.isExpandedDirectory).map(GetPath.getPath) + return { + deltaY, + expandedPaths, + maxLineY, + minLineY, + root, + } +} diff --git a/packages/explorer-view/src/parts/SavedState/SavedState.ts b/packages/explorer-view/src/parts/SavedState/SavedState.ts new file mode 100644 index 0000000..b9344cb --- /dev/null +++ b/packages/explorer-view/src/parts/SavedState/SavedState.ts @@ -0,0 +1,7 @@ +export interface SavedState { + readonly deltaY: number + readonly expandedPaths: readonly string[] + readonly maxLineY: number + readonly minLineY: number + readonly root: string +} diff --git a/packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts b/packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts new file mode 100644 index 0000000..fa9beb4 --- /dev/null +++ b/packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts @@ -0,0 +1,23 @@ +import type { ScrollIntoResult } from '../ScrollIntoResult/ScrollIntoResult.ts' + +export const scrollInto = (index: number, minLineY: number, maxLineY: number): ScrollIntoResult => { + const diff = maxLineY - minLineY + const smallerHalf = Math.floor(diff / 2) + const largerHalf = diff - smallerHalf + if (index < minLineY) { + return { + newMaxLineY: index + largerHalf, + newMinLineY: index - smallerHalf, + } + } + if (index >= maxLineY) { + return { + newMaxLineY: index + largerHalf, + newMinLineY: index - smallerHalf, + } + } + return { + newMaxLineY: maxLineY, + newMinLineY: minLineY, + } +} diff --git a/packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts b/packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts new file mode 100644 index 0000000..26cf9e8 --- /dev/null +++ b/packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts @@ -0,0 +1,4 @@ +export interface ScrollIntoResult { + readonly newMaxLineY: number + readonly newMinLineY: number +} diff --git a/packages/explorer-view/src/parts/SelectAll/SelectAll.ts b/packages/explorer-view/src/parts/SelectAll/SelectAll.ts new file mode 100644 index 0000000..d347680 --- /dev/null +++ b/packages/explorer-view/src/parts/SelectAll/SelectAll.ts @@ -0,0 +1,15 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +// TODO select all should only select all items in the current folder +// and when calling it next item, expand selection to its parent folder +export const selectAll = (state: ExplorerState): ExplorerState => { + const { items } = state + const newItems = items.map((item) => ({ + ...item, + selected: true, + })) + return { + ...state, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/SelectDown/SelectDown.ts b/packages/explorer-view/src/parts/SelectDown/SelectDown.ts new file mode 100644 index 0000000..41bbd3b --- /dev/null +++ b/packages/explorer-view/src/parts/SelectDown/SelectDown.ts @@ -0,0 +1,30 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +const getLastSelectedIndex = (items: readonly ExplorerItem[]): number => { + let lastSelectedIndex = -1 + for (let index = 0; index < items.length; index++) { + if (items[index].selected) { + lastSelectedIndex = index + } + } + return lastSelectedIndex +} + +export const selectDown = (state: ExplorerState): ExplorerState => { + const { focusedIndex, items } = state + const lastSelectedIndex = getLastSelectedIndex(items) + const targetIndex = lastSelectedIndex === -1 ? focusedIndex : lastSelectedIndex + if (targetIndex >= items.length - 1) { + return state + } + const newItems = items.map((item, i) => ({ + ...item, + selected: i === targetIndex + 1 ? true : item.selected || i === focusedIndex, + })) + return { + ...state, + focusedIndex: targetIndex + 1, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts b/packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts new file mode 100644 index 0000000..77fbe2e --- /dev/null +++ b/packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetFocusedFile from '../GetFocusedFile/GetFocusedFile.ts' + +export const selectForCompare = (state: ExplorerState): ExplorerState => { + const focusedFile = GetFocusedFile.getFocusedFile(state) + if (!focusedFile) { + return state + } + return { + ...state, + compareSourceUri: focusedFile.path, + } +} diff --git a/packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts b/packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts new file mode 100644 index 0000000..ebffff3 --- /dev/null +++ b/packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const setSelectedIndices = (state: ExplorerState, indices: number[]): ExplorerState => { + const { items } = state + const newItems = items.map((item, i) => ({ + ...item, + selected: indices.includes(i), + })) + return { + ...state, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/SelectUp/SelectUp.ts b/packages/explorer-view/src/parts/SelectUp/SelectUp.ts new file mode 100644 index 0000000..702f50d --- /dev/null +++ b/packages/explorer-view/src/parts/SelectUp/SelectUp.ts @@ -0,0 +1,18 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const selectUp = (state: ExplorerState): ExplorerState => { + const { focusedIndex, items } = state + const firstSelectedIndex = items.findIndex((item) => item.selected) + const targetIndex = firstSelectedIndex === -1 ? focusedIndex : firstSelectedIndex + if (targetIndex <= 0) { + return state + } + const newItems = items.map((item, i) => ({ + ...item, + selected: i === targetIndex - 1 ? true : item.selected, + })) + return { + ...state, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/Selection/Selection.ts b/packages/explorer-view/src/parts/Selection/Selection.ts new file mode 100644 index 0000000..5d81d28 --- /dev/null +++ b/packages/explorer-view/src/parts/Selection/Selection.ts @@ -0,0 +1,4 @@ +export interface Selection { + readonly end: number + readonly start: number +} diff --git a/packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts b/packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts new file mode 100644 index 0000000..c35850b --- /dev/null +++ b/packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const sendMessagePortToFileSystemWorker = async (port: any): Promise => { + await RendererWorker.sendMessagePortToFileSystemWorker(port, 0) +} diff --git a/packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts b/packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts new file mode 100644 index 0000000..8186bd1 --- /dev/null +++ b/packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const sendMessagePortToIconThemeWorker = async (port: any): Promise => { + await RendererWorker.sendMessagePortToIconThemeWorker(port, 0) +} diff --git a/packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts b/packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts new file mode 100644 index 0000000..d18eed8 --- /dev/null +++ b/packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts @@ -0,0 +1,24 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const setDeltaY = async (state: ExplorerState, deltaY: number): Promise => { + if (!Number.isFinite(deltaY)) { + return state + } + const { height, itemHeight, items } = state + if (deltaY < 0) { + deltaY = 0 + } else if (deltaY > items.length * itemHeight - height) { + deltaY = Math.max(items.length * itemHeight - height, 0) + } + if (state.deltaY === deltaY) { + return state + } + const minLineY = Math.round(deltaY / itemHeight) + const maxLineY = minLineY + Math.round(height / itemHeight) + return { + ...state, + deltaY, + maxLineY, + minLineY, + } +} diff --git a/packages/explorer-view/src/parts/SetFocus/SetFocus.ts b/packages/explorer-view/src/parts/SetFocus/SetFocus.ts new file mode 100644 index 0000000..a723a52 --- /dev/null +++ b/packages/explorer-view/src/parts/SetFocus/SetFocus.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const setFocus = (key: number): Promise => { + return RendererWorker.invoke('Focus.setFocus', key) +} diff --git a/packages/explorer-view/src/parts/Settings/Settings.ts b/packages/explorer-view/src/parts/Settings/Settings.ts new file mode 100644 index 0000000..8ef1d39 --- /dev/null +++ b/packages/explorer-view/src/parts/Settings/Settings.ts @@ -0,0 +1,6 @@ +export interface Settings { + readonly confirmDelete: boolean + readonly confirmPaste: boolean + readonly sourceControlDecorations: boolean + readonly useChevrons: boolean +} diff --git a/packages/explorer-view/src/parts/Severity/Severity.ts b/packages/explorer-view/src/parts/Severity/Severity.ts new file mode 100644 index 0000000..13162c2 --- /dev/null +++ b/packages/explorer-view/src/parts/Severity/Severity.ts @@ -0,0 +1,4 @@ +export const None = 0 +export const Info = 1 +export const Warning = 2 +export const Error = 3 diff --git a/packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts b/packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts new file mode 100644 index 0000000..8014dba --- /dev/null +++ b/packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts @@ -0,0 +1,5 @@ +import { RendererWorker } from '@lvce-editor/rpc-registry' + +export const showErrorAlert = async (errorMessage: string): Promise => { + await RendererWorker.confirm(errorMessage) +} diff --git a/packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts b/packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts new file mode 100644 index 0000000..e7d52d9 --- /dev/null +++ b/packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts @@ -0,0 +1,6 @@ +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as CompareDirent from '../CompareDirent/CompareDirent.ts' + +export const sortExplorerItems = (rawDirents: readonly RawDirent[]): readonly RawDirent[] => { + return rawDirents.toSorted(CompareDirent.compareDirent) +} diff --git a/packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts b/packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts new file mode 100644 index 0000000..dfe4080 --- /dev/null +++ b/packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts @@ -0,0 +1,11 @@ +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as SortExplorerItems from '../SortExplorerItems/SortExplorerItems.ts' + +export const sortPathDirentsMap = (map: Record): Record => { + const sortedMap: Record = Object.create(null) + for (const [key, value] of Object.entries(map)) { + const sorted = SortExplorerItems.sortExplorerItems(value) + sortedMap[key] = sorted + } + return sortedMap +} diff --git a/packages/explorer-view/src/parts/Terminate/Terminate.ts b/packages/explorer-view/src/parts/Terminate/Terminate.ts new file mode 100644 index 0000000..d47184c --- /dev/null +++ b/packages/explorer-view/src/parts/Terminate/Terminate.ts @@ -0,0 +1,3 @@ +export const terminate = (): void => { + globalThis.close() +} diff --git a/packages/explorer-view/src/parts/Timeout/Timeout.ts b/packages/explorer-view/src/parts/Timeout/Timeout.ts new file mode 100644 index 0000000..39a09dc --- /dev/null +++ b/packages/explorer-view/src/parts/Timeout/Timeout.ts @@ -0,0 +1,5 @@ +export const sleep = async (duration: number): Promise => { + const { promise, resolve } = Promise.withResolvers() + setTimeout(resolve, duration) + await promise +} diff --git a/packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts b/packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts new file mode 100644 index 0000000..b75aee8 --- /dev/null +++ b/packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts @@ -0,0 +1,12 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../DirentType/DirentType.ts' + +export const toCollapsedDirent = (dirent: ExplorerItem): ExplorerItem => { + if (dirent.type === DirentType.DirectoryExpanded) { + return { + ...dirent, + type: DirentType.Directory, + } + } + return dirent +} diff --git a/packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts b/packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts new file mode 100644 index 0000000..128a400 --- /dev/null +++ b/packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts @@ -0,0 +1,24 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import { join2 } from '../Path/Path.ts' + +// TODO figure out whether this uses too much memory (name,path -> redundant, depth could be computed on demand) +export const toDisplayDirent = ( + parentPath: string, + parentDepth: number, + rawDirentType: number, + rawDirentName: string, + index: number, + length: number, +): ExplorerItem => { + const path = join2(parentPath, rawDirentName) + return { + depth: parentDepth + 1, + icon: '', + name: rawDirentName, + path, // TODO storing absolute path might be too costly, could also store relative path here + posInSet: index + 1, + selected: false, + setSize: length, + type: rawDirentType, + } +} diff --git a/packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts b/packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts new file mode 100644 index 0000000..383f37e --- /dev/null +++ b/packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts @@ -0,0 +1,23 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as SortExplorerItems from '../SortExplorerItems/SortExplorerItems.ts' +import { toDisplayDirent } from '../ToDisplayDirent/ToDisplayDirent.ts' + +export const toDisplayDirents = ( + pathSeparator: string, + rawDirents: readonly RawDirent[], + parentDirentPath: string, + parentDirentDepth: number, + excluded: readonly string[], + expanded: boolean = false, +): readonly ExplorerItem[] => { + rawDirents = SortExplorerItems.sortExplorerItems(rawDirents) + const result: ExplorerItem[] = [] + const visibleItems = rawDirents.filter((item) => !excluded.includes(item.name)) + const count = visibleItems.length + for (let i = 0; i < visibleItems.length; i++) { + const rawDirent = visibleItems[i] + result.push(toDisplayDirent(parentDirentPath, parentDirentDepth, rawDirent.type, rawDirent.name, i, count)) + } + return result +} diff --git a/packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts b/packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts new file mode 100644 index 0000000..019e67c --- /dev/null +++ b/packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts @@ -0,0 +1,9 @@ +import type { IconRequest } from '../IconRequest/IconRequest.ts' +import { getSimpleIconRequestType } from '../GetSimpleIconRequestType/GetSimpleIconRequestType.ts' + +export const toSimpleIconRequest = (request: IconRequest): any => { + return { + name: request.name, + type: getSimpleIconRequestType(request.type), + } +} diff --git a/packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts b/packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts new file mode 100644 index 0000000..034b649 --- /dev/null +++ b/packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts @@ -0,0 +1,20 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' + +export const toggleIndividualSelection = async (state: ExplorerState, index: number): Promise => { + const { items } = state + + // If index is out of range, do nothing + if (index < 0 || index >= items.length) { + return state + } + + const newItems = items.map((item, i) => ({ + ...item, + selected: i === index ? !item.selected : item.selected, + })) + + return { + ...state, + items: newItems, + } +} diff --git a/packages/explorer-view/src/parts/Tree/Tree.ts b/packages/explorer-view/src/parts/Tree/Tree.ts new file mode 100644 index 0000000..8503737 --- /dev/null +++ b/packages/explorer-view/src/parts/Tree/Tree.ts @@ -0,0 +1,5 @@ +import type { TreeItem } from '../TreeItem/TreeItem.ts' + +export interface Tree { + readonly [key: string]: readonly TreeItem[] +} diff --git a/packages/explorer-view/src/parts/TreeItem/TreeItem.ts b/packages/explorer-view/src/parts/TreeItem/TreeItem.ts new file mode 100644 index 0000000..20b326c --- /dev/null +++ b/packages/explorer-view/src/parts/TreeItem/TreeItem.ts @@ -0,0 +1,4 @@ +export interface TreeItem { + readonly name: string + readonly type: number +} diff --git a/packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts b/packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts new file mode 100644 index 0000000..8f03bcf --- /dev/null +++ b/packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts @@ -0,0 +1,9 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { Tree } from '../Tree/Tree.ts' +import { treeToArrayInternal } from '../TreeToArrayInternal/TreeToArrayInternal.ts' + +export const treeToArray = (map: Tree, root: string): readonly ExplorerItem[] => { + const items: ExplorerItem[] = [] + treeToArrayInternal(map, root, items, '', 1) + return items +} diff --git a/packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts b/packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts new file mode 100644 index 0000000..a2fc8e9 --- /dev/null +++ b/packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts @@ -0,0 +1,27 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { Tree } from '../Tree/Tree.ts' +import { join2 } from '../Path/Path.ts' + +export const treeToArrayInternal = (map: Tree, root: string, items: ExplorerItem[], path: string, depth: number): void => { + const children = map[path] + if (!children) { + return + } + const count = children.length + for (let i = 0; i < count; i++) { + const child = children[i] + const childPath = join2(path, child.name) + const absolutePath = join2(root, childPath) + items.push({ + depth, + icon: '', + name: child.name, + path: absolutePath, + posInSet: i + 1, + selected: false, + setSize: count, + type: child.type, + }) + treeToArrayInternal(map, root, items, childPath, depth + 1) + } +} diff --git a/packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts b/packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts new file mode 100644 index 0000000..e09928e --- /dev/null +++ b/packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts @@ -0,0 +1,3 @@ +export interface TreeUpdate { + [key: string]: readonly any[] +} diff --git a/packages/explorer-view/src/parts/UiStrings/UiStrings.ts b/packages/explorer-view/src/parts/UiStrings/UiStrings.ts new file mode 100644 index 0000000..0a504d6 --- /dev/null +++ b/packages/explorer-view/src/parts/UiStrings/UiStrings.ts @@ -0,0 +1,34 @@ +export const CollapseAllFoldersInExplorer = 'Collapse All Folders in Explorer' +export const Copy = 'Copy' +export const CopyPath = 'Copy Path' +export const CopyRelativePath = 'Copy Relative Path' +export const CompareWithSelected = 'Compare with Selected' +export const Cut = 'Cut' +export const Delete = 'Delete' +export const DeleteConfirmationMultiple = 'Are you sure you want to delete {0} items?' +export const DeleteConfirmationSingle = 'Are you sure you want to delete "{0}"?' +export const Explorer = 'Explorer' +export const FileNameCannotStartWithSlash = 'A file or folder name cannot start with a slash.' +export const FileOrFolderAlreadyExists = 'A file or folder **{PH1}** already exists at this location. Please choose a different name.' +export const FileOrFolderNameMustBeProvider = 'A file or folder name must be provided.' +export const FileCannotStartWithSlash = 'A file cannot start with slash.' +export const FileCannotStartWithDot = 'A file or folder name cannot start with a dot.' +export const FileCannotStartWithBackSlash = 'A file or folder name cannot start with a backslash.' +export const FilesExplorer = 'Files Explorer' +export const LeadingOrTrailingWhitespaceDetected = 'Leading or trailing whitespace detected in file or folder name.' +export const NewFile = 'New File...' +export const NewFolder = 'New Folder...' +export const NoFolderOpen = 'No Folder Open' +export const OpenAnotherFolder = 'Open another folder' +export const OpenContainingFolder = 'Open Containing Folder' +export const OpenFolder = 'Open folder' +export const OpenInIntegratedTerminal = 'Open in integrated Terminal' +export const Paste = 'Paste' +export const PasteConfirmation = 'Are you sure you want to paste these files?' +export const RefreshExplorer = 'Refresh Explorer' +export const RemoveFolderFromWorkspace = 'Remove folder from workspace' +export const Rename = 'Rename' +export const SelectForCompare = 'Select for Compare' +export const TheNameIsNotValid = 'The name **{0}** is not valid as a file or folder name. Please choose a different name.' +export const TypeAFileName = 'Type file name. Press Enter to confirm or Escape to cancel.' // TODO use keybinding +export const YouHaveNotYetOpenedAFolder = 'You have not yet opened a folder.' diff --git a/packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts b/packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts new file mode 100644 index 0000000..a8ecb9c --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts @@ -0,0 +1,34 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { RawDirent } from '../RawDirent/RawDirent.ts' +import * as CompareDirent from '../CompareDirent/CompareDirent.ts' +import { createTree } from '../CreateTree/CreateTree.ts' +import { join2 } from '../Path/Path.ts' +import { treeToArray } from '../TreeToArray/TreeToArray.ts' + +export const updateDirentsAtPath = ( + items: readonly ExplorerItem[], + path: string, + root: string, + newDirents: readonly RawDirent[], +): readonly ExplorerItem[] => { + const sortedDirents = newDirents + .map((dirent, index) => ({ + depth: 0, // TODO + icon: '', + name: dirent.name, + path: join2(path, dirent.name), + posInSet: index + 1, + selected: false, + setSize: newDirents.length, + type: dirent.type, + })) + .toSorted(CompareDirent.compareDirent) + + const tree = createTree(items, root) + const updatedTree = { + ...tree, + [path]: sortedDirents, + } + const newItems = treeToArray(updatedTree, root) + return newItems +} diff --git a/packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts b/packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts new file mode 100644 index 0000000..5a456c6 --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts @@ -0,0 +1,25 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' +import { getEditingIcon } from '../GetEditingIcon/GetEditingIcon.ts' +import { getSiblingFileNames } from '../GetSiblingFileNames/GetSiblingFileNames.ts' +import * as InputSource from '../InputSource/InputSource.ts' +import * as ValidateFileName2 from '../ValidateFileName2/ValidateFileName2.ts' + +export const updateEditingValue = async (state: ExplorerState, value: string, inputSource: number = InputSource.User): Promise => { + const { editingIndex, editingType, focusedIndex, items, pathSeparator, root } = state + const editingIcon = await getEditingIcon(editingType, value, items[editingIndex]?.type) + + // Get sibling file names for validation during file/folder creation + let siblingFileNames: readonly string[] = [] + if (editingType === ExplorerEditingType.CreateFile || editingType === ExplorerEditingType.CreateFolder) { + siblingFileNames = getSiblingFileNames(items, focusedIndex, root, pathSeparator) + } + + const editingErrorMessage = ValidateFileName2.validateFileName2(value, siblingFileNames) + return { + ...state, + editingErrorMessage, + editingIcon, + editingValue: value, + } +} diff --git a/packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts b/packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts new file mode 100644 index 0000000..b9adeca --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts @@ -0,0 +1,57 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import { createTree } from '../CreateTree/CreateTree.ts' +import * as GetFileIcons from '../GetFileIcons/GetFileIcons.ts' +import * as GetIndex from '../GetIndex/GetIndex.ts' +import * as GetExplorerMaxLineY from '../GetMaxLineY/GetMaxLineY.ts' +import { getParentFolder } from '../GetParentFolder/GetParentFolder.ts' +import { getPathParts } from '../GetPathParts/GetPathParts.ts' +import { getPathPartsChildren } from '../GetPathPartsChildren/GetPathPartsChildren.ts' +import { mergeTrees } from '../MergeTrees/MergeTrees.ts' +import { join2 } from '../Path/Path.ts' +import { treeToArray } from '../TreeToArray/TreeToArray.ts' + +export interface ExplorerUpdateResult { + readonly newFileIconCache: FileIconCache + readonly newFocusedIndex: number + readonly newIcons: readonly string[] + readonly newItems: readonly ExplorerItem[] + readonly newMaxLineY: number + readonly newMinLineY: number +} + +export const updateExplorerAfterFileOperations = async ( + state: ExplorerState, + operations: readonly FileOperation[], +): Promise => { + const { editingValue, fileIconCache, focusedIndex, height, itemHeight, items, minLineY, pathSeparator, root } = state + const newFileName = editingValue + const parentFolder = getParentFolder(items, focusedIndex, root, pathSeparator) + const absolutePath = join2(parentFolder, newFileName) + + // TODO based on operations, find out which paths need to be updated + // then read the direcories that need to be updated + // and update the explorer + const pathPaths = getPathParts(root, absolutePath, pathSeparator) + const children = await getPathPartsChildren(pathPaths) + const tree = createTree(items, root) + const childTree = createTree(children, root) + const merged = mergeTrees(tree, childTree) + const newItems = treeToArray(merged, root) + const dirents = newItems + const newFocusedIndex = GetIndex.getIndex(newItems, absolutePath) + const maxLineY = GetExplorerMaxLineY.getExplorerMaxLineY(minLineY, height, itemHeight, dirents.length) + const visible = dirents.slice(minLineY, maxLineY) + const { icons, newFileIconCache } = await GetFileIcons.getFileIcons(visible, fileIconCache) + + return { + newFileIconCache, + newFocusedIndex, + newIcons: icons, + newItems: dirents, + newMaxLineY: maxLineY, + newMinLineY: minLineY, + } +} diff --git a/packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts b/packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts new file mode 100644 index 0000000..ace7194 --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts @@ -0,0 +1,15 @@ +import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' +import type { IconRequest } from '../IconRequest/IconRequest.ts' + +export const updateIconCache = (iconCache: FileIconCache, missingRequests: readonly IconRequest[], newIcons: readonly string[]): FileIconCache => { + if (missingRequests.length === 0) { + return iconCache + } + const newFileIconCache = { ...iconCache } + for (let i = 0; i < missingRequests.length; i++) { + const request = missingRequests[i] + const icon = newIcons[i] + newFileIconCache[request.path] = icon + } + return newFileIconCache +} diff --git a/packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts b/packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts new file mode 100644 index 0000000..fff10de --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts @@ -0,0 +1,13 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import * as GetFileIcons from '../GetFileIcons/GetFileIcons.ts' + +export const updateIcons = async (state: ExplorerState): Promise => { + const { items, maxLineY, minLineY } = state + const visible = items.slice(minLineY, maxLineY) + const { icons, newFileIconCache } = await GetFileIcons.getFileIcons(visible, Object.create(null)) + return { + ...state, + fileIconCache: newFileIconCache, + icons, + } +} diff --git a/packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts b/packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts new file mode 100644 index 0000000..80a7683 --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts @@ -0,0 +1,24 @@ +import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' +import { getTopLevelDirents } from '../GetTopLevelDirents/GetTopLevelDirents.ts' +import { mergeDirents } from '../MergeDirents/MergeDirents.ts' + +// TODO add lots of tests for this +export const updateRoot = async (state1: ExplorerState): Promise => { + // @ts-ignore + if (state1.disposed) { + return state1 + } + // const file = nativeFiles.files[0] + const topLevelDirents = await getTopLevelDirents(state1.root, state1.pathSeparator, []) + // const state2 = Viewlet.getState('Explorer') + // // TODO what if root changes while reading directories? + // if (state2.disposed || state2.root !== state1.root) { + // return state2 + // } + const newDirents = mergeDirents(state1.items, topLevelDirents) + const state3 = { + ...state1, + items: newDirents, + } + return state3 +} diff --git a/packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts b/packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts new file mode 100644 index 0000000..2467584 --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts @@ -0,0 +1,13 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const updateTree = ( + tree: Record, + path: string, + newDirents: readonly ExplorerItem[], +): Record => { + const updatedTree = { + ...tree, + [path]: newDirents, + } + return updatedTree +} diff --git a/packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts b/packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts new file mode 100644 index 0000000..62ee59b --- /dev/null +++ b/packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts @@ -0,0 +1,12 @@ +import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' + +export const updateTree2 = ( + tree: Record, + update: Record, +): Record => { + const updatedTree = { + ...tree, + ...update, + } + return updatedTree +} diff --git a/packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts b/packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts new file mode 100644 index 0000000..602ee02 --- /dev/null +++ b/packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts @@ -0,0 +1,54 @@ +import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' +import { createUploadTree } from '../CreateUploadTree/CreateUploadTree.ts' +import * as GetFileOperations from '../GetFileOperations/GetFileOperations.ts' + +export interface DroppedFileItem { + readonly kind: 'file' + readonly value: FileSystemFileHandle +} + +export type DroppedItem = DroppedFileItem | FileSystemHandle +export type DroppedArgs = readonly DroppedFileItem[] | readonly FileSystemHandle[] + +export const isDroppedFile = (item: DroppedItem): item is DroppedFileItem => { + return item.kind === 'file' && 'value' in item +} + +export const getFileSystemHandle = (item: DroppedItem): FileSystemHandle => { + if (isDroppedFile(item)) { + return item.value + } + return item +} + +export const getDroppedName = (item: DroppedItem): string => { + if (isDroppedFile(item)) { + return item.value.name + } + return item.name +} + +const getFileSystemHandlesNormalized = (fileSystemHandles: DroppedArgs): readonly FileSystemHandle[] => { + const normalized: FileSystemHandle[] = [] + for (const item of fileSystemHandles) { + normalized.push(getFileSystemHandle(item)) + } + return normalized +} + +export const uploadFileSystemHandles = async (root: string, pathSeparator: string, fileSystemHandles: DroppedArgs): Promise => { + if (fileSystemHandles.length === 0) { + return true + } + const fileSystemHandlesNormalized = getFileSystemHandlesNormalized(fileSystemHandles) + const uploadTree = await createUploadTree(root, fileSystemHandlesNormalized) + const fileOperations = GetFileOperations.getFileOperations(root, uploadTree) + await ApplyFileOperations.applyFileOperations(fileOperations) + + // TODO + // 1. in electron, use webutils.getPathForFile to see if a path is available + // 2. else, walk all files and folders recursively and upload all of them (if there are many, show a progress bar) + + // TODO send file system operations to renderer worker + return true +} diff --git a/packages/explorer-view/src/parts/VError/VError.ts b/packages/explorer-view/src/parts/VError/VError.ts new file mode 100644 index 0000000..a261b97 --- /dev/null +++ b/packages/explorer-view/src/parts/VError/VError.ts @@ -0,0 +1 @@ +export * from '@lvce-editor/verror' diff --git a/packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts b/packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts new file mode 100644 index 0000000..a80700f --- /dev/null +++ b/packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts @@ -0,0 +1,150 @@ +// copied from https://github.com/microsoft/vscode/blob/85925efe02b1be4671c5f37af8386a75a8b35ecc/src/vs/workbench/contrib/files/browser/fileActions.ts by Microsoft (License MIT) +// as well as from https://github.com/microsoft/vscode/blob/b012ab96ad1677c00d3061cf7f20953b57b393a5/src/vs/base/common/strings.ts by Microsoft (License MIT) + +import type { ValidateFileNameResult } from '../ValidateFileNameResult/ValidateFileNameResult.ts' +import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' +import { hasLeadingOrTrailingWhitespace } from '../HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts' +import { isValidBasename } from '../IsValidBaseName/IsValidBaseName.ts' +import * as Severity from '../Severity/Severity.ts' + +/** + * @returns New array with all falsy values removed. The original array IS NOT modified. + */ +export function coalesce(array: ReadonlyArray): T[] { + return array.filter((e): e is T => !!e) +} + +/** + * Removes all occurrences of needle from the beginning and end of haystack. + * @param haystack string to trim + * @param needle the thing to trim (default is a blank) + */ +export function trim(haystack: string, needle: string = ' '): string { + const trimmed = ltrim(haystack, needle) + return rtrim(trimmed, needle) +} + +/** + * Removes all occurrences of needle from the beginning of haystack. + * @param haystack string to trim + * @param needle the thing to trim + */ +export function ltrim(haystack: string, needle: string): string { + if (!haystack || !needle) { + return haystack + } + + const needleLen = needle.length + if (needleLen === 0 || haystack.length === 0) { + return haystack + } + + let offset = 0 + + while (haystack.indexOf(needle, offset) === offset) { + offset = offset + needleLen + } + return haystack.slice(Math.max(0, offset)) +} + +/** + * Removes all occurrences of needle from the end of haystack. + * @param haystack string to trim + * @param needle the thing to trim + */ +export function rtrim(haystack: string, needle: string): string { + if (!haystack || !needle) { + return haystack + } + + const needleLen = needle.length, + haystackLen = haystack.length + + if (needleLen === 0 || haystackLen === 0) { + return haystack + } + + let offset = haystackLen + + while (true) { + const idx = haystack.lastIndexOf(needle, offset - 1) + if (idx === -1 || idx + needleLen !== offset) { + break + } + if (idx === 0) { + return '' + } + offset = idx + } + + return haystack.slice(0, Math.max(0, offset)) +} + +function getWellFormedFileName(filename: string): string { + if (!filename) { + return filename + } + + // Trim tabs + filename = trim(filename, '\t') + + // Remove trailing slashes + filename = rtrim(filename, '/') + filename = rtrim(filename, '\\') + + return filename +} + +export function validateFileName(name: string, existingName: string, siblingFileNames: readonly string[]): ValidateFileNameResult { + // Produce a well formed file name + name = getWellFormedFileName(name) + + // Name not provided + if (!name || name.length === 0 || /^\s+$/.test(name)) { + return { + content: ExplorerStrings.fileOrFolderNameMustBeProvided(), + severity: Severity.Error, + } + } + + // Relative paths only + if (name[0] === '/' || name[0] === '\\') { + return { + content: ExplorerStrings.fileNameCannotStartWithSlash(), + severity: Severity.Error, + } + } + + const names = coalesce(name.split(/[\\/]/)) + + if (name !== existingName) { + // Do not allow to overwrite existing file + const child = siblingFileNames.find((sibling) => sibling === name) + if (child) { + return { + content: ExplorerStrings.fileOrFolderAlreadyExists(name), + severity: Severity.Error, + } + } + } + + // Check for invalid file name. + if (names.some((folderName) => !isValidBasename(folderName, false))) { + return { + content: ExplorerStrings.theNameIsNotValid(), + severity: Severity.Error, + } + } + + if (names.some(hasLeadingOrTrailingWhitespace)) { + return { + content: ExplorerStrings.leadingOrTrailingWhitespaceDetected(), + severity: Severity.Warning, + } + } + + return { + content: '', + severity: 0, + } +} diff --git a/packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts b/packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts new file mode 100644 index 0000000..5c5e0a3 --- /dev/null +++ b/packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts @@ -0,0 +1,32 @@ +import * as Character from '../Character/Character.ts' +import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' + +export const validateFileName2 = (name: string, siblingFileNames: readonly string[] = []): string => { + if (!name) { + const editingErrorMessage = ExplorerStrings.fileOrFolderNameMustBeProvided() + return editingErrorMessage + } + if (name.startsWith(Character.Slash)) { + return ExplorerStrings.fileCannotStartWithSlash() + } + if (name.startsWith(Character.BackSlash)) { + return ExplorerStrings.fileCannotStartWithBackSlash() + } + + // Disallow reserved directory names + if (name === '.' || name === '..' || name === '...') { + return ExplorerStrings.theNameIsNotValid() + } + + // Disallow any filename starting with ../ + if (name.startsWith('../')) { + return ExplorerStrings.theNameIsNotValid() + } + + // Check if file already exists + if (siblingFileNames.includes(name)) { + return ExplorerStrings.fileOrFolderAlreadyExists(name) + } + + return '' +} diff --git a/packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts b/packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts new file mode 100644 index 0000000..093eab9 --- /dev/null +++ b/packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts @@ -0,0 +1,4 @@ +export interface ValidateFileNameResult { + readonly content: string + readonly severity: number +} diff --git a/packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts b/packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts new file mode 100644 index 0000000..ee19a40 --- /dev/null +++ b/packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts @@ -0,0 +1,17 @@ +import * as Path from '../Path/Path.ts' + +export const validateFolderCopy = (sourcePath: string, targetPath: string): string | null => { + // Remove trailing separators for comparison + const normalizedSource = sourcePath.replace(/[/\\]+$/, '') + const normalizedTarget = targetPath.replace(/[/\\]+$/, '') + + // Check if the target path is a subfolder of the source path + if (normalizedTarget.startsWith(normalizedSource + '/') || normalizedTarget.startsWith(normalizedSource + '\\')) { + // Extract folder name using the appropriate path separator + const pathSeparator = normalizedSource.includes('\\') ? '\\' : '/' + const folderName = Path.getBaseName(pathSeparator, normalizedSource) + return `Cannot copy folder ${folderName} into a subfolder of itself` + } + + return null +} diff --git a/packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts b/packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts new file mode 100644 index 0000000..a6ba1a3 --- /dev/null +++ b/packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts @@ -0,0 +1,16 @@ +import type { FileOperation } from '../FileOperation/FileOperation.ts' +import * as FileOperationType from '../FileOperationType/FileOperationType.ts' +import * as ValidateFolderCopy from '../ValidateFolderCopy/ValidateFolderCopy.ts' + +export const validateOperations = (operations: readonly FileOperation[]): readonly string[] => { + const errors: string[] = [] + for (const operation of operations) { + if (operation.type === FileOperationType.Copy) { + const errorMessage = ValidateFolderCopy.validateFolderCopy(operation.from, operation.path) + if (errorMessage) { + errors.push(errorMessage) + } + } + } + return errors +} diff --git a/packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts b/packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts new file mode 100644 index 0000000..9543643 --- /dev/null +++ b/packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts @@ -0,0 +1,10 @@ +export interface ViewletAction { + readonly badgeText?: string + readonly command: string + readonly icon?: string + readonly id: string + readonly name?: string + readonly placeholder?: string + readonly type: number + readonly value?: string +} diff --git a/packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts b/packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts new file mode 100644 index 0000000..87d8651 --- /dev/null +++ b/packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts @@ -0,0 +1,5 @@ +export const Button = 1 +export const Div = 4 +export const Input = 6 +export const Img = 17 +export const P = 50 diff --git a/packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts b/packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts new file mode 100644 index 0000000..b16588a --- /dev/null +++ b/packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts @@ -0,0 +1 @@ +export { text } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts b/packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts new file mode 100644 index 0000000..c8af396 --- /dev/null +++ b/packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts @@ -0,0 +1 @@ +export type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts b/packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts new file mode 100644 index 0000000..f590d17 --- /dev/null +++ b/packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts @@ -0,0 +1,20 @@ +export interface VisibleExplorerItem { + readonly ariaExpanded: string | undefined // TODO make it always string + readonly chevron: number + readonly className: string + readonly decoration?: string + readonly depth: number + readonly hasEditingError: boolean + readonly icon: string + readonly id: string | undefined // TODO make it always string + readonly indent: number + readonly index: number + readonly isCut: boolean + readonly isEditing: boolean + readonly isIgnored: boolean + readonly name: string + readonly path: string + readonly posInSet: number + readonly selected: boolean + readonly setSize: number +} diff --git a/packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts b/packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts new file mode 100644 index 0000000..faaebcc --- /dev/null +++ b/packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts @@ -0,0 +1,2 @@ +export const FocusExplorer = 13 +export const FocusExplorerEditBox = 14 diff --git a/packages/explorer-view/test/AcceptCreate.test.ts b/packages/explorer-view/test/AcceptCreate.test.ts new file mode 100644 index 0000000..87338c6 --- /dev/null +++ b/packages/explorer-view/test/AcceptCreate.test.ts @@ -0,0 +1,274 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { acceptCreate } from '../src/parts/AcceptCreate/AcceptCreate.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import * as ExplorerStrings from '../src/parts/ExplorerStrings/ExplorerStrings.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' + +test.skip('acceptCreate - empty file name', async () => { + const state: ExplorerState = { + ...createDefaultState(), + editingValue: '', + } + + const result = await acceptCreate(state, DirentType.File) + expect(result).toEqual({ + ...state, + editingErrorMessage: ExplorerStrings.fileOrFolderNameMustBeProvided(), + }) +}) + +test('acceptCreate - successful file creation', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.mkdir'() { + return + }, + 'FileSystem.readDirWithFileTypes'(path: string) { + if (path === 'memfs:///workspace') { + return [{ name: 'test', type: DirentType.Directory }] + } + if (path === 'memfs:///workspace/test') { + return [{ name: 'test.txt', type: DirentType.File }] + } + throw new Error(`unexpected file read ${path}`) + }, + 'FileSystem.writeFile'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return Array(2).fill('') + }, + 'Main.openUri'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 1, + editingValue: 'test.txt', + fileIconCache: {}, + focusedIndex: 0, + height: 100, + itemHeight: 20, + items: [ + { + depth: 0, + name: 'test', + path: 'memfs:///workspace/test', + selected: false, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'test.txt', + path: 'memfs:///workspace/test/test.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.EditingFile, + }, + ], + minLineY: 0, + root: 'memfs:///workspace', + } + + const result = await acceptCreate(state, DirentType.File) + expect(result).toEqual({ + ...state, + editingIndex: -1, + editingType: ExplorerEditingType.None, + focus: FocusId.List, + focusedIndex: 1, + items: [ + { + depth: 1, + icon: '', + name: 'test', + path: 'memfs:///workspace/test', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: 'test.txt', + path: 'memfs:///workspace/test/test.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ], + }) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', 'memfs:///workspace/test'], + ['FileSystem.writeFile', 'memfs:///workspace/test/test.txt', ''], + ['FileSystem.readDirWithFileTypes', 'memfs:///workspace'], + ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/test'], + ['Layout.handleWorkspaceRefresh'], + ['Main.openUri', 'memfs:///workspace/test/test.txt', true], + ]) +}) + +test('acceptCreate - successful folder creation does not open uri', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.mkdir'() { + return + }, + 'FileSystem.readDirWithFileTypes'(path: string) { + if (path === 'memfs:///workspace') { + return [{ name: 'test', type: DirentType.Directory }] + } + if (path === 'memfs:///workspace/test') { + return [{ name: 'newfolder', type: DirentType.Directory }] + } + throw new Error(`unexpected file read ${path}`) + }, + 'FileSystem.writeFile'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return Array(2).fill('') + }, + 'Main.openUri'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 1, + editingValue: 'newfolder', + fileIconCache: {}, + focusedIndex: 0, + height: 100, + itemHeight: 20, + items: [ + { + depth: 0, + name: 'test', + path: 'memfs:///workspace/test', + selected: false, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'newfolder', + path: 'memfs:///workspace/test/newfolder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.EditingFolder, + }, + ], + minLineY: 0, + root: 'memfs:///workspace', + } + + const result = await acceptCreate(state, DirentType.Directory) + expect(result.editingIndex).toBe(-1) + expect(result.editingType).toBe(ExplorerEditingType.None) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', 'memfs:///workspace/test'], + ['FileSystem.mkdir', 'memfs:///workspace/test/newfolder'], + ['FileSystem.readDirWithFileTypes', 'memfs:///workspace'], + ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/test'], + ['Layout.handleWorkspaceRefresh'], + ]) +}) + +test('acceptCreate - nested folder creation uses the file parent when a file is focused', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.mkdir'() { + return + }, + 'FileSystem.readDirWithFileTypes'(path: string) { + if (path === 'memfs:///workspace') { + return [ + { name: 'a', type: DirentType.Directory }, + { name: 'file1.txt', type: DirentType.File }, + ] + } + if (path === 'memfs:///workspace/a') { + return [{ name: 'b', type: DirentType.Directory }] + } + if (path === 'memfs:///workspace/a/b') { + return [{ name: 'c', type: DirentType.Directory }] + } + throw new Error(`unexpected file read ${path}`) + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return Array(5).fill('') + }, + 'Main.openUri'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 1, + editingValue: 'a/b/c', + fileIconCache: {}, + focusedIndex: 0, + height: 100, + itemHeight: 20, + items: [ + { + depth: 0, + icon: '', + name: 'file1.txt', + path: 'memfs:///workspace/file1.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + { + depth: 0, + icon: '', + name: '', + path: 'memfs:///workspace', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.EditingFolder, + }, + ], + minLineY: 0, + pathSeparator: '/', + root: 'memfs:///workspace', + } + + await acceptCreate(state, DirentType.Directory) + + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', 'memfs:///workspace/a'], + ['FileSystem.mkdir', 'memfs:///workspace/a/b'], + ['FileSystem.mkdir', 'memfs:///workspace/a/b/c'], + ['FileSystem.readDirWithFileTypes', 'memfs:///workspace'], + ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/a'], + ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/a/b'], + ['Layout.handleWorkspaceRefresh'], + ]) +}) diff --git a/packages/explorer-view/test/AcceptCreateFile.test.ts b/packages/explorer-view/test/AcceptCreateFile.test.ts new file mode 100644 index 0000000..d885f34 --- /dev/null +++ b/packages/explorer-view/test/AcceptCreateFile.test.ts @@ -0,0 +1,51 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { acceptCreateFile } from '../src/parts/AcceptCreateFile/AcceptCreateFile.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' + +test('acceptCreateFile', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.createFile'() {}, + 'FileSystem.readDirWithFileTypes'(...params: any[]) { + const path = params[0] + if (path === '/test') { + return [{ name: 'folder1', type: DirentType.Directory }] + } + return [] + }, + 'FileSystem.writeFile'() {}, + 'IconTheme.getFolderIcon'() { + return 'folder-icon' + }, + 'IconTheme.getIcons'() { + return ['folder-icon'] + }, + 'Main.openUri'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingValue: 'test.txt', + items: [ + { + depth: 0, + name: 'test', + path: 'test', + selected: false, + type: 1, + }, + ], + root: '/test', + } + const newState = await acceptCreateFile(state) + expect(newState.editingIndex).toBe(-1) + expect(newState.editingType).toBe(0) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.writeFile', 'test/test.txt', ''], + ['Layout.handleWorkspaceRefresh'], + ['Main.openUri', 'test/test.txt', true], + ]) +}) diff --git a/packages/explorer-view/test/AcceptEdit.test.ts b/packages/explorer-view/test/AcceptEdit.test.ts new file mode 100644 index 0000000..bd66557 --- /dev/null +++ b/packages/explorer-view/test/AcceptEdit.test.ts @@ -0,0 +1,204 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import * as ViewletExplorerAcceptEdit from '../src/parts/AcceptEdit/AcceptEdit.ts' +import * as ViewletExplorer from '../src/parts/Create/Create.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import * as FileSystem from '../src/parts/FileSystem/FileSystem.ts' +import * as PathSeparatorType from '../src/parts/PathSeparatorType/PathSeparatorType.ts' + +test.skip('acceptEdit - rename', async () => { + // @ts-ignore + FileSystem.rename.mockImplementation(() => {}) + const state: ExplorerState = { + ...ViewletExplorer.create(1, '', 0, 0, 0, 0, [], 0), + deltaY: 0, + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'b.txt', + focusedIndex: 0, + height: 600, + items: [ + { + depth: 1, + icon: '', + name: 'a.txt', + path: '/test/a.txt', + posInSet: 1, + setSize: 1, + type: DirentType.File, + }, + ], + maxLineY: 2, + minLineY: 1, + pathSeparator: PathSeparatorType.Slash, + root: '/test', + top: 0, + } + expect(await ViewletExplorerAcceptEdit.acceptEdit(state)).toMatchObject({ + items: [ + { + depth: 1, + icon: '', + name: 'b.txt', + path: '/test/b.txt', + posInSet: 1, + setSize: 1, + type: DirentType.File, + }, + ], + }) + expect(FileSystem.rename).toHaveBeenCalledTimes(1) + expect(FileSystem.rename).toHaveBeenCalledWith('/test/a.txt', '/test/b.txt') +}) + +test.skip('acceptEdit - rename - nested file', async () => { + // @ts-ignore + FileSystem.rename.mockImplementation(() => {}) + const state: ExplorerState = { + ...ViewletExplorer.create(1, '', 0, 0, 0, 0, [], 0), + deltaY: 0, + editingIndex: 1, + editingType: ExplorerEditingType.Rename, + editingValue: 'c.txt', + focusedIndex: 0, + height: 600, + items: [ + { + depth: 1, + icon: '', + name: 'a', + path: '/test/a', + posInSet: 1, + setSize: 1, + type: DirentType.Directory, + }, + { + depth: 2, + icon: '', + name: 'b.txt', + path: '/test/a/b.txt', + posInSet: 1, + setSize: 1, + type: DirentType.File, + }, + ], + maxLineY: 2, + minLineY: 1, + pathSeparator: PathSeparatorType.Slash, + root: '/test', + top: 0, + } + expect(await ViewletExplorerAcceptEdit.acceptEdit(state)).toMatchObject({ + focusedIndex: 1, + items: [ + { + depth: 1, + icon: '', + name: 'a', + path: '/test/a', + posInSet: 1, + setSize: 1, + type: DirentType.Directory, + }, + { + depth: 2, + icon: '', + name: 'c.txt', + path: '/test/a/c.txt', + posInSet: 1, + setSize: 1, + type: DirentType.File, + }, + ], + }) +}) + +test.skip('acceptEdit - create - insert folder', async () => { + // @ts-ignore + FileSystem.mkdir.mockImplementation(() => {}) + const state: ExplorerState = { + ...ViewletExplorer.create(1, '', 0, 0, 0, 0, [], 0), + deltaY: 0, + editingIndex: 0, + editingType: ExplorerEditingType.CreateFolder, + editingValue: 'c', + focusedIndex: -1, + height: 600, + items: [ + { + depth: 1, + icon: '', + name: 'a', + path: '/test/a', + posInSet: 1, + setSize: 3, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'b', + path: '/test/b', + posInSet: 2, + setSize: 3, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'd', + path: '/test/d', + posInSet: 3, + setSize: 3, + type: DirentType.Directory, + }, + ], + maxLineY: 2, + minLineY: 1, + pathSeparator: PathSeparatorType.Slash, + root: '/test', + top: 0, + } + expect(await ViewletExplorerAcceptEdit.acceptEdit(state)).toMatchObject({ + focusedIndex: 2, + items: [ + { + depth: 1, + icon: '', + name: 'a', + path: '/test/a', + posInSet: 1, + setSize: 4, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'b', + path: '/test/b', + posInSet: 2, + setSize: 4, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'c', + path: '/test/c', + posInSet: 3, + setSize: 4, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'd', + path: '/test/d', + posInSet: 3, // TODO should be 4 + setSize: 3, // TODO should be 4 + type: DirentType.Directory, + }, + ], + }) +}) diff --git a/packages/explorer-view/test/AcceptRename.test.ts b/packages/explorer-view/test/AcceptRename.test.ts new file mode 100644 index 0000000..0aa1c98 --- /dev/null +++ b/packages/explorer-view/test/AcceptRename.test.ts @@ -0,0 +1,228 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { acceptRename } from '../src/parts/AcceptRename/AcceptRename.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import * as PathSeparatorType from '../src/parts/PathSeparatorType/PathSeparatorType.ts' + +test.skip('acceptRename - basic file rename', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'b.txt', type: DirentType.File }, + { name: 'c.txt', type: DirentType.File }, + ] + }, + 'FileSystem.rename'() { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'b.txt', + items: [ + { depth: 0, name: 'a.txt', path: '/test/a.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'c.txt', path: '/test/c.txt', selected: false, type: DirentType.File }, + ], + pathSeparator: PathSeparatorType.Slash, + } + + const result = await acceptRename(state) + expect(result.items).toHaveLength(2) + expect(result.items[0].name).toBe('b.txt') + expect(result.items[0].path).toBe('/test/b.txt') + expect(result.items[1].name).toBe('c.txt') + expect(result.focusedIndex).toBe(0) + expect(result.editingIndex).toBe(-1) + expect(result.editingType).toBe(ExplorerEditingType.None) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['FileSystem.rename', '/test/a.txt', '/test/b.txt'], + ['FileSystem.readDirWithFileTypes', '/test'], + ]), + ) +}) + +test.skip('acceptRename - folder rename', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'folder2', type: DirentType.Directory }, + { name: 'file.txt', type: DirentType.File }, + ] + }, + 'FileSystem.rename'() { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'folder2', + items: [ + { depth: 0, name: 'folder1', path: '/test/folder1', selected: false, type: DirentType.Directory }, + { depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }, + ], + pathSeparator: PathSeparatorType.Slash, + } + + const result = await acceptRename(state) + expect(result.items).toHaveLength(2) + expect(result.items[0].name).toBe('folder2') + expect(result.items[0].path).toBe('/test/folder2') + expect(result.items[1].name).toBe('file.txt') + expect(result.focusedIndex).toBe(0) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['FileSystem.rename', '/test/folder1', '/test/folder2'], + ['FileSystem.readDirWithFileTypes', '/test'], + ]), + ) +}) + +test.skip('acceptRename - nested file rename', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'b.txt', type: DirentType.File }, + { name: 'c.txt', type: DirentType.File }, + ] + }, + 'FileSystem.rename'() { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 1, + editingType: ExplorerEditingType.Rename, + editingValue: 'b.txt', + items: [ + { depth: 0, name: 'folder', path: '/test/folder', selected: false, type: DirentType.Directory }, + { depth: 1, name: 'a.txt', path: '/test/folder/a.txt', selected: false, type: DirentType.File }, + { depth: 1, name: 'c.txt', path: '/test/folder/c.txt', selected: false, type: DirentType.File }, + ], + pathSeparator: PathSeparatorType.Slash, + } + + const result = await acceptRename(state) + expect(result.items).toHaveLength(3) + expect(result.items[0].name).toBe('folder') + expect(result.items[1].name).toBe('b.txt') + expect(result.items[1].path).toBe('/test/folder/b.txt') + expect(result.items[2].name).toBe('c.txt') + expect(result.focusedIndex).toBe(1) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['FileSystem.rename', '/test/folder/a.txt', '/test/folder/b.txt'], + ['FileSystem.readDirWithFileTypes', '/test/folder'], + ]), + ) +}) + +test.skip('acceptRename - preserves nested items', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [{ name: 'folder2', type: DirentType.Directory }] + }, + 'FileSystem.rename'() { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'folder2', + items: [ + { depth: 0, name: 'folder1', path: '/test/folder1', selected: false, type: DirentType.Directory }, + { depth: 1, name: 'nested.txt', path: '/test/folder1/nested.txt', selected: false, type: DirentType.File }, + ], + pathSeparator: PathSeparatorType.Slash, + } + + const result = await acceptRename(state) + expect(result.items).toHaveLength(2) + expect(result.items[0].name).toBe('folder2') + expect(result.items[0].path).toBe('/test/folder2') + expect(result.items[1].name).toBe('nested.txt') + expect(result.items[1].path).toBe('/test/folder2/nested.txt') + expect(result.focusedIndex).toBe(0) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['FileSystem.rename', '/test/folder1', '/test/folder2'], + ['FileSystem.readDirWithFileTypes', '/test'], + ]), + ) +}) + +test.skip('acceptRename - handles rename error', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.rename'() { + return Promise.reject(new Error('rename failed')) + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'b.txt', + items: [{ depth: 0, name: 'a.txt', path: '/test/a.txt', selected: false, type: DirentType.File }], + pathSeparator: PathSeparatorType.Slash, + } + + const result = await acceptRename(state) + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([['FileSystem.rename', '/test/a.txt', '/test/b.txt']]) +}) + +test.skip('acceptRename - maintains sorting order', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'b.txt', type: DirentType.File }, + { name: 'folder', type: DirentType.Directory }, + { name: 'z.txt', type: DirentType.File }, + ] + }, + 'FileSystem.rename'() { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'b.txt', + items: [ + { depth: 0, name: 'a.txt', path: '/test/a.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'folder', path: '/test/folder', selected: false, type: DirentType.Directory }, + { depth: 0, name: 'z.txt', path: '/test/z.txt', selected: false, type: DirentType.File }, + ], + pathSeparator: PathSeparatorType.Slash, + } + + const result = await acceptRename(state) + expect(result.items).toHaveLength(3) + expect(result.items[0].name).toBe('b.txt') + expect(result.items[1].name).toBe('folder') + expect(result.items[2].name).toBe('z.txt') + expect(result.focusedIndex).toBe(0) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['FileSystem.rename', '/test/a.txt', '/test/b.txt'], + ['FileSystem.readDirWithFileTypes', '/test'], + ]), + ) +}) diff --git a/packages/explorer-view/test/AdjustScrollAfterPaste.test.ts b/packages/explorer-view/test/AdjustScrollAfterPaste.test.ts new file mode 100644 index 0000000..7074f3c --- /dev/null +++ b/packages/explorer-view/test/AdjustScrollAfterPaste.test.ts @@ -0,0 +1,80 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { adjustScrollAfterPaste } from '../src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' + +test('should adjust scroll when focused index is below minLineY', () => { + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 100, + height: 100, + itemHeight: 20, + maxLineY: 10, + minLineY: 5, + } + + const result = adjustScrollAfterPaste(state, 2) + + expect(result.focusedIndex).toBe(2) + expect(result.focused).toBe(true) + expect(result.minLineY).toBe(0) + expect(result.maxLineY).toBe(5) + expect(result.deltaY).toBe(0) +}) + +test('should adjust scroll when focused index is above maxLineY', () => { + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 100, + height: 100, + itemHeight: 20, + maxLineY: 10, + minLineY: 5, + } + + const result = adjustScrollAfterPaste(state, 15) + + expect(result.focusedIndex).toBe(15) + expect(result.focused).toBe(true) + expect(result.minLineY).toBe(13) + expect(result.maxLineY).toBe(18) + expect(result.deltaY).toBe(260) +}) + +test('should not adjust scroll when focused index is within viewport', () => { + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 100, + height: 100, + itemHeight: 20, + maxLineY: 10, + minLineY: 5, + } + + const result = adjustScrollAfterPaste(state, 7) + + expect(result.focusedIndex).toBe(7) + expect(result.focused).toBe(true) + expect(result.minLineY).toBe(5) + expect(result.maxLineY).toBe(10) + expect(result.deltaY).toBe(100) +}) + +test('should handle edge case with odd viewport size', () => { + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 100, + height: 120, + itemHeight: 20, + maxLineY: 11, // Odd size: 6 items + minLineY: 5, + } + + const result = adjustScrollAfterPaste(state, 2) + + expect(result.focusedIndex).toBe(2) + expect(result.focused).toBe(true) + expect(result.minLineY).toBe(-1) + expect(result.maxLineY).toBe(5) + expect(result.deltaY).toBe(-20) +}) diff --git a/packages/explorer-view/test/ApplyFileOperations.test.ts b/packages/explorer-view/test/ApplyFileOperations.test.ts new file mode 100644 index 0000000..45eafd1 --- /dev/null +++ b/packages/explorer-view/test/ApplyFileOperations.test.ts @@ -0,0 +1,51 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { FileOperation } from '../src/parts/FileOperation/FileOperation.ts' +import { applyFileOperations } from '../src/parts/ApplyFileOperations/ApplyFileOperations.ts' +import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' + +test('should apply empty operations', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() {}, + 'FileSystem.writeFile'() {}, + }) + const operations: readonly FileOperation[] = [] + await applyFileOperations(operations) + expect(mockRpc.invocations).toEqual([]) +}) + +test('should create folder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() {}, + 'FileSystem.writeFile'() {}, + }) + const operations: readonly FileOperation[] = [{ path: '/test/folder', type: FileOperationType.CreateFolder }] + await applyFileOperations(operations) + expect(mockRpc.invocations).toEqual([['FileSystem.mkdir', '/test/folder']]) +}) + +test('should create file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() {}, + 'FileSystem.writeFile'() {}, + }) + const operations: readonly FileOperation[] = [{ path: '/test/file.txt', text: 'content', type: FileOperationType.CreateFile }] + await applyFileOperations(operations) + expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test/file.txt', 'content']]) +}) + +test('should apply multiple operations in sequence', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() {}, + 'FileSystem.writeFile'() {}, + }) + const operations: readonly FileOperation[] = [ + { path: '/test/folder', type: FileOperationType.CreateFolder }, + { path: '/test/folder/file.txt', text: 'content', type: FileOperationType.CreateFile }, + ] + await applyFileOperations(operations) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', '/test/folder'], + ['FileSystem.writeFile', '/test/folder/file.txt', 'content'], + ]) +}) diff --git a/packages/explorer-view/test/CanBeDroppedInto.test.ts b/packages/explorer-view/test/CanBeDroppedInto.test.ts new file mode 100644 index 0000000..7d82625 --- /dev/null +++ b/packages/explorer-view/test/CanBeDroppedInto.test.ts @@ -0,0 +1,59 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as CanBeDroppedInto from '../src/parts/CanBeDroppedInto/CanBeDroppedInto.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' + +test('canBeDroppedInto - directory', () => { + const item: ExplorerItem = { + depth: 0, + name: 'directory', + path: '/directory', + selected: false, + type: DirentType.Directory, + } + expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(true) +}) + +test('canBeDroppedInto - directory expanded', () => { + const item: ExplorerItem = { + depth: 0, + name: 'directory', + path: '/directory', + selected: false, + type: DirentType.DirectoryExpanded, + } + expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(true) +}) + +test('canBeDroppedInto - directory expanding', () => { + const item: ExplorerItem = { + depth: 0, + name: 'directory', + path: '/directory', + selected: false, + type: DirentType.DirectoryExpanding, + } + expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(true) +}) + +test('canBeDroppedInto - file', () => { + const item: ExplorerItem = { + depth: 0, + name: 'file.txt', + path: '/file.txt', + selected: false, + type: DirentType.File, + } + expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(false) +}) + +test('canBeDroppedInto - unknown type', () => { + const item: ExplorerItem = { + depth: 0, + name: 'unknown', + path: '/unknown', + selected: false, + type: 999_999, + } + expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(false) +}) diff --git a/packages/explorer-view/test/CancelEdit.test.ts b/packages/explorer-view/test/CancelEdit.test.ts new file mode 100644 index 0000000..0dc8706 --- /dev/null +++ b/packages/explorer-view/test/CancelEdit.test.ts @@ -0,0 +1,224 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { cancelEdit } from '../src/parts/CancelEdit/CancelEdit.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' + +test('cancelEdit', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 1, + editingType: ExplorerEditingType.CreateFile, + editingValue: 'test.txt', + } + + const result = await cancelEdit(state) + expect(result).toEqual({ + ...state, + editingIndex: -1, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: true, + focusedIndex: -1, + }) + expect(mockRpc.invocations).toEqual([]) +}) + +test('cancelEdit - removes editing items', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 1, + editingType: ExplorerEditingType.CreateFile, + editingValue: 'test.txt', + items: [ + { + depth: 0, + icon: '', + name: 'file1.txt', + path: '/file1.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + { + depth: 0, + icon: '', + name: 'test.txt', + path: '/test.txt', + posInSet: 2, + selected: false, + setSize: 1, + type: DirentType.EditingFile, + }, + { + depth: 0, + icon: '', + name: 'newfolder', + path: '/newfolder', + posInSet: 3, + selected: false, + setSize: 1, + type: DirentType.EditingFolder, + }, + ], + } + + const result = await cancelEdit(state) + expect(result.items).toHaveLength(1) + expect(result.items[0].type).toBe(DirentType.File) + expect(result).toEqual({ + ...state, + editingIndex: -1, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: true, + focusedIndex: 0, + items: [state.items[0]], + }) + expect(mockRpc.invocations).toEqual([]) +}) + +test('cancelEdit - rename file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'test.txt', + items: [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.EditingFile, + }, + ], + } + + const result = await cancelEdit(state) + expect(result).toEqual({ + ...state, + editingIndex: -1, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: true, + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + }, + ], + }) + expect(mockRpc.invocations).toEqual([]) +}) + +test('cancelEdit - rename folder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'test', + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.EditingFolder, + }, + ], + } + + const result = await cancelEdit(state) + expect(result).toEqual({ + ...state, + editingIndex: -1, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: true, + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + }, + ], + }) + expect(mockRpc.invocations).toEqual([]) +}) + +test('cancelEdit - create file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 1, + editingType: ExplorerEditingType.CreateFile, + editingValue: 'test.txt', + items: [ + { + depth: 0, + name: 'file1.txt', + path: '/file1.txt', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.EditingFile, + }, + ], + } + + const result = await cancelEdit(state) + expect(result.items).toHaveLength(1) + expect(result.items[0].type).toBe(DirentType.File) + expect(result).toEqual({ + ...state, + editingIndex: -1, + editingType: ExplorerEditingType.None, + editingValue: '', + focus: FocusId.List, + focused: true, + focusedIndex: 0, + items: [state.items[0]], + }) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/CancelTypeAhead.test.ts b/packages/explorer-view/test/CancelTypeAhead.test.ts new file mode 100644 index 0000000..ff3d038 --- /dev/null +++ b/packages/explorer-view/test/CancelTypeAhead.test.ts @@ -0,0 +1,17 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { cancelTypeAhead } from '../src/parts/CancelTypeAhead/CancelTypeAhead.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' + +test('cancelTypeAhead - clears focusWord only', () => { + const initialState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 2, + focusWord: 'abc', + } + + const result = cancelTypeAhead(initialState) + + expect(result.focusWord).toBe('') + expect(result.focusedIndex).toBe(2) +}) diff --git a/packages/explorer-view/test/ClipBoard.test.ts b/packages/explorer-view/test/ClipBoard.test.ts new file mode 100644 index 0000000..b3e84ae --- /dev/null +++ b/packages/explorer-view/test/ClipBoard.test.ts @@ -0,0 +1,34 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as ClipBoard from '../src/parts/ClipBoard/ClipBoard.ts' + +test('writeText', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'() {}, + }) + await ClipBoard.writeText('test text') + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'test text']]) +}) + +test('readNativeFiles', async () => { + const expectedResult = { + files: ['/test/file1.txt', '/test/file2.txt'], + type: 'copy', + } + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return expectedResult + }, + }) + const result = await ClipBoard.readNativeFiles() + expect(result).toEqual(expectedResult) + expect(mockRpc.invocations).toEqual([['ClipBoard.readNativeFiles']]) +}) + +test('writeNativeFiles', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeNativeFiles'() {}, + }) + await ClipBoard.writeNativeFiles('copy', ['/test/file.txt']) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'copy', ['/test/file.txt']]]) +}) diff --git a/packages/explorer-view/test/CollapseAll.test.ts b/packages/explorer-view/test/CollapseAll.test.ts new file mode 100644 index 0000000..e8fd104 --- /dev/null +++ b/packages/explorer-view/test/CollapseAll.test.ts @@ -0,0 +1,38 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { collapseAll } from '../src/parts/CollapseAll/CollapseAll.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' + +test('collapseAll - empty state', async () => { + const state: ExplorerState = createDefaultState() + const result = await collapseAll(state) + expect(result).toEqual(state) +}) + +test('collapseAll - with nested items', async () => { + const state: ExplorerState = { + ...createDefaultState(), + fileIconCache: { + '/folder1': 'icon', + '/folder1/file1.txt': 'icon', + '/folder2': 'icon', + '/folder2/file2.txt': 'icon', + }, + items: [ + { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }, + { depth: 2, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: DirentType.File }, + { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: DirentType.Directory }, + { depth: 2, name: 'file2.txt', path: '/folder2/file2.txt', selected: false, type: DirentType.File }, + ], + } + + const result = await collapseAll(state) + expect(result).toEqual({ + ...state, + items: [ + { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }, + { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: DirentType.Directory }, + ], + }) +}) diff --git a/packages/explorer-view/test/CommandMap.test.ts b/packages/explorer-view/test/CommandMap.test.ts new file mode 100644 index 0000000..abb67c4 --- /dev/null +++ b/packages/explorer-view/test/CommandMap.test.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@jest/globals' +import * as CommandMap from '../src/parts/CommandMap/CommandMap.ts' + +test('commandMap', () => { + expect(typeof CommandMap.commandMap).toBe('object') +}) diff --git a/packages/explorer-view/test/CompareWithSelected.test.ts b/packages/explorer-view/test/CompareWithSelected.test.ts new file mode 100644 index 0000000..6de1abd --- /dev/null +++ b/packages/explorer-view/test/CompareWithSelected.test.ts @@ -0,0 +1,46 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { compareWithSelected } from '../src/parts/CompareWithSelected/CompareWithSelected.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' + +test('compareWithSelected - opens diff for selected and focused file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Main.openUri'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + compareSourceUri: '/a.txt', + focusedIndex: 1, + items: [ + { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'b.txt', path: '/b.txt', selected: false, type: DirentType.File }, + ], + } + + const result = await compareWithSelected(state) + + expect(mockRpc.invocations).toEqual([['Main.openUri', 'diff:///a.txt<->/b.txt', true]]) + expect(result).toEqual({ + ...state, + compareSourceUri: '', + }) +}) + +test('compareWithSelected - ignores same focused file', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + + const state: ExplorerState = { + ...createDefaultState(), + compareSourceUri: '/a.txt', + focusedIndex: 0, + items: [{ depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }], + } + + const result = await compareWithSelected(state) + + expect(mockRpc.invocations).toEqual([]) + expect(result).toBe(state) +}) diff --git a/packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts b/packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts new file mode 100644 index 0000000..b6d6869 --- /dev/null +++ b/packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts @@ -0,0 +1,119 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { Tree } from '../src/parts/Tree/Tree.ts' +import { computeExplorerRenamedDirentUpdate } from '../src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts' + +test('computeExplorerRenamedDirentUpdate - basic rename', () => { + const root = '/' + const parentPath = '/parent' + const oldUri = '/parent/old' + const newUri = '/parent/new' + const children: ExplorerItem[] = [ + { + depth: 1, + icon: '', + name: 'child1', + path: '/parent/child1', + posInSet: 1, + selected: false, + setSize: 2, + type: 1, + }, + { + depth: 1, + icon: '', + name: 'child2', + path: '/parent/child2', + posInSet: 2, + selected: false, + setSize: 2, + type: 1, + }, + ] + const tree: Tree = { + 'parent/old': [ + { + name: 'nested', + type: 1, + }, + ], + } + + const result = computeExplorerRenamedDirentUpdate(root, parentPath, oldUri, children, tree, newUri) + + expect(result).toEqual({ + parent: children, + 'parent/new': tree['parent/old'], + }) +}) + +test('computeExplorerRenamedDirentUpdate - empty tree', () => { + const root = '/' + const parentPath = '/parent' + const oldUri = '/parent/old' + const newUri = '/parent/new' + const children: ExplorerItem[] = [] + const tree: Tree = {} + + const result = computeExplorerRenamedDirentUpdate(root, parentPath, oldUri, children, tree, newUri) + + expect(result).toEqual({ + parent: [], + 'parent/new': [], + }) +}) + +test('computeExplorerRenamedDirentUpdate - deep nested rename', () => { + const root = '/' + const parentPath = '/' + const oldUri = '/old' + const newUri = '/new' + const children: ExplorerItem[] = [ + { + depth: 1, + icon: '', + name: 'old', + path: '/old', + posInSet: 1, + selected: false, + setSize: 1, + type: 1, + }, + ] + const tree: Tree = { + old: [ + { + name: 'level1', + type: 1, + }, + ], + 'old/level1': [ + { + name: 'level2', + type: 1, + }, + ], + 'old/level1/level2': [ + { + name: 'level3', + type: 1, + }, + ], + 'old/level1/level2/level3': [ + { + name: 'file.txt', + type: 2, + }, + ], + } + + const result = computeExplorerRenamedDirentUpdate(root, parentPath, oldUri, children, tree, newUri) + + expect(result).toEqual({ + '': children, + new: tree['old'], + 'new/level1': tree['old/level1'], + 'new/level1/level2': tree['old/level1/level2'], + 'new/level1/level2/level3': tree['old/level1/level2/level3'], + }) +}) diff --git a/packages/explorer-view/test/ConfirmDelete.test.ts b/packages/explorer-view/test/ConfirmDelete.test.ts new file mode 100644 index 0000000..e00642b --- /dev/null +++ b/packages/explorer-view/test/ConfirmDelete.test.ts @@ -0,0 +1,26 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { confirmDelete } from '../src/parts/ConfirmDelete/ConfirmDelete.ts' + +test('confirmDelete - single file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'() { + return true + }, + }) + const result = await confirmDelete(['/test/file.txt']) + expect(result).toBe(true) + expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to delete "/test/file.txt"?', undefined]]) +}) + +test('confirmDelete - multiple files', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'() { + return false + }, + }) + + const result = await confirmDelete(['/test/file1.txt', '/test/file2.txt', '/test/file3.txt']) + expect(result).toBe(false) + expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to delete 3 items?', undefined]]) +}) diff --git a/packages/explorer-view/test/ConfirmPaste.test.ts b/packages/explorer-view/test/ConfirmPaste.test.ts new file mode 100644 index 0000000..0cdc4b9 --- /dev/null +++ b/packages/explorer-view/test/ConfirmPaste.test.ts @@ -0,0 +1,25 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { confirmPaste } from '../src/parts/ConfirmPaste/ConfirmPaste.ts' + +test('confirmPaste returns true when user confirms', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'() { + return true + }, + }) + const result = await confirmPaste() + expect(result).toBe(true) + expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to paste these files?', undefined]]) +}) + +test('confirmPaste returns false when user cancels', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'() { + return false + }, + }) + const result = await confirmPaste() + expect(result).toBe(false) + expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to paste these files?', undefined]]) +}) diff --git a/packages/explorer-view/test/CopyFilesElectron.test.ts b/packages/explorer-view/test/CopyFilesElectron.test.ts new file mode 100644 index 0000000..d0dcf9b --- /dev/null +++ b/packages/explorer-view/test/CopyFilesElectron.test.ts @@ -0,0 +1,30 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { DroppedArgs } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' +import { copyFilesElectron } from '../src/parts/CopyFilesElectron/CopyFilesElectron.ts' + +test('copyFilesElectron', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.copy'() { + return undefined + }, + 'FileSystem.getPathSeparator'() { + return '/' + }, + }) + + const root = '/test' + const fileHandles: DroppedArgs = [ + { kind: 'file', value: { kind: 'file', name: 'file1.txt' } as FileSystemFileHandle }, + { kind: 'file', value: { kind: 'file', name: 'file2.txt' } as FileSystemFileHandle }, + ] + const files: readonly File[] = [] + const paths = ['/source/file1.txt', '/source/file2.txt'] + + await copyFilesElectron(root, fileHandles, files, paths) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.getPathSeparator', '/test'], + ['FileSystem.copy', '/source/file1.txt', '/test/file1.txt'], + ['FileSystem.copy', '/source/file2.txt', '/test/file2.txt'], + ]) +}) diff --git a/packages/explorer-view/test/CopyPath.test.ts b/packages/explorer-view/test/CopyPath.test.ts new file mode 100644 index 0000000..21208f7 --- /dev/null +++ b/packages/explorer-view/test/CopyPath.test.ts @@ -0,0 +1,65 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { copyPath } from '../src/parts/CopyPath/CopyPath.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' + +test('copyPath - writes absolute path of focused dirent to clipboard', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'(text: string) { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }], + } + + const result = await copyPath(state) + + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', '/test/file.txt']]) +}) + +test('copyPath - writes workspace path when no focused dirent', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'(text: string) { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [], + root: 'memfs:///workspace', + } + + const result = await copyPath(state) + + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'memfs:///workspace']]) +}) + +test('copyPath - writes workspace path when focused index is out of bounds', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'(text: string) { + return + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 2, + items: [{ depth: 0, name: 'file.txt', path: 'memfs:///workspace/file.txt', selected: false, type: DirentType.File }], + root: 'memfs:///workspace', + } + + const result = await copyPath(state) + + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'memfs:///workspace']]) +}) diff --git a/packages/explorer-view/test/CopyRelativePath.test.ts b/packages/explorer-view/test/CopyRelativePath.test.ts new file mode 100644 index 0000000..18d5970 --- /dev/null +++ b/packages/explorer-view/test/CopyRelativePath.test.ts @@ -0,0 +1,85 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { copyRelativePath } from '../src/parts/CopyRelativePath/CopyRelativePath.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' + +test('copyRelativePath - copies relative path of focused dirent', async (): Promise => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }], + } + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'() {}, + }) + const result = await copyRelativePath(state) + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'test/file.txt']]) +}) + +test('copyRelativePath - returns state when no focused dirent', async (): Promise => { + const state = createDefaultState() + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'() {}, + }) + const result = await copyRelativePath(state) + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test('copyRelativePath - slices first character from path', async (): Promise => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'file.txt', path: '/single', selected: false, type: DirentType.File }], + } + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'() {}, + }) + await copyRelativePath(state) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'single']]) +}) + +test('copyRelativePath - handles nested paths correctly', async (): Promise => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'file.txt', path: '/a/b/c/file.txt', selected: false, type: DirentType.File }], + } + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'() {}, + }) + await copyRelativePath(state) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'a/b/c/file.txt']]) +}) + +test('copyRelativePath - strips workspace root prefix from runtime paths', async (): Promise => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'file.txt', path: 'memfs:///workspace/a/b.txt', selected: false, type: DirentType.File }], + pathSeparator: '/', + root: 'memfs:///workspace', + } + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'() {}, + }) + await copyRelativePath(state) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'a/b.txt']]) +}) + +test('copyRelativePath - returns state after writing to clipboard', async (): Promise => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }], + } + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeText'() {}, + }) + const result = await copyRelativePath(state) + expect(result).toBe(state) + expect(mockRpc.invocations).toHaveLength(1) +}) diff --git a/packages/explorer-view/test/Create2.test.ts b/packages/explorer-view/test/Create2.test.ts new file mode 100644 index 0000000..7bb1236 --- /dev/null +++ b/packages/explorer-view/test/Create2.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from '@jest/globals' +import { create2 } from '../src/parts/Create2/Create2.ts' +import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' + +test('create2', () => { + const uid = 1 + const uri = 'test' + const x = 0 + const y = 0 + const width = 100 + const height = 200 + const args = {} + const parentUid = 0 + const platform = 0 + + create2(uid, uri, x, y, width, height, args, parentUid, platform) + + const state = ExplorerStates.get(uid) + expect(state).toBeDefined() +}) diff --git a/packages/explorer-view/test/CreateDecorationMap.test.ts b/packages/explorer-view/test/CreateDecorationMap.test.ts new file mode 100644 index 0000000..ea78b95 --- /dev/null +++ b/packages/explorer-view/test/CreateDecorationMap.test.ts @@ -0,0 +1,95 @@ +import { test, expect } from '@jest/globals' +import { createDecorationMap } from '../src/parts/CreateDecorationMap/CreateDecorationMap.ts' + +test('createDecorationMap - creates map from single decoration', () => { + const decorations = [{ decoration: 'modified', uri: '/home/user/file.txt' }] + const result = createDecorationMap(decorations) + expect(result).toEqual({ + 'file:///home/user/file.txt': 'modified', + }) +}) + +test('createDecorationMap - creates map from multiple decorations', () => { + const decorations = [ + { decoration: 'modified', uri: '/home/user/file1.txt' }, + { decoration: 'added', uri: '/home/user/file2.txt' }, + { decoration: 'deleted', uri: '/home/user/file3.txt' }, + ] + const result = createDecorationMap(decorations) + expect(result).toEqual({ + 'file:///home/user/file1.txt': 'modified', + 'file:///home/user/file2.txt': 'added', + 'file:///home/user/file3.txt': 'deleted', + }) +}) + +test('createDecorationMap - handles URIs that are already URIs', () => { + const decorations = [ + { decoration: 'modified', uri: 'file:///home/user/file1.txt' }, + { decoration: 'added', uri: 'https://example.com/file.txt' }, + ] + const result = createDecorationMap(decorations) + expect(result).toEqual({ + 'file:///home/user/file1.txt': 'modified', + 'https://example.com/file.txt': 'added', + }) +}) + +test('createDecorationMap - handles empty array', () => { + const decorations: readonly any[] = [] + const result = createDecorationMap(decorations) + expect(result).toEqual({}) + expect(Object.getPrototypeOf(result)).toBe(null) +}) + +test('createDecorationMap - uses Object.create(null) for prototype-less map', () => { + const decorations = [{ decoration: 'modified', uri: '/home/user/file.txt' }] + const result = createDecorationMap(decorations) + expect(Object.getPrototypeOf(result)).toBe(null) + expect('toString' in result).toBe(false) +}) + +test('createDecorationMap - handles mixed paths and URIs', () => { + const decorations = [ + { decoration: 'modified', uri: '/absolute/path.txt' }, + { decoration: 'added', uri: 'file:///already/uri.txt' }, + { decoration: 'deleted', uri: 'https://example.com/file.txt' }, + ] + const result = createDecorationMap(decorations) + expect(result).toEqual({ + 'file:///absolute/path.txt': 'modified', + 'file:///already/uri.txt': 'added', + 'https://example.com/file.txt': 'deleted', + }) +}) + +test('createDecorationMap - handles duplicate URIs (last one wins)', () => { + const decorations = [ + { decoration: 'modified', uri: '/home/user/file.txt' }, + { decoration: 'added', uri: '/home/user/file.txt' }, + ] + const result = createDecorationMap(decorations) + expect(result).toEqual({ + 'file:///home/user/file.txt': 'added', + }) +}) + +test('createDecorationMap - handles empty decoration strings', () => { + const decorations = [ + { decoration: '', uri: '/home/user/file1.txt' }, + { decoration: 'modified', uri: '/home/user/file2.txt' }, + ] + const result = createDecorationMap(decorations) + expect(result).toEqual({ + 'file:///home/user/file1.txt': '', + 'file:///home/user/file2.txt': 'modified', + }) +}) + +test('createDecorationMap - handles root path', () => { + const decorations = [{ decoration: 'modified', uri: '/' }] + const result = createDecorationMap(decorations) + expect(result).toEqual({ + 'file:///': 'modified', + }) +}) diff --git a/packages/explorer-view/test/CreateNestedPath.test.ts b/packages/explorer-view/test/CreateNestedPath.test.ts new file mode 100644 index 0000000..9aa2b47 --- /dev/null +++ b/packages/explorer-view/test/CreateNestedPath.test.ts @@ -0,0 +1,42 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { createNestedPath } from '../src/parts/CreateNestedPath/CreateNestedPath.ts' + +test('createNestedPath - creates all directories', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return + }, + }) + const root = '/a' + await createNestedPath(root, '/a/b/c', '/') + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', '/ab'], + ['FileSystem.mkdir', '/ab/c'], + ]) +}) + +test('createNestedPath - handles existing directories', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return Promise.reject(new Error('Directory already exists')) + }, + }) + const root = '/a' + await createNestedPath(root, '/a/b/c', '/') + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', '/ab'], + ['FileSystem.mkdir', '/ab/c'], + ]) +}) + +test('createNestedPath - propagates other errors', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return Promise.reject(new Error('Permission denied')) + }, + }) + const root = '/a' + await expect(createNestedPath(root, '/a/b/c', '/')).rejects.toThrow('Permission denied') + expect(mockRpc.invocations).toEqual([['FileSystem.mkdir', '/ab']]) +}) diff --git a/packages/explorer-view/test/CreateUploadTree.test.ts b/packages/explorer-view/test/CreateUploadTree.test.ts new file mode 100644 index 0000000..81c398a --- /dev/null +++ b/packages/explorer-view/test/CreateUploadTree.test.ts @@ -0,0 +1,106 @@ +import { test, expect } from '@jest/globals' +import { createUploadTree } from '../src/parts/CreateUploadTree/CreateUploadTree.ts' + +test('createUploadTree with files', async (): Promise => { + const fileHandle = { + async getFile(): Promise<{ text(): Promise }> { + return { + async text(): Promise { + return 'file content' + }, + } + }, + isSameEntry: async (): Promise => false, + kind: 'file', + name: 'test.txt', + } as FileSystemHandle + + const result = await createUploadTree('root', [fileHandle]) + expect(result).toEqual({ + 'test.txt': 'file content', + }) +}) + +test('createUploadTree with directories', async (): Promise => { + const fileHandle = { + async getFile(): Promise<{ text(): Promise }> { + return { + async text(): Promise { + return 'file content' + }, + } + }, + isSameEntry: async (): Promise => false, + kind: 'file', + name: 'test.txt', + } as FileSystemHandle + + const directoryHandle = { + isSameEntry: async (): Promise => false, + kind: 'directory', + name: 'dir', + values(): { [Symbol.asyncIterator](): AsyncGenerator } { + return { + [Symbol.asyncIterator]: async function* (): AsyncGenerator { + yield fileHandle + }, + } + }, + } as FileSystemHandle + + const result = await createUploadTree('root', [directoryHandle]) + expect(result).toEqual({ + dir: { + 'test.txt': 'file content', + }, + }) +}) + +test('createUploadTree with mixed content', async (): Promise => { + const fileHandle1 = { + async getFile(): Promise<{ text(): Promise }> { + return { + async text(): Promise { + return 'file content 1' + }, + } + }, + isSameEntry: async (): Promise => false, + kind: 'file', + name: 'test1.txt', + } as FileSystemHandle + + const fileHandle2 = { + async getFile(): Promise<{ text(): Promise }> { + return { + async text(): Promise { + return 'file content 2' + }, + } + }, + isSameEntry: async (): Promise => false, + kind: 'file', + name: 'test2.txt', + } as FileSystemHandle + + const directoryHandle = { + isSameEntry: async (): Promise => false, + kind: 'directory', + name: 'dir', + values(): { [Symbol.asyncIterator](): AsyncGenerator } { + return { + [Symbol.asyncIterator]: async function* (): AsyncGenerator { + yield fileHandle2 + }, + } + }, + } as FileSystemHandle + + const result = await createUploadTree('root', [fileHandle1, directoryHandle]) + expect(result).toEqual({ + dir: { + 'test2.txt': 'file content 2', + }, + 'test1.txt': 'file content 1', + }) +}) diff --git a/packages/explorer-view/test/Diff2.test.ts b/packages/explorer-view/test/Diff2.test.ts new file mode 100644 index 0000000..3b97a1f --- /dev/null +++ b/packages/explorer-view/test/Diff2.test.ts @@ -0,0 +1,34 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { diff2 } from '../src/parts/Diff2/Diff2.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' +import { set } from '../src/parts/ExplorerStates/ExplorerStates.ts' + +test('diff2 - empty states', () => { + const uid = 1 + const oldState: ExplorerState = createDefaultState() + const newState: ExplorerState = { + ...oldState, + items: [], + } + set(uid, oldState, newState) + const result = diff2(uid) + expect(result).toEqual([12]) +}) + +test('diff2 - different states', () => { + const uid = 2 + const oldState: ExplorerState = { + ...createDefaultState(), + items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: DirentType.File }], + } + const newState: ExplorerState = { + ...oldState, + items: [{ depth: 0, name: 'file2.txt', path: '/file2.txt', selected: false, type: DirentType.File }], + } + ExplorerStates.set(uid, oldState, newState) + const result = diff2(uid) + expect(result).toEqual([12]) +}) diff --git a/packages/explorer-view/test/DiffEditingSelection.test.ts b/packages/explorer-view/test/DiffEditingSelection.test.ts new file mode 100644 index 0000000..c8755e7 --- /dev/null +++ b/packages/explorer-view/test/DiffEditingSelection.test.ts @@ -0,0 +1,24 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { diffEditingSelection } from '../src/parts/DiffEditingSelection/DiffEditingSelection.ts' + +test('diffEditingSelection - returns undefined when selection is the same', () => { + const state: ExplorerState = { + ...createDefaultState(), + editingSelectionEnd: 5, + editingSelectionStart: 0, + } + const result = diffEditingSelection(state, 0, 5) + expect(result).toBe(undefined) +}) + +test('diffEditingSelection - returns new selection when different', () => { + const state: ExplorerState = { + ...createDefaultState(), + editingSelectionEnd: 5, + editingSelectionStart: 0, + } + const result = diffEditingSelection(state, 1, 6) + expect(result).toEqual({ end: 6, start: 1 }) +}) diff --git a/packages/explorer-view/test/DiffFocus.test.ts b/packages/explorer-view/test/DiffFocus.test.ts new file mode 100644 index 0000000..b542a67 --- /dev/null +++ b/packages/explorer-view/test/DiffFocus.test.ts @@ -0,0 +1,45 @@ +import { expect, test } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { isEqual } from '../src/parts/DiffFocus/DiffFocus.ts' + +test('isEqual should return true when focused and focus are equal', () => { + const oldState = { + ...createDefaultState(), + focus: 1, + focused: true, + } + const newState = { + ...createDefaultState(), + focus: 1, + focused: true, + } + expect(isEqual(oldState, newState)).toBe(true) +}) + +test('isEqual should return false when focused differs', () => { + const oldState = { + ...createDefaultState(), + focus: 1, + focused: true, + } + const newState = { + ...createDefaultState(), + focus: 1, + focused: false, + } + expect(isEqual(oldState, newState)).toBe(false) +}) + +test('isEqual should return false when focus differs', () => { + const oldState = { + ...createDefaultState(), + focus: 1, + focused: true, + } + const newState = { + ...createDefaultState(), + focus: 2, + focused: true, + } + expect(isEqual(oldState, newState)).toBe(false) +}) diff --git a/packages/explorer-view/test/DiffSelection.test.ts b/packages/explorer-view/test/DiffSelection.test.ts new file mode 100644 index 0000000..adbec21 --- /dev/null +++ b/packages/explorer-view/test/DiffSelection.test.ts @@ -0,0 +1,29 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { isEqual } from '../src/parts/DiffSelection/DiffSelection.ts' + +test('isEqual - same selection', () => { + const state: ExplorerState = { + ...createDefaultState(), + editingSelectionEnd: 5, + editingSelectionStart: 0, + } + const result = isEqual(state, state) + expect(result).toBe(true) +}) + +test('isEqual - different selection', () => { + const oldState: ExplorerState = { + ...createDefaultState(), + editingSelectionEnd: 5, + editingSelectionStart: 0, + } + const newState: ExplorerState = { + ...createDefaultState(), + editingSelectionEnd: 6, + editingSelectionStart: 1, + } + const result = isEqual(oldState, newState) + expect(result).toBe(false) +}) diff --git a/packages/explorer-view/test/DiffValue.test.ts b/packages/explorer-view/test/DiffValue.test.ts new file mode 100644 index 0000000..91b4455 --- /dev/null +++ b/packages/explorer-view/test/DiffValue.test.ts @@ -0,0 +1,31 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { isEqual } from '../src/parts/DiffValue/DiffValue.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' + +test('isEqual - same focus and editing value', () => { + const state1 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } + const state2 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } + + expect(isEqual(state1, state2)).toBe(true) +}) + +test('isEqual - different focus', () => { + const state1 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } + const state2 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.List } + expect(isEqual(state1, state2)).toBe(true) +}) + +test('isEqual - different editing value', () => { + const state1 = { ...createDefaultState(), editingValue: 'test1', focus: FocusId.Input } + const state2 = { ...createDefaultState(), editingValue: 'test2', focus: FocusId.Input } + + expect(isEqual(state1, state2)).toBe(false) +}) + +test('isEqual - new focus is list', () => { + const state1 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } + const state2 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.List } + + expect(isEqual(state1, state2)).toBe(true) +}) diff --git a/packages/explorer-view/test/EnsureUris.test.ts b/packages/explorer-view/test/EnsureUris.test.ts new file mode 100644 index 0000000..0ae1e68 --- /dev/null +++ b/packages/explorer-view/test/EnsureUris.test.ts @@ -0,0 +1,40 @@ +import { test, expect } from '@jest/globals' +import { ensureUri, ensureUris } from '../src/parts/EnsureUris/EnsureUris.ts' + +test('ensureUri - adds file:// prefix to paths starting with /', () => { + expect(ensureUri('/home/user/file.txt')).toBe('file:///home/user/file.txt') + expect(ensureUri('/')).toBe('file:///') + expect(ensureUri('/path/to/directory/')).toBe('file:///path/to/directory/') +}) + +test('ensureUri - returns string as-is if it does not start with /', () => { + expect(ensureUri('file:///home/user/file.txt')).toBe('file:///home/user/file.txt') + expect(ensureUri('https://example.com/file.txt')).toBe('https://example.com/file.txt') + expect(ensureUri('relative/path/file.txt')).toBe('relative/path/file.txt') + expect(ensureUri('')).toBe('') +}) + +test('ensureUris - processes array of strings', () => { + const input = ['/home/user/file1.txt', '/home/user/file2.txt', 'file:///already/uri.txt'] + const result = ensureUris(input) + expect(result).toEqual(['file:///home/user/file1.txt', 'file:///home/user/file2.txt', 'file:///already/uri.txt']) +}) + +test('ensureUris - handles empty array', () => { + const result = ensureUris([]) + expect(result).toEqual([]) +}) + +test('ensureUris - handles mixed paths and URIs', () => { + const input = ['/absolute/path.txt', 'file:///already/uri.txt', 'https://example.com/file.txt', '/another/path'] + const result = ensureUris(input) + expect(result).toEqual(['file:///absolute/path.txt', 'file:///already/uri.txt', 'https://example.com/file.txt', 'file:///another/path']) +}) + +test('ensureUris - preserves readonly array type', () => { + const input: readonly string[] = ['/path1', '/path2'] + const result = ensureUris(input) + expect(result).toEqual(['file:///path1', 'file:///path2']) + // Verify it returns a readonly array + expect(Object.isFrozen(result) || Array.isArray(result)).toBe(true) +}) diff --git a/packages/explorer-view/test/ExpandAll.test.ts b/packages/explorer-view/test/ExpandAll.test.ts new file mode 100644 index 0000000..fa6455f --- /dev/null +++ b/packages/explorer-view/test/ExpandAll.test.ts @@ -0,0 +1,74 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { expandAll } from '../src/parts/ExpandAll/ExpandAll.ts' + +test('expandAll - no focused item', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file1', path: '/dir1/file1', type: DirentType.File }, + { name: 'file2', path: '/dir1/file2', type: DirentType.File }, + ] + }, + 'IconTheme.getFileIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getFolderIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getIcons'() { + return ['icon1', 'icon2'] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + } + const result = await expandAll(state) + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test('expandAll - expand directories at same depth', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file1', path: '/dir1/file1', type: DirentType.File }, + { name: 'file2', path: '/dir1/file2', type: DirentType.File }, + ] + }, + 'IconTheme.getFileIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getFolderIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getIcons'() { + return ['icon1', 'icon2'] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 0, name: 'dir1', path: '/dir1', selected: false, type: DirentType.Directory }, + { depth: 0, name: 'dir2', path: '/dir2', selected: false, type: DirentType.Directory }, + ], + } + + const result = await expandAll(state) + + expect(result.items).toHaveLength(6) + expect(result.items[0].type).toBe(DirentType.DirectoryExpanded) + expect(result.items[1].type).toBe(DirentType.File) + expect(result.items[2].name).toBe('file2') + expect(result.items[3].name).toBe('dir2') + expect(result.fileIconCache).toBeDefined() + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/dir1'], + ['FileSystem.readDirWithFileTypes', '/dir2'], + ]) +}) diff --git a/packages/explorer-view/test/ExpandRecursively.test.ts b/packages/explorer-view/test/ExpandRecursively.test.ts new file mode 100644 index 0000000..4f99fe6 --- /dev/null +++ b/packages/explorer-view/test/ExpandRecursively.test.ts @@ -0,0 +1,92 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { Directory, File } from '../src/parts/DirentType/DirentType.ts' +import { expandRecursively } from '../src/parts/ExpandRecursively/ExpandRecursively.ts' + +test.skip('expand root directory', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [ + { isSymbolicLink: false, name: 'file1.txt', type: 'file' }, + { isSymbolicLink: false, name: 'dir1', type: 'directory' }, + ] + }, + 'IconTheme.getFileIcon'() { + return 'file-icon' + }, + 'IconTheme.getFolderIcon'() { + return 'folder-icon' + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: File }, + { depth: 0, name: 'dir1', path: '/test/dir1', selected: false, type: Directory }, + ], + root: '/test', + } + const newState = await expandRecursively(state) + expect(newState.items).toHaveLength(2) + expect(newState.items[0].name).toBe('file1.txt') + expect(newState.items[1].name).toBe('dir1') + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('expand focused directory', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [ + { isSymbolicLink: false, name: 'file1.txt', type: 'file' }, + { isSymbolicLink: false, name: 'file2.txt', type: 'file' }, + ] + }, + 'IconTheme.getFileIcon'() { + return 'file-icon' + }, + 'IconTheme.getFolderIcon'() { + return 'folder-icon' + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 0, name: 'dir1', path: '/test/dir1', selected: false, type: Directory }, + { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: File }, + ], + } + const newState = await expandRecursively(state) + expect(newState.items).toHaveLength(2) + expect(newState.items[0].name).toBe('file1.txt') + expect(newState.items[1].name).toBe('file2.txt') + expect(mockRpc.invocations).toEqual([]) +}) + +test('do not expand file', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: File, + }, + ], + } + const newState = await expandRecursively(state) + expect(newState.items).toHaveLength(1) + expect(newState.items[0].type).toBe(File) +}) diff --git a/packages/explorer-view/test/ExplorerStrings.test.ts b/packages/explorer-view/test/ExplorerStrings.test.ts new file mode 100644 index 0000000..10c46ae --- /dev/null +++ b/packages/explorer-view/test/ExplorerStrings.test.ts @@ -0,0 +1,104 @@ +import { expect, test } from '@jest/globals' +import * as ExplorerStrings from '../src/parts/ExplorerStrings/ExplorerStrings.ts' + +test('newFile', () => { + expect(ExplorerStrings.newFile()).toBe('New File...') +}) + +test('newFolder', () => { + expect(ExplorerStrings.newFolder()).toBe('New Folder...') +}) + +test('openContainingFolder', () => { + expect(ExplorerStrings.openContainingFolder()).toBe('Open Containing Folder') +}) + +test('openInIntegratedTerminal', () => { + expect(ExplorerStrings.openInIntegratedTerminal()).toBe('Open in integrated Terminal') +}) + +test('cut', () => { + expect(ExplorerStrings.cut()).toBe('Cut') +}) + +test('copy', () => { + expect(ExplorerStrings.copy()).toBe('Copy') +}) + +test('paste', () => { + expect(ExplorerStrings.paste()).toBe('Paste') +}) + +test('copyPath', () => { + expect(ExplorerStrings.copyPath()).toBe('Copy Path') +}) + +test('copyRelativePath', () => { + expect(ExplorerStrings.copyRelativePath()).toBe('Copy Relative Path') +}) + +test('rename', () => { + expect(ExplorerStrings.rename()).toBe('Rename') +}) + +test('deleteItem', () => { + expect(ExplorerStrings.deleteItem()).toBe('Delete') +}) + +test('refresh', () => { + expect(ExplorerStrings.refresh()).toBe('Refresh Explorer') +}) + +test('collapseAll', () => { + expect(ExplorerStrings.collapseAll()).toBe('Collapse All Folders in Explorer') +}) + +test('explorer', () => { + expect(ExplorerStrings.explorer()).toBe('Explorer') +}) + +test('filesExplorer', () => { + expect(ExplorerStrings.filesExplorer()).toBe('Files Explorer') +}) + +test('youHaveNotYetOpenedAFolder', () => { + expect(ExplorerStrings.youHaveNotYetOpenedAFolder()).toBe('You have not yet opened a folder.') +}) + +test('openFolder', () => { + expect(ExplorerStrings.openFolder()).toBe('Open folder') +}) + +test('openAnotherFolder', () => { + expect(ExplorerStrings.openAnotherFolder()).toBe('Open another folder') +}) + +test('noFolderOpen', () => { + expect(ExplorerStrings.noFolderOpen()).toBe('No Folder Open') +}) + +test('fileOrFolderNameMustBeProvided', () => { + expect(ExplorerStrings.fileOrFolderNameMustBeProvided()).toBe('A file or folder name must be provided.') +}) + +test('typeAFileName', () => { + expect(ExplorerStrings.typeAFileName()).toBe('Type file name. Press Enter to confirm or Escape to cancel.') +}) + +test('fileNameCannotStartWithSlash', () => { + expect(ExplorerStrings.fileNameCannotStartWithSlash()).toBe('A file or folder name cannot start with a slash.') +}) + +test('fileOrFolderAlreadyExists', () => { + expect(ExplorerStrings.fileOrFolderAlreadyExists('test-file.txt')).toBe( + 'A file or folder **test-file.txt** already exists at this location. Please choose a different name.', + ) +}) + +test('theNameIsNotValid', () => { + expect(ExplorerStrings.theNameIsNotValid()).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +}) + +test('leadingOrTrailingWhitespaceDetected', () => { + expect(ExplorerStrings.leadingOrTrailingWhitespaceDetected()).toBe('Leading or trailing whitespace detected in file or folder name.') +}) diff --git a/packages/explorer-view/test/FileSystem.test.ts b/packages/explorer-view/test/FileSystem.test.ts new file mode 100644 index 0000000..66750eb --- /dev/null +++ b/packages/explorer-view/test/FileSystem.test.ts @@ -0,0 +1,100 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as FileSystem from '../src/parts/FileSystem/FileSystem.ts' + +test('readDirWithFileTypes', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file.txt', type: 1 }, + { name: 'folder', type: 2 }, + ] + }, + }) + + const result = await FileSystem.readDirWithFileTypes('/test') + expect(result).toEqual([ + { name: 'file.txt', type: 1 }, + { name: 'folder', type: 2 }, + ]) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) +}) + +test('writeFile', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.writeFile'() { + return undefined + }, + }) + + await expect(FileSystem.writeFile('/test/file.txt', 'content')).resolves.toBeUndefined() + expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test/file.txt', 'content']]) +}) + +test('remove', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.remove'() { + return undefined + }, + }) + + await expect(FileSystem.remove('/test/file.txt')).resolves.toBeUndefined() + expect(mockRpc.invocations).toEqual([['FileSystem.remove', '/test/file.txt']]) +}) + +test('mkdir', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return undefined + }, + }) + + await expect(FileSystem.mkdir('/test/newfolder')).resolves.toBeUndefined() + expect(mockRpc.invocations).toEqual([['FileSystem.mkdir', '/test/newfolder']]) +}) + +test('rename', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.rename'() { + return undefined + }, + }) + + await expect(FileSystem.rename('/test/old.txt', '/test/new.txt')).resolves.toBeUndefined() + expect(mockRpc.invocations).toEqual([['FileSystem.rename', '/test/old.txt', '/test/new.txt']]) +}) + +test('copy', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.copy'() { + return undefined + }, + }) + + await expect(FileSystem.copy('/test/source.txt', '/test/dest.txt')).resolves.toBeUndefined() + expect(mockRpc.invocations).toEqual([['FileSystem.copy', '/test/source.txt', '/test/dest.txt']]) +}) + +test('getRealPath', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getRealPath'() { + return '/real/path' + }, + }) + + const path = await FileSystem.getRealPath('/test/link') + expect(path).toBe('/real/path') + expect(mockRpc.invocations).toEqual([['FileSystem.getRealPath', '/test/link']]) +}) + +test('getPathSeparator', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + }) + + const result = await FileSystem.getPathSeparator('/') + expect(result).toBe('/') + expect(mockRpc.invocations).toEqual([['FileSystem.getPathSeparator', '/']]) +}) diff --git a/packages/explorer-view/test/FilterByFocusWord.test.ts b/packages/explorer-view/test/FilterByFocusWord.test.ts new file mode 100644 index 0000000..6481ec5 --- /dev/null +++ b/packages/explorer-view/test/FilterByFocusWord.test.ts @@ -0,0 +1,26 @@ +import { expect, test } from '@jest/globals' +import { filterByFocusWord } from '../src/parts/FilterByFocusWord/FilterByFocusWord.ts' + +test('filterByFocusWord - basic match', () => { + const items = ['apple', 'banana', 'cherry'] + expect(filterByFocusWord(items, -1, 'b')).toBe(1) +}) + +test('filterByFocusWord - no match', () => { + const items = ['apple', 'banana', 'cherry'] + expect(filterByFocusWord(items, -1, 'x')).toBe(-1) +}) + +test('filterByFocusWord - cycle through matches', () => { + const items = ['apple', 'banana', 'berry'] + // First match + expect(filterByFocusWord(items, -1, 'b')).toBe(1) + // Next match after current focus + expect(filterByFocusWord(items, 1, 'b')).toBe(2) + // Wrap around to first match + expect(filterByFocusWord(items, 2, 'b')).toBe(1) +}) + +test('filterByFocusWord - empty items', () => { + expect(filterByFocusWord([], -1, 'a')).toBe(-1) +}) diff --git a/packages/explorer-view/test/Focus.test.ts b/packages/explorer-view/test/Focus.test.ts new file mode 100644 index 0000000..cbf6280 --- /dev/null +++ b/packages/explorer-view/test/Focus.test.ts @@ -0,0 +1,16 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' +import { focus } from '../src/parts/Focus/Focus.js' + +test('focus - assigns focus if not present', () => { + const state = { ...createDefaultState(), focus: undefined as unknown as number } + const result = focus(state) + expect(result.focus).toBeDefined() + expect(result).not.toBe(state) +}) + +test('focus - does not change state if focus present', () => { + const state = { ...createDefaultState(), focus: 123 } + const result = focus(state) + expect(result).toBe(state) +}) diff --git a/packages/explorer-view/test/FocusFirst.test.ts b/packages/explorer-view/test/FocusFirst.test.ts new file mode 100644 index 0000000..7111541 --- /dev/null +++ b/packages/explorer-view/test/FocusFirst.test.ts @@ -0,0 +1,78 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ViewletExplorerFocusFirst from '../src/parts/FocusFirst/FocusFirst.ts' + +test('focusFirst', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + height: 600, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + posInSet: 0, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusFirst.focusFirst(state)).toMatchObject({ + focusedIndex: 0, + }) +}) + +test('focusFirst - no dirents', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + height: 600, + items: [], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusFirst.focusFirst(state)).toBe(state) +}) + +test('focusFirst - focus already at first', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + height: 600, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + posInSet: 0, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusFirst.focusFirst(state)).toBe(state) +}) diff --git a/packages/explorer-view/test/FocusIndex.test.ts b/packages/explorer-view/test/FocusIndex.test.ts new file mode 100644 index 0000000..916a1d6 --- /dev/null +++ b/packages/explorer-view/test/FocusIndex.test.ts @@ -0,0 +1,169 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ViewletExplorerFocusIndex from '../src/parts/FocusIndex/FocusIndex.ts' + +test('focusIndex - scroll up', () => { + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 0, + focusedIndex: 1, + height: 600, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + selected: false, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + selected: true, + type: DirentType.File, + }, + ], + maxLineY: 2, + minLineY: 1, + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusIndex.focusIndex(state, 0)).toMatchObject({ + focusedIndex: 0, + items: [ + { + selected: false, + }, + { + selected: false, + }, + ], + maxLineY: 1, + minLineY: 0, + }) +}) + +test('focusIndex - scroll down', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + selected: true, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + ], + maxLineY: 1, + minLineY: 0, + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusIndex.focusIndex(state, 1)).toMatchObject({ + focusedIndex: 1, + items: [ + { + selected: false, + }, + { + selected: false, + }, + ], + maxLineY: 2, + minLineY: 1, + }) +}) + +test('focusIndex - focus container', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + selected: true, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + ], + maxLineY: 1, + minLineY: 0, + } + expect(ViewletExplorerFocusIndex.focusIndex(state, -1)).toMatchObject({ + focusedIndex: -1, + items: [ + { + selected: false, + }, + { + selected: false, + }, + ], + maxLineY: 1, + minLineY: 0, + }) +}) + +test('focusIndex - unselects all other items', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + selected: true, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + selected: true, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.js', + path: '/index.js', + selected: true, + type: DirentType.File, + }, + ], + maxLineY: 3, + minLineY: 0, + } + expect(ViewletExplorerFocusIndex.focusIndex(state, 1)).toMatchObject({ + focusedIndex: 1, + items: [ + { + selected: false, + }, + { + selected: false, + }, + { + selected: false, + }, + ], + }) +}) diff --git a/packages/explorer-view/test/FocusLast.test.ts b/packages/explorer-view/test/FocusLast.test.ts new file mode 100644 index 0000000..68e879e --- /dev/null +++ b/packages/explorer-view/test/FocusLast.test.ts @@ -0,0 +1,80 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import * as ViewletExplorer from '../src/parts/Create/Create.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ViewletExplorerFocusLast from '../src/parts/FocusLast/FocusLast.ts' + +test('focusLast', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + height: 600, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + posInSet: 0, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusLast.focusLast(state)).toMatchObject({ + focusedIndex: 1, + }) +}) + +test('focusLast - no dirents', () => { + const state: ExplorerState = { + // @ts-ignore + ...ViewletExplorer.create(1), + focusedIndex: -1, + items: [], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusLast.focusLast(state)).toMatchObject({ + focusedIndex: -1, + }) +}) + +test('focusLast - focus already at last', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + items: [ + { + depth: 1, + name: 'index.css', + path: '/index.css', + posInSet: 0, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 1, + name: 'index.html', + path: '/index.html', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusLast.focusLast(state)).toBe(state) +}) diff --git a/packages/explorer-view/test/FocusNext.test.ts b/packages/explorer-view/test/FocusNext.test.ts new file mode 100644 index 0000000..76e0b9d --- /dev/null +++ b/packages/explorer-view/test/FocusNext.test.ts @@ -0,0 +1,110 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ViewletExplorerFocusNext from '../src/parts/FocusNext/FocusNext.ts' + +test('focusNext', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + height: 600, + items: [ + { + depth: 0, + name: 'index.css', + path: '/index.css', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'test-folder', + path: '/test-folder', + selected: false, + type: DirentType.Directory, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusNext.focusNext(state)).toMatchObject({ + focusedIndex: 1, + }) +}) + +test('focusNext - when no focus', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + height: 600, + items: [ + { + depth: 0, + name: 'index.css', + path: '/index.css', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'test-folder', + path: '/test-folder', + selected: false, + type: DirentType.Directory, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusNext.focusNext(state)).toMatchObject({ + focusedIndex: 0, + }) +}) + +test('focusNext - at end', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 2, + height: 600, + items: [ + { + depth: 0, + name: 'index.css', + path: '/index.css', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'test-folder', + path: '/test-folder', + selected: false, + type: DirentType.Directory, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusNext.focusNext(state)).toMatchObject({ + focusedIndex: 2, + }) +}) diff --git a/packages/explorer-view/test/FocusNone.test.ts b/packages/explorer-view/test/FocusNone.test.ts new file mode 100644 index 0000000..1253fe0 --- /dev/null +++ b/packages/explorer-view/test/FocusNone.test.ts @@ -0,0 +1,16 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { focusNone } from '../src/parts/FocusNone/FocusNone.ts' + +test('should return state if focusedIndex is -1', () => { + const state: ExplorerState = { ...createDefaultState(), focusedIndex: -1 } + const result = focusNone(state) + expect(result).toBe(state) +}) + +test('should call focusIndex if focusedIndex is not -1', () => { + const state: ExplorerState = { ...createDefaultState(), focusedIndex: 2 } + const result = focusNone(state) + expect(result.focusedIndex).toBe(-1) +}) diff --git a/packages/explorer-view/test/FocusPrevious.test.ts b/packages/explorer-view/test/FocusPrevious.test.ts new file mode 100644 index 0000000..45cb98c --- /dev/null +++ b/packages/explorer-view/test/FocusPrevious.test.ts @@ -0,0 +1,123 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ViewletExplorerFocusPrevious from '../src/parts/FocusPrevious/FocusPrevious.ts' + +test('focusPrevious', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + height: 600, + items: [ + { + depth: 0, + name: 'index.css', + path: '/index.css', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'test-folder', + path: '/test-folder', + selected: false, + type: DirentType.Directory, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ + focusedIndex: 0, + }) +}) + +test('focusPrevious - at start', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + height: 600, + items: [ + { + depth: 0, + name: 'index.css', + path: '/index.css', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'test-folder', + path: '/test-folder', + selected: false, + type: DirentType.Directory, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ + focusedIndex: 0, + }) +}) + +test('focusPrevious - when no focus', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + height: 600, + items: [ + { + depth: 0, + name: 'index.css', + path: '/index.css', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'index.html', + path: '/index.html', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + name: 'test-folder', + path: '/test-folder', + selected: false, + type: DirentType.Directory, + }, + ], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ + focusedIndex: 2, + }) +}) + +test('focusPrevious - when no focus and no dirents', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + height: 600, + items: [], + root: '/home/test-user/test-path', + } + expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ + focusedIndex: -1, + }) +}) diff --git a/packages/explorer-view/test/GenerateUniqueName.test.ts b/packages/explorer-view/test/GenerateUniqueName.test.ts new file mode 100644 index 0000000..5fa16e8 --- /dev/null +++ b/packages/explorer-view/test/GenerateUniqueName.test.ts @@ -0,0 +1,143 @@ +import { expect, test } from '@jest/globals' +import { generateUniqueName } from '../src/parts/GenerateUniqueName/GenerateUniqueName.ts' + +test('generateUniqueName - no conflict', () => { + const result = generateUniqueName('file.txt', ['/test/other.txt'], '/test') + expect(result).toBe('file.txt') +}) + +test('generateUniqueName - single conflict', () => { + const result = generateUniqueName('file.txt', ['/test/file.txt'], '/test') + expect(result).toBe('file copy.txt') +}) + +test('generateUniqueName - multiple conflicts', () => { + const result = generateUniqueName('file.txt', ['/test/file.txt', '/test/file copy.txt'], '/test') + expect(result).toBe('file copy 1.txt') +}) + +test('generateUniqueName - multiple numbered conflicts', () => { + const result = generateUniqueName('file.txt', ['/test/file.txt', '/test/file copy.txt', '/test/file copy 1.txt', '/test/file copy 2.txt'], '/test') + expect(result).toBe('file copy 3.txt') +}) + +test('generateUniqueName - file without extension', () => { + const result = generateUniqueName('README', ['/test/README'], '/test') + expect(result).toBe('README copy') +}) + +test('generateUniqueName - file without extension multiple conflicts', () => { + const result = generateUniqueName('README', ['/test/README', '/test/README copy', '/test/README copy 1'], '/test') + expect(result).toBe('README copy 2') +}) + +test('generateUniqueName - file starting with dot', () => { + const result = generateUniqueName('.gitignore', ['/test/.gitignore'], '/test') + expect(result).toBe('.gitignore copy') +}) + +test('generateUniqueName - file ending with dot', () => { + const result = generateUniqueName('file.', ['/test/file.'], '/test') + expect(result).toBe('file. copy') +}) + +test('generateUniqueName - file with multiple dots', () => { + const result = generateUniqueName('file.backup.txt', ['/test/file.backup.txt'], '/test') + expect(result).toBe('file.backup copy.txt') +}) + +test('generateUniqueName - file with only dot', () => { + const result = generateUniqueName('.', ['/test/.'], '/test') + expect(result).toBe('. copy') +}) + +test('generateUniqueName - empty filename', () => { + const result = generateUniqueName('', ['/test/'], '/test') + expect(result).toBe(' copy') +}) + +test('generateUniqueName - filename with spaces', () => { + const result = generateUniqueName('my file.txt', ['/test/my file.txt'], '/test') + expect(result).toBe('my file copy.txt') +}) + +test('generateUniqueName - filename with special characters', () => { + const result = generateUniqueName('file@#$%.txt', ['/test/file@#$%.txt'], '/test') + expect(result).toBe('file@#$% copy.txt') +}) + +test('generateUniqueName - filename with numbers', () => { + const result = generateUniqueName('file123.txt', ['/test/file123.txt'], '/test') + expect(result).toBe('file123 copy.txt') +}) + +test('generateUniqueName - filename that looks like a copy', () => { + const result = generateUniqueName('file copy.txt', ['/test/file copy.txt'], '/test') + expect(result).toBe('file copy copy.txt') +}) + +test('generateUniqueName - filename that looks like a numbered copy', () => { + const result = generateUniqueName('file copy 1.txt', ['/test/file copy 1.txt'], '/test') + expect(result).toBe('file copy 1 copy.txt') +}) + +test('generateUniqueName - complex extension', () => { + const result = generateUniqueName('file.tar.gz', ['/test/file.tar.gz'], '/test') + expect(result).toBe('file.tar copy.gz') +}) + +test('generateUniqueName - hidden file with extension', () => { + const result = generateUniqueName('.config.json', ['/test/.config.json'], '/test') + expect(result).toBe('.config copy.json') +}) + +test('generateUniqueName - very long filename', () => { + const longName = 'a'.repeat(100) + '.txt' + const result = generateUniqueName(longName, [`/test/${longName}`], '/test') + expect(result).toBe('a'.repeat(100) + ' copy.txt') +}) + +test('generateUniqueName - unicode filename', () => { + const result = generateUniqueName('café.txt', ['/test/café.txt'], '/test') + expect(result).toBe('café copy.txt') +}) + +test('generateUniqueName - filename with emoji', () => { + const result = generateUniqueName('file🚀.txt', ['/test/file🚀.txt'], '/test') + expect(result).toBe('file🚀 copy.txt') +}) + +test('generateUniqueName - case sensitive', () => { + const result = generateUniqueName('File.txt', ['/test/file.txt'], '/test') + expect(result).toBe('File.txt') +}) + +test('generateUniqueName - different root path', () => { + const result = generateUniqueName('file.txt', ['/different/file.txt'], '/test') + expect(result).toBe('file.txt') +}) + +test('generateUniqueName - root path with trailing slash', () => { + const result = generateUniqueName('file.txt', ['/test/file.txt'], '/test/') + expect(result).toBe('file copy.txt') +}) + +test('generateUniqueName - multiple conflicts with gaps', () => { + const result = generateUniqueName('file.txt', ['/test/file.txt', '/test/file copy.txt', '/test/file copy 3.txt'], '/test') + expect(result).toBe('file copy 1.txt') +}) + +test('generateUniqueName - filename with copy in middle', () => { + const result = generateUniqueName('copyfile.txt', ['/test/copyfile.txt'], '/test') + expect(result).toBe('copyfile copy.txt') +}) + +test('generateUniqueName - filename ending with copy', () => { + const result = generateUniqueName('mycopy.txt', ['/test/mycopy.txt'], '/test') + expect(result).toBe('mycopy copy.txt') +}) + +test('generateUniqueName - filename with copy and number', () => { + const result = generateUniqueName('filecopy1.txt', ['/test/filecopy1.txt'], '/test') + expect(result).toBe('filecopy1 copy.txt') +}) diff --git a/packages/explorer-view/test/GetActionButtonVirtualDom.test.ts b/packages/explorer-view/test/GetActionButtonVirtualDom.test.ts new file mode 100644 index 0000000..12c941a --- /dev/null +++ b/packages/explorer-view/test/GetActionButtonVirtualDom.test.ts @@ -0,0 +1,28 @@ +import { expect, test } from '@jest/globals' +import * as ActionType from '../src/parts/ActionType/ActionType.ts' +import * as GetActionButtonVirtualDom from '../src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts' + +test('getActionButtonVirtualDom', () => { + const action = { + command: 'newFile', + icon: 'NewFile', + id: 'New File', + name: 'NewFile', + type: ActionType.Button, + } + expect(GetActionButtonVirtualDom.getActionButtonVirtualDom(action)).toEqual([ + { + childCount: 1, + className: 'IconButton', + name: 'NewFile', + title: 'New File', + type: 1, + }, + { + childCount: 0, + className: 'MaskIcon MaskIconNewFile', + role: 'none', + type: 4, + }, + ]) +}) diff --git a/packages/explorer-view/test/GetActionVirtualDom.test.ts b/packages/explorer-view/test/GetActionVirtualDom.test.ts new file mode 100644 index 0000000..43e6d2e --- /dev/null +++ b/packages/explorer-view/test/GetActionVirtualDom.test.ts @@ -0,0 +1,26 @@ +import { expect, test } from '@jest/globals' +import type { ViewletAction } from '../src/parts/ViewletAction/ViewletAction.ts' +import * as ActionType from '../src/parts/ActionType/ActionType.ts' +import { getActionVirtualDom } from '../src/parts/GetActionVirtualDom/GetActionVirtualDom.ts' + +test('getActionVirtualDom - button action', () => { + const action: ViewletAction = { + command: 'test.command', + icon: 'test-icon', + id: 'test-button', + type: ActionType.Button, + } + const result = getActionVirtualDom(action) + expect(result).toHaveLength(2) + expect(result[0].type).toBe(1) +}) + +test('getActionVirtualDom - unknown action type', () => { + const action: ViewletAction = { + command: 'test.command', + id: 'test-unknown', + type: 999, // Using a number that's not defined in ActionType + } + const result = getActionVirtualDom(action) + expect(result).toEqual([]) +}) diff --git a/packages/explorer-view/test/GetActions.test.ts b/packages/explorer-view/test/GetActions.test.ts new file mode 100644 index 0000000..4be0973 --- /dev/null +++ b/packages/explorer-view/test/GetActions.test.ts @@ -0,0 +1,42 @@ +import { expect, test } from '@jest/globals' +import * as ActionType from '../src/parts/ActionType/ActionType.ts' +import * as ViewletExplorerStrings from '../src/parts/ExplorerStrings/ExplorerStrings.ts' +import * as GetActions from '../src/parts/GetActions/GetActions.ts' +import * as MaskIcon from '../src/parts/MaskIcon/MaskIcon.ts' + +test('getActions - with root', () => { + expect(GetActions.getActions('/test-root')).toEqual([ + { + command: 'newFile', + icon: MaskIcon.NewFile, + id: ViewletExplorerStrings.newFile(), + name: 'NewFile', + type: ActionType.Button, + }, + { + command: 'newFolder', + icon: MaskIcon.NewFolder, + id: ViewletExplorerStrings.newFolder(), + name: 'NewFolder', + type: ActionType.Button, + }, + { + command: 'refresh', + icon: MaskIcon.Refresh, + id: ViewletExplorerStrings.refresh(), + name: 'Refresh', + type: ActionType.Button, + }, + { + command: 'collapseAll', + icon: MaskIcon.CollapseAll, + id: ViewletExplorerStrings.collapseAll(), + name: 'CollapseAll', + type: ActionType.Button, + }, + ]) +}) + +test('getActions - no root', () => { + expect(GetActions.getActions('')).toEqual([]) +}) diff --git a/packages/explorer-view/test/GetChevronType.test.ts b/packages/explorer-view/test/GetChevronType.test.ts new file mode 100644 index 0000000..f31f4a4 --- /dev/null +++ b/packages/explorer-view/test/GetChevronType.test.ts @@ -0,0 +1,32 @@ +import { expect, test } from '@jest/globals' +import * as ChevronType from '../src/parts/ChevronType/ChevronType.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as GetChevronType from '../src/parts/GetChevronType/GetChevronType.ts' + +test('getChevronType - chevrons disabled', () => { + expect(GetChevronType.getChevronType(DirentType.Directory, false)).toBe(ChevronType.None) +}) + +test('getChevronType - directory', () => { + expect(GetChevronType.getChevronType(DirentType.Directory, true)).toBe(ChevronType.Right) +}) + +test('getChevronType - directory expanded', () => { + expect(GetChevronType.getChevronType(DirentType.DirectoryExpanded, true)).toBe(ChevronType.Down) +}) + +test('getChevronType - directory expanding', () => { + expect(GetChevronType.getChevronType(DirentType.DirectoryExpanding, true)).toBe(ChevronType.Down) +}) + +test('getChevronType - file', () => { + expect(GetChevronType.getChevronType(DirentType.File, true)).toBe(ChevronType.None) +}) + +test('getChevronType - symlink file', () => { + expect(GetChevronType.getChevronType(DirentType.SymLinkFile, true)).toBe(ChevronType.None) +}) + +test('getChevronType - unknown type', () => { + expect(GetChevronType.getChevronType(999_999, true)).toBe(ChevronType.None) +}) diff --git a/packages/explorer-view/test/GetChevronVirtualDom.test.ts b/packages/explorer-view/test/GetChevronVirtualDom.test.ts new file mode 100644 index 0000000..d23ec90 --- /dev/null +++ b/packages/explorer-view/test/GetChevronVirtualDom.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from '@jest/globals' +import * as ChevronDownVirtualDom from '../src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts' +import * as ChevronRightVirtualDom from '../src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts' +import * as GetChevronVirtualDom from '../src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts' + +test('getChevronVirtualDom - no chevron', () => { + expect(GetChevronVirtualDom.getChevronVirtualDom(0)).toEqual([]) +}) + +test('getChevronVirtualDom - right chevron', () => { + expect(GetChevronVirtualDom.getChevronVirtualDom(1)).toEqual([ChevronRightVirtualDom.chevronRightVirtualDom]) +}) + +test('getChevronVirtualDom - down chevron', () => { + expect(GetChevronVirtualDom.getChevronVirtualDom(2)).toEqual([ChevronDownVirtualDom.chevronDownVirtualDom]) +}) diff --git a/packages/explorer-view/test/GetClickFn.test.ts b/packages/explorer-view/test/GetClickFn.test.ts new file mode 100644 index 0000000..cbf8c12 --- /dev/null +++ b/packages/explorer-view/test/GetClickFn.test.ts @@ -0,0 +1,52 @@ +import { expect, test } from '@jest/globals' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as GetClickFn from '../src/parts/GetClickFn/GetClickFn.ts' +import * as HandleClickDirectory from '../src/parts/HandleClickDirectory/HandleClickDirectory.ts' +import * as HandleClickDirectoryExpanded from '../src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' +import * as HandleClickDirectoryExpanding from '../src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts' +import * as HandleClickFile from '../src/parts/HandleClickFile/HandleClickFile.ts' +import * as HandleClickSymlink from '../src/parts/HandleClickSymlink/HandleClickSymlink.ts' + +test('getClickFn - file', () => { + expect(GetClickFn.getClickFn(DirentType.File)).toBe(HandleClickFile.handleClickFile) +}) + +test('getClickFn - symlink file', () => { + expect(GetClickFn.getClickFn(DirentType.SymLinkFile)).toBe(HandleClickFile.handleClickFile) +}) + +test('getClickFn - directory', () => { + expect(GetClickFn.getClickFn(DirentType.Directory)).toBe(HandleClickDirectory.handleClickDirectory) +}) + +test('getClickFn - symlink folder', () => { + expect(GetClickFn.getClickFn(DirentType.SymLinkFolder)).toBe(HandleClickDirectory.handleClickDirectory) +}) + +test('getClickFn - directory expanding', () => { + expect(GetClickFn.getClickFn(DirentType.DirectoryExpanding)).toBe(HandleClickDirectoryExpanding.handleClickDirectoryExpanding) +}) + +test('getClickFn - directory expanded', () => { + expect(GetClickFn.getClickFn(DirentType.DirectoryExpanded)).toBe(HandleClickDirectoryExpanded.handleClickDirectoryExpanded) +}) + +test('getClickFn - symlink', () => { + expect(GetClickFn.getClickFn(DirentType.Symlink)).toBe(HandleClickSymlink.handleClickSymLink) +}) + +test('getClickFn - character device', () => { + expect(() => GetClickFn.getClickFn(DirentType.CharacterDevice)).toThrow('Cannot open character device files') +}) + +test('getClickFn - block device', () => { + expect(() => GetClickFn.getClickFn(DirentType.BlockDevice)).toThrow('Cannot open block device files') +}) + +test('getClickFn - socket', () => { + expect(() => GetClickFn.getClickFn(DirentType.Socket)).toThrow('Cannot open socket files') +}) + +test('getClickFn - unknown type', () => { + expect(() => GetClickFn.getClickFn(999_999)).toThrow('unsupported dirent type 999999') +}) diff --git a/packages/explorer-view/test/GetCss.test.ts b/packages/explorer-view/test/GetCss.test.ts new file mode 100644 index 0000000..abe63dc --- /dev/null +++ b/packages/explorer-view/test/GetCss.test.ts @@ -0,0 +1,119 @@ +import { test, expect } from '@jest/globals' +import { getCss } from '../src/parts/GetCss/GetCss.ts' + +test('getCss - basic scrollBarHeight and empty indents', () => { + const scrollBarHeight = 20 + const scrollBarTop = 0 + const uniqueIndents: readonly number[] = [] + const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) + expect(result).toBe(`.Explorer { + --ScrollBarThumbHeight: 20px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 0px; + --ErrorMessageLeft: 0px; + --ErrorMessageWidth: 0px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +}`) +}) + +test('getCss - with single indent', () => { + const scrollBarHeight = 15 + const scrollBarTop = 0 + const uniqueIndents: readonly number[] = [10] + const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) + expect(result).toBe(`.Explorer { + --ScrollBarThumbHeight: 15px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 0px; + --ErrorMessageLeft: 0px; + --ErrorMessageWidth: 0px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-10 { + padding-left: 10px; +}`) +}) + +test('getCss - with multiple indents', () => { + const scrollBarHeight = 25 + const scrollBarTop = 0 + const uniqueIndents: readonly number[] = [0, 20, 40] + const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) + expect(result).toBe(`.Explorer { + --ScrollBarThumbHeight: 25px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 0px; + --ErrorMessageLeft: 0px; + --ErrorMessageWidth: 0px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-0 { + padding-left: 0px; +} +.Indent-20 { + padding-left: 20px; +} +.Indent-40 { + padding-left: 40px; +}`) +}) + +test('getCss - with zero scrollBarHeight', () => { + const scrollBarHeight = 0 + const scrollBarTop = 0 + const uniqueIndents: readonly number[] = [5, 10] + const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) + expect(result).toBe(`.Explorer { + --ScrollBarThumbHeight: 0px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 0px; + --ErrorMessageLeft: 0px; + --ErrorMessageWidth: 0px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-5 { + padding-left: 5px; +} +.Indent-10 { + padding-left: 10px; +}`) +}) + +test('getCss - with large indents', () => { + const scrollBarHeight = 30 + const scrollBarTop = 0 + const uniqueIndents: readonly number[] = [100, 200, 300] + const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) + expect(result).toBe(`.Explorer { + --ScrollBarThumbHeight: 30px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 0px; + --ErrorMessageLeft: 0px; + --ErrorMessageWidth: 0px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-100 { + padding-left: 100px; +} +.Indent-200 { + padding-left: 200px; +} +.Indent-300 { + padding-left: 300px; +}`) +}) diff --git a/packages/explorer-view/test/GetDragData.test.ts b/packages/explorer-view/test/GetDragData.test.ts new file mode 100644 index 0000000..adaf71a --- /dev/null +++ b/packages/explorer-view/test/GetDragData.test.ts @@ -0,0 +1,26 @@ +import { test, expect } from '@jest/globals' +import { getDragData } from '../src/parts/GetDragData/GetDragData.js' + +test('getDragData - single url', () => { + const urls: string[] = ['/a.txt'] + const result = getDragData(urls) + expect(result.items[0]).toEqual({ data: 'file:///a.txt', type: 'text/uri-list' }) + expect(result.items[1]).toEqual({ data: 'file:///a.txt', type: 'text/plain' }) + expect(result.label).toBe('a.txt') +}) + +test('getDragData - multiple urls', () => { + const urls: string[] = ['/a.txt', '/b.txt'] + const result = getDragData(urls) + expect(result.items[0]).toEqual({ data: 'file:///a.txt\nfile:///b.txt', type: 'text/uri-list' }) + expect(result.items[1]).toEqual({ data: 'file:///a.txt\nfile:///b.txt', type: 'text/plain' }) + expect(result.label).toBe('2') +}) + +test('getDragData - empty', () => { + const urls: string[] = [] + const result = getDragData(urls) + expect(result.items[0]).toEqual({ data: '', type: 'text/uri-list' }) + expect(result.items[1]).toEqual({ data: '', type: 'text/plain' }) + expect(result.label).toBe('0') +}) diff --git a/packages/explorer-view/test/GetDragLabel.test.ts b/packages/explorer-view/test/GetDragLabel.test.ts new file mode 100644 index 0000000..442d536 --- /dev/null +++ b/packages/explorer-view/test/GetDragLabel.test.ts @@ -0,0 +1,15 @@ +import { test, expect } from '@jest/globals' +import { getDragLabel } from '../src/parts/GetDragLabel/GetDragLabel.js' + +test('getDragLabel - single url', () => { + expect(getDragLabel(['file:///a.txt'])).toBe('a.txt') +}) + +test('getDragLabel - multiple urls', () => { + expect(getDragLabel(['file:///a.txt', 'file:///b.txt'])).toBe('2') + expect(getDragLabel(['file:///a.txt', 'file:///b.txt', 'file:///c.txt'])).toBe('3') +}) + +test('getDragLabel - empty', () => { + expect(getDragLabel([])).toBe('0') +}) diff --git a/packages/explorer-view/test/GetDropHandler.test.ts b/packages/explorer-view/test/GetDropHandler.test.ts new file mode 100644 index 0000000..8145367 --- /dev/null +++ b/packages/explorer-view/test/GetDropHandler.test.ts @@ -0,0 +1,14 @@ +import { expect, test } from '@jest/globals' +import { getDropHandler } from '../src/parts/GetDropHandler/GetDropHandler.ts' +import * as HandleDropIndex from '../src/parts/HandleDropIndex/HandleDropIndex.ts' +import * as HandleDropRoot from '../src/parts/HandleDropRoot/HandleDropRoot.ts' + +test('get root drop handler', () => { + const handler = getDropHandler(-1) + expect(handler).toBe(HandleDropRoot.handleDropRoot) +}) + +test('get index drop handler', () => { + const handler = getDropHandler(0) + expect(handler).toBe(HandleDropIndex.handleDropIndex) +}) diff --git a/packages/explorer-view/test/GetEditingIcon.test.ts b/packages/explorer-view/test/GetEditingIcon.test.ts new file mode 100644 index 0000000..6627760 --- /dev/null +++ b/packages/explorer-view/test/GetEditingIcon.test.ts @@ -0,0 +1,121 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import * as GetEditingIcon from '../src/parts/GetEditingIcon/GetEditingIcon.ts' + +test('getEditingIcon - CreateFile', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return 'file-icon' + }, + }) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.CreateFile, 'test.txt') + expect(result).toBe('file-icon') + expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) +}) + +test('getEditingIcon - CreateFolder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFolderIcon'() { + return 'folder-icon' + }, + }) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.CreateFolder, 'test-folder') + expect(result).toBe('folder-icon') + expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) +}) + +test('getEditingIcon - Rename File', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return 'file-icon' + }, + }) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test.txt', DirentType.File) + expect(result).toBe('file-icon') + expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) +}) + +test('getEditingIcon - Rename EditingFile', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return 'file-icon' + }, + }) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test.txt', DirentType.EditingFile) + expect(result).toBe('file-icon') + expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) +}) + +test('getEditingIcon - Rename Directory', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFolderIcon'() { + return 'folder-icon' + }, + }) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test-folder', DirentType.Directory) + expect(result).toBe('folder-icon') + expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) +}) + +test('getEditingIcon - Rename EditingFolder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFolderIcon'() { + return 'folder-icon' + }, + }) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test-folder', DirentType.EditingFolder) + expect(result).toBe('folder-icon') + expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) +}) + +test('getEditingIcon - Rename EditingDirectoryExpanded', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFolderIcon'() { + return 'folder-icon' + }, + }) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test-folder', DirentType.EditingDirectoryExpanded) + expect(result).toBe('folder-icon') + expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) +}) + +test('getEditingIcon - Rename with unsupported dirent type', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test', DirentType.Symlink) + expect(result).toBe('') + expect(mockRpc.invocations).toEqual([]) +}) + +test('getEditingIcon - Rename without dirent type', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test') + expect(result).toBe('') + expect(mockRpc.invocations).toEqual([]) +}) + +test('getEditingIcon - None editing type', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + + const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.None, 'test') + expect(result).toBe('') + expect(mockRpc.invocations).toEqual([]) +}) + +test('getEditingIcon - unknown editing type', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + + const result = await GetEditingIcon.getEditingIcon(999, 'test') + expect(result).toBe('') + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/GetEditingType.test.ts b/packages/explorer-view/test/GetEditingType.test.ts new file mode 100644 index 0000000..047e6e7 --- /dev/null +++ b/packages/explorer-view/test/GetEditingType.test.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@jest/globals' +import { DELTA_EDITING } from '../src/parts/DeltaEditing/DeltaEditing.ts' +import { getEditingType } from '../src/parts/GetEditingType/GetEditingType.ts' + +test('should add DELTA_EDITING if direntType < DELTA_EDITING', () => { + const result = getEditingType(1) + expect(result).toBe(1 + DELTA_EDITING) +}) + +test('should return direntType if direntType >= DELTA_EDITING', () => { + const result = getEditingType(DELTA_EDITING) + expect(result).toBe(DELTA_EDITING) +}) diff --git a/packages/explorer-view/test/GetErrorCode.test.ts b/packages/explorer-view/test/GetErrorCode.test.ts new file mode 100644 index 0000000..d31060b --- /dev/null +++ b/packages/explorer-view/test/GetErrorCode.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from '@jest/globals' +import * as GetErrorCode from '../src/parts/GetErrorCode/GetErrorCode.ts' + +test('getErrorCode - returns code from object error', () => { + const error = { + code: 'ENOENT', + } + expect(GetErrorCode.getErrorCode(error)).toBe('ENOENT') +}) + +test('getErrorCode - returns empty string for error without string code', () => { + const error = { + code: 404, + } + expect(GetErrorCode.getErrorCode(error)).toBe('') +}) + +test('getErrorCode - returns empty string for null', () => { + expect(GetErrorCode.getErrorCode(null)).toBe('') +}) diff --git a/packages/explorer-view/test/GetErrorMessage.test.ts b/packages/explorer-view/test/GetErrorMessage.test.ts new file mode 100644 index 0000000..32b7c88 --- /dev/null +++ b/packages/explorer-view/test/GetErrorMessage.test.ts @@ -0,0 +1,14 @@ +import { expect, test } from '@jest/globals' +import * as GetErrorMessage from '../src/parts/GetErrorMessage/GetErrorMessage.ts' + +test('getErrorMessage - returns message from Error instance', () => { + expect(GetErrorMessage.getErrorMessage(new Error('Failed to load'))).toBe('Failed to load') +}) + +test('getErrorMessage - returns string error as is', () => { + expect(GetErrorMessage.getErrorMessage('Failed to load')).toBe('Failed to load') +}) + +test('getErrorMessage - returns fallback for unknown error', () => { + expect(GetErrorMessage.getErrorMessage({ message: 'Hidden' })).toBe('Unknown error') +}) diff --git a/packages/explorer-view/test/GetErrorMessageDom.test.ts b/packages/explorer-view/test/GetErrorMessageDom.test.ts new file mode 100644 index 0000000..d33c1ec --- /dev/null +++ b/packages/explorer-view/test/GetErrorMessageDom.test.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@jest/globals' +import { getErrorMessageDom } from '../src/parts/GetErrorMessageDom/GetErrorMessageDom.ts' + +test('should return empty array for empty error message', () => { + const result = getErrorMessageDom('') + expect(result).toEqual([]) +}) + +test('should return dom nodes for non-empty error message', () => { + const result = getErrorMessageDom('Error!') + expect(Array.isArray(result)).toBe(true) + expect(result.length).toBeGreaterThan(0) +}) diff --git a/packages/explorer-view/test/GetExcluded.test.ts b/packages/explorer-view/test/GetExcluded.test.ts new file mode 100644 index 0000000..16499bb --- /dev/null +++ b/packages/explorer-view/test/GetExcluded.test.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@jest/globals' +import * as GetExcluded from '../src/parts/GetExcluded/GetExcluded.ts' + +test('getExcluded - returns empty array by default', () => { + expect(GetExcluded.getExcluded()).toEqual([]) +}) diff --git a/packages/explorer-view/test/GetExpandedDirents.test.ts b/packages/explorer-view/test/GetExpandedDirents.test.ts new file mode 100644 index 0000000..55b2d89 --- /dev/null +++ b/packages/explorer-view/test/GetExpandedDirents.test.ts @@ -0,0 +1,27 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import { Directory, DirectoryExpanded, File } from '../src/parts/DirentType/DirentType.ts' +import { getExpandedDirents } from '../src/parts/GetExpandedDirents/GetExpandedDirents.ts' + +test('getExpandedDirents - empty array', () => { + const items: readonly ExplorerItem[] = [] + expect(getExpandedDirents(items)).toHaveLength(0) +}) + +test('getExpandedDirents - no expanded items', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: Directory }, + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, + ] + expect(getExpandedDirents(items)).toHaveLength(0) +}) + +test('getExpandedDirents - with expanded items', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, + ] + const result = getExpandedDirents(items) + expect(result).toHaveLength(1) + expect(result[0].name).toBe('folder1') +}) diff --git a/packages/explorer-view/test/GetExpandedType.test.ts b/packages/explorer-view/test/GetExpandedType.test.ts new file mode 100644 index 0000000..8f05e91 --- /dev/null +++ b/packages/explorer-view/test/GetExpandedType.test.ts @@ -0,0 +1,28 @@ +import { expect, test } from '@jest/globals' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExpandedType from '../src/parts/ExpandedType/ExpandedType.ts' +import * as GetExpandedType from '../src/parts/GetExpandedType/GetExpandedType.ts' + +test('getExpandedType - directory', () => { + expect(GetExpandedType.getExpandedType(DirentType.Directory)).toBe(ExpandedType.Collapsed) +}) + +test('getExpandedType - directory expanding', () => { + expect(GetExpandedType.getExpandedType(DirentType.DirectoryExpanding)).toBe(ExpandedType.Expanded) +}) + +test('getExpandedType - directory expanded', () => { + expect(GetExpandedType.getExpandedType(DirentType.DirectoryExpanded)).toBe(ExpandedType.Expanded) +}) + +test('getExpandedType - file', () => { + expect(GetExpandedType.getExpandedType(DirentType.File)).toBe(ExpandedType.None) +}) + +test('getExpandedType - symlink file', () => { + expect(GetExpandedType.getExpandedType(DirentType.SymLinkFile)).toBe(ExpandedType.None) +}) + +test('getExpandedType - unknown type', () => { + expect(GetExpandedType.getExpandedType(999_999)).toBe(ExpandedType.None) +}) diff --git a/packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts b/packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts new file mode 100644 index 0000000..1421d64 --- /dev/null +++ b/packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts @@ -0,0 +1,158 @@ +import { expect, test } from '@jest/globals' +import type { VisibleExplorerItem } from '../src/parts/VisibleExplorerItem/VisibleExplorerItem.ts' +import { getExplorerItemVirtualDom } from '../src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts' + +test('basic item', () => { + const item: VisibleExplorerItem = { + ariaExpanded: undefined, + chevron: 0, + className: '', + depth: 1, + hasEditingError: false, + icon: 'file', + id: '1', + indent: 0, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'test.txt', + path: '/test.txt', + posInSet: 1, + selected: false, + setSize: 2, + } + const dom = getExplorerItemVirtualDom(item) + expect(dom).toHaveLength(4) + expect(dom[0].type).toBe(4) + expect(dom[0].role).toBe('treeitem') + expect(dom[0].ariaLabel).toBe('test.txt') + expect(dom[0].title).toBe('/test.txt') +}) + +test('file uri item removes file scheme from title', () => { + const item: VisibleExplorerItem = { + ariaExpanded: undefined, + chevron: 0, + className: '', + depth: 1, + hasEditingError: false, + icon: 'file', + id: '1', + indent: 0, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'test.txt', + path: 'file:///test.txt', + posInSet: 1, + selected: false, + setSize: 2, + } + const dom = getExplorerItemVirtualDom(item) + expect(dom[0].title).toBe('/test.txt') +}) + +test('non-file uri item keeps scheme in title', () => { + const item: VisibleExplorerItem = { + ariaExpanded: undefined, + chevron: 0, + className: '', + depth: 1, + hasEditingError: false, + icon: 'file', + id: '1', + indent: 0, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'test.txt', + path: 'memfs:///test.txt', + posInSet: 1, + selected: false, + setSize: 2, + } + const dom = getExplorerItemVirtualDom(item) + expect(dom[0].title).toBe('memfs:///test.txt') +}) + +test('item with chevron', () => { + const item: VisibleExplorerItem = { + ariaExpanded: 'true', + chevron: 1, + className: '', + depth: 1, + hasEditingError: false, + icon: 'folder', + id: '1', + indent: 0, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'test', + path: '/test', + posInSet: 1, + selected: false, + setSize: 2, + } + const dom = getExplorerItemVirtualDom(item) + expect(dom).toHaveLength(5) + expect(dom[0].type).toBe(4) + expect(dom[0].role).toBe('treeitem') + expect(dom[0].ariaLabel).toBe('test') +}) + +test('item in editing state', () => { + const item: VisibleExplorerItem = { + ariaExpanded: undefined, + chevron: 0, + className: '', + depth: 1, + hasEditingError: false, + icon: 'file', + id: '1', + indent: 0, + index: 0, + isCut: false, + isEditing: true, + isIgnored: false, + name: 'test.txt', + path: '/test.txt', + posInSet: 1, + selected: false, + setSize: 2, + } + const dom = getExplorerItemVirtualDom(item) + expect(dom).toHaveLength(3) + expect(dom[0].type).toBe(4) + expect(dom[0].role).toBe('treeitem') +}) + +test('item with error', () => { + const item: VisibleExplorerItem = { + ariaExpanded: undefined, + chevron: 0, + className: '', + depth: 1, + hasEditingError: true, + icon: 'file', + id: '1', + indent: 0, + index: 0, + isCut: false, + isEditing: true, + isIgnored: false, + name: 'test.txt', + path: '/test.txt', + posInSet: 1, + selected: false, + setSize: 2, + } + const dom = getExplorerItemVirtualDom(item) + expect(dom).toHaveLength(3) + expect(dom[0].type).toBe(4) + expect(dom[0].role).toBe('treeitem') +}) diff --git a/packages/explorer-view/test/GetExplorerMaxLineY.test.ts b/packages/explorer-view/test/GetExplorerMaxLineY.test.ts new file mode 100644 index 0000000..f66f2d9 --- /dev/null +++ b/packages/explorer-view/test/GetExplorerMaxLineY.test.ts @@ -0,0 +1,66 @@ +import { expect, test } from '@jest/globals' +import * as GetExplorerMaxLineY from '../src/parts/GetMaxLineY/GetMaxLineY.ts' + +test('getExplorerMaxLineY - basic functionality', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 10)).toBe(6) +}) + +test('getExplorerMaxLineY - with offset minLineY', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(50, 100, 20, 10)).toBe(56) +}) + +test('getExplorerMaxLineY - direntsLength smaller than visible items', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 200, 20, 3)).toBe(3) +}) + +test('getExplorerMaxLineY - direntsLength larger than visible items', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 20)).toBe(6) +}) + +test('getExplorerMaxLineY - exact fit', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 6)).toBe(6) +}) + +test('getExplorerMaxLineY - zero height', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 0, 20, 10)).toBe(0) +}) + +test('getExplorerMaxLineY - zero itemHeight', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 0, 10)).toBe(0) +}) + +test('getExplorerMaxLineY - negative height', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, -100, 20, 10)).toBe(0) +}) + +test('getExplorerMaxLineY - negative itemHeight', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, -20, 10)).toBe(0) +}) + +test('getExplorerMaxLineY - zero direntsLength', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 0)).toBe(0) +}) + +test('getExplorerMaxLineY - small height with small itemHeight', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 10, 5, 10)).toBe(3) +}) + +test('getExplorerMaxLineY - large height with small itemHeight', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 1000, 10, 50)).toBe(50) +}) + +test('getExplorerMaxLineY - partial height division', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 75, 20, 10)).toBe(5) +}) + +test('getExplorerMaxLineY - negative minLineY', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(-10, 100, 20, 10)).toBe(-4) +}) + +test('getExplorerMaxLineY - very small height', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 1, 20, 10)).toBe(2) +}) + +test('getExplorerMaxLineY - height smaller than itemHeight', () => { + expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 10, 20, 10)).toBe(2) +}) diff --git a/packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts b/packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts new file mode 100644 index 0000000..7f48843 --- /dev/null +++ b/packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts @@ -0,0 +1,130 @@ +import { expect, test } from '@jest/globals' +import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' +import { dropTargetFull } from '../src/parts/DropTargetFull/DropTargetFull.ts' +import * as GetExplorerWelcomeVirtualDom from '../src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts' + +test('getExplorerWelcomeVirtualDom - wide', () => { + expect(GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(true, [])).toEqual([ + { + childCount: 1, + className: 'Viewlet Explorer', + onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, + onDragLeave: DomEventListenerFunctions.HandleDragLeave, + onDragOver: DomEventListenerFunctions.HandleDragOver, + onDrop: DomEventListenerFunctions.HandleDrop, + tabIndex: 0, + type: 4, + }, + { + childCount: 2, + className: 'Welcome', + type: 4, + }, + { + childCount: 1, + className: 'WelcomeMessage', + type: 50, + }, + { + childCount: 0, + text: 'You have not yet opened a folder.', + type: 12, + }, + { + childCount: 1, + className: 'Button ButtonPrimary ButtonWide', + name: 'OpenFolder', + onClick: DomEventListenerFunctions.HandleClickOpenFolder, + type: 1, + }, + { + childCount: 0, + text: 'Open folder', + type: 12, + }, + ]) +}) + +test('getExplorerWelcomeVirtualDom - narrow', () => { + expect(GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(false, [])).toEqual([ + { + childCount: 1, + className: 'Viewlet Explorer', + onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, + onDragLeave: DomEventListenerFunctions.HandleDragLeave, + onDragOver: DomEventListenerFunctions.HandleDragOver, + onDrop: DomEventListenerFunctions.HandleDrop, + tabIndex: 0, + type: 4, + }, + { + childCount: 2, + className: 'Welcome', + type: 4, + }, + { + childCount: 1, + className: 'WelcomeMessage', + type: 50, + }, + { + childCount: 0, + text: 'You have not yet opened a folder.', + type: 12, + }, + { + childCount: 1, + className: 'Button ButtonPrimary ButtonNarrow', + name: 'OpenFolder', + onClick: DomEventListenerFunctions.HandleClickOpenFolder, + type: 1, + }, + { + childCount: 0, + text: 'Open folder', + type: 12, + }, + ]) +}) + +test('getExplorerWelcomeVirtualDom - drop target', () => { + expect(GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(true, dropTargetFull)).toEqual([ + { + childCount: 1, + className: 'Viewlet Explorer DropTarget', + onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, + onDragLeave: DomEventListenerFunctions.HandleDragLeave, + onDragOver: DomEventListenerFunctions.HandleDragOver, + onDrop: DomEventListenerFunctions.HandleDrop, + tabIndex: 0, + type: 4, + }, + { + childCount: 2, + className: 'Welcome', + type: 4, + }, + { + childCount: 1, + className: 'WelcomeMessage', + type: 50, + }, + { + childCount: 0, + text: 'You have not yet opened a folder.', + type: 12, + }, + { + childCount: 1, + className: 'Button ButtonPrimary ButtonWide', + name: 'OpenFolder', + onClick: DomEventListenerFunctions.HandleClickOpenFolder, + type: 1, + }, + { + childCount: 0, + text: 'Open folder', + type: 12, + }, + ]) +}) diff --git a/packages/explorer-view/test/GetFileArray.test.ts b/packages/explorer-view/test/GetFileArray.test.ts new file mode 100644 index 0000000..5c59b1e --- /dev/null +++ b/packages/explorer-view/test/GetFileArray.test.ts @@ -0,0 +1,40 @@ +import { test, expect } from '@jest/globals' +import { getFileArray } from '../src/parts/GetFileArray/GetFileArray.ts' + +class MockFileList implements FileList { + private files: File[] = [] + + constructor(files: File[] = []) { + this.files = files + } + + get length(): number { + return this.files.length + } + + item(index: number): File | null { + return this.files[index] || null + } + + [Symbol.iterator](): any { + return this.files[Symbol.iterator]() + } + + [index: number]: File +} + +test('getFileArray converts FileList to array', () => { + const mockFile = new File(['test'], 'test.txt') + const mockFileList = new MockFileList([mockFile]) + + const result = getFileArray(mockFileList) + expect(result).toHaveLength(1) + expect(result[0]).toBe(mockFile) +}) + +test('getFileArray handles empty FileList', () => { + const mockFileList = new MockFileList() + + const result = getFileArray(mockFileList) + expect(result).toHaveLength(0) +}) diff --git a/packages/explorer-view/test/GetFileDecorations.test.ts b/packages/explorer-view/test/GetFileDecorations.test.ts new file mode 100644 index 0000000..64169ee --- /dev/null +++ b/packages/explorer-view/test/GetFileDecorations.test.ts @@ -0,0 +1,166 @@ +import { test, expect, jest } from '@jest/globals' +import { SourceControlWorker } from '@lvce-editor/rpc-registry' +import type { FileDecoration } from '../src/parts/FileDecoration/FileDecoration.ts' + +test.skip('getFileDecorations - returns empty array when decorationsEnabled is false', async () => { + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['/file1.txt'], false, '', 0) + expect(result).toEqual([]) +}) + +test('getFileDecorations - returns empty array when no provider IDs', async () => { + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) + expect(result).toEqual([]) + expect(mockRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0]]) +}) + +test.skip('getFileDecorations - returns decorations for single file', async () => { + const decorations: FileDecoration[] = [{ decoration: 'modified', uri: 'file:///file1.txt' }] + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return ['git'] + }, + 'SourceControl.getFileDecorations'() { + return decorations + }, + }) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) + expect(result).toEqual(decorations) + expect(mockRpc.invocations).toEqual([ + ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], + ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', '', 0]], + ]) +}) + +test.skip('getFileDecorations - converts paths to URIs', async () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///file1.txt' }, + { decoration: 'added', uri: 'file:///file2.txt' }, + ] + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return ['git'] + }, + 'SourceControl.getFileDecorations'() { + return decorations + }, + }) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['/file1.txt', '/file2.txt'], true, '', 0) + expect(result).toEqual(decorations) + expect(mockRpc.invocations).toEqual([ + ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], + ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', 'file:///file2.txt', '', 0]], + ]) +}) + +test.skip('getFileDecorations - handles URIs that are already URIs', async () => { + const decorations: FileDecoration[] = [{ decoration: 'modified', uri: 'file:///file1.txt' }] + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return ['git'] + }, + 'SourceControl.getFileDecorations'() { + return decorations + }, + }) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['file:///file1.txt'], true, '', 0) + expect(result).toEqual(decorations) + expect(mockRpc.invocations).toEqual([ + ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], + ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', '', 0]], + ]) +}) + +test.skip('getFileDecorations - uses first provider ID when multiple are available', async () => { + const decorations: FileDecoration[] = [{ decoration: 'modified', uri: 'file:///file1.txt' }] + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return ['git', 'svn', 'hg'] + }, + 'SourceControl.getFileDecorations'() { + return decorations + }, + }) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) + expect(result).toEqual(decorations) + expect(mockRpc.invocations).toEqual([ + ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], + ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', '', 0]], + ]) +}) + +test('getFileDecorations - returns empty array when getEnabledProviderIds throws', async () => { + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + throw new Error('Provider error') + }, + }) + + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) + expect(result).toEqual([]) + expect(mockRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0]]) + expect(consoleErrorSpy).toHaveBeenCalled() + + consoleErrorSpy.mockRestore() +}) + +test('getFileDecorations - returns empty array when getFileDecorations throws', async () => { + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return ['git'] + }, + 'SourceControl.getFileDecorations'() { + throw new Error('Decorations error') + }, + }) + + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) + expect(result).toEqual([]) + expect(mockRpc.invocations).toEqual([ + ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], + ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt'], '', 0], + ]) + expect(consoleErrorSpy).toHaveBeenCalled() + + consoleErrorSpy.mockRestore() +}) + +test('getFileDecorations - handles empty URIs array', async () => { + using mockRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return ['git'] + }, + 'SourceControl.getFileDecorations'() { + return [] + }, + }) + + const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') + const result = await getFileDecorations('file', '/root', [], true, '', 0) + expect(result).toEqual([]) + expect(mockRpc.invocations).toEqual([ + ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], + ['SourceControl.getFileDecorations', 'git', [], '', 0], + ]) +}) diff --git a/packages/explorer-view/test/GetFileHandles.test.ts b/packages/explorer-view/test/GetFileHandles.test.ts new file mode 100644 index 0000000..a642439 --- /dev/null +++ b/packages/explorer-view/test/GetFileHandles.test.ts @@ -0,0 +1,23 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { getFileHandles } from '../src/parts/GetFileHandles/GetFileHandles.ts' + +class MockFileHandle { + constructor(public name: string) {} +} + +test('getFileHandles', async () => { + const fileIds = [1, 2, 3] + const mockFiles = [new MockFileHandle('file1'), new MockFileHandle('file2'), new MockFileHandle('file3')] + + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystemHandle.getFileHandles'() { + return mockFiles + }, + }) + + const result = await getFileHandles(fileIds) + expect(result).toBe(mockFiles) + expect(result[0]).toBeInstanceOf(MockFileHandle) + expect(mockRpc.invocations).toEqual([['FileSystemHandle.getFileHandles', fileIds]]) +}) diff --git a/packages/explorer-view/test/GetFileIconVirtualDom.test.ts b/packages/explorer-view/test/GetFileIconVirtualDom.test.ts new file mode 100644 index 0000000..12b85b6 --- /dev/null +++ b/packages/explorer-view/test/GetFileIconVirtualDom.test.ts @@ -0,0 +1,25 @@ +import { expect, test } from '@jest/globals' +import * as AriaRoles from '../src/parts/AriaRoles/AriaRoles.ts' +import * as ClassNames from '../src/parts/ClassNames/ClassNames.ts' +import * as GetFileIconVirtualDom from '../src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts' +import * as VirtualDomElements from '../src/parts/VirtualDomElements/VirtualDomElements.ts' + +test('getFileIconVirtualDom - with icon path', () => { + expect(GetFileIconVirtualDom.getFileIconVirtualDom('/icons/file.svg')).toEqual({ + childCount: 0, + className: ClassNames.FileIcon, + role: AriaRoles.None, + src: '/icons/file.svg', + type: VirtualDomElements.Img, + }) +}) + +test('getFileIconVirtualDom - empty icon path', () => { + expect(GetFileIconVirtualDom.getFileIconVirtualDom('')).toEqual({ + childCount: 0, + className: ClassNames.FileIcon, + role: AriaRoles.None, + src: '', + type: VirtualDomElements.Img, + }) +}) diff --git a/packages/explorer-view/test/GetFileIcons.test.ts b/packages/explorer-view/test/GetFileIcons.test.ts new file mode 100644 index 0000000..bb72046 --- /dev/null +++ b/packages/explorer-view/test/GetFileIcons.test.ts @@ -0,0 +1,103 @@ +import { test, expect } from '@jest/globals' +import { IconThemeWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { FileIconCache } from '../src/parts/FileIconCache/FileIconCache.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as GetFileIcons from '../src/parts/GetFileIcons/GetFileIcons.ts' + +test('getFileIcons - empty dirents', async () => { + using mockRpc = IconThemeWorker.registerMockRpc({}) + + const result = await GetFileIcons.getFileIcons([], {}) + expect(result).toEqual({ + icons: [], + newFileIconCache: {}, + }) + expect(mockRpc.invocations).toEqual([]) +}) + +test('getFileIcons - all cached', async () => { + using mockRpc = IconThemeWorker.registerMockRpc({}) + + const dirents: readonly ExplorerItem[] = [ + { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'b', path: '/b', selected: false, type: DirentType.Directory }, + ] + const cache: FileIconCache = { + '/a.txt': 'cached-a', + '/b': 'cached-b', + } + const result = await GetFileIcons.getFileIcons(dirents, cache) + expect(result).toEqual({ + icons: ['cached-a', 'cached-b'], + newFileIconCache: cache, + }) + expect(mockRpc.invocations).toEqual([]) +}) + +test('getFileIcons - none cached', async () => { + const dirents: readonly ExplorerItem[] = [ + { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'b', path: '/b', selected: false, type: DirentType.Directory }, + ] + + using mockRpc = IconThemeWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return ['file-icon', 'folder-icon'] + }, + }) + + const result = await GetFileIcons.getFileIcons(dirents, {}) + expect(result).toEqual({ + icons: ['file-icon', 'folder-icon'], + newFileIconCache: { + '/a.txt': 'file-icon', + '/b': 'folder-icon', + }, + }) + expect(mockRpc.invocations).toEqual([ + [ + 'IconTheme.getIcons', + [ + { name: 'a.txt', type: 1 }, + { name: 'b', type: 2 }, + ], + ], + ]) +}) + +test('getFileIcons - mixed cache', async () => { + const dirents: readonly ExplorerItem[] = [ + { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'b', path: '/b', selected: false, type: DirentType.Directory }, + { depth: 0, name: 'c.txt', path: '/c.txt', selected: false, type: DirentType.File }, + ] + const cache: FileIconCache = { + '/a.txt': 'cached-a', + } + + using mockRpc = IconThemeWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return ['folder-icon', 'file-icon'] + }, + }) + + const result = await GetFileIcons.getFileIcons(dirents, cache) + expect(result).toEqual({ + icons: ['cached-a', 'folder-icon', 'file-icon'], + newFileIconCache: { + '/a.txt': 'cached-a', + '/b': 'folder-icon', + '/c.txt': 'file-icon', + }, + }) + expect(mockRpc.invocations).toEqual([ + [ + 'IconTheme.getIcons', + [ + { name: 'b', type: 2 }, + { name: 'c.txt', type: 1 }, + ], + ], + ]) +}) diff --git a/packages/explorer-view/test/GetFileOperations.test.ts b/packages/explorer-view/test/GetFileOperations.test.ts new file mode 100644 index 0000000..f0c258f --- /dev/null +++ b/packages/explorer-view/test/GetFileOperations.test.ts @@ -0,0 +1,45 @@ +import { expect, test } from '@jest/globals' +import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' +import { getFileOperations } from '../src/parts/GetFileOperations/GetFileOperations.ts' + +test('getFileOperations - empty tree', () => { + const root = '/test' + const uploadTree = {} + expect(getFileOperations(root, uploadTree)).toEqual([]) +}) + +test('getFileOperations - single file', () => { + const root = '/test' + const uploadTree = { + 'file.txt': 'content', + } + expect(getFileOperations(root, uploadTree)).toEqual([{ path: '/test/file.txt', text: 'content', type: FileOperationType.CreateFile }]) +}) + +test('getFileOperations - single folder', () => { + const root = '/test' + const uploadTree = { + folder: {}, + } + expect(getFileOperations(root, uploadTree)).toEqual([{ path: '/test/folder', type: FileOperationType.CreateFolder }]) +}) + +test.skip('getFileOperations - nested structure', () => { + const root = '/test' + const uploadTree = { + 'file3.txt': 'content3', + folder1: { + 'file1.txt': 'content1', + subfolder: { + 'file2.txt': 'content2', + }, + }, + } + expect(getFileOperations(root, uploadTree)).toEqual([ + { path: '/test/folder1', type: FileOperationType.CreateFolder }, + { path: '/test/folder1/file1.txt', text: 'content1', type: FileOperationType.CreateFile }, + { path: '/test/folder1/subfolder', type: FileOperationType.CreateFolder }, + { path: '/test/folder1/subfolder/file2.txt', text: 'content2', type: FileOperationType.CreateFile }, + { path: '/test/file3.txt', text: 'content3', type: FileOperationType.CreateFile }, + ]) +}) diff --git a/packages/explorer-view/test/GetFileOperationsCopy.test.ts b/packages/explorer-view/test/GetFileOperationsCopy.test.ts new file mode 100644 index 0000000..a2b2802 --- /dev/null +++ b/packages/explorer-view/test/GetFileOperationsCopy.test.ts @@ -0,0 +1,87 @@ +import { expect, test } from '@jest/globals' +import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' +import { getFileOperationsCopy } from '../src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts' + +test('getFileOperationsCopy - no conflicts', () => { + const root = '/test' + const existingUris = ['/test/existing.txt'] + const files = ['/source/file.txt'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file.txt', type: FileOperationType.Copy }]) +}) + +test('getFileOperationsCopy - single conflict', () => { + const root = '/test' + const existingUris = ['/test/file.txt'] + const files = ['/source/file.txt'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file copy.txt', type: FileOperationType.Copy }]) +}) + +test('getFileOperationsCopy - multiple conflicts', () => { + const root = '/test' + const existingUris = ['/test/file.txt', '/test/file copy.txt'] + const files = ['/source/file.txt'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file copy 1.txt', type: FileOperationType.Copy }]) +}) + +test('getFileOperationsCopy - multiple numbered conflicts', () => { + const root = '/test' + const existingUris = ['/test/file.txt', '/test/file copy.txt', '/test/file copy 1.txt', '/test/file copy 2.txt'] + const files = ['/source/file.txt'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file copy 3.txt', type: FileOperationType.Copy }]) +}) + +test('getFileOperationsCopy - file without extension', () => { + const root = '/test' + const existingUris = ['/test/README'] + const files = ['/source/README'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([{ from: '/source/README', path: '/test/README copy', type: FileOperationType.Copy }]) +}) + +test('getFileOperationsCopy - file without extension multiple conflicts', () => { + const root = '/test' + const existingUris = ['/test/README', '/test/README copy', '/test/README copy 1'] + const files = ['/source/README'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([{ from: '/source/README', path: '/test/README copy 2', type: FileOperationType.Copy }]) +}) + +test('getFileOperationsCopy - multiple files with conflicts', () => { + const root = '/test' + const existingUris = ['/test/file1.txt', '/test/file2.txt'] + const files = ['/source/file1.txt', '/source/file2.txt'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([ + { from: '/source/file1.txt', path: '/test/file1 copy.txt', type: FileOperationType.Copy }, + { from: '/source/file2.txt', path: '/test/file2 copy.txt', type: FileOperationType.Copy }, + ]) +}) + +test('getFileOperationsCopy - empty existingUris', () => { + const root = '/test' + const existingUris: readonly string[] = [] + const files = ['/source/file.txt'] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file.txt', type: FileOperationType.Copy }]) +}) + +test('getFileOperationsCopy - empty files', () => { + const root = '/test' + const existingUris = ['/test/existing.txt'] + const files: readonly string[] = [] + + const result = getFileOperationsCopy(root, existingUris, files, root) + expect(result).toEqual([]) +}) diff --git a/packages/explorer-view/test/GetFileOperationsRename.test.ts b/packages/explorer-view/test/GetFileOperationsRename.test.ts new file mode 100644 index 0000000..5ab7478 --- /dev/null +++ b/packages/explorer-view/test/GetFileOperationsRename.test.ts @@ -0,0 +1,16 @@ +import { test, expect } from '@jest/globals' +import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' +import { getFileOperationsRename } from '../src/parts/GetFileOperationsRename/GetFileOperationsRename.ts' + +test('should return rename operation', () => { + const ops = getFileOperationsRename('/folder/old.txt', 'new.txt') + expect(ops).toHaveLength(1) + expect(ops[0].type).toBe(FileOperationType.Rename) + expect(ops).toEqual([ + { + from: '/folder/old.txt', + path: '/folder/new.txt', + type: 4, + }, + ]) +}) diff --git a/packages/explorer-view/test/GetFilePaths.test.ts b/packages/explorer-view/test/GetFilePaths.test.ts new file mode 100644 index 0000000..9f6028d --- /dev/null +++ b/packages/explorer-view/test/GetFilePaths.test.ts @@ -0,0 +1,39 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { getFilePaths } from '../src/parts/GetFilePaths/GetFilePaths.ts' +import * as PlatformType from '../src/parts/PlatformType/PlatformType.ts' + +test('getFilePaths - non-electron platform', async () => { + const files = [new File([], 'test.txt')] + const paths = await getFilePaths(files, PlatformType.Web) + expect(paths).toEqual(['']) +}) + +test('getFilePaths - electron platform', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystemHandle.getFilePathElectron'() { + return '/path/to/file' + }, + }) + + const files = [new File([], 'test.txt')] + const paths = await getFilePaths(files, PlatformType.Electron) + expect(paths).toEqual(['/path/to/file']) + expect(mockRpc.invocations).toEqual([['FileSystemHandle.getFilePathElectron', files[0]]]) +}) + +test('getFilePaths - multiple files', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystemHandle.getFilePathElectron'() { + return '/path/to/file' + }, + }) + + const files = [new File([], 'test1.txt'), new File([], 'test2.txt')] + const paths = await getFilePaths(files, PlatformType.Electron) + expect(paths).toEqual(['/path/to/file', '/path/to/file']) + expect(mockRpc.invocations).toEqual([ + ['FileSystemHandle.getFilePathElectron', files[0]], + ['FileSystemHandle.getFilePathElectron', files[1]], + ]) +}) diff --git a/packages/explorer-view/test/GetFittingIndex.test.ts b/packages/explorer-view/test/GetFittingIndex.test.ts new file mode 100644 index 0000000..0fa04b3 --- /dev/null +++ b/packages/explorer-view/test/GetFittingIndex.test.ts @@ -0,0 +1,41 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getFittingIndex } from '../src/parts/GetFittingIndex/GetFittingIndex.ts' + +test('getFittingIndex returns the focused folder index', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.Directory }, + { depth: 0, name: 'file.txt', path: '/file.txt', selected: false, type: DirentType.File }, + ] + + expect(getFittingIndex(items, 0)).toBe(0) +}) + +test('getFittingIndex returns the closest parent folder before a focused file', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.DirectoryExpanded }, + { depth: 1, name: 'file-a.txt', path: '/folder/file-a.txt', selected: false, type: DirentType.File }, + { depth: 1, name: 'file-b.txt', path: '/folder/file-b.txt', selected: false, type: DirentType.File }, + ] + + expect(getFittingIndex(items, 2)).toBe(0) +}) + +test('getFittingIndex treats symlink folders as valid insertion targets', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'link', path: '/link', selected: false, type: DirentType.SymLinkFolder }, + { depth: 0, name: 'file.txt', path: '/file.txt', selected: false, type: DirentType.File }, + ] + + expect(getFittingIndex(items, 1)).toBe(0) +}) + +test('getFittingIndex returns -1 when there is no folder at or before the start index', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'file-a.txt', path: '/file-a.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'file-b.txt', path: '/file-b.txt', selected: false, type: DirentType.File }, + ] + + expect(getFittingIndex(items, 1)).toBe(-1) +}) diff --git a/packages/explorer-view/test/GetFocusedIndexCancel.test.ts b/packages/explorer-view/test/GetFocusedIndexCancel.test.ts new file mode 100644 index 0000000..4e97a87 --- /dev/null +++ b/packages/explorer-view/test/GetFocusedIndexCancel.test.ts @@ -0,0 +1,41 @@ +import { expect, test } from '@jest/globals' +import { getFocusedIndexCancel } from '../src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts' + +test('getFocusedIndexCancel - clamps index to last remaining item when edited placeholder was removed', () => { + const items = [ + { + depth: 0, + name: 'file1.txt', + path: '/file1.txt', + selected: false, + type: 2, + }, + ] + + const result = getFocusedIndexCancel(items, 1) + + expect(result).toBe(0) +}) + +test('getFocusedIndexCancel - returns original editing index when still in bounds', () => { + const items = [ + { + depth: 0, + name: 'file1.txt', + path: '/file1.txt', + selected: false, + type: 2, + }, + { + depth: 0, + name: 'file2.txt', + path: '/file2.txt', + selected: false, + type: 2, + }, + ] + + const result = getFocusedIndexCancel(items, 1) + + expect(result).toBe(1) +}) diff --git a/packages/explorer-view/test/GetFriendlyErrorMessage.test.ts b/packages/explorer-view/test/GetFriendlyErrorMessage.test.ts new file mode 100644 index 0000000..a1b37d7 --- /dev/null +++ b/packages/explorer-view/test/GetFriendlyErrorMessage.test.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@jest/globals' +import * as GetFriendlyErrorMessage from '../src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts' + +test('getFriendlyErrorMessage - maps permission errors', () => { + expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Access denied', 'EACCES')).toBe('permission was denied') + expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Access denied', 'EPERM')).toBe('permission was denied') +}) + +test('getFriendlyErrorMessage - maps busy error', () => { + expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Busy', 'EBUSY')).toBe('the folder is currently in use') +}) + +test('getFriendlyErrorMessage - returns explicit message for unknown code', () => { + expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Custom failure', 'UNKNOWN')).toBe('Custom failure') +}) + +test('getFriendlyErrorMessage - returns generic fallback for empty message', () => { + expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('', 'UNKNOWN')).toBe('an unexpected error occurred') +}) diff --git a/packages/explorer-view/test/GetIconVirtualDom.test.ts b/packages/explorer-view/test/GetIconVirtualDom.test.ts new file mode 100644 index 0000000..5a6aee7 --- /dev/null +++ b/packages/explorer-view/test/GetIconVirtualDom.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from '@jest/globals' +import * as AriaRoles from '../src/parts/AriaRoles/AriaRoles.ts' +import * as GetIconVirtualDom from '../src/parts/GetIconVirtualDom/GetIconVirtualDom.ts' +import * as VirtualDomElements from '../src/parts/VirtualDomElements/VirtualDomElements.ts' + +test('getIconVirtualDom - with icon', () => { + expect(GetIconVirtualDom.getIconVirtualDom('File')).toEqual({ + childCount: 0, + className: 'MaskIcon MaskIconFile', + role: AriaRoles.None, + type: VirtualDomElements.Div, + }) +}) + +test('getIconVirtualDom - with custom element type', () => { + expect(GetIconVirtualDom.getIconVirtualDom('Folder', VirtualDomElements.Div)).toEqual({ + childCount: 0, + className: 'MaskIcon MaskIconFolder', + role: AriaRoles.None, + type: VirtualDomElements.Div, + }) +}) diff --git a/packages/explorer-view/test/GetIndex.test.ts b/packages/explorer-view/test/GetIndex.test.ts new file mode 100644 index 0000000..635f45a --- /dev/null +++ b/packages/explorer-view/test/GetIndex.test.ts @@ -0,0 +1,25 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import { getIndex } from '../src/parts/GetIndex/GetIndex.ts' + +test('getIndex - finds item', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, + { depth: 0, name: 'b', path: '/b', selected: true, type: 2 }, + { depth: 0, name: 'c', path: '/c', selected: false, type: 1 }, + ] + expect(getIndex(items, '/b')).toBe(1) +}) + +test('getIndex - item not found', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, + { depth: 0, name: 'b', path: '/b', selected: false, type: 2 }, + ] + expect(getIndex(items, '/not-found')).toBe(-1) +}) + +test('getIndex - empty array', () => { + const items: readonly ExplorerItem[] = [] + expect(getIndex(items, '/any')).toBe(-1) +}) diff --git a/packages/explorer-view/test/GetIndexFromPosition.test.ts b/packages/explorer-view/test/GetIndexFromPosition.test.ts new file mode 100644 index 0000000..071b4f8 --- /dev/null +++ b/packages/explorer-view/test/GetIndexFromPosition.test.ts @@ -0,0 +1,302 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { getIndexFromPosition } from '../src/parts/GetIndexFromPosition/GetIndexFromPosition.ts' + +test('getIndexFromPosition', () => { + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + confirmPaste: false, + cutItems: [], + deltaY: 0, + dropTargets: [], + editingErrorMessage: '', + editingIcon: '', + editingIndex: -1, + editingSelectionEnd: 0, + editingSelectionStart: 0, + editingType: 0, + editingValue: '', + excluded: [], + fileIconCache: { + 'test:///virtual-dom/.git': 'test://file-icons/folder_type_git.svg', + 'test:///virtual-dom/.git/branches': 'test://file-icons/default_folder.svg', + 'test:///virtual-dom/.git/COMMIT_EDITMSG': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/config': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/description': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/FETCH_HEAD': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/HEAD': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/hooks': 'test://file-icons/folder_type_hook.svg', + 'test:///virtual-dom/.git/index': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/info': 'test://file-icons/default_folder.svg', + 'test:///virtual-dom/.git/logs': 'test://file-icons/folder_type_log.svg', + 'test:///virtual-dom/.git/objects': 'test://file-icons/default_folder.svg', + 'test:///virtual-dom/.git/ORIG_HEAD': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/packed-refs': 'test://file-icons/default_file.svg', + 'test:///virtual-dom/.git/refs': 'test://file-icons/default_folder.svg', + 'test:///virtual-dom/.git/rr-cache': 'test://file-icons/default_folder.svg', + 'test:///virtual-dom/.github': 'test://file-icons/folder_type_github.svg', + 'test:///virtual-dom/.gitignore': 'test://file-icons/file_type_git.svg', + 'test:///virtual-dom/.gitpod.Dockerfile': 'test://file-icons/file_type_docker.svg', + 'test:///virtual-dom/.gitpod.yml': 'test://file-icons/file_type_gitpod.svg', + 'test:///virtual-dom/.nvmrc': 'test://file-icons/file_type_node.svg', + 'test:///virtual-dom/.vscode': 'test://file-icons/folder_type_vscode.svg', + 'test:///virtual-dom/dist': 'test://file-icons/folder_type_dist.svg', + 'test:///virtual-dom/eslint.config.js': 'test://file-icons/file_type_eslint.svg', + 'test:///virtual-dom/lerna.json': 'test://file-icons/file_type_lerna.svg', + 'test:///virtual-dom/LICENSE': 'test://file-icons/file_type_license.svg', + 'test:///virtual-dom/node_modules': 'test://file-icons/folder_type_node.svg', + 'test:///virtual-dom/package-lock.json': 'test://file-icons/file_type_npm.svg', + 'test:///virtual-dom/package.json': 'test://file-icons/file_type_npm.svg', + 'test:///virtual-dom/packages': 'test://file-icons/folder_type_package.svg', + 'test:///virtual-dom/README.md': 'test://file-icons/file_type_markdown.svg', + 'test:///virtual-dom/scripts': 'test://file-icons/folder_type_script.svg', + 'test:///virtual-dom/tsconfig.json': 'test://file-icons/file_type_tsconfig.svg', + 'test:///virtual-dom/virtual-dom-worker': 'test://file-icons/default_folder.svg', + }, + finalDeltaY: 0, + focus: 0, + focused: false, + focusedIndex: 0, + focusWord: '', + focusWordTimeout: 800, + handleOffset: 0, + height: 964, + hoverIndex: -1, + icons: [ + 'test://file-icons/folder_type_git.svg', + 'test://file-icons/folder_type_github.svg', + 'test://file-icons/folder_type_vscode.svg', + 'test://file-icons/folder_type_dist.svg', + 'test://file-icons/folder_type_node.svg', + 'test://file-icons/folder_type_package.svg', + 'test://file-icons/folder_type_script.svg', + 'test://file-icons/default_folder.svg', + 'test://file-icons/file_type_git.svg', + 'test://file-icons/file_type_docker.svg', + 'test://file-icons/file_type_gitpod.svg', + 'test://file-icons/file_type_node.svg', + 'test://file-icons/file_type_license.svg', + 'test://file-icons/file_type_markdown.svg', + 'test://file-icons/file_type_eslint.svg', + 'test://file-icons/file_type_lerna.svg', + 'test://file-icons/file_type_npm.svg', + 'test://file-icons/file_type_npm.svg', + 'test://file-icons/file_type_tsconfig.svg', + ], + inputSource: 0, + isPointerDown: false, + itemHeight: 22, + items: [ + { + depth: 1, + icon: '', + name: '.git', + path: 'test:///virtual-dom/.git', + posInSet: 1, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: '.github', + path: 'test:///virtual-dom/.github', + posInSet: 2, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: '.vscode', + path: 'test:///virtual-dom/.vscode', + posInSet: 3, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: 'dist', + path: 'test:///virtual-dom/dist', + posInSet: 4, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: 'node_modules', + path: 'test:///virtual-dom/node_modules', + posInSet: 5, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: 'packages', + path: 'test:///virtual-dom/packages', + posInSet: 6, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: 'scripts', + path: 'test:///virtual-dom/scripts', + posInSet: 7, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: 'virtual-dom-worker', + path: 'test:///virtual-dom/virtual-dom-worker', + posInSet: 8, + selected: false, + setSize: 19, + type: 3, + }, + { + depth: 1, + icon: '', + name: '.gitignore', + path: 'test:///virtual-dom/.gitignore', + posInSet: 9, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: '.gitpod.Dockerfile', + path: 'test:///virtual-dom/.gitpod.Dockerfile', + posInSet: 10, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: '.gitpod.yml', + path: 'test:///virtual-dom/.gitpod.yml', + posInSet: 11, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: '.nvmrc', + path: 'test:///virtual-dom/.nvmrc', + posInSet: 12, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'LICENSE', + path: 'test:///virtual-dom/LICENSE', + posInSet: 13, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'README.md', + path: 'test:///virtual-dom/README.md', + posInSet: 14, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'eslint.config.js', + path: 'test:///virtual-dom/eslint.config.js', + posInSet: 15, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'lerna.json', + path: 'test:///virtual-dom/lerna.json', + posInSet: 16, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'package-lock.json', + path: 'test:///virtual-dom/package-lock.json', + posInSet: 17, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'package.json', + path: 'test:///virtual-dom/package.json', + posInSet: 18, + selected: false, + setSize: 19, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'tsconfig.json', + path: 'test:///virtual-dom/tsconfig.json', + posInSet: 19, + selected: false, + setSize: 19, + type: 7, + }, + ], + maxLineY: 19, + minLineY: 0, + parentUid: 43, + pasteShouldMove: false, + pathSeparator: '/', + platform: 2, + pointerDownIndex: -1, + root: 'test:///virtual-dom', + scrollBarActive: false, + scrollBarHeight: 0, + sourceControlIgnoredUris: [], + uid: 44, + useChevrons: true, + version: 0, + width: 170, + x: 29, + y: 1671, + } + expect(getIndexFromPosition(state, 988, 1700)).toBe(1) +}) diff --git a/packages/explorer-view/test/GetInputDom.test.ts b/packages/explorer-view/test/GetInputDom.test.ts new file mode 100644 index 0000000..14d8755 --- /dev/null +++ b/packages/explorer-view/test/GetInputDom.test.ts @@ -0,0 +1,48 @@ +import { expect, test } from '@jest/globals' +import * as ClassNames from '../src/parts/ClassNames/ClassNames.ts' +import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' +import { getInputDom } from '../src/parts/GetInputDom/GetInputDom.ts' +import * as InputName from '../src/parts/InputName/InputName.ts' +import * as VirtualDomElements from '../src/parts/VirtualDomElements/VirtualDomElements.ts' + +test('getInputDom - without error', () => { + const result = getInputDom(true, false) + expect(result).toEqual([ + { + ariaLabel: 'Type file name. Press Enter to confirm or Escape to cancel.', + autocapitalize: 'off', + autocomplete: 'off', + autocorrect: 'off', + childCount: 0, + className: `ExplorerInputBox`, + id: 'ExplorerInput', + name: InputName.ExplorerInput, + onBlur: DomEventListenerFunctions.HandleInputBlur, + onClick: DomEventListenerFunctions.HandleInputClick, + onInput: DomEventListenerFunctions.HandleEditingInput, + spellcheck: 'false', + type: VirtualDomElements.Input, + }, + ]) +}) + +test('getInputDom - with error', () => { + const result = getInputDom(true, true) + expect(result).toEqual([ + { + ariaLabel: 'Type file name. Press Enter to confirm or Escape to cancel.', + autocapitalize: 'off', + autocomplete: 'off', + autocorrect: 'off', + childCount: 0, + className: expect.stringContaining(ClassNames.InputBox), + id: 'ExplorerInput', + name: InputName.ExplorerInput, + onBlur: DomEventListenerFunctions.HandleInputBlur, + onClick: DomEventListenerFunctions.HandleInputClick, + onInput: DomEventListenerFunctions.HandleEditingInput, + spellcheck: 'false', + type: VirtualDomElements.Input, + }, + ]) +}) diff --git a/packages/explorer-view/test/GetKeyBindings.test.ts b/packages/explorer-view/test/GetKeyBindings.test.ts new file mode 100644 index 0000000..adfe23b --- /dev/null +++ b/packages/explorer-view/test/GetKeyBindings.test.ts @@ -0,0 +1,7 @@ +import { expect, test } from '@jest/globals' +import { getKeyBindings } from '../src/parts/GetKeyBindings/GetKeyBindings.ts' + +test('getKeyBindings', () => { + const keyBindings = getKeyBindings() + expect(keyBindings).toBeDefined() +}) diff --git a/packages/explorer-view/test/GetMenuEntries2.test.ts b/packages/explorer-view/test/GetMenuEntries2.test.ts new file mode 100644 index 0000000..ea1d5dd --- /dev/null +++ b/packages/explorer-view/test/GetMenuEntries2.test.ts @@ -0,0 +1,94 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { set } from '../src/parts/ExplorerStates/ExplorerStates.ts' +import { getMenuEntries2 } from '../src/parts/GetMenuEntries2/GetMenuEntries2.ts' + +test('getMenuEntries2 - root', () => { + const uid = 1 + const state: ExplorerState = createDefaultState() + set(uid, state, state) + const menuEntries = getMenuEntries2(state) + expect(menuEntries.length).toBeGreaterThan(0) +}) + +test('getMenuEntries2 - directory', () => { + const uid = 1 + const item: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: true, + type: DirentType.Directory, + } + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [item], + } + set(uid, state, state) + const menuEntries = getMenuEntries2(state) + expect(menuEntries.length).toBeGreaterThan(0) +}) + +test('getMenuEntries2 - file', () => { + const uid = 1 + const item: ExplorerItem = { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + } + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [item], + } + set(uid, state, state) + const menuEntries = getMenuEntries2(state) + expect(menuEntries.length).toBeGreaterThan(0) +}) + +test('getMenuEntries2 - file shows select for compare by default', () => { + const uid = 1 + const item: ExplorerItem = { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + } + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [item], + } + set(uid, state, state) + const menuEntries = getMenuEntries2(state) + expect(menuEntries.some((entry) => entry.id === 'selectForCompare')).toBe(true) + expect(menuEntries.some((entry) => entry.id === 'compareWithSelected')).toBe(false) +}) + +test('getMenuEntries2 - file shows compare with selected for different file', () => { + const uid = 1 + const item: ExplorerItem = { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + } + const state: ExplorerState = { + ...createDefaultState(), + compareSourceUri: '/other.txt', + focusedIndex: 0, + items: [item], + } + set(uid, state, state) + const menuEntries = getMenuEntries2(state) + expect(menuEntries.some((entry) => entry.id === 'compareWithSelected')).toBe(true) + expect(menuEntries.some((entry) => entry.id === 'selectForCompare')).toBe(false) +}) diff --git a/packages/explorer-view/test/GetMissingIconRequests.test.ts b/packages/explorer-view/test/GetMissingIconRequests.test.ts new file mode 100644 index 0000000..400f9df --- /dev/null +++ b/packages/explorer-view/test/GetMissingIconRequests.test.ts @@ -0,0 +1,32 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { FileIconCache } from '../src/parts/FileIconCache/FileIconCache.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as GetMissingIconRequests from '../src/parts/GetMissingIconRequests/GetMissingIconRequests.ts' + +test('getMissingIconRequests - empty list', () => { + const dirents: readonly ExplorerItem[] = [] + const cache: FileIconCache = {} + expect(GetMissingIconRequests.getMissingIconRequests(dirents, cache)).toEqual([]) +}) + +test('getMissingIconRequests - all in cache', () => { + const dirents: readonly ExplorerItem[] = [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }] + const cache: FileIconCache = { + '/test/file.txt': 'icon', + } + expect(GetMissingIconRequests.getMissingIconRequests(dirents, cache)).toEqual([]) +}) + +test('getMissingIconRequests - some missing', () => { + const dirents: readonly ExplorerItem[] = [ + { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'file2.txt', path: '/test/file2.txt', selected: false, type: DirentType.File }, + ] + const cache: FileIconCache = { + '/test/file1.txt': 'icon', + } + expect(GetMissingIconRequests.getMissingIconRequests(dirents, cache)).toEqual([ + { name: 'file2.txt', path: '/test/file2.txt', type: DirentType.File }, + ]) +}) diff --git a/packages/explorer-view/test/GetMouseActions.test.ts b/packages/explorer-view/test/GetMouseActions.test.ts new file mode 100644 index 0000000..cb2e1ff --- /dev/null +++ b/packages/explorer-view/test/GetMouseActions.test.ts @@ -0,0 +1,14 @@ +import { test, expect } from '@jest/globals' +import { getMouseActions } from '../src/parts/GetMouseActions/GetMouseActions.ts' + +test('should return mouse actions array', () => { + const actions = getMouseActions() + expect(Array.isArray(actions)).toBe(true) + expect(actions.length).toBeGreaterThan(0) + for (const action of actions) { + expect(action).toHaveProperty('description') + expect(action).toHaveProperty('button') + expect(action).toHaveProperty('command') + expect(action).toHaveProperty('when') + } +}) diff --git a/packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts b/packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts new file mode 100644 index 0000000..f61b36a --- /dev/null +++ b/packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts @@ -0,0 +1,256 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getNewChildDirentsForNewDirent } from '../src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts' + +test.skip('getNewChildDirentsForNewDirent - empty directory', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const items = [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + ] + + const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.File) + + expect(result).toEqual([ + { + depth: 2, + icon: '', + name: '', + path: '', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ]) + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('getNewChildDirentsForNewDirent - directory with existing children', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const items = [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/root/folder/file1.txt', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: 'file2.txt', + path: '/root/folder/file2.txt', + posInSet: 2, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ] + + const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.File) + + expect(result).toEqual([ + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/root/folder/file1.txt', + posInSet: 1, + selected: false, + setSize: 3, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: 'file2.txt', + path: '/root/folder/file2.txt', + posInSet: 2, + selected: false, + setSize: 3, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: '', + path: '', + posInSet: 3, + selected: false, + setSize: 3, + type: DirentType.File, + }, + ]) + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('getNewChildDirentsForNewDirent - directory with no children', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const items = [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + ] + + const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.DirectoryExpanded) + + expect(result).toEqual([ + { + depth: 2, + icon: '', + name: '', + path: '', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + ]) + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('getNewChildDirentsForNewDirent - different dirent types', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const items = [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/root/folder/file1.txt', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: 'folder1', + path: '/root/folder/folder1', + posInSet: 2, + selected: false, + setSize: 2, + type: DirentType.DirectoryExpanded, + }, + ] + + const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.SymLinkFolder) + + expect(result).toEqual([ + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/root/folder/file1.txt', + posInSet: 1, + selected: false, + setSize: 4, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: 'folder1', + path: '/root/folder/folder1', + posInSet: 2, + selected: false, + setSize: 4, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: '', + path: '', + posInSet: 3, + selected: false, + setSize: 4, + type: DirentType.SymLinkFolder, + }, + ]) + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('getNewChildDirentsForNewDirent - error case', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + throw new Error('Failed to read directory') + }, + }) + + const items = [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + ] + + await expect(getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.File)).rejects.toThrow('Failed to read directory') + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/GetNewDirentsAccept.test.ts b/packages/explorer-view/test/GetNewDirentsAccept.test.ts new file mode 100644 index 0000000..a0c6776 --- /dev/null +++ b/packages/explorer-view/test/GetNewDirentsAccept.test.ts @@ -0,0 +1,129 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getNewDirentsAccept } from '../src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts' + +test('getNewDirentsAccept - create file in root', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.writeFile'() { + return + }, + }) + + const items: readonly ExplorerItem[] = [] + const editingValue = 'test.txt' + const focusedIndex = -1 + const root = '/root' + const pathSeparator = '/' + const newDirentType = DirentType.File + const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) + expect(result.dirents).toHaveLength(1) + expect(result.dirents[0]).toEqual({ + depth: 1, + icon: '', + name: 'test.txt', + path: '/root/test.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }) + expect(result.newFocusedIndex).toBe(0) + expect(mockRpc.invocations).toEqual([]) +}) + +test('getNewDirentsAccept - create file in subfolder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.writeFile'() { + return + }, + }) + + const newDirentType = DirentType.File + + const editingValue = 'test.txt' + const focusedIndex = 0 + const root = '/root' + const pathSeparator = '/' + const items = [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: 2, + }, + ] + + const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) + + expect(result.dirents).toHaveLength(2) + expect(result.dirents[1]).toEqual({ + depth: 2, + icon: '', + name: 'test.txt', + path: '/root/folder/test.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }) + expect(result.newFocusedIndex).toBe(1) + expect(mockRpc.invocations).toEqual([]) +}) + +test('getNewDirentsAccept - create nested file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return + }, + 'FileSystem.writeFile'() { + return + }, + }) + + const items: readonly ExplorerItem[] = [] + const editingValue = 'a/b/c/test.txt' + const focusedIndex = -1 + const root = '/root' + const pathSeparator = '/' + const newDirentType = DirentType.File + const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) + expect(result.dirents).toHaveLength(1) + expect(result.dirents[0]).toEqual({ + depth: 1, + icon: '', + name: 'a/b/c/test.txt', + path: '/root/a/b/c/test.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }) + expect(result.newFocusedIndex).toBe(0) + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('getNewDirentsAccept - handle error', async () => { + RendererWorker.registerMockRpc({ + 'FileSystem.writeFile'() { + return Promise.reject(new Error('Failed to create file')) + }, + }) + + const editingValue = 'test.txt' + const focusedIndex = -1 + const root = '/root' + const pathSeparator = '/' + const items: readonly ExplorerItem[] = [] + const newDirentType = DirentType.File + + const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) + + expect(result.dirents).toEqual(items) + expect(result.newFocusedIndex).toBe(focusedIndex) +}) diff --git a/packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts b/packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts new file mode 100644 index 0000000..ffbe02e --- /dev/null +++ b/packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts @@ -0,0 +1,45 @@ +import { expect, test } from '@jest/globals' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getNewDirentsForCancelRename } from '../src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts' + +test('getNewDirentsForCancelRename - file', () => { + const items = [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.EditingFile, + }, + ] + const result = getNewDirentsForCancelRename(items, 0) + expect(result).toHaveLength(1) + expect(result[0]).toEqual({ + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + }) +}) + +test('getNewDirentsForCancelRename - folder', () => { + const items = [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.EditingFolder, + }, + ] + const result = getNewDirentsForCancelRename(items, 0) + expect(result).toHaveLength(1) + expect(result[0]).toEqual({ + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + }) +}) diff --git a/packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts b/packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts new file mode 100644 index 0000000..92774c4 --- /dev/null +++ b/packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts @@ -0,0 +1,238 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getNewDirentsForNewDirent } from '../src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts' + +test('getNewDirentsForNewDirent - folder with existing children', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const defaultState = createDefaultState() + const state: ExplorerState = { + ...defaultState, + focusedIndex: 0, + items: [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/root/folder/file1.txt', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: 'file2.txt', + path: '/root/folder/file2.txt', + posInSet: 2, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ], + } + const root = '/root' + + const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) + + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/root/folder/file1.txt', + posInSet: 1, + selected: false, + setSize: 4, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: 'file2.txt', + path: '/root/folder/file2.txt', + posInSet: 2, + selected: false, + setSize: 4, + type: DirentType.File, + }, + { + depth: 2, + icon: '', + name: '', + path: '/root/folder', + posInSet: 3, + selected: false, + setSize: 4, + type: DirentType.File, + }, + ]) + expect(mockRpc.invocations).toEqual([]) +}) + +test('getNewDirentsForNewDirent - folder without children', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const defaultState = createDefaultState() + const state: ExplorerState = { + ...defaultState, + focusedIndex: 0, + items: [ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + ], + } + + const root = '/root' + + const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) + + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: '', + path: '/root/folder', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ]) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/root/folder']]) +}) + +test('getNewDirentsForNewDirent - no items', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const defaultState = createDefaultState() + const state: ExplorerState = { + ...defaultState, + focusedIndex: -1, + items: [], + } + const root = '/root' + + const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) + + expect(result).toEqual([ + { + depth: 0, + icon: '', + name: '', + path: '/root', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ]) + expect(mockRpc.invocations).toEqual([]) +}) + +test('getNewDirentsForNewDirent - focusedIndex -1 with existing items', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const defaultState = createDefaultState() + const state: ExplorerState = { + ...defaultState, + focusedIndex: -1, + items: [ + { + depth: 0, + icon: '', + name: 'file1.txt', + path: '/root/file1.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ], + } + const root = '/root' + + const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) + + expect(result).toEqual([ + { + depth: 0, + icon: '', + name: 'file1.txt', + path: '/root/file1.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + { + depth: 0, + icon: '', + name: '', + path: '/root', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ]) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/GetNewDirentsForRename.test.ts b/packages/explorer-view/test/GetNewDirentsForRename.test.ts new file mode 100644 index 0000000..5cc8bcf --- /dev/null +++ b/packages/explorer-view/test/GetNewDirentsForRename.test.ts @@ -0,0 +1,45 @@ +import { expect, test } from '@jest/globals' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getNewDirentsForRename } from '../src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts' + +test('getNewDirentsForRename - file', () => { + const items = [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + }, + ] + const result = getNewDirentsForRename(items, 0) + expect(result).toHaveLength(1) + expect(result[0]).toEqual({ + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.EditingFile, + }) +}) + +test('getNewDirentsForRename - folder', () => { + const items = [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + }, + ] + const result = getNewDirentsForRename(items, 0) + expect(result).toHaveLength(1) + expect(result[0]).toEqual({ + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.EditingFolder, + }) +}) diff --git a/packages/explorer-view/test/GetNewDropTargets.test.ts b/packages/explorer-view/test/GetNewDropTargets.test.ts new file mode 100644 index 0000000..deaaa49 --- /dev/null +++ b/packages/explorer-view/test/GetNewDropTargets.test.ts @@ -0,0 +1,32 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getNewDropTargets } from '../src/parts/GetNewDropTargets/GetNewDropTargets.ts' + +test('getNewDropTargets - index -1', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [], + } + const result = getNewDropTargets(state, -1) + expect(result).toEqual([-1]) +}) + +test('getNewDropTargets - cannot be dropped into', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + const result = getNewDropTargets(state, 0) + expect(result).toEqual([-1, 0, 1]) +}) + +test('getNewDropTargets - can be dropped into', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], + } + const result = getNewDropTargets(state, 0) + expect(result).toEqual([0]) +}) diff --git a/packages/explorer-view/test/GetNumberOfVisibleItems.test.ts b/packages/explorer-view/test/GetNumberOfVisibleItems.test.ts new file mode 100644 index 0000000..4b45d6c --- /dev/null +++ b/packages/explorer-view/test/GetNumberOfVisibleItems.test.ts @@ -0,0 +1,26 @@ +import { expect, test } from '@jest/globals' +import * as GetNumberOfVisibleItems from '../src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts' + +test('getNumberOfVisibleItems - empty state', () => { + expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(600, 22)).toBe(29) +}) + +test('getNumberOfVisibleItems - partial height', () => { + expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(100, 22)).toBe(6) +}) + +test('getNumberOfVisibleItems - exact division', () => { + expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(88, 22)).toBe(5) +}) + +test('getNumberOfVisibleItems - small height', () => { + expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(10, 22)).toBe(2) +}) + +test('getNumberOfVisibleItems - zero height', () => { + expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(0, 22)).toBe(0) +}) + +test('getNumberOfVisibleItems - negative height', () => { + expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(-100, 22)).toBe(0) +}) diff --git a/packages/explorer-view/test/GetPasteHandler.test.ts b/packages/explorer-view/test/GetPasteHandler.test.ts new file mode 100644 index 0000000..339240d --- /dev/null +++ b/packages/explorer-view/test/GetPasteHandler.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from '@jest/globals' +import * as GetPasteHandler from '../src/parts/GetPasteHandler/GetPasteHandler.ts' +import * as HandlePasteCopy from '../src/parts/HandlePasteCopy/HandlePasteCopy.ts' +import * as HandlePasteCut from '../src/parts/HandlePasteCut/HandlePasteCut.ts' +import * as HandlePasteNone from '../src/parts/HandlePasteNone/HandlePasteNone.ts' +import * as NativeFileTypes from '../src/parts/NativeFileTypes/NativeFileTypes.ts' + +test('getPasteHandler - none', () => { + expect(GetPasteHandler.getPasteHandler(NativeFileTypes.None)).toBe(HandlePasteNone.handlePasteNone) +}) + +test('getPasteHandler - copy', () => { + expect(GetPasteHandler.getPasteHandler(NativeFileTypes.Copy)).toBe(HandlePasteCopy.handlePasteCopy) +}) + +test('getPasteHandler - cut', () => { + expect(GetPasteHandler.getPasteHandler(NativeFileTypes.Cut)).toBe(HandlePasteCut.handlePasteCut) +}) + +test('getPasteHandler - invalid type', () => { + expect(() => GetPasteHandler.getPasteHandler('invalid')).toThrow('unexpected native paste type: invalid') +}) diff --git a/packages/explorer-view/test/GetPath.test.ts b/packages/explorer-view/test/GetPath.test.ts new file mode 100644 index 0000000..3c0304f --- /dev/null +++ b/packages/explorer-view/test/GetPath.test.ts @@ -0,0 +1,86 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import { File } from '../src/parts/DirentType/DirentType.ts' +import * as GetPath from '../src/parts/GetPath/GetPath.ts' + +test('getPath - file dirent', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'test.txt', + path: '/test/test.txt', + selected: true, + type: 1, + } + expect(GetPath.getPath(dirent)).toBe('/test/test.txt') +}) + +test('getPath - directory dirent', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'folder', + path: '/test/folder', + selected: false, + type: 2, + } + expect(GetPath.getPath(dirent)).toBe('/test/folder') +}) + +test('getPath - nested path', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'file.js', + path: '/test/folder/subfolder/file.js', + selected: false, + type: 1, + } + expect(GetPath.getPath(dirent)).toBe('/test/folder/subfolder/file.js') +}) + +test('getPath - root path', () => { + const dirent: ExplorerItem = { + depth: 0, + name: '', + path: '/', + selected: false, + type: 2, + } + expect(GetPath.getPath(dirent)).toBe('/') +}) + +test('getPath - empty path', () => { + const dirent: ExplorerItem = { + depth: 0, + name: '', + path: '', + selected: false, + type: 2, + } + expect(GetPath.getPath(dirent)).toBe('') +}) + +test('getPath - with spaces in path', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'my file.txt', + path: '/test/my folder/my file.txt', + selected: true, + type: 1, + } + expect(GetPath.getPath(dirent)).toBe('/test/my folder/my file.txt') +}) + +test('getPath - with special characters in path', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'file@test.txt', + path: '/test/folder#1/file@test.txt', + selected: true, + type: 1, + } + expect(GetPath.getPath(dirent)).toBe('/test/folder#1/file@test.txt') +}) + +test('getPath', () => { + const item = { depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: File } + expect(GetPath.getPath(item)).toBe('/test.txt') +}) diff --git a/packages/explorer-view/test/GetPathParts.test.ts b/packages/explorer-view/test/GetPathParts.test.ts new file mode 100644 index 0000000..4c1c92d --- /dev/null +++ b/packages/explorer-view/test/GetPathParts.test.ts @@ -0,0 +1,98 @@ +import { expect, test } from '@jest/globals' +import * as GetPathParts from '../src/parts/GetPathParts/GetPathParts.ts' +import * as PathSeparatorType from '../src/parts/PathSeparatorType/PathSeparatorType.ts' + +test('getPathParts - empty path', () => { + expect(GetPathParts.getPathParts('', '', PathSeparatorType.Slash)).toEqual([]) +}) + +test('getPathParts - root path', () => { + expect(GetPathParts.getPathParts('/', '/', PathSeparatorType.Slash)).toEqual([]) +}) + +test('getPathParts - single level', () => { + expect(GetPathParts.getPathParts('/root', '/root/folder', PathSeparatorType.Slash)).toEqual([ + { + depth: 0, + expanded: true, + path: '/root', + pathSeparator: '/', + root: '/root', + }, + ]) +}) + +test('getPathParts - multiple levels', () => { + expect(GetPathParts.getPathParts('/root', '/root/folder/subfolder/file.txt', PathSeparatorType.Slash)).toEqual([ + { + depth: 0, + expanded: true, + path: '/root', + pathSeparator: '/', + root: '/root', + }, + { + depth: 1, + expanded: true, + path: '/root/folder', + pathSeparator: '/', + root: '/root', + }, + { + depth: 2, + expanded: true, + path: '/root/folder/subfolder', + pathSeparator: '/', + root: '/root', + }, + ]) +}) + +test('getPathParts - path equals root', () => { + expect(GetPathParts.getPathParts('/root', '/root', PathSeparatorType.Slash)).toEqual([]) +}) + +test('getPathParts - trailing slash', () => { + expect(GetPathParts.getPathParts('/root', '/root/folder/', PathSeparatorType.Slash)).toEqual([ + { + depth: 0, + expanded: true, + path: '/root', + pathSeparator: '/', + root: '/root', + }, + { + depth: 1, + expanded: true, + path: '/root/folder', + pathSeparator: '/', + root: '/root', + }, + ]) +}) + +test('getPathParts - multiple slashes', () => { + expect(GetPathParts.getPathParts('/root', '/root/folder//subfolder', PathSeparatorType.Slash)).toEqual([ + { + depth: 0, + expanded: true, + path: '/root', + pathSeparator: '/', + root: '/root', + }, + { + depth: 1, + expanded: true, + path: '/root/folder', + pathSeparator: '/', + root: '/root', + }, + { + depth: 2, + expanded: true, + path: '/root/folder/', + pathSeparator: '/', + root: '/root', + }, + ]) +}) diff --git a/packages/explorer-view/test/GetPathSeparator.test.ts b/packages/explorer-view/test/GetPathSeparator.test.ts new file mode 100644 index 0000000..27ccd51 --- /dev/null +++ b/packages/explorer-view/test/GetPathSeparator.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as GetPathSeparator from '../src/parts/GetPathSeparator/GetPathSeparator.ts' + +test('getPathSeparator - delegates to file system module', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + }) + + const result = await GetPathSeparator.getPathSeparator('/workspace') + + expect(result).toBe('/') + expect(mockRpc.invocations).toEqual([['FileSystem.getPathSeparator', '/workspace']]) +}) diff --git a/packages/explorer-view/test/GetPaths.test.ts b/packages/explorer-view/test/GetPaths.test.ts new file mode 100644 index 0000000..013c63a --- /dev/null +++ b/packages/explorer-view/test/GetPaths.test.ts @@ -0,0 +1,20 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import { Directory, File } from '../src/parts/DirentType/DirentType.ts' +import { getPaths } from '../src/parts/GetPaths/GetPaths.ts' + +test('getPaths - empty array', () => { + const items: readonly ExplorerItem[] = [] + expect(getPaths(items)).toHaveLength(0) +}) + +test('getPaths - with items', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: Directory }, + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, + ] + const result = getPaths(items) + expect(result).toHaveLength(2) + expect(result[0]).toBe('/folder1') + expect(result[1]).toBe('/file1.txt') +}) diff --git a/packages/explorer-view/test/GetProtoMapInternal.test.ts b/packages/explorer-view/test/GetProtoMapInternal.test.ts new file mode 100644 index 0000000..9e49ac1 --- /dev/null +++ b/packages/explorer-view/test/GetProtoMapInternal.test.ts @@ -0,0 +1,211 @@ +import { test, expect } from '@jest/globals' +import type { RawDirent } from '../src/parts/RawDirent/RawDirent.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getProtoMapInternal } from '../src/parts/GetProtoMapInternal/GetProtoMapInternal.ts' + +test('getProtoMapInternal - empty directory', () => { + const root = '/root' + const pathToDirents = { + '/root': [], + } + const expandedPaths: string[] = [] + const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) + expect(result).toEqual([]) +}) + +test('getProtoMapInternal - directory with files', () => { + const root = '/root' + const pathToDirents: Record = { + '/root': [ + { name: 'file1.txt', type: DirentType.File }, + { name: 'file2.txt', type: DirentType.File }, + ], + } + const expandedPaths: string[] = [] + const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'file1.txt', + path: '/root/file1.txt', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.File, + }, + { + depth: 1, + icon: '', + name: 'file2.txt', + path: '/root/file2.txt', + posInSet: 2, + selected: false, + setSize: 2, + type: DirentType.File, + }, + ]) +}) + +test('getProtoMapInternal - directory with subdirectories', () => { + const root = '/root' + const pathToDirents: Record = { + '/root': [ + { name: 'folder1', type: DirentType.Directory }, + { name: 'folder2', type: DirentType.Directory }, + ], + '/root/folder1': [{ name: 'file1.txt', type: DirentType.File }], + '/root/folder2': [{ name: 'file2.txt', type: DirentType.File }], + } + const expandedPaths: string[] = ['/root/folder1'] + const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'folder1', + path: '/root/folder1', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/root/folder1/file1.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + { + depth: 1, + icon: '', + name: 'folder2', + path: '/root/folder2', + posInSet: 2, + selected: false, + setSize: 2, + type: DirentType.Directory, + }, + { + depth: 2, + icon: '', + name: 'file2.txt', + path: '/root/folder2/file2.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: 7, + }, + ]) +}) + +test('getProtoMapInternal - directory with different file types', () => { + const root = '/root' + const pathToDirents: Record = { + '/root': [ + { name: 'file.txt', type: DirentType.File }, + { name: 'symlink.txt', type: DirentType.SymLinkFile }, + { name: 'folder', type: DirentType.Directory }, + { name: 'symlink-folder', type: DirentType.SymLinkFolder }, + ], + } + const expandedPaths: string[] = [] + const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'file.txt', + path: '/root/file.txt', + posInSet: 1, + selected: false, + setSize: 4, + type: DirentType.File, + }, + { + depth: 1, + icon: '', + name: 'symlink.txt', + path: '/root/symlink.txt', + posInSet: 2, + selected: false, + setSize: 4, + type: DirentType.SymLinkFile, + }, + { + depth: 1, + icon: '', + name: 'folder', + path: '/root/folder', + posInSet: 3, + selected: false, + setSize: 4, + type: DirentType.Directory, + }, + { + depth: 1, + icon: '', + name: 'symlink-folder', + path: '/root/symlink-folder', + posInSet: 4, + selected: false, + setSize: 4, + type: DirentType.SymLinkFolder, + }, + ]) +}) + +test('getProtoMapInternal - non-existent directory', () => { + const root = '/root' + const pathToDirents = {} + const expandedPaths: string[] = [] + const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) + expect(result).toEqual([]) +}) + +test('getProtoMapInternal - nested directory structure', () => { + const root = '/root' + const pathToDirents: Record = { + '/root': [{ name: 'folder1', type: DirentType.Directory }], + '/root/folder1': [{ name: 'folder2', type: DirentType.Directory }], + '/root/folder1/folder2': [{ name: 'file.txt', type: DirentType.File }], + } + const expandedPaths: string[] = ['/root/folder1', '/root/folder1/folder2'] + const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'folder1', + path: '/root/folder1', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 2, + icon: '', + name: 'folder2', + path: '/root/folder1/folder2', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 3, + icon: '', + name: 'file.txt', + path: '/root/folder1/folder2/file.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ]) +}) diff --git a/packages/explorer-view/test/GetRenderer.test.ts b/packages/explorer-view/test/GetRenderer.test.ts new file mode 100644 index 0000000..04928b1 --- /dev/null +++ b/packages/explorer-view/test/GetRenderer.test.ts @@ -0,0 +1,32 @@ +import { test, expect } from '@jest/globals' +import * as DiffType from '../src/parts/DiffType/DiffType.ts' +import { getRenderer } from '../src/parts/GetRenderer/GetRenderer.ts' + +test('should return RenderItems for RenderItems diffType', () => { + const renderer = getRenderer(DiffType.RenderItems) + expect(typeof renderer).toBe('function') +}) + +test('should return RenderFocus for RenderFocus diffType', () => { + const renderer = getRenderer(DiffType.RenderFocus) + expect(typeof renderer).toBe('function') +}) + +test('should return RenderFocusContext for RenderFocusContext diffType', () => { + const renderer = getRenderer(DiffType.RenderFocusContext) + expect(typeof renderer).toBe('function') +}) + +test('should return RenderValue for RenderValue diffType', () => { + const renderer = getRenderer(DiffType.RenderValue) + expect(typeof renderer).toBe('function') +}) + +test('should return RenderEditingSelection for RenderSelection diffType', () => { + const renderer = getRenderer(DiffType.RenderSelection) + expect(typeof renderer).toBe('function') +}) + +test('should throw for unknown diffType', () => { + expect(() => getRenderer(9999)).toThrow('unknown renderer') +}) diff --git a/packages/explorer-view/test/GetRestoredDeltaY.test.ts b/packages/explorer-view/test/GetRestoredDeltaY.test.ts new file mode 100644 index 0000000..6ccbc30 --- /dev/null +++ b/packages/explorer-view/test/GetRestoredDeltaY.test.ts @@ -0,0 +1,14 @@ +import { expect, test } from '@jest/globals' +import * as GetRestoredDeltaY from '../src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts' + +test('getRestoredDeltaY - returns saved deltaY when it is numeric', () => { + expect(GetRestoredDeltaY.getRestoredDeltaY({ deltaY: 42 })).toBe(42) +}) + +test('getRestoredDeltaY - returns 0 when deltaY is missing', () => { + expect(GetRestoredDeltaY.getRestoredDeltaY({})).toBe(0) +}) + +test('getRestoredDeltaY - returns 0 when state is undefined', () => { + expect(GetRestoredDeltaY.getRestoredDeltaY(undefined)).toBe(0) +}) diff --git a/packages/explorer-view/test/GetSavedRoot.test.ts b/packages/explorer-view/test/GetSavedRoot.test.ts new file mode 100644 index 0000000..75cae89 --- /dev/null +++ b/packages/explorer-view/test/GetSavedRoot.test.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@jest/globals' +import * as GetSavedRoot from '../src/parts/GetSavedRoot/GetSavedRoot.ts' + +test('getSavedRoot - returns workspace path', () => { + expect(GetSavedRoot.getSavedRoot({ root: '/stale-workspace' }, '/workspace')).toBe('/workspace') +}) diff --git a/packages/explorer-view/test/GetScrollBarVirtualDom.test.ts b/packages/explorer-view/test/GetScrollBarVirtualDom.test.ts new file mode 100644 index 0000000..870e47f --- /dev/null +++ b/packages/explorer-view/test/GetScrollBarVirtualDom.test.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@jest/globals' +import { getScrollBarVirtualDom } from '../src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts' + +test('getScrollBarVirtualDom - no scrollbar when height is 0', () => { + const dom = getScrollBarVirtualDom(0) + expect(dom).toEqual([]) +}) + +test('getScrollBarVirtualDom - renders scrollbar', () => { + const dom = getScrollBarVirtualDom(100) + expect(dom).toEqual([ + { + childCount: 1, + className: 'ScrollBar ScrollBarSmall', + type: 4, + }, + { + childCount: 0, + className: 'ScrollBarThumb', + type: 4, + }, + ]) +}) diff --git a/packages/explorer-view/test/GetSettings.test.ts b/packages/explorer-view/test/GetSettings.test.ts new file mode 100644 index 0000000..568f87c --- /dev/null +++ b/packages/explorer-view/test/GetSettings.test.ts @@ -0,0 +1,75 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { getSettings } from '../src/parts/GetSettings/GetSettings.ts' + +test('getSettings - useChevrons true', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Preferences.get'() { + return undefined + }, + }) + const settings = await getSettings() + expect(settings).toEqual({ + confirmDelete: false, + confirmPaste: false, + sourceControlDecorations: true, + useChevrons: true, + }) + expect(mockRpc.invocations).toEqual([ + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ]) +}) + +test('getSettings - useChevrons false', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Preferences.get'(settingName: string) { + if (settingName === 'explorer.useChevrons') { + return false + } + if (settingName === 'explorer.confirmdelete') { + return true + } + if (settingName === 'explorer.sourceControlDecorations') { + return false + } + return undefined + }, + }) + const settings = await getSettings() + expect(settings).toEqual({ + confirmDelete: false, + confirmPaste: false, + sourceControlDecorations: false, + useChevrons: false, + }) + expect(mockRpc.invocations).toEqual([ + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ]) +}) + +test('getSettings - useChevrons undefined', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Preferences.get'() { + return undefined + }, + }) + const settings = await getSettings() + expect(settings).toEqual({ + confirmDelete: false, + confirmPaste: false, + sourceControlDecorations: true, + useChevrons: true, + }) + expect(mockRpc.invocations).toEqual([ + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ]) +}) diff --git a/packages/explorer-view/test/GetSiblingFileNames.test.ts b/packages/explorer-view/test/GetSiblingFileNames.test.ts new file mode 100644 index 0000000..685b6be --- /dev/null +++ b/packages/explorer-view/test/GetSiblingFileNames.test.ts @@ -0,0 +1,97 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as GetSiblingFileNames from '../src/parts/GetSiblingFileNames/GetSiblingFileNames.ts' + +test('getSiblingFileNames - root level files', () => { + const items: readonly ExplorerItem[] = [ + { + depth: 0, + icon: '', + name: 'file1.txt', + path: '/root/file1.txt', + posInSet: 0, + selected: false, + setSize: 2, + type: 1, + }, + { + depth: 0, + icon: '', + name: 'file2.txt', + path: '/root/file2.txt', + posInSet: 1, + selected: false, + setSize: 2, + type: 1, + }, + { + depth: 1, + icon: '', + name: 'file3.txt', + path: '/root/folder/file3.txt', + posInSet: 0, + selected: false, + setSize: 1, + type: 1, + }, + ] + + const result = GetSiblingFileNames.getSiblingFileNames(items, 0, '/root', '/') + expect(result).toEqual(['file1.txt', 'file2.txt']) +}) + +test('getSiblingFileNames - folder level files', () => { + const items: readonly ExplorerItem[] = [ + { + depth: 0, + icon: '', + name: 'file1.txt', + path: '/root/file1.txt', + posInSet: 0, + selected: false, + setSize: 1, + type: 1, + }, + { + depth: 1, + icon: '', + name: 'file2.txt', + path: '/root/folder/file2.txt', + posInSet: 0, + selected: false, + setSize: 2, + type: 1, + }, + { + depth: 1, + icon: '', + name: 'file3.txt', + path: '/root/folder/file3.txt', + posInSet: 1, + selected: false, + setSize: 2, + type: 1, + }, + ] + + const result = GetSiblingFileNames.getSiblingFileNames(items, 1, '/root', '/') + expect(result).toEqual(['file2.txt', 'file3.txt']) +}) + +test('getSiblingFileNames - no siblings', () => { + const items: readonly ExplorerItem[] = [ + { + depth: 0, + icon: '', + name: 'file1.txt', + path: '/root/file1.txt', + posInSet: 0, + selected: false, + setSize: 1, + type: 1, + }, + ] + + const result = GetSiblingFileNames.getSiblingFileNames(items, 0, '/root', '/') + expect(result).toEqual(['file1.txt']) +}) diff --git a/packages/explorer-view/test/GetSymlinkType.test.ts b/packages/explorer-view/test/GetSymlinkType.test.ts new file mode 100644 index 0000000..7448fbc --- /dev/null +++ b/packages/explorer-view/test/GetSymlinkType.test.ts @@ -0,0 +1,18 @@ +import { test, expect } from '@jest/globals' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { getSymlinkType } from '../src/parts/GetSymlinkType/GetSymlinkType.ts' + +test('getSymlinkType - File', () => { + expect(getSymlinkType(DirentType.File)).toBe(DirentType.SymLinkFile) +}) + +test('getSymlinkType - Directory', () => { + expect(getSymlinkType(DirentType.Directory)).toBe(DirentType.SymLinkFolder) +}) + +test('getSymlinkType - Default', () => { + expect(getSymlinkType(DirentType.BlockDevice)).toBe(DirentType.Symlink) + expect(getSymlinkType(DirentType.CharacterDevice)).toBe(DirentType.Symlink) + expect(getSymlinkType(DirentType.Socket)).toBe(DirentType.Symlink) + expect(getSymlinkType(DirentType.Unknown)).toBe(DirentType.Symlink) +}) diff --git a/packages/explorer-view/test/GetTreeItemIndent.test.ts b/packages/explorer-view/test/GetTreeItemIndent.test.ts new file mode 100644 index 0000000..5590bbb --- /dev/null +++ b/packages/explorer-view/test/GetTreeItemIndent.test.ts @@ -0,0 +1,18 @@ +import { expect, test } from '@jest/globals' +import * as GetTreeItemIndent from '../src/parts/GetTreeItemIndent/GetTreeItemIndent.ts' + +test('getTreeItemIndent - depth 0', () => { + expect(GetTreeItemIndent.getTreeItemIndent(0)).toBe(0) +}) + +test('getTreeItemIndent - depth 1', () => { + expect(GetTreeItemIndent.getTreeItemIndent(1)).toBe(12) +}) + +test('getTreeItemIndent - depth 2', () => { + expect(GetTreeItemIndent.getTreeItemIndent(2)).toBe(24) +}) + +test('getTreeItemIndent - depth 3', () => { + expect(GetTreeItemIndent.getTreeItemIndent(3)).toBe(36) +}) diff --git a/packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts b/packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts new file mode 100644 index 0000000..35295c5 --- /dev/null +++ b/packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from '@jest/globals' +import * as GetTreeItemIndentWithChevron from '../src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts' + +test('getTreeItemIndentWithChevron - depth 0', () => { + const chevron = 0 + expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(0, chevron)).toBe(26) +}) + +test('getTreeItemIndentWithChevron - depth 1', () => { + const chevron = 0 + expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(1, chevron)).toBe(34) +}) + +test('getTreeItemIndentWithChevron - depth 2', () => { + const chevron = 0 + expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(2, chevron)).toBe(42) +}) + +test('getTreeItemIndentWithChevron - depth 3', () => { + const chevron = 0 + expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(3, chevron)).toBe(50) +}) diff --git a/packages/explorer-view/test/GetVisibleExplorerItems.test.ts b/packages/explorer-view/test/GetVisibleExplorerItems.test.ts new file mode 100644 index 0000000..b7589e5 --- /dev/null +++ b/packages/explorer-view/test/GetVisibleExplorerItems.test.ts @@ -0,0 +1,90 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { FileDecoration } from '../src/parts/FileDecoration/FileDecoration.ts' +import { getVisibleExplorerItems } from '../src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts' + +test('getVisibleExplorerItems - basic', () => { + const items: ExplorerItem[] = [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: 0, + }, + ] + const editingIcon = '' + const decorations: readonly FileDecoration[] = [] + const result = getVisibleExplorerItems(items, 0, 1, 0, -1, '', ['icon'], true, [], editingIcon, [], [], decorations) + expect(result).toHaveLength(1) + expect(result[0]).toMatchObject({ + ariaExpanded: undefined, + chevron: 0, + depth: 0, + hasEditingError: false, + icon: 'icon', + id: 'TreeItemActive', + indent: 26, + isEditing: false, + name: 'test', + path: '/test', + }) +}) + +test('getVisibleExplorerItems - editing', () => { + const items: ExplorerItem[] = [ + { + depth: 0, + name: 'test', + path: '/test', + selected: true, + type: 0, + }, + ] + const editingIcon = '' + const decorations: readonly FileDecoration[] = [] + const result = getVisibleExplorerItems(items, 0, 1, 0, 0, 'error', ['icon'], true, [], editingIcon, [], [], decorations) + expect(result).toHaveLength(1) + expect(result[0]).toMatchObject({ + hasEditingError: true, + isEditing: true, + }) +}) + +test('getVisibleExplorerItems - new item', () => { + const items: readonly ExplorerItem[] = [] + const editingIcon = '' + const decorations: readonly FileDecoration[] = [] + + const result = getVisibleExplorerItems(items, 0, 1, -1, -1, 'error', [], true, [], editingIcon, [], [], decorations) + expect(result).toHaveLength(0) + // expect(result[0]).toMatchObject({ + // depth: 3, + // name: 'new', + // path: '/test/new', + // isEditing: true, + // hasEditingError: true, + // }) +}) + +test('getVisibleExplorerItems - ignored item is dimmed', () => { + const items: ExplorerItem[] = [ + { + depth: 0, + name: 'ignored.txt', + path: '/ignored.txt', + selected: false, + type: 0, + }, + ] + const editingIcon = '' + const ignored = ['/ignored.txt'] + const decorations: readonly FileDecoration[] = [] + + const result = getVisibleExplorerItems(items, 0, 1, 0, -1, '', ['icon'], true, [], editingIcon, [], ignored, decorations) + expect(result).toHaveLength(1) + expect(result[0]).toMatchObject({ + isCut: false, + isIgnored: true, + }) +}) diff --git a/packages/explorer-view/test/HandleArrowLeft.test.ts b/packages/explorer-view/test/HandleArrowLeft.test.ts new file mode 100644 index 0000000..856e628 --- /dev/null +++ b/packages/explorer-view/test/HandleArrowLeft.test.ts @@ -0,0 +1,122 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleArrowLeft } from '../src/parts/HandleArrowLeft/HandleArrowLeft.ts' + +test('handleArrowLeft - no focused item', () => { + const state: ExplorerState = { ...createDefaultState(), focusedIndex: -1 } + const result = handleArrowLeft(state) + expect(result).toBe(state) +}) + +test('handleArrowLeft - directory', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + }, + ], + } + const result = handleArrowLeft(state) + expect(result).toBeDefined() +}) + +test('handleArrowLeft - file', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + }, + ], + } + const result = handleArrowLeft(state) + expect(result).toBeDefined() +}) + +test('handleArrowLeft - symlink file', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.SymLinkFile, + }, + ], + } + const result = handleArrowLeft(state) + expect(result).toBeDefined() +}) + +test('handleArrowLeft - expanded directory', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 0, + // @ts-ignore + expanded: true, + level: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.DirectoryExpanded, + }, + ], + } + const result = handleArrowLeft(state) + expect(result).toBeDefined() +}) + +test('handleArrowLeft - expanding directory', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.DirectoryExpanding, + }, + ], + } + const result = handleArrowLeft(state) + expect(result).toBeDefined() +}) + +test('handleArrowLeft - symlink folder', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.SymLinkFolder, + }, + ], + } + const result = handleArrowLeft(state) + expect(result).toBeDefined() +}) diff --git a/packages/explorer-view/test/HandleArrowRight.test.ts b/packages/explorer-view/test/HandleArrowRight.test.ts new file mode 100644 index 0000000..15fec10 --- /dev/null +++ b/packages/explorer-view/test/HandleArrowRight.test.ts @@ -0,0 +1,111 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleArrowRight } from '../src/parts/HandleArrowRight/HandleArrowRight.ts' + +test('handleArrowRight - no focused item', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + } + const result = await handleArrowRight(state) + expect(result).toBe(state) +}) + +test('handleArrowRight - file', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + const result = await handleArrowRight(state) + expect(result).toBe(state) +}) + +test.skip('handleArrowRight - directory', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], + } + const result = await handleArrowRight(state) + expect(result).not.toBe(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test('handleArrowRight - symlink file', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.SymLinkFile }], + } + const result = await handleArrowRight(state) + expect(result).toBe(state) +}) + +test.skip('handleArrowRight - symlink folder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.SymLinkFolder }], + } + const result = await handleArrowRight(state) + expect(result).not.toBe(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('handleArrowRight - directory expanded', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.DirectoryExpanded }], + } + const result = await handleArrowRight(state) + expect(result).not.toBe(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test.skip('handleArrowRight - symlink', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getRealPath'() { + return '/real/path' + }, + 'FileSystem.stat'() { + return { isDirectory: (): boolean => false } + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Symlink }], + } + const result = await handleArrowRight(state) + expect(result).not.toBe(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test('handleArrowRight - invalid type', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: 999 }], + } + await expect(handleArrowRight(state)).rejects.toThrow('unsupported file type 999') +}) diff --git a/packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts b/packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts new file mode 100644 index 0000000..0eb22bd --- /dev/null +++ b/packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts @@ -0,0 +1,39 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleArrowRightDirectoryExpanded } from '../src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts' + +test.skip('handleArrowRightDirectoryExpanded - last item', () => { + const state: ExplorerState = createDefaultState() + const dirent = { depth: 0 } + const result = handleArrowRightDirectoryExpanded(state, dirent) + expect(result).toBe(state) +}) + +test('handleArrowRightDirectoryExpanded - next item has higher depth', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 1 }, + ], + } + const dirent = { depth: 0 } + const result = handleArrowRightDirectoryExpanded(state, dirent) + expect(result.focusedIndex).toBe(1) +}) + +test('handleArrowRightDirectoryExpanded - next item has same depth', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, + { depth: 0, name: 'b', path: '/b', selected: false, type: 1 }, + ], + } + const dirent = { depth: 0 } + const result = handleArrowRightDirectoryExpanded(state, dirent) + expect(result).toBe(state) +}) diff --git a/packages/explorer-view/test/HandleBlur.test.ts b/packages/explorer-view/test/HandleBlur.test.ts new file mode 100644 index 0000000..8bd3d4d --- /dev/null +++ b/packages/explorer-view/test/HandleBlur.test.ts @@ -0,0 +1,71 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import { handleBlur } from '../src/parts/HandleBlur/HandleBlur.ts' + +test('handleBlur - when not editing, sets focused to false', async () => { + const state: ExplorerState = createDefaultState() + const newState = await handleBlur(state) + expect(newState.focused).toBe(false) +}) + +test.skip('handleBlur - when editing, keeps state unchanged', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.writeFile'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return Array(1).fill('') + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.CreateFile, + editingValue: 'created.txt', + items: [ + { + depth: 0, + name: '1', + path: '1', + selected: false, + type: DirentType.File, + }, + ], + } + const newState = await handleBlur(state) + expect(newState).toEqual({ + ...state, + editingIndex: -1, + editingType: 0, + fileIconCache: { + '1': '', + '1/created.txt': '', + }, + focus: 1, + focusedIndex: 1, + icons: ['', ''], + maxLineY: 2, + }) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.getPathSeparator'], + ['FileSystem.writeFile', '1/created.txt', ''], + ['IconTheme.getFileIcon', { depth: 0, name: '1', path: '1', selected: false, type: DirentType.File }], + [ + 'IconTheme.getIcons', + [ + { depth: 0, name: '1', path: '1', selected: false, type: DirentType.File }, + { depth: 0, name: 'created.txt', path: '1/created.txt', selected: false, type: DirentType.File }, + ], + ], + ]) +}) diff --git a/packages/explorer-view/test/HandleButtonClick.test.ts b/packages/explorer-view/test/HandleButtonClick.test.ts new file mode 100644 index 0000000..0c4f702 --- /dev/null +++ b/packages/explorer-view/test/HandleButtonClick.test.ts @@ -0,0 +1,88 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import { handleButtonClick } from '../src/parts/HandleButtonClick/HandleButtonClick.ts' +import * as InputName from '../src/parts/InputName/InputName.ts' + +test('handleButtonClick - CollapseAll', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + items: [ + { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.DirectoryExpanded }, + { depth: 2, name: 'file1', path: '/folder1/file1', selected: false, type: DirentType.File }, + { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: DirentType.DirectoryExpanded }, + ], + } + const newState = await handleButtonClick(state, InputName.CollapseAll) + expect(newState.items).toHaveLength(2) + expect(newState.items[0].name).toBe('folder1') + expect(newState.items[1].name).toBe('folder2') + expect(newState.focusedIndex).toBe(0) +}) + +test('handleButtonClick - NewFile', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }], + } + const newState = await handleButtonClick(state, InputName.NewFile) + expect(newState.editingType).toBe(ExplorerEditingType.CreateFile) + expect(newState.editingIndex).toBeGreaterThanOrEqual(0) + expect(newState.editingValue).toBe('') +}) + +test('handleButtonClick - NewFolder', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }], + } + const newState = await handleButtonClick(state, InputName.NewFolder) + expect(newState.editingType).toBe(ExplorerEditingType.CreateFolder) + expect(newState.editingIndex).toBeGreaterThanOrEqual(0) + expect(newState.editingValue).toBe('') +}) + +test('handleButtonClick - Refresh', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readdir'() { + return [] + }, + 'FileSystem.stat'() { + return DirentType.File + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return Array(1).fill('') + }, + }) + + const state = createDefaultState() + const newState = await handleButtonClick(state, InputName.Refresh) + expect(newState.items).toBeDefined() +}) + +test('handleButtonClick - unknown button name returns state unchanged', async () => { + const state = createDefaultState() + const newState = await handleButtonClick(state, 'UnknownButton') + expect(newState).toBe(state) +}) diff --git a/packages/explorer-view/test/HandleClickAt.test.ts b/packages/explorer-view/test/HandleClickAt.test.ts new file mode 100644 index 0000000..ebbc58d --- /dev/null +++ b/packages/explorer-view/test/HandleClickAt.test.ts @@ -0,0 +1,83 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleClickAt } from '../src/parts/HandleClickAt/HandleClickAt.ts' +import { LeftClick } from '../src/parts/MouseEventType/MouseEventType.ts' + +test.skip('handleClickAt - left click without shift', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + ], + } + const result = await handleClickAt(state, false, LeftClick, false, false, 0, 0) + expect(result).toBeDefined() +}) + +test.skip('handleClickAt - shift click with no selection', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + ], + } + const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) + expect(result).toBeDefined() +}) + +test('handleClickAt - shift click with existing selection', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) + expect(result).toBeDefined() +}) + +test('handleClickAt - non left click', async () => { + const state: ExplorerState = createDefaultState() + const shiftKey = false + const ctrlKey = false + const result = await handleClickAt(state, false, 2, ctrlKey, shiftKey, 0, 0) + expect(result).toBe(state) +}) + +test('handleClickAt - left click', async () => { + const state: ExplorerState = createDefaultState() + const shiftKey = false + const ctrlKey = false + const result = await handleClickAt(state, false, LeftClick, ctrlKey, shiftKey, 0, 0) + expect(result).toBeDefined() +}) + +test.skip('handleClickAt - shift click with no selection', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + ], + } + const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) + expect(result).toBeDefined() +}) + +test('handleClickAt - shift click with existing selection', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) + expect(result).toBeDefined() +}) diff --git a/packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts b/packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts new file mode 100644 index 0000000..17422ae --- /dev/null +++ b/packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts @@ -0,0 +1,11 @@ +import { test, expect, jest } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleClickCurrentButKeepFocus } from '../src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts' + +test('handleClickCurrentButKeepFocus', async () => { + const state = createDefaultState() + const spy = jest.spyOn(console, 'warn').mockImplementation(() => {}) + const newState = await handleClickCurrentButKeepFocus(state) + expect(newState).toBeDefined() + expect(spy).toHaveBeenCalledTimes(1) +}) diff --git a/packages/explorer-view/test/HandleClickDirectory.test.ts b/packages/explorer-view/test/HandleClickDirectory.test.ts new file mode 100644 index 0000000..6215e53 --- /dev/null +++ b/packages/explorer-view/test/HandleClickDirectory.test.ts @@ -0,0 +1,169 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' +import { handleClickDirectory } from '../src/parts/HandleClickDirectory/HandleClickDirectory.ts' + +test('handleClickDirectory - updates state with focus', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }, + { isDirectory: false, isSymbolicLink: false, name: 'child2', path: '/test/child2' }, + ] + }, + }) + + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const state: ExplorerState = { + ...createDefaultState(), + items: [dirent], + } + const index = 0 + const keepFocus = true + + const newState = await handleClickDirectory(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(3) + expect(newState.items[0]).toBe(dirent) + expect(newState.items[1].name).toBe('child1') + expect(newState.items[2].name).toBe('child2') + expect(newState.focusedIndex).toBe(0) + expect(newState.focused).toBe(true) + expect(newState.focus).toBe(FocusId.List) + expect(dirent.type).toBe(DirentType.DirectoryExpanded) + expect(dirent.icon).toBe('') +}) + +test('handleClickDirectory - updates state without focus', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }, + { isDirectory: false, isSymbolicLink: false, name: 'child2', path: '/test/child2' }, + ] + }, + }) + + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const state: ExplorerState = { + ...createDefaultState(), + items: [dirent], + } + const index = 0 + const keepFocus = false + + const newState = await handleClickDirectory(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(3) + expect(newState.focusedIndex).toBe(0) + expect(newState.focused).toBe(false) + expect(newState.focus).toBe(FocusId.List) + expect(dirent.type).toBe(DirentType.DirectoryExpanded) + expect(dirent.icon).toBe('') +}) + +test('handleClickDirectory - with empty child dirents', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const state: ExplorerState = { + ...createDefaultState(), + items: [dirent], + } + const index = 0 + const keepFocus = true + + const newState = await handleClickDirectory(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(1) + expect(newState.items[0]).toBe(dirent) + expect(newState.focusedIndex).toBe(0) + expect(newState.focused).toBe(true) + expect(dirent.type).toBe(DirentType.DirectoryExpanded) + expect(dirent.icon).toBe('') +}) + +test('handleClickDirectory - with multiple items in state', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [{ isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'other', path: '/other', selected: false, type: DirentType.File }, + { depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }, + { depth: 0, name: 'another', path: '/another', selected: false, type: DirentType.File }, + ], + } + const dirent = state.items[1] + const index = 1 + const keepFocus = true + + const newState = await handleClickDirectory(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(4) + expect(newState.items[0].name).toBe('other') + expect(newState.items[1]).toBe(dirent) + expect(newState.items[2].name).toBe('child1') + expect(newState.items[3].name).toBe('another') + expect(newState.focusedIndex).toBe(1) + expect(newState.focused).toBe(true) + expect(dirent.type).toBe(DirentType.DirectoryExpanded) + expect(dirent.icon).toBe('') +}) + +test('handleClickDirectory - dirent not found in items', async () => { + using _mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [{ isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [{ depth: 0, name: 'other', path: '/other', selected: false, type: DirentType.File }], + } + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const index = 0 + const keepFocus = true + + const newState = await handleClickDirectory(state, dirent, index, keepFocus) + + // Should return original state when dirent not found + expect(newState).toBe(state) +}) diff --git a/packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts b/packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts new file mode 100644 index 0000000..f0aba8a --- /dev/null +++ b/packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts @@ -0,0 +1,181 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleClickDirectoryExpanded } from '../src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' + +test.skip('collapse expanded directory', async () => { + const state: ExplorerState = createDefaultState() + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const index = 0 + const keepFocus = true + + const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(1) + expect(newState.focusedIndex).toBe(0) + expect(newState.focused).toBe(true) +}) + +test('collapse expanded directory with children', async () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const child1: ExplorerItem = { + depth: 1, + name: 'child1', + path: '/test/child1', + selected: false, + type: DirentType.File, + } + const child2: ExplorerItem = { + depth: 1, + name: 'child2', + path: '/test/child2', + selected: false, + type: DirentType.File, + } + const state: ExplorerState = { + ...createDefaultState(), + fileIconCache: { + '/test/': '', + '/test/child1': '', + '/test/child2': '', + }, + items: [dirent, child1, child2], + } + const index = 0 + const keepFocus = true + + const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(1) + expect(newState.focusedIndex).toBe(0) + expect(newState.focused).toBe(true) +}) + +test('collapse expanded directory with many items preserves icons', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const dirent = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const items = [dirent] + const fileIconCache: Record = { '/test/': 'folder-icon' } + + // Add 10 items with unique icons + for (let i = 0; i < 10; i++) { + const child: ExplorerItem = { + depth: 1, + name: `child${i}`, + path: `/test/child${i}`, + selected: false, + type: DirentType.File, + } + items.push(child) + fileIconCache[`/test/child${i}`] = `icon-${i}` + } + + const state: ExplorerState = { + ...createDefaultState(), + fileIconCache, + items, + } + const index = 0 + const keepFocus = true + + const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(1) + expect(newState.focusedIndex).toBe(0) + expect(newState.focused).toBe(true) + expect(newState.fileIconCache['/test/']).toBe('folder-icon') + expect(mockRpc.invocations).toEqual([]) +}) + +test('collapse expanded directory with scroll position adjustment', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const otherFolder: ExplorerItem = { + depth: 0, + name: '1', + path: '/1', + selected: false, + type: DirentType.Directory, + } + + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const items: ExplorerItem[] = [otherFolder, dirent] + const fileIconCache: Record = { + '/1': 'folder-icon-1', + '/test': 'folder-icon-2', + } + + // Add 10 items with unique icons + for (let i = 0; i < 5; i++) { + const child: ExplorerItem = { + depth: 1, + name: `child${i}`, + path: `/test/child${i}`, + selected: false, + type: DirentType.File, + } + items.push(child) + fileIconCache[`/test/child${i}`] = `icon-${i}` + } + + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 20, // User has scrolled down + fileIconCache, + height: 100, + itemHeight: 20, + items, + maxLineY: 6, + minLineY: 1, + } + const index = 1 + const keepFocus = true + + const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) + + expect(newState.items).toHaveLength(2) + expect(newState.focusedIndex).toBe(1) + expect(newState.focused).toBe(true) + expect(newState.minLineY).toBe(0) + expect(newState.maxLineY).toBe(2) + // After collapsing, since only one item remains and it fits in viewport, + // scroll position should be reset to 0 + expect(newState.deltaY).toBe(0) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts b/packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts new file mode 100644 index 0000000..e74ef95 --- /dev/null +++ b/packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts @@ -0,0 +1,35 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleClickDirectoryExpanding } from '../src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts' + +test('handleClickDirectoryExpanding - updates state with focus', async () => { + const state: ExplorerState = createDefaultState() + const dirent = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.File, + } + const newState = await handleClickDirectoryExpanding(state, dirent, 1, true) + expect(newState.focusedIndex).toBe(1) + expect(newState.focused).toBe(true) + expect(dirent.type).toBe(DirentType.Directory) +}) + +test('handleClickDirectoryExpanding - updates state without focus', async () => { + const state: ExplorerState = createDefaultState() + const dirent = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.File, + } + const newState = await handleClickDirectoryExpanding(state, dirent, 2, false) + expect(newState.focusedIndex).toBe(2) + expect(newState.focused).toBe(false) + expect(dirent.type).toBe(DirentType.Directory) +}) diff --git a/packages/explorer-view/test/HandleClickOpenFolder.test.ts b/packages/explorer-view/test/HandleClickOpenFolder.test.ts new file mode 100644 index 0000000..91526a2 --- /dev/null +++ b/packages/explorer-view/test/HandleClickOpenFolder.test.ts @@ -0,0 +1,17 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleClickOpenFolder } from '../src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts' + +test('handleClickOpenFolder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Dialog.openFolder'() { + return + }, + }) + + const state = createDefaultState() + const newState = await handleClickOpenFolder(state) + expect(newState).toBe(state) + expect(mockRpc.invocations).toEqual([['Dialog.openFolder']]) +}) diff --git a/packages/explorer-view/test/HandleClickSymlink.test.ts b/packages/explorer-view/test/HandleClickSymlink.test.ts new file mode 100644 index 0000000..3431ea7 --- /dev/null +++ b/packages/explorer-view/test/HandleClickSymlink.test.ts @@ -0,0 +1,67 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleClickSymLink } from '../src/parts/HandleClickSymlink/HandleClickSymlink.ts' + +test('handleClickSymLink - file symlink', async () => { + const state: ExplorerState = createDefaultState() + const dirent: ExplorerItem = { + depth: 0, + name: 'symlink', + path: '/test/symlink', + selected: false, + type: DirentType.Symlink, + } + const index = 0 + + const mockRealPath = '/test/real-file' + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getRealPath'() { + return mockRealPath + }, + 'FileSystem.stat'() { + return DirentType.File + }, + 'Main.openUri'() { + return undefined + }, + }) + + await handleClickSymLink(state, dirent, index) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.getRealPath', '/test/symlink'], + ['FileSystem.stat', '/test/real-file'], + ['Main.openUri', '/test/symlink', true], + ]) +}) + +test('handleClickSymLink - unsupported type', async () => { + const state: ExplorerState = createDefaultState() + const dirent: ExplorerItem = { + depth: 0, + name: 'symlink', + path: '/test/symlink', + selected: false, + type: DirentType.Symlink, + } + const index = 0 + + const mockRealPath = '/test/real-file' + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getRealPath'() { + return mockRealPath + }, + 'FileSystem.stat'() { + return DirentType.Directory + }, + }) + + await expect(handleClickSymLink(state, dirent, index)).rejects.toThrow('unsupported file type') + expect(mockRpc.invocations).toEqual([ + ['FileSystem.getRealPath', '/test/symlink'], + ['FileSystem.stat', '/test/real-file'], + ]) +}) diff --git a/packages/explorer-view/test/HandleContextMenu.test.ts b/packages/explorer-view/test/HandleContextMenu.test.ts new file mode 100644 index 0000000..6d63355 --- /dev/null +++ b/packages/explorer-view/test/HandleContextMenu.test.ts @@ -0,0 +1,37 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleContextMenu } from '../src/parts/HandleContextMenu/HandleContextMenu.ts' +import { Keyboard } from '../src/parts/MouseEventType/MouseEventType.ts' + +test('handleContextMenu - keyboard', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ContextMenu.show2'() { + return + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const state = createDefaultState() + const newState = await handleContextMenu(state, Keyboard, 0, 0) + expect(newState).toBeDefined() + expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 0, 20, { menuId: 4 }]]) +}) + +test('handleContextMenu - mouse', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ContextMenu.show2'() { + return + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const state = createDefaultState() + const newState = await handleContextMenu(state, 2, 100, 100) + expect(newState).toBeDefined() + expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 100, 100, { menuId: 4 }]]) +}) diff --git a/packages/explorer-view/test/HandleContextMenuKeyboard.test.ts b/packages/explorer-view/test/HandleContextMenuKeyboard.test.ts new file mode 100644 index 0000000..c5811bc --- /dev/null +++ b/packages/explorer-view/test/HandleContextMenuKeyboard.test.ts @@ -0,0 +1,26 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as HandleContextMenuKeyboard from '../src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts' + +test('handleContextMenuKeyboard', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ContextMenu.show2'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 2, + itemHeight: 20, + minLineY: 0, + x: 100, + y: 200, + } + const result = await HandleContextMenuKeyboard.handleContextMenuKeyboard(state) + expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 100, 260, { menuId: 4 }]]) + expect(result).toEqual({ + ...state, + focused: false, + }) +}) diff --git a/packages/explorer-view/test/HandleContextMenuMouseAt.test.ts b/packages/explorer-view/test/HandleContextMenuMouseAt.test.ts new file mode 100644 index 0000000..5007946 --- /dev/null +++ b/packages/explorer-view/test/HandleContextMenuMouseAt.test.ts @@ -0,0 +1,24 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as HandleContextMenuMouseAt from '../src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts' + +test('handleContextMenuMouseAt', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ContextMenu.show2'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + itemHeight: 20, + minLineY: 0, + uid: 1, + x: 0, + y: 0, + } + const result = await HandleContextMenuMouseAt.handleContextMenuMouseAt(state, 100, 200) + expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 100, 200, { menuId: 4 }]]) + expect(result).toEqual({ ...state, focused: false, focusedIndex: -1 }) +}) diff --git a/packages/explorer-view/test/HandleCopy.test.ts b/packages/explorer-view/test/HandleCopy.test.ts new file mode 100644 index 0000000..b4a318e --- /dev/null +++ b/packages/explorer-view/test/HandleCopy.test.ts @@ -0,0 +1,42 @@ +import { expect, jest, test } from '@jest/globals' +import { RendererWorker as RpcRendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleCopy } from '../src/parts/HandleCopy/HandleCopy.ts' + +test('handleCopy - with focused dirent', async () => { + using mockRpc = RpcRendererWorker.registerMockRpc({ + 'ClipBoard.writeNativeFiles'() {}, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + const result = await handleCopy(state) + + expect(mockRpc.invocations).toEqual(expect.arrayContaining([['ClipBoard.writeNativeFiles', 'copy', ['/test.txt']]])) + expect(result).toEqual({ + ...state, + pasteShouldMove: false, + }) +}) + +test('handleCopy - without focused dirent', async () => { + using mockRpc = RpcRendererWorker.registerMockRpc({ + 'ClipBoard.writeNativeFiles'() {}, + }) + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + items: [], + } + const result = await handleCopy(state) + expect(mockRpc.invocations).toEqual([]) + expect(result).toBe(state) + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith('[ViewletExplorer/handleCopy] no dirent selected') + spy.mockRestore() +}) diff --git a/packages/explorer-view/test/HandleCut.test.ts b/packages/explorer-view/test/HandleCut.test.ts new file mode 100644 index 0000000..b30fe06 --- /dev/null +++ b/packages/explorer-view/test/HandleCut.test.ts @@ -0,0 +1,37 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleCut } from '../src/parts/HandleCut/HandleCut.ts' + +test('handleCut - with focused dirent', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeNativeFiles'() {}, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + const result = await handleCut(state) + + expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'cut', ['/test.txt']]]) + expect(result).toEqual({ + ...state, + cutItems: ['/test.txt'], + pasteShouldMove: true, + }) +}) + +test('handleCut - without focused dirent', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + items: [], + } + const result = await handleCut(state) + expect(mockRpc.invocations).toEqual([]) + expect(result).toBe(state) +}) diff --git a/packages/explorer-view/test/HandleDoubleClick.test.ts b/packages/explorer-view/test/HandleDoubleClick.test.ts new file mode 100644 index 0000000..c073be9 --- /dev/null +++ b/packages/explorer-view/test/HandleDoubleClick.test.ts @@ -0,0 +1,198 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import { handleDoubleClick } from '../src/parts/HandleDoubleClick/HandleDoubleClick.ts' + +test('handleDoubleClick - double click on empty area creates new file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() { + return undefined + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'(requests: readonly any[]) { + return requests.map((param) => { + if (param.type === 2) { + return `folder-icon` + } + return `file-icon` + }) + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + itemHeight: 20, + items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], + maxLineY: 1, + minLineY: 0, + y: 0, + } + + // Double click on empty area (position that doesn't match any item) + const result = await handleDoubleClick(state, 0, 100) + expect(result).toEqual({ + ...state, + editingIndex: 1, + editingType: ExplorerEditingType.CreateFile, + editingValue: '', + focus: 2, + focusedIndex: 1, + items: [ + { + depth: 0, + name: 'testfolder', + path: '/testfolder', + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 1, + icon: '', + name: '', + path: '/testfolder', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.EditingFile, + }, + ], + visibleExplorerItems: expect.anything(), + }) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/testfolder']]) +}) + +test('handleDoubleClick - double click on item returns same state', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + itemHeight: 20, + items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], + maxLineY: 1, + minLineY: 0, + y: 0, + } + + // Double click on item (position that matches an item) + const result = await handleDoubleClick(state, 0, 10) + expect(result).toBe(state) +}) + +test('handleDoubleClick - double click on item with multiple items returns same state', async () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + itemHeight: 20, + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }, + { depth: 0, name: 'folder2', path: '/folder2', selected: false, type: DirentType.Directory }, + ], + maxLineY: 2, + minLineY: 0, + y: 0, + } + + // Double click on first item + const result = await handleDoubleClick(state, 0, 10) + expect(result).toBe(state) + + // Double click on second item + const result2 = await handleDoubleClick(state, 0, 30) + expect(result2).toBe(state) +}) + +test('handleDoubleClick - double click on empty area with scrolled state creates new file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() { + return undefined + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'(requests: readonly any[]) { + return requests.map((param) => { + if (param.type === 2) { + return `folder-icon` + } + return `file-icon` + }) + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + itemHeight: 20, + items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], + maxLineY: 1, + minLineY: 0, + y: 0, + } + + // Double click on empty area with scrolled position + const result = await handleDoubleClick(state, 0, 100) + expect(result).toEqual({ + ...state, + editingIndex: 1, + editingType: ExplorerEditingType.CreateFile, + editingValue: '', + focus: 2, + focusedIndex: 1, + items: [ + { + depth: 0, + name: 'testfolder', + path: '/testfolder', + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 1, + icon: '', + name: '', + path: '/testfolder', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.EditingFile, + }, + ], + visibleExplorerItems: expect.anything(), + }) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/testfolder']]) +}) diff --git a/packages/explorer-view/test/HandleDragLeave.test.ts b/packages/explorer-view/test/HandleDragLeave.test.ts new file mode 100644 index 0000000..373d5a5 --- /dev/null +++ b/packages/explorer-view/test/HandleDragLeave.test.ts @@ -0,0 +1,9 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleDragLeave } from '../src/parts/HandleDragLeave/HandleDragLeave.ts' + +test('handleDragLeave returns state unchanged', () => { + const state = createDefaultState() + const result = handleDragLeave(state) + expect(result).toBe(state) +}) diff --git a/packages/explorer-view/test/HandleDragOver.test.ts b/packages/explorer-view/test/HandleDragOver.test.ts new file mode 100644 index 0000000..9fc0afa --- /dev/null +++ b/packages/explorer-view/test/HandleDragOver.test.ts @@ -0,0 +1,29 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleDragOver } from '../src/parts/HandleDragOver/HandleDragOver.ts' + +test.skip('handleDragOver - returns same state when drop targets are equal', () => { + const state: ExplorerState = { + ...createDefaultState(), + dropTargets: [1, 2], + } + const result = handleDragOver(state, 100, 100) + expect(result).toBe(state) +}) + +test('handleDragOver - returns new state when drop targets change', () => { + const state: ExplorerState = { + ...createDefaultState(), + dropTargets: [1], + } + const result = handleDragOver(state, 200, 200) + expect(result).not.toBe(state) + expect(result.dropTargets).not.toEqual(state.dropTargets) +}) + +test.skip('handleDragOver - throws error for invalid coordinates', () => { + const state = createDefaultState() + expect(() => handleDragOver(state, Number.NaN, 100)).toThrow() + expect(() => handleDragOver(state, 100, Number.NaN)).toThrow() +}) diff --git a/packages/explorer-view/test/HandleDrop.test.ts b/packages/explorer-view/test/HandleDrop.test.ts new file mode 100644 index 0000000..1426e86 --- /dev/null +++ b/packages/explorer-view/test/HandleDrop.test.ts @@ -0,0 +1,98 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleDrop } from '../src/parts/HandleDrop/HandleDrop.ts' + +class MockFile implements File { + constructor( + public name: string, + public path: string, + public size: number = 0, + public type: string = 'text/plain', + public lastModified: number = 0, + public webkitRelativePath: string = '', + ) {} + + async arrayBuffer(): Promise { + return new ArrayBuffer(0) + } + + slice(): Blob { + return new Blob() + } + + stream(): ReadableStream> { + return new ReadableStream() + } + + async text(): Promise { + return '' + } + + async bytes(): Promise> { + return new Uint8Array(0) + } +} + +class MockFileList implements FileList { + private files: readonly File[] + + constructor(files: readonly File[]) { + this.files = files + } + + get length(): number { + return this.files.length + } + + item(index: number): File | null { + return this.files[index] || null + } + + [index: number]: File + + // @ts-ignore + [Symbol.iterator](): Iterator { + return this.files[Symbol.iterator]() + } +} + +test('handleDrop - successful drop', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystemHandle.getFileHandles'() { + return [] + }, + 'IconTheme.getIcons'() { + return [''] + }, + }) + + const state = createDefaultState() + const fileList = new MockFileList([new MockFile('test.txt', '/test.txt')]) + + // @ts-ignore + const result = await handleDrop(state, 0, 0, [1], fileList) + expect(result).toBeDefined() + expect(mockRpc.invocations).toEqual([ + ['FileSystemHandle.getFileHandles', [1]], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('handleDrop - error case', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystemHandle.getFileHandles'() { + throw new Error('test error') + }, + }) + + const state = createDefaultState() + const fileList = new MockFileList([new MockFile('test.txt', '/test.txt')]) + + // @ts-ignore + await expect(handleDrop(state, 0, 0, [1], fileList)).rejects.toThrow(new Error('Failed to drop files: test error')) + expect(mockRpc.invocations).toEqual([['FileSystemHandle.getFileHandles', [1]]]) +}) diff --git a/packages/explorer-view/test/HandleDropRootDefault.test.ts b/packages/explorer-view/test/HandleDropRootDefault.test.ts new file mode 100644 index 0000000..c0fa1a8 --- /dev/null +++ b/packages/explorer-view/test/HandleDropRootDefault.test.ts @@ -0,0 +1,199 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker, SourceControlWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import type { DroppedArgs } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleDrop } from '../src/parts/HandleDropRootDefault/HandleDropRootDefault.ts' + +test('handleDropRootDefault opens dropped folder as workspace when workspace is empty', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [{ isDirectory: false, isFile: true, name: 'inside.txt' }] + }, + 'PersistentFileHandle.addHandle'() { + return undefined + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return 'html://dropped-folder' + }, + 'Workspace.setPath'() { + return undefined + }, + }) + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + root: '', + } + const fileHandle = { + kind: 'directory', + name: 'dropped-folder', + } as FileSystemDirectoryHandle + const fileHandles: DroppedArgs = [fileHandle] + + const result = await handleDrop(state, fileHandles, [], []) + + expect(result.root).toBe('html://dropped-folder') + expect(result.dropTargets).toEqual([]) + expect(result.items).toHaveLength(1) + expect(mockRpc.invocations).toEqual([ + ['PersistentFileHandle.addHandle', 'dropped-folder', fileHandle], + ['Workspace.setPath', 'html://dropped-folder'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', 'html://dropped-folder'], + ['FileSystem.readDirWithFileTypes', 'html://dropped-folder'], + ]) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) + +test('handleDropRootDefault opens first dropped folder as workspace when two folders are dropped into empty workspace', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [{ isDirectory: false, isFile: true, name: 'inside.txt' }] + }, + 'PersistentFileHandle.addHandle'() { + return undefined + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return 'html://first-folder' + }, + 'Workspace.setPath'() { + return undefined + }, + }) + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + root: '', + } + const firstFolderHandle = { + kind: 'directory', + name: 'first-folder', + } as FileSystemDirectoryHandle + const secondFolderHandle = { + kind: 'directory', + name: 'second-folder', + } as FileSystemDirectoryHandle + const fileHandles: DroppedArgs = [firstFolderHandle, secondFolderHandle] + + const result = await handleDrop(state, fileHandles, [], []) + + expect(result.root).toBe('html://first-folder') + expect(result.dropTargets).toEqual([]) + expect(result.items).toHaveLength(1) + expect(mockRpc.invocations).toEqual([ + ['PersistentFileHandle.addHandle', 'first-folder', firstFolderHandle], + ['Workspace.setPath', 'html://first-folder'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', 'html://first-folder'], + ['FileSystem.readDirWithFileTypes', 'html://first-folder'], + ]) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) + +test('handleDropRootDefault ignores dropped file when workspace is empty', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + const state: ExplorerState = { + ...createDefaultState(), + root: '', + } + const fileHandle = { + kind: 'file', + name: 'dropped-file.txt', + } as FileSystemFileHandle + const fileHandles: DroppedArgs = [fileHandle] + + const result = await handleDrop(state, fileHandles, [], []) + + expect(result.root).toBe('') + expect(result.dropTargets).toEqual([]) + expect(result.items).toEqual([]) + expect(mockRpc.invocations).toEqual([]) +}) + +test('handleDropRootDefault opens dropped folder as workspace when file and folder are dropped into empty workspace', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [{ isDirectory: false, isFile: true, name: 'folder-inside.txt' }] + }, + 'PersistentFileHandle.addHandle'() { + return undefined + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return 'html://dropped-folder' + }, + 'Workspace.setPath'() { + return undefined + }, + }) + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + root: '', + } + const fileHandle = { + kind: 'file', + name: 'dropped-file.txt', + } as FileSystemFileHandle + const directoryHandle = { + kind: 'directory', + name: 'dropped-folder', + } as FileSystemDirectoryHandle + const fileHandles: DroppedArgs = [fileHandle, directoryHandle] + + const result = await handleDrop(state, fileHandles, [], []) + + expect(result.root).toBe('html://dropped-folder') + expect(result.dropTargets).toEqual([]) + expect(result.items).toHaveLength(1) + expect(mockRpc.invocations).toEqual([ + ['PersistentFileHandle.addHandle', 'dropped-folder', directoryHandle], + ['Workspace.setPath', 'html://dropped-folder'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', 'html://dropped-folder'], + ['FileSystem.readDirWithFileTypes', 'html://dropped-folder'], + ]) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/HandleDropRootElectron.test.ts b/packages/explorer-view/test/HandleDropRootElectron.test.ts new file mode 100644 index 0000000..198f5e2 --- /dev/null +++ b/packages/explorer-view/test/HandleDropRootElectron.test.ts @@ -0,0 +1,82 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker, SourceControlWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import type { DroppedArgs } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleDrop } from '../src/parts/HandleDropRootElectron/HandleDropRootElectron.ts' + +test('handleDropRootElectron opens dropped folder as workspace when workspace is empty', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [{ isDirectory: false, isFile: true, name: 'inside.txt' }] + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/home/simon/dotfiles' + }, + 'Workspace.setPath'() { + return undefined + }, + }) + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + root: '', + } + const fileHandle = { + kind: 'directory', + name: 'dotfiles', + } as FileSystemDirectoryHandle + const fileHandles: DroppedArgs = [fileHandle] + + const result = await handleDrop(state, fileHandles, [], ['/home/simon/dotfiles']) + + expect(result.root).toBe('/home/simon/dotfiles') + expect(result.dropTargets).toEqual([]) + expect(result.items).toHaveLength(1) + expect(mockRpc.invocations).toEqual([ + ['Workspace.setPath', '/home/simon/dotfiles'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/home/simon/dotfiles'], + ['FileSystem.readDirWithFileTypes', '/home/simon/dotfiles'], + ]) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) + +test('handleDropRootElectron ignores dropped file when workspace is empty', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + const state: ExplorerState = { + ...createDefaultState(), + dropTargets: [0], + root: '', + } + const fileHandles: DroppedArgs = [ + { + kind: 'file', + value: { + kind: 'file', + name: 'dropped-file.txt', + } as FileSystemFileHandle, + }, + ] + + const result = await handleDrop(state, fileHandles, [], ['/home/simon/dropped-file.txt']) + + expect(result.root).toBe('') + expect(result.dropTargets).toEqual([]) + expect(result.items).toEqual([]) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/HandleEscape.test.ts b/packages/explorer-view/test/HandleEscape.test.ts new file mode 100644 index 0000000..b69d825 --- /dev/null +++ b/packages/explorer-view/test/HandleEscape.test.ts @@ -0,0 +1,17 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleEscape } from '../src/parts/HandleEscape/HandleEscape.ts' + +test('handleEscape - clears cutItems and keeps other state', async () => { + const initialState: ExplorerState = { + ...createDefaultState(), + cutItems: ['/a/b.txt', '/c/d.txt'], + focusedIndex: 1, + } + + const result = await handleEscape(initialState) + + expect(result.cutItems).toEqual([]) + expect(result.focusedIndex).toBe(1) +}) diff --git a/packages/explorer-view/test/HandleFocus.test.ts b/packages/explorer-view/test/HandleFocus.test.ts new file mode 100644 index 0000000..b83ae25 --- /dev/null +++ b/packages/explorer-view/test/HandleFocus.test.ts @@ -0,0 +1,27 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' +import { handleFocus } from '../src/parts/HandleFocus/HandleFocus.ts' + +test('handleFocus keeps input focus while editing', async () => { + const state = { + ...createDefaultState(), + editingIndex: 1, + focus: FocusId.Input, + } + + const result = await handleFocus(state) + + expect(result).toBe(state) +}) + +test('handleFocus switches to list focus when not editing', async () => { + const state = createDefaultState() + + const result = await handleFocus(state) + + expect(result).toEqual({ + ...state, + focus: FocusId.List, + }) +}) diff --git a/packages/explorer-view/test/HandleInputBlur.test.ts b/packages/explorer-view/test/HandleInputBlur.test.ts new file mode 100644 index 0000000..ed40ac1 --- /dev/null +++ b/packages/explorer-view/test/HandleInputBlur.test.ts @@ -0,0 +1,22 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleInputBlur } from '../src/parts/HandleInputBlur/HandleInputBlur.ts' + +test('should cancel edit if there is an error message', async () => { + const state: ExplorerState = { ...createDefaultState(), editingErrorMessage: 'error', editingValue: 'foo' } + const result = await handleInputBlur(state) + expect(result.editingValue).toBe('foo') +}) + +test('should cancel edit if editing value is empty', async () => { + const state: ExplorerState = { ...createDefaultState(), editingErrorMessage: '', editingValue: '' } + const result = await handleInputBlur(state) + expect(result.editingValue).toBe('') +}) + +test('should accept edit if no error and value present', async () => { + const state: ExplorerState = { ...createDefaultState(), editingErrorMessage: '', editingType: 0, editingValue: 'foo' } + const result = await handleInputBlur(state) + expect(result.editingValue).toBe('foo') +}) diff --git a/packages/explorer-view/test/HandleKeyDown.test.ts b/packages/explorer-view/test/HandleKeyDown.test.ts new file mode 100644 index 0000000..7249289 --- /dev/null +++ b/packages/explorer-view/test/HandleKeyDown.test.ts @@ -0,0 +1,54 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleKeyDown } from '../src/parts/HandleKeyDown/HandleKeyDown.ts' + +test.skip('handleKeyDown - empty state', () => { + const state = createDefaultState() + const newState = handleKeyDown(state, 'a') + expect(newState.focusWord).toBe('a') + expect(newState.focusedIndex).toBe(0) +}) + +test.skip('handleKeyDown - with items', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'apple', path: '/apple', selected: false, type: 0 }, + { depth: 0, name: 'banana', path: '/banana', selected: false, type: 0 }, + { depth: 0, name: 'cherry', path: '/cherry', selected: false, type: 0 }, + ], + } + const newState = handleKeyDown(state, 'b') + expect(newState.focusWord).toBe('b') + expect(newState.focusedIndex).toBe(1) +}) + +test.skip('handleKeyDown - no match', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'apple', path: '/apple', selected: false, type: 0 }, + { depth: 0, name: 'banana', path: '/banana', selected: false, type: 0 }, + { depth: 0, name: 'cherry', path: '/cherry', selected: false, type: 0 }, + ], + } + const newState = handleKeyDown(state, 'x') + expect(newState.focusWord).toBe('x') + expect(newState.focusedIndex).toBe(0) +}) + +test.skip('handleKeyDown - multiple characters', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'apple', path: '/apple', selected: false, type: 0 }, + { depth: 0, name: 'banana', path: '/banana', selected: false, type: 0 }, + { depth: 0, name: 'cherry', path: '/cherry', selected: false, type: 0 }, + ], + } + let newState = handleKeyDown(state, 'b') + newState = handleKeyDown(newState, 'a') + expect(newState.focusWord).toBe('ba') + expect(newState.focusedIndex).toBe(1) +}) diff --git a/packages/explorer-view/test/HandlePaste.test.ts b/packages/explorer-view/test/HandlePaste.test.ts new file mode 100644 index 0000000..b29c30b --- /dev/null +++ b/packages/explorer-view/test/HandlePaste.test.ts @@ -0,0 +1,204 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handlePaste } from '../src/parts/HandlePaste/HandlePaste.ts' +import * as NativeFileTypes from '../src/parts/NativeFileTypes/NativeFileTypes.ts' + +test('should handle paste with no files (none type)', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return { + files: [], + type: NativeFileTypes.None, + } + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handlePaste(initialState) + + expect(result).toBe(initialState) + expect(mockRpc.invocations).toEqual([['ClipBoard.readNativeFiles']]) +}) + +test('should handle paste with copy type', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return { + files: ['/source/file1.txt', '/source/file2.txt'], + type: NativeFileTypes.Copy, + } + }, + 'FileSystem.copy'() {}, + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getIcons'() { + return [''] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handlePaste(initialState) + + expect(result).toBeDefined() + expect(result).toHaveProperty('items') + expect(result).toHaveProperty('icons') + expect(mockRpc.invocations).toEqual([ + ['ClipBoard.readNativeFiles'], + ['FileSystem.copy', '/source/file1.txt', '/file1.txt'], + ['FileSystem.copy', '/source/file2.txt', '/file2.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('should handle paste with cut type', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return { + files: ['/source/file1.txt', '/source/file2.txt'], + type: NativeFileTypes.Cut, + } + }, + 'FileSystem.copy'() {}, + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.rename'() {}, + 'IconTheme.getIcons'() { + return [''] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handlePaste(initialState) + + expect(result).toBeDefined() + expect(result).toHaveProperty('items') + expect(result).toHaveProperty('icons') + expect(mockRpc.invocations).toEqual([ + ['ClipBoard.readNativeFiles'], + ['FileSystem.copy', '/source/file1.txt', '/file1.txt'], + ['FileSystem.copy', '/source/file2.txt', '/file2.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('should handle paste with multiple files', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return { + files: ['/source/file1.txt', '/source/file2.txt', '/source/folder1', '/source/folder2/file3.txt'], + type: NativeFileTypes.Copy, + } + }, + 'FileSystem.copy'() {}, + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getIcons'() { + return [''] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handlePaste(initialState) + + expect(result).toBeDefined() + expect(result).toHaveProperty('items') + expect(result).toHaveProperty('icons') + expect(mockRpc.invocations).toEqual([ + ['ClipBoard.readNativeFiles'], + ['FileSystem.copy', '/source/file1.txt', '/file1.txt'], + ['FileSystem.copy', '/source/file2.txt', '/file2.txt'], + ['FileSystem.copy', '/source/folder1', '/folder1'], + ['FileSystem.copy', '/source/folder2/file3.txt', '/file3.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('should handle paste with empty files array', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return { + files: [], + type: NativeFileTypes.Copy, + } + }, + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getIcons'() { + return [''] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handlePaste(initialState) + + expect(result).toBeDefined() + expect(result).toHaveProperty('items') + expect(result).toHaveProperty('icons') + expect(mockRpc.invocations).toEqual([['ClipBoard.readNativeFiles'], ['FileSystem.readDirWithFileTypes', '/']]) +}) + +test('should preserve state properties when handling paste', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return { + files: ['/source/file.txt'], + type: NativeFileTypes.Copy, + } + }, + 'FileSystem.copy'() {}, + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getIcons'() { + return [''] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handlePaste(initialState) + + expect(result).toBeDefined() + expect(result).toHaveProperty('items') + expect(result).toHaveProperty('icons') + expect(mockRpc.invocations).toEqual([ + ['ClipBoard.readNativeFiles'], + ['FileSystem.copy', '/source/file.txt', '/file.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) diff --git a/packages/explorer-view/test/HandlePasteCopy.test.ts b/packages/explorer-view/test/HandlePasteCopy.test.ts new file mode 100644 index 0000000..26c847d --- /dev/null +++ b/packages/explorer-view/test/HandlePasteCopy.test.ts @@ -0,0 +1,145 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handlePasteCopy } from '../src/parts/HandlePasteCopy/HandlePasteCopy.ts' + +test('should focus on first newly created file after paste copy', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.copy'() { + return undefined + }, + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'index.js', type: DirentType.File }, + { name: 'index copy.js', type: DirentType.File }, + ] + }, + 'IconTheme.getIcons'() { + return ['', ''] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'index.js', path: '/test/index.js', selected: false, type: DirentType.File }], + root: '/test', + } + + const nativeFiles = { + files: ['/source/index.js'], + source: 'gnomeCopiedFiles' as const, + type: 'copy' as const, + } + + const result = await handlePasteCopy(initialState, nativeFiles) + + expect(result).toBeDefined() + expect(result.items).toHaveLength(2) + const focusedItem = result.items[result.focusedIndex] + expect(focusedItem.path).toBe('/test/index copy.js') + expect(result.focused).toBe(true) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.copy', '/source/index.js', '/test/index copy.js'], + ['FileSystem.readDirWithFileTypes', '/test'], + ]) +}) + +test('should handle paste copy with multiple files and focus on first', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.copy'() { + return undefined + }, + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file1.txt', type: DirentType.File }, + { name: 'file1 copy.txt', type: DirentType.File }, + { name: 'file2.txt', type: DirentType.File }, + { name: 'file2 copy.txt', type: DirentType.File }, + ] + }, + 'IconTheme.getIcons'() { + return ['', '', '', ''] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: DirentType.File }, + { depth: 0, name: 'file2.txt', path: '/test/file2.txt', selected: false, type: DirentType.File }, + ], + root: '/test', + } + + const nativeFiles = { + files: ['/source/file1.txt', '/source/file2.txt'], + source: 'gnomeCopiedFiles' as const, + type: 'copy' as const, + } + + const result = await handlePasteCopy(initialState, nativeFiles) + + expect(result).toBeDefined() + expect(result.items).toHaveLength(4) + const focusedItem = result.items[result.focusedIndex] + expect(focusedItem.path).toBe('/test/file1 copy.txt') + expect(result.focused).toBe(true) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.copy', '/source/file1.txt', '/test/file1 copy.txt'], + ['FileSystem.copy', '/source/file2.txt', '/test/file2 copy.txt'], + ['FileSystem.readDirWithFileTypes', '/test'], + ]) +}) + +test('should handle paste copy with empty files array', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getIcons'() { + return [] + }, + 'Preferences.get'() { + return false + }, + }) + + const initialState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [], + root: '/test', + } + + const nativeFiles = { + files: [], + source: 'gnomeCopiedFiles' as const, + type: 'copy' as const, + } + + const result = await handlePasteCopy(initialState, nativeFiles) + + expect(result).toBeDefined() + expect(result.items).toHaveLength(0) + expect(result.focusedIndex).toBe(0) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) +}) diff --git a/packages/explorer-view/test/HandlePointerDown.test.ts b/packages/explorer-view/test/HandlePointerDown.test.ts new file mode 100644 index 0000000..bae2bc3 --- /dev/null +++ b/packages/explorer-view/test/HandlePointerDown.test.ts @@ -0,0 +1,36 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' +import { handlePointerDown } from '../src/parts/HandlePointerDown/HandlePointerDown.ts' +import * as MouseEventType from '../src/parts/MouseEventType/MouseEventType.ts' + +test('left click outside items', () => { + const state = createDefaultState() + const result = handlePointerDown(state, MouseEventType.LeftClick, 100, 100) + expect(result).toEqual({ + ...state, + focus: FocusId.List, + focused: true, + focusedIndex: -1, + }) +}) + +test.skip('right click outside items', () => { + const state = createDefaultState() + const result = handlePointerDown(state, 2, 100, 100) + expect(result).toEqual({ + ...state, + focusedIndex: -1, + }) +}) + +test('left click on item', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + const result = handlePointerDown(state, MouseEventType.LeftClick, 0, 0) + expect(result).toEqual(state) +}) diff --git a/packages/explorer-view/test/HandleRangeSelection.test.ts b/packages/explorer-view/test/HandleRangeSelection.test.ts new file mode 100644 index 0000000..0eec359 --- /dev/null +++ b/packages/explorer-view/test/HandleRangeSelection.test.ts @@ -0,0 +1,75 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleRangeSelection } from '../src/parts/HandleRangeSelection/HandleRangeSelection.ts' + +const createItem = (name: string, selected: boolean): ExplorerItem => ({ + depth: 0, + name, + path: `/${name}`, + selected, + type: 0, +}) + +test('handleRangeSelection - forward range', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const newState = handleRangeSelection(state, 0, 2) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(true) +}) + +test('handleRangeSelection - backward range', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + expect(() => handleRangeSelection(state, 2, 0)).toThrow(new Error('startIndex must be less than or equal to endIndex')) +}) + +test('handleRangeSelection - preserve existing selections', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: true, type: 0 }, + ], + } + const newState = handleRangeSelection(state, 0, 2) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(true) +}) + +test('selects items in range', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [createItem('a', false), createItem('b', false), createItem('c', false), createItem('d', false)], + } + + const newState = handleRangeSelection(state, 1, 2) + + expect(newState.items).toEqual([createItem('a', false), createItem('b', true), createItem('c', true), createItem('d', false)]) +}) + +test('throws error when startIndex > endIndex', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [createItem('a', false), createItem('b', false)], + } + + expect(() => handleRangeSelection(state, 1, 0)).toThrow('startIndex must be less than or equal to endIndex') +}) diff --git a/packages/explorer-view/test/HandleResize.test.ts b/packages/explorer-view/test/HandleResize.test.ts new file mode 100644 index 0000000..00b44a3 --- /dev/null +++ b/packages/explorer-view/test/HandleResize.test.ts @@ -0,0 +1,63 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleResize } from '../src/parts/HandleResize/HandleResize.ts' + +test('handleResize updates dimensions, viewport lines and scrollbarHeight', () => { + const items: readonly ExplorerItem[] = Array.from({ length: 10 }, (_, index) => ({ + depth: 0, + name: `file-${index}`, + path: `/file-${index}`, + selected: false, + type: 1, + })) + const state: ExplorerState = { + ...createDefaultState(), + itemHeight: 20, + items, + } + + const result = handleResize(state, { height: 100, width: 300 }) + + expect(result).toEqual({ + ...state, + height: 100, + maxLineY: 6, + minLineY: 0, + scrollBarHeight: 50, + width: 300, + }) +}) + +test('handleResize clamps deltaY when viewport gets larger', () => { + const items: readonly ExplorerItem[] = Array.from({ length: 10 }, (_, index) => ({ + depth: 0, + name: `file-${index}`, + path: `/file-${index}`, + selected: false, + type: 1, + })) + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 180, + height: 20, + itemHeight: 20, + items, + maxLineY: 1, + minLineY: 9, + } + + const result = handleResize(state, { height: 120, width: 300 }) + + expect(result.deltaY).toBe(80) + expect(result.minLineY).toBe(4) + expect(result.maxLineY).toBe(11) + expect(result.scrollBarHeight).toBe(72) +}) + +test('handleResize returns same state for invalid dimensions', () => { + const state: ExplorerState = createDefaultState() + const result = handleResize(state, { height: Number.NaN, width: 200 }) + expect(result).toBe(state) +}) diff --git a/packages/explorer-view/test/HandleSelection.test.ts b/packages/explorer-view/test/HandleSelection.test.ts new file mode 100644 index 0000000..b8161bf --- /dev/null +++ b/packages/explorer-view/test/HandleSelection.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' +import { handleSelection } from '../src/parts/HandleSelection/HandleSelection.js' + +test('handleSelection toggles selection of item at index', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, + { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, + { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, + ], + } + + const newState = handleSelection(state, 1) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[2].selected).toBe(false) +}) diff --git a/packages/explorer-view/test/HandleUpload.test.ts b/packages/explorer-view/test/HandleUpload.test.ts new file mode 100644 index 0000000..b96ed65 --- /dev/null +++ b/packages/explorer-view/test/HandleUpload.test.ts @@ -0,0 +1,24 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker as RpcRendererWorker } from '@lvce-editor/rpc-registry' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleUpload } from '../src/parts/HandleUpload/HandleUpload.ts' + +test('should upload a file', async () => { + using mockRpc = RpcRendererWorker.registerMockRpc({ + 'FileSystem.writeFile'(...args: any[]) { + // Mock implementation + }, + }) + const state = createDefaultState() + const file = { name: 'test.txt', text: (): string => 'hello' } + const dirents = [{ file, type: 1 }] + await handleUpload(state, dirents) + expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', expect.stringContaining('test.txt'), 'hello']]) +}) + +test('should do nothing for empty dirents', async () => { + using mockRpc = RpcRendererWorker.registerMockRpc({}) + const state = createDefaultState() + await handleUpload(state, []) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/HandleWheel.test.ts b/packages/explorer-view/test/HandleWheel.test.ts new file mode 100644 index 0000000..688add2 --- /dev/null +++ b/packages/explorer-view/test/HandleWheel.test.ts @@ -0,0 +1,59 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleWheel } from '../src/parts/HandleWheel/HandleWheel.ts' + +test('handleWheel calls SetDeltaY with correct delta', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 10, + height: 50, + itemHeight: 20, + items: [ + { depth: 0, name: 'test1', path: '/test1', selected: false, type: 1 }, + { depth: 0, name: 'test2', path: '/test2', selected: false, type: 1 }, + { depth: 0, name: 'test3', path: '/test3', selected: false, type: 1 }, + { depth: 0, name: 'test4', path: '/test4', selected: false, type: 1 }, + { depth: 0, name: 'test5', path: '/test5', selected: false, type: 1 }, + ], + } + const result = await handleWheel(state, 0, 5) + expect(result.deltaY).toBe(15) + expect(mockRpc.invocations).toEqual([]) +}) + +test('handleWheel with negative delta', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + deltaY: 10, + height: 50, + itemHeight: 20, + items: [ + { depth: 0, name: 'test1', path: '/test1', selected: false, type: 1 }, + { depth: 0, name: 'test2', path: '/test2', selected: false, type: 1 }, + { depth: 0, name: 'test3', path: '/test3', selected: false, type: 1 }, + { depth: 0, name: 'test4', path: '/test4', selected: false, type: 1 }, + { depth: 0, name: 'test5', path: '/test5', selected: false, type: 1 }, + ], + } + const result = await handleWheel(state, 0, -3) + expect(result.deltaY).toBe(7) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/HandleWorkspaceChange.test.ts b/packages/explorer-view/test/HandleWorkspaceChange.test.ts new file mode 100644 index 0000000..f1d533d --- /dev/null +++ b/packages/explorer-view/test/HandleWorkspaceChange.test.ts @@ -0,0 +1,293 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker, SourceControlWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { handleWorkspaceChange } from '../src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts' + +test('should update state with new workspace path and load content', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/workspace/path' + }, + }) + + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handleWorkspaceChange(initialState) + + expect(result.root).toBe('/new/workspace/path') + expect(result).toHaveProperty('items') + expect(result).toHaveProperty('icons') + expect(result).toHaveProperty('fileIconCache') + expect(result).toHaveProperty('minLineY') + expect(result).toHaveProperty('deltaY') + expect(result).toHaveProperty('maxLineY') + expect(result).toHaveProperty('pathSeparator') + expect(result).toHaveProperty('excluded') + expect(result).toHaveProperty('useChevrons') + expect(mockRpc.invocations).toEqual([ + ['Workspace.getPath'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/new/workspace/path'], + ['FileSystem.readDirWithFileTypes', '/new/workspace/path'], + ]) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) + +test('should preserve state properties when updating workspace', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Preferences.get'() { + return true + }, + 'Workspace.getPath'() { + return '/another/workspace' + }, + }) + + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handleWorkspaceChange(initialState) + + expect(result.uid).toBe(initialState.uid) + expect(result.parentUid).toBe(initialState.parentUid) + expect(result.focusedIndex).toBe(initialState.focusedIndex) + expect(result.focused).toBe(initialState.focused) + expect(result.hoverIndex).toBe(initialState.hoverIndex) + expect(result.x).toBe(initialState.x) + expect(result.y).toBe(initialState.y) + expect(result.width).toBe(initialState.width) + expect(result.height).toBe(initialState.height) + expect(result.version).toBe(initialState.version) + expect(result.editingIndex).toBe(initialState.editingIndex) + expect(result.itemHeight).toBe(initialState.itemHeight) + expect(result.platform).toBe(initialState.platform) + expect(result.focus).toBe(initialState.focus) + expect(result.inputSource).toBe(initialState.inputSource) + expect(result.focusWord).toBe(initialState.focusWord) + expect(result.focusWordTimeout).toBe(initialState.focusWordTimeout) + expect(result.finalDeltaY).toBe(initialState.finalDeltaY) + expect(result.scrollBarHeight).toBe(initialState.scrollBarHeight) + expect(result.handleOffset).toBe(initialState.handleOffset) + expect(result.scrollBarActive).toBe(initialState.scrollBarActive) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['Workspace.getPath'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/another/workspace'], + ['FileSystem.readDirWithFileTypes', '/another/workspace'], + ]), + ) + expect(mockSourceControlRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', '', '/another/workspace', '', 0]]) +}) + +test('should handle workspace path change with existing content', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [ + { isDirectory: false, isFile: true, name: 'file1.txt' }, + { isDirectory: true, isFile: false, name: 'folder1' }, + ] + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/changed/workspace/path' + }, + }) + + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handleWorkspaceChange(initialState) + + expect(result.root).toBe('/changed/workspace/path') + expect(result.items).toHaveLength(2) + expect(result.pathSeparator).toBe('/') + expect(result.useChevrons).toBe(false) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['Workspace.getPath'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/changed/workspace/path'], + ['FileSystem.readDirWithFileTypes', '/changed/workspace/path'], + ]), + ) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) + +test('should handle workspace path change with chevrons enabled', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Preferences.get'() { + return true + }, + 'Workspace.getPath'() { + return '/chevron/workspace' + }, + }) + + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handleWorkspaceChange(initialState) + + expect(result.root).toBe('/chevron/workspace') + expect(result.useChevrons).toBe(true) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['Workspace.getPath'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/chevron/workspace'], + ['FileSystem.readDirWithFileTypes', '/chevron/workspace'], + ]), + ) + expect(mockSourceControlRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', '', '/chevron/workspace', '', 0]]) +}) + +test('should handle different path separators', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '\\' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return 'C:\\windows\\workspace' + }, + }) + + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handleWorkspaceChange(initialState) + + expect(result.root).toBe('C:\\windows\\workspace') + expect(result.pathSeparator).toBe('\\') + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['Workspace.getPath'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', 'C:\\windows\\workspace'], + ['FileSystem.readDirWithFileTypes', 'C:\\windows\\workspace'], + ]), + ) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) + +test('should set load error state when reading folder fails', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + const error = Object.assign(new Error('Permission denied'), { + code: 'EACCES', + }) + throw error + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/restricted/workspace' + }, + }) + + const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ + 'SourceControl.getEnabledProviderIds'() { + return [] + }, + }) + + const initialState: ExplorerState = createDefaultState() + const result = await handleWorkspaceChange(initialState) + + expect(result.root).toBe('/restricted/workspace') + expect(result.hasError).toBe(true) + expect(result.errorCode).toBe('EACCES') + expect(result.errorMessage).toBe('permission was denied') + expect(result.items).toEqual([]) + expect(mockRpc.invocations).toEqual( + expect.arrayContaining([ + ['Workspace.getPath'], + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/restricted/workspace'], + ['FileSystem.readDirWithFileTypes', '/restricted/workspace'], + ]), + ) + expect(mockSourceControlRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/IsAscii.test.ts b/packages/explorer-view/test/IsAscii.test.ts new file mode 100644 index 0000000..8939116 --- /dev/null +++ b/packages/explorer-view/test/IsAscii.test.ts @@ -0,0 +1,20 @@ +import { test, expect } from '@jest/globals' +import { isAscii } from '../src/parts/IsAscii/IsAscii.js' + +test('isAscii - lowercase ascii', () => { + expect(isAscii('a')).toBe(true) + expect(isAscii('z')).toBe(true) +}) + +test('isAscii - uppercase ascii', () => { + expect(isAscii('A')).toBe(false) + expect(isAscii('Z')).toBe(false) +}) + +test('isAscii - non-ascii', () => { + expect(isAscii('ä')).toBe(false) + expect(isAscii('1')).toBe(false) + expect(isAscii('-')).toBe(false) + expect(isAscii(' ')).toBe(false) + expect(isAscii('')).toBe(false) +}) diff --git a/packages/explorer-view/test/IsDirectoryHandle.test.ts b/packages/explorer-view/test/IsDirectoryHandle.test.ts new file mode 100644 index 0000000..e3893d0 --- /dev/null +++ b/packages/explorer-view/test/IsDirectoryHandle.test.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@jest/globals' +import { isDirectoryHandle } from '../src/parts/IsDirectoryHandle/IsDirectoryHandle.ts' + +test('isDirectoryHandle', () => { + const fileHandle = { + kind: 'file', + } as FileSystemHandle + const directoryHandle = { + kind: 'directory', + } as FileSystemHandle + expect(isDirectoryHandle(fileHandle)).toBe(false) + expect(isDirectoryHandle(directoryHandle)).toBe(true) +}) diff --git a/packages/explorer-view/test/IsEqual.test.ts b/packages/explorer-view/test/IsEqual.test.ts new file mode 100644 index 0000000..cbdd666 --- /dev/null +++ b/packages/explorer-view/test/IsEqual.test.ts @@ -0,0 +1,30 @@ +import { expect, test } from '@jest/globals' +import * as IsEqual from '../src/parts/IsEqual/IsEqual.ts' + +test('isEqual - empty arrays', () => { + expect(IsEqual.isEqual([], [])).toBe(true) +}) + +test('isEqual - arrays with same elements', () => { + expect(IsEqual.isEqual([1, 2, 3], [1, 2, 3])).toBe(true) +}) + +test('isEqual - arrays with different elements', () => { + expect(IsEqual.isEqual([1, 2, 3], [1, 2, 4])).toBe(false) +}) + +test('isEqual - arrays with different lengths', () => { + expect(IsEqual.isEqual([1, 2], [1, 2, 3])).toBe(false) +}) + +test('isEqual - arrays with same elements in different order', () => { + expect(IsEqual.isEqual([1, 2, 3], [3, 2, 1])).toBe(false) +}) + +test('isEqual - arrays with string elements', () => { + expect(IsEqual.isEqual(['a', 'b', 'c'], ['a', 'b', 'c'])).toBe(true) +}) + +test('isEqual - arrays with mixed elements', () => { + expect(IsEqual.isEqual([1, 'b', true], [1, 'b', true])).toBe(true) +}) diff --git a/packages/explorer-view/test/IsExpanded.test.ts b/packages/explorer-view/test/IsExpanded.test.ts new file mode 100644 index 0000000..090ed11 --- /dev/null +++ b/packages/explorer-view/test/IsExpanded.test.ts @@ -0,0 +1,23 @@ +import { test, expect } from '@jest/globals' +import { Directory, DirectoryExpanded, DirectoryExpanding, File } from '../src/parts/DirentType/DirentType.ts' +import { isExpanded } from '../src/parts/IsExpanded/IsExpanded.ts' + +test('isExpanded - DirectoryExpanded', () => { + const item = { depth: 0, name: 'test', path: '/test', selected: false, type: DirectoryExpanded } + expect(isExpanded(item)).toBe(true) +}) + +test('isExpanded - DirectoryExpanding', () => { + const item = { depth: 0, name: 'test', path: '/test', selected: false, type: DirectoryExpanding } + expect(isExpanded(item)).toBe(true) +}) + +test('isExpanded - Directory', () => { + const item = { depth: 0, name: 'test', path: '/test', selected: false, type: Directory } + expect(isExpanded(item)).toBe(false) +}) + +test('isExpanded - File', () => { + const item = { depth: 0, name: 'test', path: '/test', selected: false, type: File } + expect(isExpanded(item)).toBe(false) +}) diff --git a/packages/explorer-view/test/IsExpandedDirectory.test.ts b/packages/explorer-view/test/IsExpandedDirectory.test.ts new file mode 100644 index 0000000..b33142b --- /dev/null +++ b/packages/explorer-view/test/IsExpandedDirectory.test.ts @@ -0,0 +1,48 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as IsExpandedDirectory from '../src/parts/IsExpandedDirectory/IsExpandedDirectory.ts' + +test('isExpandedDirectory - expanded directory', () => { + const item: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.DirectoryExpanded, + } + expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(true) +}) + +test('isExpandedDirectory - collapsed directory', () => { + const item: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(false) +}) + +test('isExpandedDirectory - expanding directory', () => { + const item: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.DirectoryExpanding, + } + expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(false) +}) + +test('isExpandedDirectory - file', () => { + const item: ExplorerItem = { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + } + expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(false) +}) diff --git a/packages/explorer-view/test/IsFileHandle.test.ts b/packages/explorer-view/test/IsFileHandle.test.ts new file mode 100644 index 0000000..5cf80a8 --- /dev/null +++ b/packages/explorer-view/test/IsFileHandle.test.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@jest/globals' +import { isFileHandle } from '../src/parts/IsFileHandle/IsFileHandle.ts' + +test('isFileHandle', () => { + const fileHandle = { + kind: 'file', + } as FileSystemHandle + const directoryHandle = { + kind: 'directory', + } as FileSystemHandle + expect(isFileHandle(fileHandle)).toBe(true) + expect(isFileHandle(directoryHandle)).toBe(false) +}) diff --git a/packages/explorer-view/test/IsSymbolicLink.test.ts b/packages/explorer-view/test/IsSymbolicLink.test.ts new file mode 100644 index 0000000..82bab5d --- /dev/null +++ b/packages/explorer-view/test/IsSymbolicLink.test.ts @@ -0,0 +1,59 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as IsSymbolicLink from '../src/parts/IsSymbolicLink/IsSymbolicLink.ts' + +test('isSymbolicLink - symlink', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'symlink', + path: '/symlink', + selected: false, + type: DirentType.Symlink, + } + expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(true) +}) + +test('isSymbolicLink - file', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'file.txt', + path: '/file.txt', + selected: false, + type: DirentType.File, + } + expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) +}) + +test('isSymbolicLink - directory', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'directory', + path: '/directory', + selected: false, + type: DirentType.Directory, + } + expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) +}) + +test('isSymbolicLink - symlink file', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'symlink-file', + path: '/symlink-file', + selected: false, + type: DirentType.SymLinkFile, + } + expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) +}) + +test('isSymbolicLink - symlink folder', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'symlink-folder', + path: '/symlink-folder', + selected: false, + type: DirentType.SymLinkFolder, + } + expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) +}) diff --git a/packages/explorer-view/test/IsTopLevel.test.ts b/packages/explorer-view/test/IsTopLevel.test.ts new file mode 100644 index 0000000..8fc4748 --- /dev/null +++ b/packages/explorer-view/test/IsTopLevel.test.ts @@ -0,0 +1,25 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as IsTopLevel from '../src/parts/IsTopLevel/IsTopLevel.ts' + +test('isTopLevel - depth 1', () => { + const dirent: ExplorerItem = { + depth: 1, + name: '', + path: '', + selected: false, + type: 0, + } + expect(IsTopLevel.isTopLevel(dirent)).toBe(true) +}) + +test('isTopLevel - depth 2', () => { + const dirent = { + depth: 2, + name: '', + path: '', + selected: false, + type: 0, + } + expect(IsTopLevel.isTopLevel(dirent)).toBe(false) +}) diff --git a/packages/explorer-view/test/IsUriWithinRoot.test.ts b/packages/explorer-view/test/IsUriWithinRoot.test.ts new file mode 100644 index 0000000..c95d936 --- /dev/null +++ b/packages/explorer-view/test/IsUriWithinRoot.test.ts @@ -0,0 +1,22 @@ +import { test, expect } from '@jest/globals' +import { isUriWithinRoot } from '../src/parts/IsUriWithinRoot/IsUriWithinRoot.ts' + +test('isUriWithinRoot returns true for exact root match', () => { + expect(isUriWithinRoot('/root', '/root', '/')).toBe(true) +}) + +test('isUriWithinRoot returns true for child uri', () => { + expect(isUriWithinRoot('/root', '/root/folder/file.txt', '/')).toBe(true) +}) + +test('isUriWithinRoot returns false for uri outside root', () => { + expect(isUriWithinRoot('/root', '/other/file.txt', '/')).toBe(false) +}) + +test('isUriWithinRoot returns false for matching prefix without separator', () => { + expect(isUriWithinRoot('/root', '/rooted/file.txt', '/')).toBe(false) +}) + +test('isUriWithinRoot supports roots that already end with the path separator', () => { + expect(isUriWithinRoot('/root/', '/root/folder/file.txt', '/')).toBe(true) +}) diff --git a/packages/explorer-view/test/Listen.test.ts b/packages/explorer-view/test/Listen.test.ts new file mode 100644 index 0000000..2ad7777 --- /dev/null +++ b/packages/explorer-view/test/Listen.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from '@jest/globals' +import { mockWorkerGlobalRpc } from '@lvce-editor/rpc' +import { listen } from '../src/parts/Listen/Listen.ts' + +test('listen', async () => { + const { dispose, start } = mockWorkerGlobalRpc() + const listenPromise = listen() + start() + await expect(listenPromise).resolves.toBeUndefined() + dispose() +}) diff --git a/packages/explorer-view/test/LoadContent.test.ts b/packages/explorer-view/test/LoadContent.test.ts new file mode 100644 index 0000000..d9cde44 --- /dev/null +++ b/packages/explorer-view/test/LoadContent.test.ts @@ -0,0 +1,134 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { Directory, File } from '../src/parts/DirentType/DirentType.ts' +import { loadContent } from '../src/parts/LoadContent/LoadContent.ts' + +test('loadContent clamps restored deltaY to 0 when content is shorter after reload', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'folder1', type: Directory }, + { name: 'folder2', type: Directory }, + ] + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/workspace' + }, + }) + const state: ExplorerState = createDefaultState() + + const result = await loadContent(state, { + deltaY: 4800, + expandedPaths: [], + minLineY: 240, + root: '/workspace', + }) + + expect({ + deltaY: result.deltaY, + items: result.items, + minLineY: result.minLineY, + }).toEqual({ + deltaY: 0, + items: [ + { + depth: 1, + icon: '', + name: 'folder1', + path: '/workspace/folder1', + posInSet: 1, + setSize: 2, + type: Directory, + }, + { + depth: 1, + icon: '', + name: 'folder2', + path: '/workspace/folder2', + posInSet: 2, + setSize: 2, + type: Directory, + }, + ], + minLineY: 0, + }) + expect(mockRpc.invocations).toEqual([ + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/workspace'], + ['FileSystem.readDirWithFileTypes', '/workspace'], + ]) +}) + +test('loadContent clamps restored deltaY to maxDeltaY when content is still scrollable', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file1', type: File }, + { name: 'file2', type: File }, + { name: 'file3', type: File }, + { name: 'file4', type: File }, + { name: 'file5', type: File }, + { name: 'file6', type: File }, + { name: 'file7', type: File }, + { name: 'file8', type: File }, + ] + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/workspace' + }, + }) + const state: ExplorerState = createDefaultState() + + const result = await loadContent(state, { + deltaY: 4800, + expandedPaths: [], + minLineY: 240, + root: '/workspace', + }) + + expect({ + deltaY: result.deltaY, + items: result.items, + minLineY: result.minLineY, + }).toEqual({ + deltaY: 60, + items: [ + { depth: 1, icon: '', name: 'file1', path: '/workspace/file1', posInSet: 1, setSize: 8, type: File }, + { depth: 1, icon: '', name: 'file2', path: '/workspace/file2', posInSet: 2, setSize: 8, type: File }, + { depth: 1, icon: '', name: 'file3', path: '/workspace/file3', posInSet: 3, setSize: 8, type: File }, + { depth: 1, icon: '', name: 'file4', path: '/workspace/file4', posInSet: 4, setSize: 8, type: File }, + { depth: 1, icon: '', name: 'file5', path: '/workspace/file5', posInSet: 5, setSize: 8, type: File }, + { depth: 1, icon: '', name: 'file6', path: '/workspace/file6', posInSet: 6, setSize: 8, type: File }, + { depth: 1, icon: '', name: 'file7', path: '/workspace/file7', posInSet: 7, setSize: 8, type: File }, + { depth: 1, icon: '', name: 'file8', path: '/workspace/file8', posInSet: 8, setSize: 8, type: File }, + ], + minLineY: 3, + }) + expect(mockRpc.invocations).toEqual([ + ['Preferences.get', 'explorer.useChevrons'], + ['Preferences.get', 'explorer.confirmdelete'], + ['Preferences.get', 'explorer.confirmpaste'], + ['Preferences.get', 'explorer.sourceControlDecorations'], + ['Workspace.getPath'], + ['FileSystem.getPathSeparator', '/workspace'], + ['FileSystem.readDirWithFileTypes', '/workspace'], + ]) +}) diff --git a/packages/explorer-view/test/Main.test.ts b/packages/explorer-view/test/Main.test.ts new file mode 100644 index 0000000..8f5562c --- /dev/null +++ b/packages/explorer-view/test/Main.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from '@jest/globals' +import { mockWorkerGlobalRpc } from '@lvce-editor/rpc' +import { main } from '../src/parts/Main/Main.ts' + +test('main', async () => { + const { dispose, start } = mockWorkerGlobalRpc() + const mainPromise = main() + start() + await expect(mainPromise).resolves.toBeUndefined() + dispose() +}) diff --git a/packages/explorer-view/test/MakeExpanded.test.ts b/packages/explorer-view/test/MakeExpanded.test.ts new file mode 100644 index 0000000..024c61b --- /dev/null +++ b/packages/explorer-view/test/MakeExpanded.test.ts @@ -0,0 +1,34 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { makeExpanded } from '../src/parts/MakeExpanded/MakeExpanded.ts' + +test('makeExpanded - directory', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.Directory, + } + const result = makeExpanded(dirent) + expect(result).toEqual({ + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: DirentType.DirectoryExpanded, + }) +}) + +test('makeExpanded - file', () => { + const dirent: ExplorerItem = { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + } + const result = makeExpanded(dirent) + expect(result).toEqual(dirent) +}) diff --git a/packages/explorer-view/test/NewDirent.test.ts b/packages/explorer-view/test/NewDirent.test.ts new file mode 100644 index 0000000..05ae7b1 --- /dev/null +++ b/packages/explorer-view/test/NewDirent.test.ts @@ -0,0 +1,224 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { newDirent } from '../src/parts/NewDirent/NewDirent.ts' + +const handleFileIcons = (requests: readonly any[]): readonly string[] => { + return requests.map((param) => { + if (param.type === 2) { + return `folder-icon` + } + return `file-icon` + }) +} + +test('newDirent sets focus and updates state when no item is focused', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() {}, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'(...params: any[]) { + return handleFileIcons(params[0]) + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + items: [], + } + const mockEditingType = 1 + + const result = await newDirent(mockState, mockEditingType) + expect(mockRpc.invocations).toEqual([]) + expect(result).toEqual({ + ...mockState, + editingIndex: 0, + editingType: mockEditingType, + editingValue: '', + focus: 2, + focusedIndex: 0, + items: [ + { + depth: 0, + icon: '', + name: '', + path: '/', + posInSet: 1, + selected: false, + setSize: 1, + type: 107, + }, + ], + }) +}) + +test('newDirent handles directory click when focused item is a directory', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() {}, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'(...params: any[]) { + return handleFileIcons(params[0]) + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], + } + const mockEditingType = 1 + + const result = await newDirent(mockState, mockEditingType) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) + expect(result).toEqual({ + ...mockState, + editingIndex: 1, + editingType: mockEditingType, + editingValue: '', + focus: 2, + focusedIndex: 1, + items: [ + { depth: 0, name: 'test', path: '/test', selected: false, setSize: 1, type: DirentType.DirectoryExpanded }, + { + depth: 1, + icon: '', + name: '', + path: '/test', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.EditingFile, + }, + ], + visibleExplorerItems: expect.anything(), + }) +}) + +test('newDirent updates state when focused item is not a directory', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() {}, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'(...params: any[]) { + return handleFileIcons(params[0]) + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + const mockEditingType = 1 + + const result = await newDirent(mockState, mockEditingType) + expect(mockRpc.invocations).toEqual([]) + expect(result).toEqual({ + ...mockState, + editingIndex: 1, + editingType: mockEditingType, + editingValue: '', + focus: 2, + focusedIndex: 1, + items: [ + { + depth: 0, + name: 'test.txt', + path: '/test.txt', + selected: false, + type: DirentType.File, + }, + { + depth: 0, + icon: '', + name: '', + path: '/', + posInSet: 1, + selected: false, + setSize: 1, + type: DirentType.EditingFile, + }, + ], + visibleExplorerItems: expect.anything(), + }) +}) + +test('newDirent expands a closed folder when creating a file inside it', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() {}, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'(...params: any[]) { + return handleFileIcons(params[0]) + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.Directory }], + } + const mockEditingType = 1 + + const result = await newDirent(mockState, mockEditingType) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/folder']]) + // The folder should be expanded (type changed to DirectoryExpanded) + expect(result.items[0].type).toBe(DirentType.DirectoryExpanded) + expect(result.editingIndex).toBe(1) + expect(result.items[1].type).toBe(DirentType.EditingFile) +}) diff --git a/packages/explorer-view/test/NewFile.test.ts b/packages/explorer-view/test/NewFile.test.ts new file mode 100644 index 0000000..1561a5e --- /dev/null +++ b/packages/explorer-view/test/NewFile.test.ts @@ -0,0 +1,79 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import { newFile } from '../src/parts/NewFile/NewFile.ts' + +test('newFile', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() { + return undefined + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'(requests: readonly any[]) { + return requests.map((param) => { + if (param.type === 2) { + return `folder-icon` + } + return `file-icon` + }) + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], + maxLineY: 1, + } + + const result = await newFile(state) + expect(result).toEqual({ + ...state, + editingIndex: 1, + editingType: ExplorerEditingType.CreateFile, + editingValue: '', + focus: 2, + focusedIndex: 1, + items: [ + { + depth: 0, + name: 'testfolder', + path: '/testfolder', + selected: false, + setSize: 1, + type: DirentType.DirectoryExpanded, + }, + { + depth: 1, + icon: '', + name: '', + path: '/testfolder', + posInSet: 1, + selected: false, + setSize: 2, + type: DirentType.EditingFile, + }, + ], + visibleExplorerItems: expect.anything(), + }) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/testfolder']]) +}) diff --git a/packages/explorer-view/test/NewFolder.test.ts b/packages/explorer-view/test/NewFolder.test.ts new file mode 100644 index 0000000..ecffcc0 --- /dev/null +++ b/packages/explorer-view/test/NewFolder.test.ts @@ -0,0 +1,60 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import { newFolder } from '../src/parts/NewFolder/NewFolder.ts' + +test('newFolder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.getPathSeparator'() { + return '/' + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'Focus.setFocus'() { + return undefined + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [''] + }, + 'Preferences.get'() { + return false + }, + 'Workspace.getPath'() { + return '/new/path' + }, + }) + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + items: [], + } + + const result = await newFolder(mockState) + expect(result).toEqual({ + ...mockState, + editingIndex: 0, + editingType: ExplorerEditingType.CreateFolder, + editingValue: '', + focus: 2, + focusedIndex: 0, + items: [ + { + depth: 0, + icon: '', + name: '', + path: '/', + posInSet: 1, + selected: false, + setSize: 1, + type: 103, + }, + ], + }) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/NormalizeDecorations.test.ts b/packages/explorer-view/test/NormalizeDecorations.test.ts new file mode 100644 index 0000000..6dd721f --- /dev/null +++ b/packages/explorer-view/test/NormalizeDecorations.test.ts @@ -0,0 +1,139 @@ +import { test, expect } from '@jest/globals' +import type { FileDecoration } from '../src/parts/FileDecoration/FileDecoration.ts' +import { normalizeDecorations } from '../src/parts/NormalizeDecorations/NormalizeDecorations.ts' + +test('normalizeDecorations - returns empty array when input is null', () => { + const result = normalizeDecorations(null as any) + expect(result).toEqual([]) +}) + +test('normalizeDecorations - returns empty array when input is undefined', () => { + const result = normalizeDecorations(undefined as any) + expect(result).toEqual([]) +}) + +test('normalizeDecorations - returns empty array when input is not an array', () => { + const result = normalizeDecorations('not an array' as any) + expect(result).toEqual([]) +}) + +test('normalizeDecorations - returns empty array when input is an empty array', () => { + const result = normalizeDecorations([]) + expect(result).toEqual([]) +}) + +test('normalizeDecorations - filters out invalid decorations (null)', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + null as any, + { decoration: 'added', uri: 'file:///test2.txt' }, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 'file:///test2.txt' }, + ]) +}) + +test('normalizeDecorations - filters out invalid decorations (undefined)', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + undefined as any, + { decoration: 'added', uri: 'file:///test2.txt' }, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 'file:///test2.txt' }, + ]) +}) + +test('normalizeDecorations - filters out decorations with missing decoration property', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + { uri: 'file:///test2.txt' } as any, + { decoration: 'added', uri: 'file:///test3.txt' }, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 'file:///test3.txt' }, + ]) +}) + +test('normalizeDecorations - filters out decorations with missing uri property', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added' } as any, + { decoration: 'deleted', uri: 'file:///test3.txt' }, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'deleted', uri: 'file:///test3.txt' }, + ]) +}) + +test('normalizeDecorations - filters out decorations with non-string decoration property', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 123, uri: 'file:///test2.txt' } as any, + { decoration: 'added', uri: 'file:///test3.txt' }, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 'file:///test3.txt' }, + ]) +}) + +test('normalizeDecorations - filters out decorations with non-string uri property', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 123 } as any, + { decoration: 'deleted', uri: 'file:///test3.txt' }, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'deleted', uri: 'file:///test3.txt' }, + ]) +}) + +test('normalizeDecorations - returns all valid decorations', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 'file:///test2.txt' }, + { decoration: 'deleted', uri: 'file:///test3.txt' }, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 'file:///test2.txt' }, + { decoration: 'deleted', uri: 'file:///test3.txt' }, + ]) +}) + +test('normalizeDecorations - handles mixed valid and invalid decorations', () => { + const decorations: FileDecoration[] = [ + { decoration: 'modified', uri: 'file:///test.txt' }, + null as any, + { decoration: 'added', uri: 'file:///test2.txt' }, + undefined as any, + { decoration: 'deleted' } as any, + { decoration: 'renamed', uri: 'file:///test3.txt' }, + { uri: 'file:///test4.txt' } as any, + ] + const result = normalizeDecorations(decorations) + expect(result).toEqual([ + { decoration: 'modified', uri: 'file:///test.txt' }, + { decoration: 'added', uri: 'file:///test2.txt' }, + { decoration: 'renamed', uri: 'file:///test3.txt' }, + ]) +}) + +test('normalizeDecorations - returns empty array when all decorations are invalid', () => { + const decorations: FileDecoration[] = [null as any, undefined as any, { decoration: 'added' } as any, { uri: 'file:///test.txt' } as any] + const result = normalizeDecorations(decorations) + expect(result).toEqual([]) +}) diff --git a/packages/explorer-view/test/OpenContainingFolder.test.ts b/packages/explorer-view/test/OpenContainingFolder.test.ts new file mode 100644 index 0000000..5b324e8 --- /dev/null +++ b/packages/explorer-view/test/OpenContainingFolder.test.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker as RpcRendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { openContainingFolder } from '../src/parts/OpenContainingFolder/OpenContainingFolder.ts' + +test('openContainingFolder', async () => { + using mockRpc = RpcRendererWorker.registerMockRpc({ + 'OpenNativeFolder.openNativeFolder'() {}, + }) + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: 1 }], + } + const result = await openContainingFolder(mockState) + expect(mockRpc.invocations).toEqual(expect.arrayContaining([['OpenNativeFolder.openNativeFolder', '']])) + expect(result).toBe(mockState) +}) diff --git a/packages/explorer-view/test/OpenDiff.test.ts b/packages/explorer-view/test/OpenDiff.test.ts new file mode 100644 index 0000000..b75a5c2 --- /dev/null +++ b/packages/explorer-view/test/OpenDiff.test.ts @@ -0,0 +1,13 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { openDiff } from '../src/parts/OpenDiff/OpenDiff.ts' + +test('openDiff opens file diff uri', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Main.openUri'() {}, + }) + + await openDiff('/left.txt', '/right.txt', true) + + expect(mockRpc.invocations).toEqual([['Main.openUri', 'diff:///left.txt<->/right.txt', true]]) +}) diff --git a/packages/explorer-view/test/OpenUri.test.ts b/packages/explorer-view/test/OpenUri.test.ts new file mode 100644 index 0000000..a1cba7a --- /dev/null +++ b/packages/explorer-view/test/OpenUri.test.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { openUri } from '../src/parts/OpenUri/OpenUri.ts' + +test('openUri calls ParentRpc.invoke with correct parameters', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Main.openUri'() {}, + }) + const mockUri = 'file:///test.txt' + const mockFocus = true + await openUri(mockUri, mockFocus) + expect(mockRpc.invocations).toEqual([['Main.openUri', mockUri, mockFocus]]) +}) + +test('openUri calls ParentRpc.invoke with focus false', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'Main.openUri'() {}, + }) + const mockUri = 'file:///test.txt' + const mockFocus = false + await openUri(mockUri, mockFocus) + expect(mockRpc.invocations).toEqual([['Main.openUri', mockUri, mockFocus]]) +}) diff --git a/packages/explorer-view/test/OrderDirents.test.ts b/packages/explorer-view/test/OrderDirents.test.ts new file mode 100644 index 0000000..99e6f95 --- /dev/null +++ b/packages/explorer-view/test/OrderDirents.test.ts @@ -0,0 +1,56 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import { orderDirents } from '../src/parts/OrderDirents/OrderDirents.ts' + +test('empty array returns empty array', () => { + expect(orderDirents([])).toEqual([]) +}) + +test('orders single top level item', () => { + const input: readonly ExplorerItem[] = [{ depth: 1, name: 'file1', path: '/file1', selected: false, type: 1 }] + expect(orderDirents(input)).toEqual(input) +}) + +test('orders multiple top level items', () => { + const input: readonly ExplorerItem[] = [ + { depth: 1, name: 'file2', path: '/file2', selected: false, type: 1 }, + { depth: 1, name: 'file1', path: '/file1', selected: false, type: 1 }, + ] + const expected = [ + { depth: 1, name: 'file2', path: '/file2', selected: false, type: 1 }, + { depth: 1, name: 'file1', path: '/file1', selected: false, type: 1 }, + ] + expect(orderDirents(input)).toEqual(expected) +}) + +test('orders nested items correctly', () => { + const input: readonly ExplorerItem[] = [ + { depth: 2, name: 'file1', path: '/folder1/file1', selected: false, type: 1 }, + { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, + { depth: 2, name: 'file2', path: '/folder2/file2', selected: false, type: 1 }, + { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, + ] + const expected = [ + { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, + { depth: 2, name: 'file1', path: '/folder1/file1', selected: false, type: 1 }, + { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, + { depth: 2, name: 'file2', path: '/folder2/file2', selected: false, type: 1 }, + ] + expect(orderDirents(input)).toEqual(expected) +}) + +test('orders deeply nested items correctly', () => { + const input: readonly ExplorerItem[] = [ + { depth: 3, name: 'file1', path: '/folder1/subfolder/file1', selected: false, type: 1 }, + { depth: 2, name: 'subfolder', path: '/folder1/subfolder', selected: false, type: 2 }, + { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, + { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, + ] + const expected = [ + { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, + { depth: 2, name: 'subfolder', path: '/folder1/subfolder', selected: false, type: 2 }, + { depth: 3, name: 'file1', path: '/folder1/subfolder/file1', selected: false, type: 1 }, + { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, + ] + expect(orderDirents(input)).toEqual(expected) +}) diff --git a/packages/explorer-view/test/PasteShouldMove.test.ts b/packages/explorer-view/test/PasteShouldMove.test.ts new file mode 100644 index 0000000..abcde8c --- /dev/null +++ b/packages/explorer-view/test/PasteShouldMove.test.ts @@ -0,0 +1,73 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { handleCopy } from '../src/parts/HandleCopy/HandleCopy.ts' +import { handleCut } from '../src/parts/HandleCut/HandleCut.ts' +import { handlePaste } from '../src/parts/HandlePaste/HandlePaste.ts' + +test('pasteShouldMove should be true after cut operation', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeNativeFiles'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + + const result = await handleCut(state) + + expect(result.pasteShouldMove).toBe(true) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'cut', ['/test.txt']]]) +}) + +test('pasteShouldMove should be false after copy operation', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'ClipBoard.writeNativeFiles'() {}, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + + const result = await handleCopy(state) + + expect(result.pasteShouldMove).toBe(false) + expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'copy', ['/test.txt']]]) +}) + +test('pasteShouldMove should be reset to false after paste operation', async () => { + RendererWorker.registerMockRpc({ + 'ClipBoard.readNativeFiles'() { + return { + files: ['/source/file.txt'], + type: 'copy', + } + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.rename'() {}, + 'IconTheme.getIcons'() { + return [''] + }, + 'Preferences.get'() { + return false + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, // No item focused, use root as target + pasteShouldMove: true, // Simulate state after cut operation + } + + const result = await handlePaste(state) + + expect(result.pasteShouldMove).toBe(false) +}) diff --git a/packages/explorer-view/test/Path.test.ts b/packages/explorer-view/test/Path.test.ts new file mode 100644 index 0000000..a8b2785 --- /dev/null +++ b/packages/explorer-view/test/Path.test.ts @@ -0,0 +1,25 @@ +import { test, expect } from '@jest/globals' +import { dirname, join, getBaseName } from '../src/parts/Path/Path.ts' + +test('dirname returns parent directory', () => { + expect(dirname('/', '/home/user/file.txt')).toBe('/home/user') + expect(dirname('/', '/home/user/')).toBe('/home/user') + expect(dirname('/', '/home/user')).toBe('/home') + expect(dirname('/', 'file.txt')).toBe('file.txt') + expect(dirname('/', '/')).toBe('') +}) + +test('join combines path parts', () => { + expect(join('/', 'home', 'user', 'file.txt')).toBe('home/user/file.txt') + expect(join('/', 'home', 'user', '')).toBe('home/user/') + expect(join('/', 'home', 'user')).toBe('home/user') + expect(join('/', '', 'home', 'user')).toBe('/home/user') +}) + +test('getBaseName returns last path component', () => { + expect(getBaseName('/', '/home/user/file.txt')).toBe('file.txt') + expect(getBaseName('/', '/home/user/')).toBe('') + expect(getBaseName('/', '/home/user')).toBe('user') + expect(getBaseName('/', 'file.txt')).toBe('file.txt') + expect(getBaseName('/', '/')).toBe('') +}) diff --git a/packages/explorer-view/test/Refresh.test.ts b/packages/explorer-view/test/Refresh.test.ts new file mode 100644 index 0000000..1b0b366 --- /dev/null +++ b/packages/explorer-view/test/Refresh.test.ts @@ -0,0 +1,290 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { DirectoryExpanded, File } from '../src/parts/DirentType/DirentType.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { refresh } from '../src/parts/Refresh/Refresh.ts' + +test('refresh - empty state', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = createDefaultState() + const result = await refresh(state) + expect(result.items).toHaveLength(0) + expect(result.icons).toHaveLength(0) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/']]) +}) + +test('refresh - with top level items', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file1', type: DirentType.File }, + { name: 'file2', type: DirentType.File }, + ] + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = createDefaultState() + const result = await refresh(state) + expect(result.items).toHaveLength(2) + expect(result.items[0].name).toBe('file1') + expect(result.items[1].name).toBe('file2') + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/']]) +}) + +test('refresh - preserve expanded folder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'(_path: string) { + if (_path === '/') { + return [{ name: 'folder1', type: DirentType.Directory }] + } + if (_path === '/folder1') { + return [ + { name: 'file1.txt', type: 'file' }, + { name: 'file2.txt', type: 'file' }, + ] + } + return [] + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, + { depth: 1, name: 'file2.txt', path: '/folder1/file2.txt', selected: false, type: File }, + ], + } + + const result = await refresh(state) + expect(result.items).toHaveLength(3) + expect(result.items[0].name).toBe('folder1') + expect(result.items[0].type).toBe(DirectoryExpanded) + expect(result.items[1].name).toBe('file1.txt') + expect(result.items[2].name).toBe('file2.txt') + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/'], + ['FileSystem.readDirWithFileTypes', '/folder1'], + ]) +}) + +test('refresh - remove expanded folder that no longer exists', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [{ name: 'file1.txt', type: DirentType.File }] + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, + ], + } + + const result = await refresh(state) + expect(result.items).toHaveLength(1) + expect(result.items[0].name).toBe('file1.txt') + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/'], + ['FileSystem.readDirWithFileTypes', '/folder1'], + ]) +}) + +test('refresh - nested expanded folders', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'(path: string) { + if (path === '/') { + return [{ name: 'folder1', type: DirentType.Directory }] + } + if (path === '/folder1') { + return [{ name: 'folder2', type: DirentType.Directory }] + } + if (path === '/folder1/folder2') { + return [{ name: 'file1.txt', type: DirentType.File }] + } + return [] + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 1, name: 'folder2', path: '/folder1/folder2', selected: false, type: DirectoryExpanded }, + { depth: 2, name: 'file1.txt', path: '/folder1/folder2/file1.txt', selected: false, type: File }, + ], + } + + const result = await refresh(state) + expect(result.items).toHaveLength(3) + expect(result.items[0].name).toBe('folder1') + expect(result.items[0].type).toBe(DirectoryExpanded) + expect(result.items[1].name).toBe('folder2') + expect(result.items[1].type).toBe(DirectoryExpanded) + expect(result.items[2].name).toBe('file1.txt') + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/'], + ['FileSystem.readDirWithFileTypes', '/folder1'], + ['FileSystem.readDirWithFileTypes', '/folder1/folder2'], + ]) +}) + +test('refresh - preserve directory types', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'(path: string) { + if (path === '/') { + return [ + { name: 'folder1', type: DirentType.Directory }, + { name: 'file1.txt', type: DirentType.File }, + ] + } + if (path === '/folder1') { + return [ + { name: 'subfolder', type: DirentType.Directory }, + { name: 'file2.txt', type: DirentType.File }, + ] + } + if (path === '/folder1/subfolder') { + return [{ name: 'file3.txt', type: DirentType.File }] + } + return [] + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 1, name: 'subfolder', path: '/folder1/subfolder', selected: false, type: DirectoryExpanded }, + { depth: 2, name: 'file3.txt', path: '/folder1/subfolder/file3.txt', selected: false, type: File }, + { depth: 1, name: 'file2.txt', path: '/folder1/file2.txt', selected: false, type: File }, + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, + ], + } + + const result = await refresh(state) + expect(result.items).toHaveLength(5) + expect(result.items[0].name).toBe('folder1') + expect(result.items[0].type).toBe(DirectoryExpanded) + expect(result.items[1].name).toBe('subfolder') + expect(result.items[1].type).toBe(DirectoryExpanded) + expect(result.items[2].name).toBe('file3.txt') + expect(result.items[2].type).toBe(File) + expect(result.items[3].name).toBe('file2.txt') + expect(result.items[3].type).toBe(File) + expect(result.items[4].name).toBe('file1.txt') + expect(result.items[4].type).toBe(File) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/'], + ['FileSystem.readDirWithFileTypes', '/folder1'], + ['FileSystem.readDirWithFileTypes', '/folder1/subfolder'], + ]) +}) + +test('refresh - check filesystem response', async () => { + const methodCalls: string[] = [] + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'(path: string) { + methodCalls.push('FileSystem.readDirWithFileTypes') + if (path === '/') { + return [ + { name: 'folder1', type: DirentType.Directory }, + { name: 'file1.txt', type: DirentType.File }, + ] + } + return [] + }, + 'IconTheme.getFileIcon'() { + methodCalls.push('IconTheme.getFileIcon') + return '' + }, + 'IconTheme.getFolderIcon'() { + methodCalls.push('IconTheme.getFolderIcon') + return '' + }, + 'IconTheme.getIcons'() { + methodCalls.push('IconTheme.getIcons') + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, + ], + } + + const result = await refresh(state) + expect(methodCalls).toContain('FileSystem.readDirWithFileTypes') + expect(result.items[0].type).toBe(DirectoryExpanded) + expect(result.items[1].type).toBe(File) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/'], + ['FileSystem.readDirWithFileTypes', '/folder1'], + ]) +}) diff --git a/packages/explorer-view/test/RefreshChildDirents.test.ts b/packages/explorer-view/test/RefreshChildDirents.test.ts new file mode 100644 index 0000000..cfbd2dc --- /dev/null +++ b/packages/explorer-view/test/RefreshChildDirents.test.ts @@ -0,0 +1,55 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { Directory, DirectoryExpanded } from '../src/parts/DirentType/DirentType.ts' +import { refreshChildDirents } from '../src/parts/RefreshChildDirents/RefreshChildDirents.ts' + +test('refreshChildDirents - basic', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file1.txt', type: 'file' }, + { name: 'folder1', type: 'directory' }, + ] + }, + }) + + const folder = { depth: 0, name: 'test', path: '/test', selected: false, type: Directory } + const result = await refreshChildDirents(folder, '/', []) + expect(result).toHaveLength(2) + expect(result[0].name).toBe('file1.txt') + expect(result[0].path).toBe('/test/file1.txt') + expect(result[0].depth).toBe(1) + expect(result[1].name).toBe('folder1') + expect(result[1].path).toBe('/test/folder1') + expect(result[1].depth).toBe(1) + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) +}) + +test('refreshChildDirents - with expanded folder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'(path?: string) { + if (path === '/test') { + return [{ name: 'folder1', type: 'directory' }] + } + if (path === '/test/folder1') { + return [{ name: 'file1.txt', type: 'file' }] + } + return [] + }, + }) + + const folder = { depth: 0, name: 'test', path: '/test', selected: false, type: Directory } + const result = await refreshChildDirents(folder, '/', ['/test/folder1']) + expect(result).toHaveLength(2) + expect(result[0].name).toBe('folder1') + expect(result[0].path).toBe('/test/folder1') + expect(result[0].type).toBe(DirectoryExpanded) + expect(result[0].depth).toBe(1) + expect(result[1].name).toBe('file1.txt') + expect(result[1].path).toBe('/test/folder1/file1.txt') + expect(result[1].depth).toBe(2) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/test'], + ['FileSystem.readDirWithFileTypes', '/test/folder1'], + ]) +}) diff --git a/packages/explorer-view/test/RemoveDirent.test.ts b/packages/explorer-view/test/RemoveDirent.test.ts new file mode 100644 index 0000000..727b874 --- /dev/null +++ b/packages/explorer-view/test/RemoveDirent.test.ts @@ -0,0 +1,417 @@ +import { test, expect } from '@jest/globals' +import { jest } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { Directory, DirectoryExpanded, File } from '../src/parts/DirentType/DirentType.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { removeDirent } from '../src/parts/RemoveDirent/RemoveDirent.ts' + +test('removeDirent - removes focused item', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(0) + expect(result.focusedIndex).toBe(-1) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.remove', '/file1.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('removeDirent - removes multiple selected items', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [ + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: true, type: File }, + { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, + ], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(0) + expect(result.focusedIndex).toBe(-1) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.remove', '/file1.txt'], + ['FileSystem.remove', '/file2.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('removeDirent - removes focused item and selected items', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [ + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, + { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, + { depth: 0, name: 'file3.txt', path: '/file3.txt', selected: true, type: File }, + ], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(0) + expect(result.focusedIndex).toBe(-1) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.remove', '/file1.txt'], + ['FileSystem.remove', '/file2.txt'], + ['FileSystem.remove', '/file3.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('remove file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [{ name: 'folder1', type: DirentType.Directory }] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 1, + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: Directory }, + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, + ], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(1) + expect(result.items[0].name).toBe('folder1') + expect(result.focusedIndex).toBe(0) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.remove', '/file1.txt'], + ['FileSystem.readDirWithFileTypes', '/'], + ]) +}) + +test('remove folder with children', async () => { + RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, + ], + root: '/', + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(0) + expect(result.focusedIndex).toBe(-1) +}) + +test('remove file from expanded folder', async () => { + RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'(path: string) { + if (path === '/') { + return [{ name: 'folder1', type: DirentType.Directory }] + } + if (path === '/folder1') { + return [] + } + return [] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 1, + items: [ + { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, + { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, + ], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(1) + expect(result.items[0].name).toBe('folder1') + expect(result.items[0].type).toBe(DirectoryExpanded) + expect(result.focusedIndex).toBe(0) +}) + +test.skip('removeDirent - with confirmation enabled and user confirms', async () => { + RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'(_message?: string) { + return true + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(0) + expect(result.focusedIndex).toBe(-1) +}) + +test.skip('removeDirent - with confirmation enabled and user cancels', async () => { + RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'(_message?: string) { + return false + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [ + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: true, type: File }, + { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, + ], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(2) + expect(result.focusedIndex).toBe(0) +}) + +test('removeDirent - shows error message when file operation fails', async () => { + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) + const confirmFn = jest.fn() + confirmFn.mockImplementation(() => true) + RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'(message?: string) { + return confirmFn(message) + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + throw new Error('Permission denied') + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], + } + + const result = await removeDirent(state) + expect(result).toBe(state) + expect(confirmFn).toHaveBeenCalledWith('Error: Permission denied') + expect(consoleErrorSpy).toHaveBeenCalledTimes(1) + expect(consoleErrorSpy).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('Failed to apply file operations: Permission denied'), + }), + ) + consoleErrorSpy.mockRestore() +}) + +test('removeDirent - shows error message for multiple files when operation fails', async () => { + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) + const confirmFn = jest.fn() + confirmFn.mockImplementation(() => true) + RendererWorker.registerMockRpc({ + 'ConfirmPrompt.prompt'(message?: string) { + return confirmFn(message) + }, + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + throw new Error('Access denied') + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [ + { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: true, type: File }, + { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, + ], + } + + const result = await removeDirent(state) + expect(result).toBe(state) + expect(confirmFn).toHaveBeenCalledWith('Error: Access denied') + expect(consoleErrorSpy).toHaveBeenCalledTimes(1) + expect(consoleErrorSpy).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('Failed to apply file operations: Access denied'), + }), + ) + consoleErrorSpy.mockRestore() +}) + +test('removeDirent - continues normally when no error occurs', async () => { + RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + 'FileSystem.remove'() { + return + }, + 'IconTheme.getFileIcon'() { + return '' + }, + 'IconTheme.getFolderIcon'() { + return '' + }, + 'IconTheme.getIcons'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + confirmDelete: false, + focusedIndex: 0, + items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], + } + + const result = await removeDirent(state) + expect(result.items).toHaveLength(0) + expect(result.focusedIndex).toBe(-1) +}) diff --git a/packages/explorer-view/test/RenameDirent.test.ts b/packages/explorer-view/test/RenameDirent.test.ts new file mode 100644 index 0000000..d873733 --- /dev/null +++ b/packages/explorer-view/test/RenameDirent.test.ts @@ -0,0 +1,89 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' +import * as InputSource from '../src/parts/InputSource/InputSource.ts' +import { renameDirent } from '../src/parts/RenameDirent/RenameDirent.ts' + +test('renameDirent updates state with editing properties', async () => { + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + icons: [''], + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + + const result = await renameDirent(mockState) + expect(result).toEqual({ + ...mockState, + editingIcon: '', + editingIndex: 0, + editingSelectionEnd: 4, + editingSelectionStart: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'test.txt', + focus: FocusId.Input, + inputSource: InputSource.Script, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.EditingFile }], + }) +}) + +test('renameDirent updates state with editing properties for folder', async () => { + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + icons: [''], + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], + } + + const result = await renameDirent(mockState) + expect(result).toEqual({ + ...mockState, + editingIcon: '', + editingIndex: 0, + editingSelectionEnd: 4, + editingSelectionStart: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'test', + focus: FocusId.Input, + inputSource: InputSource.Script, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.EditingFolder }], + }) +}) + +test('renameDirent handles empty state', async () => { + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: -1, + items: [], + } + + const result = await renameDirent(mockState) + expect(result).toBe(mockState) +}) + +test('renameDirent preserves icon when entering edit mode', async () => { + const mockState: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + icons: ['file-icon'], + items: [{ depth: 0, icon: 'file-icon', name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + minLineY: 0, + } + + const result = await renameDirent(mockState) + expect(result).toEqual({ + ...mockState, + editingIcon: 'file-icon', + editingIndex: 0, + editingSelectionEnd: 4, + editingSelectionStart: 0, + editingType: ExplorerEditingType.Rename, + editingValue: 'test.txt', + focus: FocusId.Input, + inputSource: InputSource.Script, + items: [{ depth: 0, icon: 'file-icon', name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.EditingFile }], + }) +}) diff --git a/packages/explorer-view/test/Render2.test.ts b/packages/explorer-view/test/Render2.test.ts new file mode 100644 index 0000000..b3455e0 --- /dev/null +++ b/packages/explorer-view/test/Render2.test.ts @@ -0,0 +1,51 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DiffType from '../src/parts/DiffType/DiffType.ts' +import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' +import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' +import * as Render2 from '../src/parts/Render2/Render2.ts' + +test('render2 - basic', () => { + const uid = 1 + const diffResult = [DiffType.RenderItems, DiffType.RenderFocus] + const oldState = createDefaultState() + const newState = { ...oldState } + ExplorerStates.set(uid, oldState, newState) + const result = Render2.render2(uid, diffResult) + expect(result).toEqual([ + [ + 'Viewlet.setDom2', + 1, + [ + { + childCount: 1, + className: 'Viewlet Explorer', + role: 'none', + type: 4, + }, + { + ariaActiveDescendant: 'TreeItemActive', + ariaLabel: 'Files Explorer', + childCount: 0, + className: 'ListItems', + onBlur: DomEventListenerFunctions.HandleListBlur, + onClick: DomEventListenerFunctions.HandleClick, + onContextMenu: DomEventListenerFunctions.HandleContextMenu, + onDblClick: DomEventListenerFunctions.HandleDoubleClick, + onDragEnd: DomEventListenerFunctions.HandleDragEnd, + onDragLeave: DomEventListenerFunctions.HandleDragLeave, + onDragOver: DomEventListenerFunctions.HandleDragOver, + onDragStart: DomEventListenerFunctions.HandleDragStart, + onDrop: DomEventListenerFunctions.HandleDrop, + onFocus: DomEventListenerFunctions.HandleListFocus, + onPointerDown: DomEventListenerFunctions.HandlePointerDown, + onWheel: DomEventListenerFunctions.HandleWheel, + // onKeyDown: 'handleListKeyDown', + role: 'tree', + tabIndex: 0, + type: 4, + }, + ], + ], + ]) +}) diff --git a/packages/explorer-view/test/RenderActions2.test.ts b/packages/explorer-view/test/RenderActions2.test.ts new file mode 100644 index 0000000..b5df30a --- /dev/null +++ b/packages/explorer-view/test/RenderActions2.test.ts @@ -0,0 +1,48 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' +import { renderActions } from '../src/parts/RenderActions2/RenderActions2.ts' + +test('should render actions for valid uid', () => { + const uid = 123 + const mockState = { ...createDefaultState(), root: '/test/path' } + + // Set up the state in ExplorerStates + ExplorerStates.set(uid, mockState, mockState) + + const result = renderActions(uid) + + // The function should return an array of VirtualDomNode + expect(Array.isArray(result)).toBe(true) + expect(result.length).toBeGreaterThan(0) + + // Check that the first element is the actions container + expect(result[0]).toHaveProperty('type') + expect(result[0]).toHaveProperty('className') +}) + +test('should handle state with empty root', () => { + const uid = 456 + const mockState = { ...createDefaultState(), root: '' } + + ExplorerStates.set(uid, mockState, mockState) + + const result = renderActions(uid) + + // When root is empty, getActions should return empty array + // but getActionsVirtualDom should still return the container + expect(Array.isArray(result)).toBe(true) + expect(result.length).toBeGreaterThan(0) +}) + +test('should handle different root paths', () => { + const uid = 789 + const mockState = { ...createDefaultState(), root: '/some/other/path' } + + ExplorerStates.set(uid, mockState, mockState) + + const result = renderActions(uid) + + expect(Array.isArray(result)).toBe(true) + expect(result.length).toBeGreaterThan(0) +}) diff --git a/packages/explorer-view/test/RenderCss.test.ts b/packages/explorer-view/test/RenderCss.test.ts new file mode 100644 index 0000000..872dac9 --- /dev/null +++ b/packages/explorer-view/test/RenderCss.test.ts @@ -0,0 +1,308 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { renderCss } from '../src/parts/RenderCss/RenderCss.ts' + +test('renderCss - basic with empty visibleExplorerItems', () => { + const oldState = createDefaultState() + const newState: ExplorerState = { + ...createDefaultState(), + scrollBarHeight: 20, + uid: 123, + visibleExplorerItems: [], + } + const result = renderCss(oldState, newState) + expect(result).toEqual([ + 'Viewlet.setCss', + 123, + `.Explorer { + --ScrollBarThumbHeight: 0px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 20px; + --ErrorMessageLeft: 48px; + --ErrorMessageWidth: 52px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +}`, + ]) +}) + +test('renderCss - with single visibleExplorerItem', () => { + const oldState = createDefaultState() + const newState: ExplorerState = { + ...createDefaultState(), + scrollBarHeight: 15, + uid: 456, + visibleExplorerItems: [ + { + ariaExpanded: undefined, + chevron: 0, + className: 'file', + depth: 0, + hasEditingError: false, + icon: 'file', + id: '1', + indent: 10, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'test.txt', + path: '/test.txt', + posInSet: 1, + selected: false, + setSize: 1, + }, + ], + } + const result = renderCss(oldState, newState) + expect(result).toEqual([ + 'Viewlet.setCss', + 456, + `.Explorer { + --ScrollBarThumbHeight: 0px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 20px; + --ErrorMessageLeft: 48px; + --ErrorMessageWidth: 52px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-10 { + padding-left: 10px; +}`, + ]) +}) + +test('renderCss - with multiple visibleExplorerItems with different indents', () => { + const oldState = createDefaultState() + const newState: ExplorerState = { + ...createDefaultState(), + scrollBarHeight: 25, + uid: 789, + visibleExplorerItems: [ + { + ariaExpanded: 'true', + chevron: 1, + className: 'folder', + depth: 0, + hasEditingError: false, + icon: 'folder', + id: '1', + indent: 0, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'folder1', + path: '/folder1', + posInSet: 1, + selected: false, + setSize: 2, + }, + { + ariaExpanded: undefined, + chevron: 0, + className: 'file', + depth: 1, + hasEditingError: false, + icon: 'file', + id: '2', + indent: 20, + index: 1, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'file1.txt', + path: '/folder1/file1.txt', + posInSet: 1, + selected: false, + setSize: 1, + }, + { + ariaExpanded: undefined, + chevron: 0, + className: 'file', + depth: 1, + hasEditingError: false, + icon: 'file', + id: '3', + indent: 20, + index: 2, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'file2.txt', + path: '/folder1/file2.txt', + posInSet: 2, + selected: false, + setSize: 1, + }, + ], + } + const result = renderCss(oldState, newState) + expect(result).toEqual([ + 'Viewlet.setCss', + 789, + `.Explorer { + --ScrollBarThumbHeight: 0px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 20px; + --ErrorMessageLeft: 48px; + --ErrorMessageWidth: 52px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-0 { + padding-left: 0px; +} +.Indent-20 { + padding-left: 20px; +}`, + ]) +}) + +test('renderCss - with duplicate indents should only generate unique indent classes', () => { + const oldState = createDefaultState() + const newState: ExplorerState = { + ...createDefaultState(), + scrollBarHeight: 30, + uid: 999, + visibleExplorerItems: [ + { + ariaExpanded: undefined, + chevron: 0, + className: 'file', + depth: 0, + hasEditingError: false, + icon: 'file', + id: '1', + indent: 10, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'file1.txt', + path: '/file1.txt', + posInSet: 1, + selected: false, + setSize: 3, + }, + { + ariaExpanded: undefined, + chevron: 0, + className: 'file', + depth: 0, + hasEditingError: false, + icon: 'file', + id: '2', + indent: 10, + index: 1, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'file2.txt', + path: '/file2.txt', + posInSet: 2, + selected: false, + setSize: 3, + }, + { + ariaExpanded: undefined, + chevron: 0, + className: 'file', + depth: 0, + hasEditingError: false, + icon: 'file', + id: '3', + indent: 20, + index: 2, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'file3.txt', + path: '/file3.txt', + posInSet: 3, + selected: false, + setSize: 3, + }, + ], + } + const result = renderCss(oldState, newState) + expect(result).toEqual([ + 'Viewlet.setCss', + 999, + `.Explorer { + --ScrollBarThumbHeight: 0px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 20px; + --ErrorMessageLeft: 48px; + --ErrorMessageWidth: 52px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-10 { + padding-left: 10px; +} +.Indent-20 { + padding-left: 20px; +}`, + ]) +}) + +test('renderCss - with zero scrollBarHeight', () => { + const oldState = createDefaultState() + const newState: ExplorerState = { + ...createDefaultState(), + scrollBarHeight: 0, + uid: 111, + visibleExplorerItems: [ + { + ariaExpanded: undefined, + chevron: 0, + className: 'file', + depth: 0, + hasEditingError: false, + icon: 'file', + id: '1', + indent: 5, + index: 0, + isCut: false, + isEditing: false, + isIgnored: false, + name: 'test.txt', + path: '/test.txt', + posInSet: 1, + selected: false, + setSize: 1, + }, + ], + } + const result = renderCss(oldState, newState) + expect(result).toEqual([ + 'Viewlet.setCss', + 111, + `.Explorer { + --ScrollBarThumbHeight: 0px; + --ScrollBarThumbTop: 0px; + --ErrorMessageTop: 20px; + --ErrorMessageLeft: 48px; + --ErrorMessageWidth: 52px; +} +.Explorer .ScrollBarThumb { + height: var(--ScrollBarThumbHeight); + translate: 0px var(--ScrollBarThumbTop); +} +.Indent-5 { + padding-left: 5px; +}`, + ]) +}) diff --git a/packages/explorer-view/test/RenderDragData.test.ts b/packages/explorer-view/test/RenderDragData.test.ts new file mode 100644 index 0000000..369fe63 --- /dev/null +++ b/packages/explorer-view/test/RenderDragData.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.js' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' +import { renderDragData } from '../src/parts/RenderDragData/RenderDragData.js' + +test('renderDragData - no items', () => { + const oldState: ExplorerState = createDefaultState() + const newState: ExplorerState = { + ...oldState, + focusedIndex: 0, + items: [], + uid: 123, + } + const result = renderDragData(oldState, newState) + expect(result).toEqual(['Viewlet.setDragData', 123, expect.anything()]) +}) diff --git a/packages/explorer-view/test/RenderEditingSelection.test.ts b/packages/explorer-view/test/RenderEditingSelection.test.ts new file mode 100644 index 0000000..bb8d91d --- /dev/null +++ b/packages/explorer-view/test/RenderEditingSelection.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as InputName from '../src/parts/InputName/InputName.ts' +import { renderEditingSelection } from '../src/parts/RenderEditingSelection/RenderEditingSelection.ts' + +test('renderEditingSelection', () => { + const oldState: ExplorerState = createDefaultState() + const newState: ExplorerState = { + ...createDefaultState(), + editingSelectionEnd: 6, + editingSelectionStart: 1, + } + const result = renderEditingSelection(oldState, newState) + expect(result).toEqual(['Viewlet.setSelectionByName', newState.uid, InputName.ExplorerInput, 1, 6]) +}) diff --git a/packages/explorer-view/test/RenderEventListeners.test.ts b/packages/explorer-view/test/RenderEventListeners.test.ts new file mode 100644 index 0000000..41e6778 --- /dev/null +++ b/packages/explorer-view/test/RenderEventListeners.test.ts @@ -0,0 +1,7 @@ +import { expect, test } from '@jest/globals' +import * as RenderEventListeners from '../src/parts/RenderEventListeners/RenderEventListeners.ts' + +test('renderEventListeners', () => { + const eventListeners = RenderEventListeners.renderEventListeners() + expect(eventListeners).toBeDefined() +}) diff --git a/packages/explorer-view/test/RenderFocus.test.ts b/packages/explorer-view/test/RenderFocus.test.ts new file mode 100644 index 0000000..71405ed --- /dev/null +++ b/packages/explorer-view/test/RenderFocus.test.ts @@ -0,0 +1,43 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' +import * as InputName from '../src/parts/InputName/InputName.ts' +import * as InputSource from '../src/parts/InputSource/InputSource.ts' +import { renderFocus } from '../src/parts/RenderFocus/RenderFocus.ts' + +test('empty array when input source is user', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + inputSource: InputSource.User, + } + const result = renderFocus(oldState, newState) + expect(result).toEqual([]) +}) + +test('focus input when focus is input', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + focus: FocusId.Input, + } + const result = renderFocus(oldState, newState) + expect(result).toEqual(['Viewlet.focusElementByName', InputName.ExplorerInput]) +}) + +test('focus list when focus is list', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + focus: FocusId.List, + } + const result = renderFocus(oldState, newState) + expect(result).toEqual(['Viewlet.focusSelector', '.ListItems']) +}) + +test('empty array when no focus state', () => { + const oldState = createDefaultState() + const newState = createDefaultState() + const result = renderFocus(oldState, newState) + expect(result).toEqual([]) +}) diff --git a/packages/explorer-view/test/RenderFocusContext.test.ts b/packages/explorer-view/test/RenderFocusContext.test.ts new file mode 100644 index 0000000..1c38345 --- /dev/null +++ b/packages/explorer-view/test/RenderFocusContext.test.ts @@ -0,0 +1,41 @@ +import { expect, test } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' +import { renderFocusContext } from '../src/parts/RenderFocusContext/RenderFocusContext.ts' +import * as WhenExpression from '../src/parts/WhenExpression/WhenExpression.ts' + +test('should return FocusExplorerEditBox when focus is Input', () => { + const oldState = createDefaultState() + const newState = { ...oldState, focus: FocusId.Input } + + const result = renderFocusContext(oldState, newState) + + expect(result).toEqual(['Viewlet.setFocusContext', newState.uid, WhenExpression.FocusExplorerEditBox]) +}) + +test('should return FocusExplorer when focus is List', () => { + const oldState = createDefaultState() + const newState = { ...oldState, focus: FocusId.List } + + const result = renderFocusContext(oldState, newState) + + expect(result).toEqual(['Viewlet.setFocusContext', newState.uid, WhenExpression.FocusExplorer]) +}) + +test('should return empty array when focus is None', () => { + const oldState = createDefaultState() + const newState = { ...oldState, focus: FocusId.None } + + const result = renderFocusContext(oldState, newState) + + expect(result).toEqual([]) +}) + +test('should return empty array for unknown focus value', () => { + const oldState = createDefaultState() + const newState = { ...oldState, focus: 999 } + + const result = renderFocusContext(oldState, newState) + + expect(result).toEqual([]) +}) diff --git a/packages/explorer-view/test/RenderItems.test.ts b/packages/explorer-view/test/RenderItems.test.ts new file mode 100644 index 0000000..1e36dc1 --- /dev/null +++ b/packages/explorer-view/test/RenderItems.test.ts @@ -0,0 +1,140 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' +import { renderItems } from '../src/parts/RenderItems/RenderItems.ts' + +test('renderItems - basic', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + focused: true, + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: 1, + }, + ], + width: 500, + } + const result = renderItems(oldState, newState) + expect(result[0]).toBe('Viewlet.setDom2') + expect(result[1]).toBeDefined() +}) + +test('renderItems - narrow width', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + focused: true, + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: 1, + }, + ], + width: 400, + } + const result = renderItems(oldState, newState) + expect(result[0]).toBe('Viewlet.setDom2') + expect(result[1]).toBeDefined() +}) + +test('renderItems - load error message', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + errorCode: 'EACCES', + errorMessage: 'permission was denied', + focused: true, + hasError: true, + items: [ + { + depth: 0, + name: 'test', + path: '/test', + selected: false, + type: 1, + }, + ], + root: '/workspace', + } + const result = renderItems(oldState, newState) + const dom = result[2] + expect(dom).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ + className: 'ListItems', + }), + ]), + ) + expect(dom).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + text: 'Could not open folder due to permission was denied (error code: EACCES).', + }), + ]), + ) +}) + +test('renderItems - editing and load error messages are both passed and load error mode is used', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + editingErrorMessage: 'file already exists', + errorCode: 'EACCES', + errorMessage: 'permission was denied', + hasError: true, + root: '/workspace', + } + const result = renderItems(oldState, newState) + const dom = result[2] + expect(dom).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ + className: 'ListItems', + }), + ]), + ) + expect(dom).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + text: 'Could not open folder due to permission was denied (error code: EACCES).', + }), + ]), + ) +}) + +test('renderItems - missing folder load error shows friendly message and button', () => { + const oldState = createDefaultState() + const newState = { + ...createDefaultState(), + errorCode: 'ENOENT', + errorMessage: 'the folder does not exist', + hasError: true, + root: '/workspace/missing-folder', + width: 500, + } + const result = renderItems(oldState, newState) + const dom = result[2] + expect(dom).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + text: 'Could not open "/workspace/missing-folder" because the folder does not exist. It may have been moved or deleted.', + }), + expect.objectContaining({ + className: 'Button ButtonPrimary ButtonWide', + name: 'OpenFolder', + onClick: DomEventListenerFunctions.HandleClickOpenFolder, + }), + expect.objectContaining({ + text: 'Open another folder', + }), + ]), + ) +}) diff --git a/packages/explorer-view/test/RenderValue.test.ts b/packages/explorer-view/test/RenderValue.test.ts new file mode 100644 index 0000000..f91b22d --- /dev/null +++ b/packages/explorer-view/test/RenderValue.test.ts @@ -0,0 +1,51 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as FocusId from '../src/parts/FocusId/FocusId.ts' +import * as InputName from '../src/parts/InputName/InputName.ts' +import * as InputSource from '../src/parts/InputSource/InputSource.ts' +import { renderValue } from '../src/parts/RenderValue/RenderValue.ts' + +test('should return empty array when inputSource is User', () => { + const oldState = createDefaultState() + const newState = { ...oldState, inputSource: InputSource.User } + + const result = renderValue(oldState, newState) + + expect(result).toEqual([]) +}) + +test('should return setValue command when focus is Input', () => { + const oldState = createDefaultState() + const newState = { ...oldState, editingValue: 'test-value', focus: FocusId.Input } + + const result = renderValue(oldState, newState) + + expect(result).toEqual(['Viewlet.setValueByName', InputName.ExplorerInput, 'test-value']) +}) + +test('should return empty array when focus is not Input', () => { + const oldState = createDefaultState() + const newState = { ...oldState, focus: FocusId.List } + + const result = renderValue(oldState, newState) + + expect(result).toEqual([]) +}) + +test('should return empty array when focus is None', () => { + const oldState = createDefaultState() + const newState = { ...oldState, focus: FocusId.None } + + const result = renderValue(oldState, newState) + + expect(result).toEqual([]) +}) + +test('should return empty array when inputSource is Script and focus is not Input', () => { + const oldState = createDefaultState() + const newState = { ...oldState, focus: FocusId.List, inputSource: InputSource.Script } + + const result = renderValue(oldState, newState) + + expect(result).toEqual([]) +}) diff --git a/packages/explorer-view/test/RequestFileIcons.test.ts b/packages/explorer-view/test/RequestFileIcons.test.ts new file mode 100644 index 0000000..ca3bcc9 --- /dev/null +++ b/packages/explorer-view/test/RequestFileIcons.test.ts @@ -0,0 +1,65 @@ +import { test, expect } from '@jest/globals' +import { IconThemeWorker } from '@lvce-editor/rpc-registry' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as RequestFileIcons from '../src/parts/RequestFileIcons/RequestFileIcons.ts' + +test('requestFileIcons - empty requests', async () => { + using mockRpc = IconThemeWorker.registerMockRpc({}) + + const result = await RequestFileIcons.requestFileIcons([]) + expect(result).toEqual([]) + expect(mockRpc.invocations).toEqual([]) +}) + +test('requestFileIcons - file icons', async () => { + const requests = [{ name: 'file.txt', path: '/test/file.txt', type: DirentType.File }] + + using mockRpc = IconThemeWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return ['file-icon'] + }, + }) + + const result = await RequestFileIcons.requestFileIcons(requests) + expect(result).toEqual(['file-icon']) + expect(mockRpc.invocations).toEqual([['IconTheme.getIcons', [{ name: 'file.txt', type: 1 }]]]) +}) + +test('requestFileIcons - folder icons', async () => { + const requests = [{ name: 'folder', path: '/test/folder', type: DirentType.Directory }] + + using mockRpc = IconThemeWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return ['folder-icon'] + }, + }) + + const result = await RequestFileIcons.requestFileIcons(requests) + expect(result).toEqual(['folder-icon']) + expect(mockRpc.invocations).toEqual([['IconTheme.getIcons', [{ name: 'folder', type: 2 }]]]) +}) + +test('requestFileIcons - mixed requests', async () => { + const requests = [ + { name: 'file.txt', path: '/test/file.txt', type: DirentType.File }, + { name: 'folder', path: '/test/folder', type: DirentType.Directory }, + ] + + using mockRpc = IconThemeWorker.registerMockRpc({ + 'IconTheme.getIcons'() { + return ['file-icon', 'folder-icon'] + }, + }) + + const result = await RequestFileIcons.requestFileIcons(requests) + expect(result).toEqual(['file-icon', 'folder-icon']) + expect(mockRpc.invocations).toEqual([ + [ + 'IconTheme.getIcons', + [ + { name: 'file.txt', type: 1 }, + { name: 'folder', type: 2 }, + ], + ], + ]) +}) diff --git a/packages/explorer-view/test/ResolveSymbolicLinks.test.ts b/packages/explorer-view/test/ResolveSymbolicLinks.test.ts new file mode 100644 index 0000000..32e46b4 --- /dev/null +++ b/packages/explorer-view/test/ResolveSymbolicLinks.test.ts @@ -0,0 +1,186 @@ +import { expect, jest, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ErrorCodes from '../src/parts/ErrorCodes/ErrorCodes.ts' +import * as ResolveSymbolicLinks from '../src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts' + +test('should resolve symbolic links to files', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.stat'(path: string) { + if (path.includes('symlink-file')) { + return DirentType.File + } + if (path.includes('symlink-dir')) { + return DirentType.Directory + } + throw new Error(`unexpected path ${path}`) + }, + }) + + const uri = '/test/path' + const rawDirents = [ + { name: 'symlink-file', type: DirentType.Symlink }, + { name: 'regular-file', type: DirentType.File }, + { name: 'symlink-dir', type: DirentType.Symlink }, + ] + + const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + + expect(result).toEqual([ + { name: 'symlink-file', type: DirentType.SymLinkFile }, + { name: 'regular-file', type: DirentType.File }, + { name: 'symlink-dir', type: DirentType.SymLinkFolder }, + ]) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.stat', '/test/path/symlink-file'], + ['FileSystem.stat', '/test/path/symlink-dir'], + ]) +}) + +test('should handle ENOENT errors by returning SymLinkFile type', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.stat'() { + const enoentError = new Error('File not found') as Error & { code: string } + enoentError.code = ErrorCodes.ENOENT + throw enoentError + }, + }) + + const uri = '/test/path' + const rawDirents = [{ name: 'broken-symlink', type: DirentType.Symlink }] + + const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + + expect(result).toEqual([{ name: 'broken-symlink', type: DirentType.SymLinkFile }]) + expect(mockRpc.invocations).toEqual([['FileSystem.stat', '/test/path/broken-symlink']]) +}) + +test('should handle other errors by returning original dirent', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.stat'() { + const otherError = new Error('Permission denied') as Error & { code: string } + otherError.code = 'EACCES' + throw otherError + }, + }) + + // Mock console.error to prevent noise in test output + const originalConsoleError = console.error + console.error = jest.fn() + + const uri = '/test/path' + const rawDirents = [{ name: 'error-symlink', type: DirentType.Symlink }] + + const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + + expect(result).toEqual([{ name: 'error-symlink', type: DirentType.Symlink }]) + expect(mockRpc.invocations).toEqual([['FileSystem.stat', '/test/path/error-symlink']]) + + // Verify console.error was called with the expected message + expect(console.error).toHaveBeenCalledWith('Failed to resolve symbolic link for error-symlink: Error: Permission denied') + + // Restore console.error + console.error = originalConsoleError +}) + +test('should handle non-symbolic link dirents without processing', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + + const uri = '/test/path' + const rawDirents = [ + { name: 'file.txt', type: DirentType.File }, + { name: 'folder', type: DirentType.Directory }, + { name: 'device', type: DirentType.BlockDevice }, + ] + + const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + + expect(result).toEqual(rawDirents) + expect(mockRpc.invocations).toEqual([]) +}) + +test('should handle empty dirents array', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + + const uri = '/test/path' + const rawDirents: any[] = [] + + const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + + expect(result).toEqual([]) + expect(mockRpc.invocations).toEqual([]) +}) + +test('should handle mixed dirents with some symlinks and some regular files', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.stat'(path: string) { + if (path.includes('symlink1')) { + return DirentType.File + } + if (path.includes('symlink2')) { + return DirentType.Directory + } + throw new Error(`unexpected path ${path}`) + }, + }) + + const uri = '/test/path' + const rawDirents = [ + { name: 'file1.txt', type: DirentType.File }, + { name: 'symlink1', type: DirentType.Symlink }, + { name: 'folder', type: DirentType.Directory }, + { name: 'symlink2', type: DirentType.Symlink }, + { name: 'file2.txt', type: DirentType.File }, + ] + + const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + + expect(result).toEqual([ + { name: 'file1.txt', type: DirentType.File }, + { name: 'symlink1', type: DirentType.SymLinkFile }, + { name: 'folder', type: DirentType.Directory }, + { name: 'symlink2', type: DirentType.SymLinkFolder }, + { name: 'file2.txt', type: DirentType.File }, + ]) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.stat', '/test/path/symlink1'], + ['FileSystem.stat', '/test/path/symlink2'], + ]) +}) + +test('should handle symlinks that resolve to different types', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.stat'(path: string) { + if (path.includes('symlink-file')) { + return DirentType.File + } + if (path.includes('symlink-dir')) { + return DirentType.Directory + } + if (path.includes('symlink-socket')) { + return DirentType.Socket + } + throw new Error(`unexpected path ${path}`) + }, + }) + + const uri = '/test/path' + const rawDirents = [ + { name: 'symlink-file', type: DirentType.Symlink }, + { name: 'symlink-dir', type: DirentType.Symlink }, + { name: 'symlink-socket', type: DirentType.Symlink }, + ] + + const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) + + expect(result).toEqual([ + { name: 'symlink-file', type: DirentType.SymLinkFile }, + { name: 'symlink-dir', type: DirentType.SymLinkFolder }, + { name: 'symlink-socket', type: DirentType.Symlink }, + ]) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.stat', '/test/path/symlink-file'], + ['FileSystem.stat', '/test/path/symlink-dir'], + ['FileSystem.stat', '/test/path/symlink-socket'], + ]) +}) diff --git a/packages/explorer-view/test/RestoreDirentType.test.ts b/packages/explorer-view/test/RestoreDirentType.test.ts new file mode 100644 index 0000000..a5e9179 --- /dev/null +++ b/packages/explorer-view/test/RestoreDirentType.test.ts @@ -0,0 +1,18 @@ +import { test, expect } from '@jest/globals' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as RestoreDirentType from '../src/parts/RestoreDirentType/RestoreDirentType.ts' + +test('restoreDirentType - directory in expanded paths', () => { + const result = RestoreDirentType.restoreDirentType(DirentType.Directory, '/test', ['/test']) + expect(result).toBe(DirentType.DirectoryExpanded) +}) + +test('restoreDirentType - directory not in expanded paths', () => { + const result = RestoreDirentType.restoreDirentType(DirentType.Directory, '/test', ['/other']) + expect(result).toBe(DirentType.Directory) +}) + +test('restoreDirentType - non-directory type', () => { + const result = RestoreDirentType.restoreDirentType(DirentType.File, '/test', ['/test']) + expect(result).toBe(DirentType.File) +}) diff --git a/packages/explorer-view/test/RestoreState.test.ts b/packages/explorer-view/test/RestoreState.test.ts new file mode 100644 index 0000000..18e6ae3 --- /dev/null +++ b/packages/explorer-view/test/RestoreState.test.ts @@ -0,0 +1,69 @@ +import { test, expect } from '@jest/globals' +import { restoreState } from '../src/parts/RestoreState/RestoreState.ts' + +test('restoreState returns default state when savedState is null', () => { + const result = restoreState(null) + expect(result).toEqual({ + deltaY: 0, + minLineY: 0, + root: '', + }) +}) + +test('restoreState returns default state when savedState is undefined', () => { + const result = restoreState(undefined) + expect(result).toEqual({ + deltaY: 0, + minLineY: 0, + root: '', + }) +}) + +test('restoreState returns correct state with valid input', () => { + const savedState = { + deltaY: 50, + minLineY: 100, + workspacePath: '/test/path', + } + const result = restoreState(savedState) + expect(result).toEqual({ + deltaY: 50, + minLineY: 100, + root: '/test/path', + }) +}) + +test('restoreState handles partial state with missing properties', () => { + const savedState = { + workspacePath: '/test/path', + } + const result = restoreState(savedState) + expect(result).toEqual({ + deltaY: 0, + minLineY: 0, + root: '/test/path', + }) +}) + +test('restoreState handles invalid property types', () => { + const savedState = { + deltaY: true, + minLineY: '100', + workspacePath: 123, + } + const result = restoreState(savedState) + expect(result).toEqual({ + deltaY: 0, + minLineY: 0, + root: '', + }) +}) + +test('restoreState handles non-object input', () => { + const result = restoreState('invalid') + expect(result).toEqual({ + deltaY: 0, + minLineY: 0, + root: '', + }) +}) diff --git a/packages/explorer-view/test/RevealItem.test.ts b/packages/explorer-view/test/RevealItem.test.ts new file mode 100644 index 0000000..d98ddf8 --- /dev/null +++ b/packages/explorer-view/test/RevealItem.test.ts @@ -0,0 +1,58 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { revealItem } from '../src/parts/RevealItem/RevealItem.ts' + +test('revealItem - item not found', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const state = createDefaultState() + const newState = await revealItem(state, 'test') + expect(newState.items).toEqual([]) + expect(mockRpc.invocations).toEqual([]) +}) + +test('revealItem - uri outside root', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + root: '/root', + } + const newState = await revealItem(state, 'non-existent:///some-file.txt') + expect(newState).toEqual(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test('revealItem - item found', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { + depth: 0, + name: 'test', + path: 'test', + selected: false, + type: 1, + }, + ], + } + const newState = await revealItem(state, 'test') + expect(newState.items[0].path).toBe('test') + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/RevealItemHidden.test.ts b/packages/explorer-view/test/RevealItemHidden.test.ts new file mode 100644 index 0000000..551d701 --- /dev/null +++ b/packages/explorer-view/test/RevealItemHidden.test.ts @@ -0,0 +1,57 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { revealItemHidden } from '../src/parts/RevealItemHidden/RevealItemHidden.ts' + +test('revealItemHidden - reveals hidden item', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'(path: string) { + if (path === '/root') { + return [{ isDirectory: true, name: 'folder1', path: '/root/folder1', type: DirentType.File }] + } + if (path === '/root/folder1') { + return [ + { isDirectory: false, name: 'file1.txt', path: '/root/folder1/file1.txt', type: DirentType.File }, + { isDirectory: false, name: 'file2.txt', path: '/root/folder1/file2.txt', type: DirentType.File }, + ] + } + return [] + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + root: '/root', + } + const newState = await revealItemHidden(state, '/root/folder1/file1.txt') + expect(newState.items.length).toBeGreaterThan(0) + expect(newState.focused).toBe(true) + expect(newState.focusedIndex).toBeGreaterThanOrEqual(0) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/root'], + ['FileSystem.readDirWithFileTypes', '/root/folder1'], + ]) +}) + +test('revealItemHidden - returns same state for empty path parts', async () => { + using mockRpc = RendererWorker.registerMockRpc({}) + const state = createDefaultState() + const newState = await revealItemHidden(state, '') + expect(newState).toEqual(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test('revealItemHidden - throws error for non-existent file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [] + }, + }) + const state = createDefaultState() + await expect(revealItemHidden(state, '/non/existent/file.txt')).rejects.toThrow('File not found in explorer') + expect(mockRpc.invocations).toEqual([ + ['FileSystem.readDirWithFileTypes', '/non'], + ['FileSystem.readDirWithFileTypes', '/non/existent'], + ]) +}) diff --git a/packages/explorer-view/test/RevealItemVisible.test.ts b/packages/explorer-view/test/RevealItemVisible.test.ts new file mode 100644 index 0000000..95bab7e --- /dev/null +++ b/packages/explorer-view/test/RevealItemVisible.test.ts @@ -0,0 +1,15 @@ +import { test, expect } from '@jest/globals' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { revealItemVisible } from '../src/parts/RevealItemVisible/RevealItemVisible.ts' + +test('revealItemVisible - updates state with new scroll position and focus', () => { + const state = createDefaultState() + const result = revealItemVisible(state, 2) + expect(result).toEqual({ + ...state, + focused: true, + focusedIndex: 2, + maxLineY: 2, + minLineY: 2, + }) +}) diff --git a/packages/explorer-view/test/SaveState.test.ts b/packages/explorer-view/test/SaveState.test.ts new file mode 100644 index 0000000..fade7e2 --- /dev/null +++ b/packages/explorer-view/test/SaveState.test.ts @@ -0,0 +1,57 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' +import { saveState } from '../src/parts/SaveState/SaveState.ts' + +test('saveState - returns correct saved state', () => { + const uid = 1 + const oldState = createDefaultState() + const newState: ExplorerState = { + ...oldState, + deltaY: 0, + items: [ + { depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.DirectoryExpanded }, + { depth: 1, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }, + ], + maxLineY: 100, + minLineY: 0, + root: '/', + } + ExplorerStates.set(uid, oldState, newState) + + const result = saveState(newState) + + expect(result).toEqual({ + deltaY: 0, + expandedPaths: ['/test'], + maxLineY: 100, + minLineY: 0, + root: '/', + }) +}) + +test('saveState - handles empty items', () => { + const uid = 1 + const oldState = createDefaultState() + const newState: ExplorerState = { + ...oldState, + deltaY: 0, + items: [], + maxLineY: 0, + minLineY: 0, + root: '/', + } + ExplorerStates.set(uid, oldState, newState) + + const result = saveState(newState) + + expect(result).toEqual({ + deltaY: 0, + expandedPaths: [], + maxLineY: 0, + minLineY: 0, + root: '/', + }) +}) diff --git a/packages/explorer-view/test/ScrollInto.test.ts b/packages/explorer-view/test/ScrollInto.test.ts new file mode 100644 index 0000000..4234f5a --- /dev/null +++ b/packages/explorer-view/test/ScrollInto.test.ts @@ -0,0 +1,34 @@ +import { test, expect } from '@jest/globals' +import { scrollInto } from '../src/parts/ScrollInto/ScrollInto.ts' + +test('when index is below minLineY', () => { + const result = scrollInto(5, 10, 20) + expect(result).toEqual({ + newMaxLineY: 10, + newMinLineY: 0, + }) +}) + +test('when index is above maxLineY', () => { + const result = scrollInto(25, 10, 20) + expect(result).toEqual({ + newMaxLineY: 30, + newMinLineY: 20, + }) +}) + +test('when index is within range', () => { + const result = scrollInto(15, 10, 20) + expect(result).toEqual({ + newMaxLineY: 20, + newMinLineY: 10, + }) +}) + +test('when range is odd', () => { + const result = scrollInto(5, 10, 21) + expect(result).toEqual({ + newMaxLineY: 11, + newMinLineY: 0, + }) +}) diff --git a/packages/explorer-view/test/SelectAll.test.ts b/packages/explorer-view/test/SelectAll.test.ts new file mode 100644 index 0000000..145583c --- /dev/null +++ b/packages/explorer-view/test/SelectAll.test.ts @@ -0,0 +1,24 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { selectAll } from '../src/parts/SelectAll/SelectAll.ts' + +const createItem = (name: string, selected: boolean): ExplorerItem => ({ + depth: 0, + name, + path: `/${name}`, + selected, + type: 0, +}) + +test('selectAll', () => { + const state = createDefaultState() + const items = [createItem('file1', false), createItem('file2', false), createItem('file3', false)] + const newState = selectAll({ + ...state, + items, + }) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(true) +}) diff --git a/packages/explorer-view/test/SelectDown.test.ts b/packages/explorer-view/test/SelectDown.test.ts new file mode 100644 index 0000000..28e2d6f --- /dev/null +++ b/packages/explorer-view/test/SelectDown.test.ts @@ -0,0 +1,128 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { selectDown } from '../src/parts/SelectDown/SelectDown.ts' + +const createTestState = (): ExplorerState => ({ + ...createDefaultState(), + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], +}) + +const createStateWithSelections = (selectedIndices: number[]): ExplorerState => { + const state = createTestState() + return { + ...state, + items: state.items.map((item, index) => ({ + ...item, + selected: selectedIndices.includes(index), + })), + } +} + +test.skip('selectDown - no selection', () => { + const state = createTestState() + const newState = selectDown(state) + expect(newState.items[0].selected).toBe(true) +}) + +test('selectDown - single selection', () => { + const state = createStateWithSelections([0]) + const newState = selectDown(state) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(true) +}) + +test('selectDown - multiple selections', () => { + const state = createStateWithSelections([0, 1]) + const newState = selectDown(state) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(true) +}) + +test('selectDown - at end', () => { + const state = createTestState() + const lastIndex = state.items.length - 1 + const stateWithSelection = createStateWithSelections([lastIndex]) + const newState = selectDown(stateWithSelection) + expect(newState.items[lastIndex].selected).toBe(true) +}) + +test('selectDown - last item', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + ], + } + const newState = selectDown(state) + expect(newState).toBe(state) +}) + +test('selectDown - first item', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + ], + } + const newState = selectDown(state) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(true) +}) + +test.skip('selectDown - multiple items with selection', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const newState = selectDown(state) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(false) +}) + +test('selectDown - multiple items with selection at bottom', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: true, type: 0 }, + ], + } + const newState = selectDown(state) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[1].selected).toBe(false) + expect(newState.items[2].selected).toBe(true) +}) + +test.skip('selectDown - multiple items with multiple selections', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [ + { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const newState = selectDown(state) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(false) +}) diff --git a/packages/explorer-view/test/SelectForCompare.test.ts b/packages/explorer-view/test/SelectForCompare.test.ts new file mode 100644 index 0000000..fa774c6 --- /dev/null +++ b/packages/explorer-view/test/SelectForCompare.test.ts @@ -0,0 +1,32 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { selectForCompare } from '../src/parts/SelectForCompare/SelectForCompare.ts' + +test('selectForCompare - stores focused file uri', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }], + } + + const result = selectForCompare(state) + + expect(result).toEqual({ + ...state, + compareSourceUri: '/a.txt', + }) +}) + +test('selectForCompare - ignores non-file focus', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 0, + items: [{ depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.Directory }], + } + + const result = selectForCompare(state) + + expect(result).toBe(state) +}) diff --git a/packages/explorer-view/test/SelectIndices.test.ts b/packages/explorer-view/test/SelectIndices.test.ts new file mode 100644 index 0000000..e482258 --- /dev/null +++ b/packages/explorer-view/test/SelectIndices.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' +import { setSelectedIndices } from '../src/parts/SelectIndices/SelectIndices.js' + +test('setSelectedIndices sets selection for given indices', () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, + { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, + { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, + ], + } + + const newState = setSelectedIndices(state, [0, 2]) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(false) + expect(newState.items[2].selected).toBe(true) +}) diff --git a/packages/explorer-view/test/SelectUp.test.ts b/packages/explorer-view/test/SelectUp.test.ts new file mode 100644 index 0000000..9c6a814 --- /dev/null +++ b/packages/explorer-view/test/SelectUp.test.ts @@ -0,0 +1,72 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { selectUp } from '../src/parts/SelectUp/SelectUp.ts' + +test('selectUp - first item', () => { + const state = createDefaultState() + const newState = selectUp(state) + expect(newState).toBe(state) +}) + +test('selectUp - second item', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + ], + } + const newState = selectUp(state) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(false) +}) + +test.skip('selectUp - multiple items with selection', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 2, + items: [ + { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const newState = selectUp(state) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(false) +}) + +test('selectUp - multiple items with selection at top', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 1, + items: [ + { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const newState = selectUp(state) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(false) + expect(newState.items[2].selected).toBe(false) +}) + +test.skip('selectUp - multiple items with multiple selections', () => { + const state: ExplorerState = { + ...createDefaultState(), + focusedIndex: 2, + items: [ + { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, + { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, + { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, + ], + } + const newState = selectUp(state) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(false) +}) diff --git a/packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts b/packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts new file mode 100644 index 0000000..e7e35ab --- /dev/null +++ b/packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts @@ -0,0 +1,77 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { sendMessagePortToFileSystemWorker } from '../src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts' + +test('sendMessagePortToFileSystemWorker calls RendererWorker.sendMessagePortToFileSystemWorker with correct parameters', async () => { + const { port1 } = new MessageChannel() + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { + return undefined + }, + }) + + await sendMessagePortToFileSystemWorker(port1) + + expect(mockRpc.invocations).toEqual([ + ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port1, 'FileSystem.handleMessagePort', 0], + ]) +}) + +test('sendMessagePortToFileSystemWorker handles different port types', async () => { + const { port1: port1a } = new MessageChannel() + const { port1: port2a } = new MessageChannel() + + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { + return undefined + }, + }) + + await sendMessagePortToFileSystemWorker(port1a) + await sendMessagePortToFileSystemWorker(port2a) + + expect(mockRpc.invocations).toEqual([ + ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port1a, 'FileSystem.handleMessagePort', 0], + ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port2a, 'FileSystem.handleMessagePort', 0], + ]) +}) + +test('sendMessagePortToFileSystemWorker propagates errors from RendererWorker', async () => { + const { port1 } = new MessageChannel() + + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { + throw new Error('RPC call failed') + }, + }) + + await expect(sendMessagePortToFileSystemWorker(port1)).rejects.toThrow('RPC call failed') + expect(mockRpc.invocations).toEqual([ + ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port1, 'FileSystem.handleMessagePort', 0], + ]) +}) + +test('sendMessagePortToFileSystemWorker returns void when successful', async () => { + const { port1 } = new MessageChannel() + + RendererWorker.registerMockRpc({ + 'FileSystem.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { + return undefined + }, + }) + + const result = await sendMessagePortToFileSystemWorker(port1) + expect(result).toBeUndefined() +}) diff --git a/packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts b/packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts new file mode 100644 index 0000000..5342b06 --- /dev/null +++ b/packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts @@ -0,0 +1,77 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { sendMessagePortToIconThemeWorker } from '../src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts' + +test('sendMessagePortToIconThemeWorker calls RendererWorker.sendMessagePortToIconThemeWorker with correct parameters', async () => { + const { port1 } = new MessageChannel() + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { + return undefined + }, + }) + + await sendMessagePortToIconThemeWorker(port1) + + expect(mockRpc.invocations).toEqual([ + ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port1, 'IconTheme.handleMessagePort', 0], + ]) +}) + +test('sendMessagePortToIconThemeWorker handles different port types', async () => { + const { port1: port1a } = new MessageChannel() + const { port1: port2a } = new MessageChannel() + + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { + return undefined + }, + }) + + await sendMessagePortToIconThemeWorker(port1a) + await sendMessagePortToIconThemeWorker(port2a) + + expect(mockRpc.invocations).toEqual([ + ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port1a, 'IconTheme.handleMessagePort', 0], + ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port2a, 'IconTheme.handleMessagePort', 0], + ]) +}) + +test('sendMessagePortToIconThemeWorker propagates errors from RendererWorker', async () => { + const { port1 } = new MessageChannel() + + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { + throw new Error('RPC call failed') + }, + }) + + await expect(sendMessagePortToIconThemeWorker(port1)).rejects.toThrow('RPC call failed') + expect(mockRpc.invocations).toEqual([ + ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port1, 'IconTheme.handleMessagePort', 0], + ]) +}) + +test('sendMessagePortToIconThemeWorker returns void when successful', async () => { + const { port1 } = new MessageChannel() + + RendererWorker.registerMockRpc({ + 'IconTheme.handleMessagePort'() { + return undefined + }, + 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { + return undefined + }, + }) + + const result = await sendMessagePortToIconThemeWorker(port1) + expect(result).toBeUndefined() +}) diff --git a/packages/explorer-view/test/SetDeltaY.test.ts b/packages/explorer-view/test/SetDeltaY.test.ts new file mode 100644 index 0000000..542f408 --- /dev/null +++ b/packages/explorer-view/test/SetDeltaY.test.ts @@ -0,0 +1,102 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { setDeltaY } from '../src/parts/SetDeltaY/SetDeltaY.ts' + +test('should not change state when deltaY is the same', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return 'icon' + }, + 'IconTheme.getFolderIcon'() { + return 'icon' + }, + 'IconTheme.getIcons'() { + return ['icon'] + }, + }) + const state: ExplorerState = createDefaultState() + const result = await setDeltaY(state, 0) + expect(result).toBe(state) + expect(mockRpc.invocations).toEqual([]) +}) + +test('should clamp deltaY to 0 when negative', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return 'icon' + }, + 'IconTheme.getFolderIcon'() { + return 'icon' + }, + 'IconTheme.getIcons'() { + return ['icon'] + }, + }) + const state: ExplorerState = createDefaultState() + const result = await setDeltaY(state, -50) + expect(result.deltaY).toBe(0) + expect(result.minLineY).toBe(0) + expect(mockRpc.invocations).toEqual([]) +}) + +test('should clamp deltaY to max scroll value', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return 'icon' + }, + 'IconTheme.getFolderIcon'() { + return 'icon' + }, + 'IconTheme.getIcons'() { + return ['icon'] + }, + }) + const items: ExplorerItem[] = Array.from({ length: 20 }, (_, i) => ({ + depth: 0, + name: `file${i}`, + path: `/file${i}`, + selected: false, + type: 1, + })) + const state: ExplorerState = { + ...createDefaultState(), + items, + } + const result = await setDeltaY(state, 500) + expect(result.deltaY).toBe(300) + expect(result.minLineY).toBe(15) + expect(mockRpc.invocations).toEqual([]) +}) + +test('should update visible items and icons', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return 'icon' + }, + 'IconTheme.getFolderIcon'() { + return 'icon' + }, + 'IconTheme.getIcons'() { + return ['icon'] + }, + }) + const items: ExplorerItem[] = Array.from({ length: 20 }, (_, i) => ({ + depth: 0, + name: `file${i}`, + path: `/file${i}`, + selected: false, + type: 1, + })) + const state: ExplorerState = { + ...createDefaultState(), + items, + } + const result = await setDeltaY(state, 100) + expect(result.deltaY).toBe(100) + expect(result.minLineY).toBe(5) + expect(result.maxLineY).toBe(10) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/SortExplorerItems.test.ts b/packages/explorer-view/test/SortExplorerItems.test.ts new file mode 100644 index 0000000..4a29405 --- /dev/null +++ b/packages/explorer-view/test/SortExplorerItems.test.ts @@ -0,0 +1,61 @@ +import { test, expect } from '@jest/globals' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { sortExplorerItems } from '../src/parts/SortExplorerItems/SortExplorerItems.ts' + +const createItem = (name: string, type: number): any => ({ + depth: 1, + name, + path: `/test/${name}`, + selected: false, + type, +}) + +test('sorts folders before files', () => { + const items = [ + createItem('file1', DirentType.File), + createItem('folder1', DirentType.Directory), + createItem('file2', DirentType.File), + createItem('folder2', DirentType.Directory), + ] + const sorted = sortExplorerItems(items) + expect(sorted[0].type).toBe(DirentType.Directory) + expect(sorted[1].type).toBe(DirentType.Directory) + expect(sorted[2].type).toBe(DirentType.File) + expect(sorted[3].type).toBe(DirentType.File) +}) + +test('sorts items alphabetically within same type', () => { + const items = [ + createItem('b', DirentType.Directory), + createItem('a', DirentType.Directory), + createItem('d', DirentType.File), + createItem('c', DirentType.File), + ] + const sorted = sortExplorerItems(items) + expect(sorted[0].name).toBe('a') + expect(sorted[1].name).toBe('b') + expect(sorted[2].name).toBe('c') + expect(sorted[3].name).toBe('d') +}) + +test('sorts numeric names correctly', () => { + const items = [createItem('10', DirentType.Directory), createItem('2', DirentType.Directory), createItem('1', DirentType.Directory)] + const sorted = sortExplorerItems(items) + expect(sorted[0].name).toBe('1') + expect(sorted[1].name).toBe('2') + expect(sorted[2].name).toBe('10') +}) + +test('handles mixed types and names', () => { + const items = [ + createItem('file2', DirentType.File), + createItem('folder1', DirentType.Directory), + createItem('file1', DirentType.File), + createItem('folder2', DirentType.Directory), + ] + const sorted = sortExplorerItems(items) + expect(sorted[0].name).toBe('folder1') + expect(sorted[1].name).toBe('folder2') + expect(sorted[2].name).toBe('file1') + expect(sorted[3].name).toBe('file2') +}) diff --git a/packages/explorer-view/test/Terminate.test.ts b/packages/explorer-view/test/Terminate.test.ts new file mode 100644 index 0000000..dda5ba4 --- /dev/null +++ b/packages/explorer-view/test/Terminate.test.ts @@ -0,0 +1,9 @@ +import { expect, jest, test } from '@jest/globals' +import { terminate } from '../src/parts/Terminate/Terminate.ts' + +test('terminate', () => { + const mockClose = jest.fn() + globalThis.close = mockClose + terminate() + expect(mockClose).toHaveBeenCalled() +}) diff --git a/packages/explorer-view/test/ToCollapsedDirent.test.ts b/packages/explorer-view/test/ToCollapsedDirent.test.ts new file mode 100644 index 0000000..05747cf --- /dev/null +++ b/packages/explorer-view/test/ToCollapsedDirent.test.ts @@ -0,0 +1,92 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { toCollapsedDirent } from '../src/parts/ToCollapsedDirent/ToCollapsedDirent.ts' + +test('should collapse expanded directory to regular directory', () => { + const expandedDir: ExplorerItem = { + depth: 1, + name: 'test-dir', + path: '/test/test-dir', + selected: false, + type: DirentType.DirectoryExpanded, + } + + const result = toCollapsedDirent(expandedDir) + + expect(result).toEqual({ + depth: 1, + name: 'test-dir', + path: '/test/test-dir', + selected: false, + type: DirentType.Directory, + }) +}) + +test('should return unchanged item for non-expanded directory', () => { + const regularDir: ExplorerItem = { + depth: 1, + name: 'test-dir', + path: '/test/test-dir', + selected: false, + type: DirentType.Directory, + } + + const result = toCollapsedDirent(regularDir) + + expect(result).toBe(regularDir) +}) + +test('should return unchanged item for file', () => { + const file: ExplorerItem = { + depth: 1, + name: 'test-file.txt', + path: '/test/test-file.txt', + selected: false, + type: DirentType.File, + } + + const result = toCollapsedDirent(file) + + expect(result).toBe(file) +}) + +test('should return unchanged item for symlink', () => { + const symlink: ExplorerItem = { + depth: 1, + name: 'test-symlink', + path: '/test/test-symlink', + selected: false, + type: DirentType.Symlink, + } + + const result = toCollapsedDirent(symlink) + + expect(result).toBe(symlink) +}) + +test('should preserve all properties when collapsing expanded directory', () => { + const expandedDir: ExplorerItem = { + depth: 2, + icon: 'folder-icon', + name: 'test-dir', + path: '/test/test-dir', + posInSet: 3, + selected: true, + setSize: 5, + type: DirentType.DirectoryExpanded, + } + + const result = toCollapsedDirent(expandedDir) + + expect(result).toEqual({ + depth: 2, + icon: 'folder-icon', + name: 'test-dir', + path: '/test/test-dir', + posInSet: 3, + selected: true, + setSize: 5, + type: DirentType.Directory, + }) +}) diff --git a/packages/explorer-view/test/ToggleIndividualSelection.test.ts b/packages/explorer-view/test/ToggleIndividualSelection.test.ts new file mode 100644 index 0000000..2d524a7 --- /dev/null +++ b/packages/explorer-view/test/ToggleIndividualSelection.test.ts @@ -0,0 +1,80 @@ +import { expect, test } from '@jest/globals' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' +import { toggleIndividualSelection } from '../src/parts/ToggleIndividualSelection/ToggleIndividualSelection.js' + +test('toggleIndividualSelection - toggles selection of item at valid index', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, + { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, + { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, + ], + } + + const newState = await toggleIndividualSelection(state, 1) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[2].selected).toBe(false) +}) + +test('toggleIndividualSelection - toggles selection from true to false', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, + { depth: 0, name: 'file2', path: '/file2', selected: true, type: 0 }, + { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, + ], + } + + const newState = await toggleIndividualSelection(state, 1) + expect(newState.items[1].selected).toBe(false) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[2].selected).toBe(false) +}) + +test('toggleIndividualSelection - does nothing when index is negative', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, + { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, + ], + } + + const newState = await toggleIndividualSelection(state, -1) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[1].selected).toBe(false) +}) + +test('toggleIndividualSelection - does nothing when index is out of range', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, + { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, + ], + } + + const newState = await toggleIndividualSelection(state, 2) + expect(newState.items[0].selected).toBe(false) + expect(newState.items[1].selected).toBe(false) +}) + +test('toggleIndividualSelection - preserves other selections', async () => { + const state: ExplorerState = { + ...createDefaultState(), + items: [ + { depth: 0, name: 'file1', path: '/file1', selected: true, type: 0 }, + { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, + { depth: 0, name: 'file3', path: '/file3', selected: true, type: 0 }, + ], + } + + const newState = await toggleIndividualSelection(state, 1) + expect(newState.items[0].selected).toBe(true) + expect(newState.items[1].selected).toBe(true) + expect(newState.items[2].selected).toBe(true) +}) diff --git a/packages/explorer-view/test/TreeToArray.test.ts b/packages/explorer-view/test/TreeToArray.test.ts new file mode 100644 index 0000000..2ff29b6 --- /dev/null +++ b/packages/explorer-view/test/TreeToArray.test.ts @@ -0,0 +1,195 @@ +import { expect, test } from '@jest/globals' +import type { Tree } from '../src/parts/Tree/Tree.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { treeToArray } from '../src/parts/TreeToArray/TreeToArray.ts' + +test('treeToArray - empty tree', () => { + const map: Tree = {} + const root = '/test' + expect(treeToArray(map, root)).toEqual([]) +}) + +test('treeToArray - single file', () => { + const map: Tree = { + '': [{ name: 'file.txt', type: DirentType.File }], + } + const root = '/test' + const result = treeToArray(map, root) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'file.txt', + path: '/test/file.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: 7, + }, + ]) +}) + +test('treeToArray - nested structure', () => { + const map: Tree = { + '': [ + { name: 'folder', type: DirentType.Directory }, + { name: 'file.txt', type: DirentType.File }, + ], + '/folder': [{ name: 'nested.txt', type: DirentType.File }], + } + const root = '/test' + const result = treeToArray(map, root) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'folder', + path: '/test/folder', + posInSet: 1, + selected: false, + setSize: 2, + type: 3, + }, + { + depth: 2, + icon: '', + name: 'nested.txt', + path: '/test/folder/nested.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'file.txt', + path: '/test/file.txt', + posInSet: 2, + selected: false, + setSize: 2, + type: 7, + }, + ]) +}) + +test('treeToArray - deep nested structure', () => { + const map: Tree = { + '': [{ name: 'folder1', type: DirentType.Directory }], + '/folder1': [{ name: 'folder2', type: DirentType.Directory }], + '/folder1/folder2': [{ name: 'deep.txt', type: DirentType.File }], + } + const root = '/test' + const result = treeToArray(map, root) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'folder1', + path: '/test/folder1', + posInSet: 1, + selected: false, + setSize: 1, + type: 3, + }, + { + depth: 2, + icon: '', + name: 'folder2', + path: '/test/folder1/folder2', + posInSet: 1, + selected: false, + setSize: 1, + type: 3, + }, + { + depth: 3, + icon: '', + name: 'deep.txt', + path: '/test/folder1/folder2/deep.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: 7, + }, + ]) +}) + +test('treeToArray - update tree and children', () => { + const map: Tree = { + '': [ + { name: 'folder1', type: DirentType.Directory }, + { name: 'folder2', type: DirentType.Directory }, + ], + '/folder1': [ + { name: 'subfolder', type: DirentType.Directory }, + { name: 'file1.txt', type: DirentType.File }, + ], + '/folder1/subfolder': [{ name: 'deep.txt', type: DirentType.File }], + '/folder2': [{ name: 'file2.txt', type: DirentType.File }], + } + const root = '/test' + const result = treeToArray(map, root) + expect(result).toEqual([ + { + depth: 1, + icon: '', + name: 'folder1', + path: '/test/folder1', + posInSet: 1, + selected: false, + setSize: 2, + type: 3, + }, + { + depth: 2, + icon: '', + name: 'subfolder', + path: '/test/folder1/subfolder', + posInSet: 1, + selected: false, + setSize: 2, + type: 3, + }, + { + depth: 3, + icon: '', + name: 'deep.txt', + path: '/test/folder1/subfolder/deep.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: 7, + }, + { + depth: 2, + icon: '', + name: 'file1.txt', + path: '/test/folder1/file1.txt', + posInSet: 2, + selected: false, + setSize: 2, + type: 7, + }, + { + depth: 1, + icon: '', + name: 'folder2', + path: '/test/folder2', + posInSet: 2, + selected: false, + setSize: 2, + type: 3, + }, + { + depth: 2, + icon: '', + name: 'file2.txt', + path: '/test/folder2/file2.txt', + posInSet: 1, + selected: false, + setSize: 1, + type: 7, + }, + ]) +}) diff --git a/packages/explorer-view/test/UpdateDirentsAtPath.test.ts b/packages/explorer-view/test/UpdateDirentsAtPath.test.ts new file mode 100644 index 0000000..8271460 --- /dev/null +++ b/packages/explorer-view/test/UpdateDirentsAtPath.test.ts @@ -0,0 +1,70 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { updateDirentsAtPath } from '../src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts' + +test.skip('updateDirentsAtPath - empty items', () => { + const items: readonly ExplorerItem[] = [] + const path = '/test' + const root = '/test' + const newDirents = [{ name: 'file.txt', type: DirentType.File }] + const result = updateDirentsAtPath(items, path, root, newDirents) + expect(result).toHaveLength(1) + expect(result[0].name).toBe('file.txt') + expect(result[0].type).toBe(DirentType.File) + expect(result[0].path).toBe('/test/file.txt') + expect(result[0].depth).toBe(0) + expect(result[0].posInSet).toBe(1) + expect(result[0].setSize).toBe(1) +}) + +test.skip('updateDirentsAtPath - update existing items', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, icon: '', name: 'folder', path: '/test/folder', posInSet: 1, selected: false, setSize: 2, type: DirentType.Directory }, + { depth: 0, icon: '', name: 'file.txt', path: '/test/file.txt', posInSet: 2, selected: false, setSize: 2, type: DirentType.File }, + ] + const path = '/test' + const root = '/test' + const newDirents = [ + { name: 'new.txt', type: DirentType.File }, + { name: 'folder', type: DirentType.Directory }, + ] + const result = updateDirentsAtPath(items, path, root, newDirents) + expect(result).toHaveLength(2) + expect(result[0].name).toBe('folder') + expect(result[0].type).toBe(DirentType.Directory) + expect(result[0].path).toBe('/test/folder') + expect(result[0].depth).toBe(0) + expect(result[0].posInSet).toBe(1) + expect(result[0].setSize).toBe(2) + expect(result[1].name).toBe('new.txt') + expect(result[1].type).toBe(DirentType.File) + expect(result[1].path).toBe('/test/new.txt') + expect(result[1].depth).toBe(0) + expect(result[1].posInSet).toBe(2) + expect(result[1].setSize).toBe(2) +}) + +test.skip('updateDirentsAtPath - nested structure', () => { + const items: readonly ExplorerItem[] = [ + { depth: 0, icon: '', name: 'folder', path: '/test/folder', posInSet: 1, selected: false, setSize: 1, type: DirentType.Directory }, + { depth: 1, icon: '', name: 'nested.txt', path: '/test/folder/nested.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, + ] + const path = '/test/folder' + const root = '/test' + const newDirents = [{ name: 'new.txt', type: DirentType.File }] + const result = updateDirentsAtPath(items, path, root, newDirents) + expect(result).toHaveLength(2) + expect(result[0].name).toBe('folder') + expect(result[0].type).toBe(DirentType.Directory) + expect(result[0].path).toBe('/test/folder') + expect(result[0].depth).toBe(0) + expect(result[0].posInSet).toBe(1) + expect(result[0].setSize).toBe(1) + expect(result[1].name).toBe('new.txt') + expect(result[1].type).toBe(DirentType.File) + expect(result[1].path).toBe('/test/folder/new.txt') + expect(result[1].depth).toBe(1) + expect(result[1].posInSet).toBe(1) + expect(result[1].setSize).toBe(1) +}) diff --git a/packages/explorer-view/test/UpdateEditingValue.test.ts b/packages/explorer-view/test/UpdateEditingValue.test.ts new file mode 100644 index 0000000..bfa0929 --- /dev/null +++ b/packages/explorer-view/test/UpdateEditingValue.test.ts @@ -0,0 +1,250 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' +import * as InputSource from '../src/parts/InputSource/InputSource.ts' +import { updateEditingValue } from '../src/parts/UpdateEditingValue/UpdateEditingValue.ts' + +test('updateEditingValue - updates state with new value', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + const state: ExplorerState = createDefaultState() + const newValue = 'new value' + const result = await updateEditingValue(state, newValue) + expect(result.editingValue).toBe(newValue) + expect(result.editingIcon).toBe('') + expect(mockRpc.invocations).toEqual([]) +}) + +test('updateEditingValue - updates state with new value and input source', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + const state: ExplorerState = createDefaultState() + const newValue = 'new value' + const result = await updateEditingValue(state, newValue, InputSource.User) + expect(result.editingValue).toBe(newValue) + expect(result.editingIcon).toBe('') + expect(mockRpc.invocations).toEqual([]) +}) + +test('updateEditingValue - updates file icon', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingType: ExplorerEditingType.CreateFile, + } + const newValue = 'test.txt' + const result = await updateEditingValue(state, newValue) + expect(result.editingValue).toBe(newValue) + expect(result.editingIcon).toBe('file-test.txt') + expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) +}) + +test('updateEditingValue - updates folder icon', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingType: ExplorerEditingType.CreateFolder, + } + const newValue = 'test' + const result = await updateEditingValue(state, newValue) + expect(result.editingValue).toBe(newValue) + expect(result.editingIcon).toBe('folder-test') + expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test' }]]) +}) + +test('updateEditingValue - updates file icon when renaming file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], + } + const newValue = 'new.txt' + const result = await updateEditingValue(state, newValue) + expect(result.editingValue).toBe(newValue) + expect(result.editingIcon).toBe('file-new.txt') + expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'new.txt' }]]) +}) + +test('updateEditingValue - updates folder icon when renaming folder', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + const state: ExplorerState = { + ...createDefaultState(), + editingIndex: 0, + editingType: ExplorerEditingType.Rename, + items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], + } + const newValue = 'new' + const result = await updateEditingValue(state, newValue) + expect(result.editingValue).toBe(newValue) + expect(result.editingIcon).toBe('folder-new') + expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'new' }]]) +}) + +test('updateEditingValue - preserves other state properties', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + const state: ExplorerState = createDefaultState() + const result = await updateEditingValue(state, 'new value') + expect(result.uid).toBe(state.uid) + expect(result.root).toBe(state.root) + expect(result.items).toBe(state.items) + expect(mockRpc.invocations).toEqual([]) +}) + +test('updateEditingValue - real-time validation during file creation', async () => { + RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingType: ExplorerEditingType.CreateFile, + focusedIndex: 0, + items: [ + { + depth: 0, + icon: '', + name: 'existing-file.txt', + path: '/root/existing-file.txt', + posInSet: 0, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ], + } + + // Test typing a name that already exists + const result = await updateEditingValue(state, 'existing-file.txt') + expect(result.editingErrorMessage).toBe('A file or folder **existing-file.txt** already exists at this location. Please choose a different name.') + + // Test typing a name that doesn't exist + const result2 = await updateEditingValue(state, 'new-file.txt') + expect(result2.editingErrorMessage).toBe('') +}) + +test('updateEditingValue - real-time validation during folder creation', async () => { + RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingType: ExplorerEditingType.CreateFolder, + focusedIndex: 0, + items: [ + { + depth: 0, + icon: '', + name: 'existing-folder', + path: '/root/existing-folder', + posInSet: 0, + selected: false, + setSize: 1, + type: DirentType.Directory, + }, + ], + } + + // Test typing a name that already exists + const result = await updateEditingValue(state, 'existing-folder') + expect(result.editingErrorMessage).toBe('A file or folder **existing-folder** already exists at this location. Please choose a different name.') + + // Test typing a name that doesn't exist + const result2 = await updateEditingValue(state, 'new-folder') + expect(result2.editingErrorMessage).toBe('') +}) + +test('updateEditingValue - no validation during rename', async () => { + RendererWorker.registerMockRpc({ + 'IconTheme.getFileIcon'(params: any) { + return `file-${params.name}` + }, + 'IconTheme.getFolderIcon'(params: any) { + return `folder-${params.name}` + }, + }) + + const state: ExplorerState = { + ...createDefaultState(), + editingType: ExplorerEditingType.Rename, + focusedIndex: 0, + items: [ + { + depth: 0, + icon: '', + name: 'existing-file.txt', + path: '/root/existing-file.txt', + posInSet: 0, + selected: false, + setSize: 1, + type: DirentType.File, + }, + ], + } + + // During rename, file existence validation should not apply + const result = await updateEditingValue(state, 'existing-file.txt') + expect(result.editingErrorMessage).toBe('') +}) diff --git a/packages/explorer-view/test/UpdateIconCache.test.ts b/packages/explorer-view/test/UpdateIconCache.test.ts new file mode 100644 index 0000000..657cca6 --- /dev/null +++ b/packages/explorer-view/test/UpdateIconCache.test.ts @@ -0,0 +1,33 @@ +import { test, expect } from '@jest/globals' +import type { FileIconCache } from '../src/parts/FileIconCache/FileIconCache.ts' +import type { IconRequest } from '../src/parts/IconRequest/IconRequest.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import * as UpdateIconCache from '../src/parts/UpdateIconCache/UpdateIconCache.ts' + +test('updateIconCache - empty requests', () => { + const cache: FileIconCache = {} + const requests: readonly IconRequest[] = [] + const newIcons: readonly string[] = [] + expect(UpdateIconCache.updateIconCache(cache, requests, newIcons)).toBe(cache) +}) + +test('updateIconCache - new icons', () => { + const cache: FileIconCache = { + '/test/file1.txt': 'icon1', + } + const requests: readonly IconRequest[] = [{ name: 'file2.txt', path: '/test/file2.txt', type: DirentType.File }] + const newIcons: readonly string[] = ['icon2'] + expect(UpdateIconCache.updateIconCache(cache, requests, newIcons)).toEqual({ + '/test/file1.txt': 'icon1', + '/test/file2.txt': 'icon2', + }) +}) + +test('updateIconCache - immutability', () => { + const cache: FileIconCache = { existing: 'icon' } + const requests: readonly IconRequest[] = [{ name: 'file.txt', path: '/test/file.txt', type: DirentType.File }] + const newIcons: readonly string[] = ['new-icon'] + const result = UpdateIconCache.updateIconCache(cache, requests, newIcons) + expect(result).not.toBe(cache) + expect(cache).toEqual({ existing: 'icon' }) +}) diff --git a/packages/explorer-view/test/UpdateIcons.test.ts b/packages/explorer-view/test/UpdateIcons.test.ts new file mode 100644 index 0000000..af5baab --- /dev/null +++ b/packages/explorer-view/test/UpdateIcons.test.ts @@ -0,0 +1,75 @@ +import { expect, test } from '@jest/globals' +import { IconThemeWorker } from '@lvce-editor/rpc-registry' +import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' +import * as CreateDefaultState from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import * as UpdateIcons from '../src/parts/UpdateIcons/UpdateIcons.ts' + +test('updateIcons - should update icons for visible items', async () => { + using mockRpc = IconThemeWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getFolderIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getIcons'() { + return ['icon1', 'icon2'] + }, + }) + const defaultState: ExplorerState = CreateDefaultState.createDefaultState() + const state: ExplorerState = { + ...defaultState, + items: [ + { depth: 1, name: 'file1.ts', path: '/test/file1.ts', selected: false, type: 1 }, + { depth: 1, name: 'file2.ts', path: '/test/file2.ts', selected: false, type: 1 }, + { depth: 1, name: 'file3.ts', path: '/test/file3.ts', selected: false, type: 1 }, + ], + maxLineY: 2, + minLineY: 0, + } + + const result = await UpdateIcons.updateIcons(state) + + expect(result.icons).toHaveLength(2) + expect(result.fileIconCache).toBeDefined() + expect(result.items).toEqual(state.items) + expect(result.minLineY).toBe(state.minLineY) + expect(result.maxLineY).toBe(state.maxLineY) + expect(mockRpc.invocations).toEqual([ + [ + 'IconTheme.getIcons', + [ + { name: 'file1.ts', type: 1 }, + { name: 'file2.ts', type: 1 }, + ], + ], + ]) +}) + +test('updateIcons - should handle empty visible items', async () => { + using mockRpc = IconThemeWorker.registerMockRpc({ + 'IconTheme.getFileIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getFolderIcon'() { + return ['icon1', 'icon2'] + }, + 'IconTheme.getIcons'() { + return ['icon1', 'icon2'] + }, + }) + const defaultState: ExplorerState = CreateDefaultState.createDefaultState() + const state: ExplorerState = { + ...defaultState, + items: [], + maxLineY: 0, + minLineY: 0, + } + + const result = await UpdateIcons.updateIcons(state) + + expect(result.icons).toHaveLength(0) + expect(result.fileIconCache).toBeDefined() + expect(result.items).toEqual(state.items) + expect(mockRpc.invocations).toEqual([]) +}) diff --git a/packages/explorer-view/test/UpdateRoot.test.ts b/packages/explorer-view/test/UpdateRoot.test.ts new file mode 100644 index 0000000..4308fd7 --- /dev/null +++ b/packages/explorer-view/test/UpdateRoot.test.ts @@ -0,0 +1,32 @@ +import { test, expect } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' +import { updateRoot } from '../src/parts/UpdateRoot/UpdateRoot.ts' + +test('updateRoot should return same disposed state', async () => { + const state = createDefaultState() + // @ disposed is used in source but not typed + // @ts-ignore + state.disposed = true + const result = await updateRoot(state) + expect(result).toBe(state) +}) + +test('updateRoot should merge dirents correctly', async () => { + const state = createDefaultState() + + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.readDirWithFileTypes'() { + return [ + { name: 'file1', type: 'file' }, + { name: 'dir1', type: 'directory' }, + ] + }, + }) + + const result = await updateRoot(state) + expect(result.items).toHaveLength(2) + expect(result.items[0].name).toBe('dir1') + expect(result.items[1].name).toBe('file1') + expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/']]) +}) diff --git a/packages/explorer-view/test/UpdateTree.test.ts b/packages/explorer-view/test/UpdateTree.test.ts new file mode 100644 index 0000000..7977059 --- /dev/null +++ b/packages/explorer-view/test/UpdateTree.test.ts @@ -0,0 +1,45 @@ +import { test, expect } from '@jest/globals' +import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' +import * as DirentType from '../src/parts/DirentType/DirentType.ts' +import { updateTree } from '../src/parts/UpdateTree/UpdateTree.ts' + +test('updateTree - empty tree', () => { + const tree = {} + const path = '/test' + const newDirents: readonly ExplorerItem[] = [ + { depth: 0, icon: '', name: 'file.txt', path: '/test/file.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, + ] + const result = updateTree(tree, path, newDirents) + expect(result).toEqual({ + '/test': newDirents, + }) +}) + +test('updateTree - existing tree', () => { + const tree = { + '/test': [{ depth: 0, icon: '', name: 'old.txt', path: '/test/old.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }], + } + const path = '/test' + const newDirents: readonly ExplorerItem[] = [ + { depth: 0, icon: '', name: 'new.txt', path: '/test/new.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, + ] + const result = updateTree(tree, path, newDirents) + expect(result).toEqual({ + '/test': newDirents, + }) +}) + +test('updateTree - nested path', () => { + const tree = { + '/test': [{ depth: 0, icon: '', name: 'folder', path: '/test/folder', posInSet: 1, selected: false, setSize: 1, type: DirentType.Directory }], + } + const path = '/test/folder' + const newDirents: readonly ExplorerItem[] = [ + { depth: 0, icon: '', name: 'nested.txt', path: '/test/folder/nested.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, + ] + const result = updateTree(tree, path, newDirents) + expect(result).toEqual({ + '/test': tree['/test'], + '/test/folder': newDirents, + }) +}) diff --git a/packages/explorer-view/test/UploadFileSystemHandles.test.ts b/packages/explorer-view/test/UploadFileSystemHandles.test.ts new file mode 100644 index 0000000..91cb8c8 --- /dev/null +++ b/packages/explorer-view/test/UploadFileSystemHandles.test.ts @@ -0,0 +1,117 @@ +import { expect, test } from '@jest/globals' +import { RendererWorker } from '@lvce-editor/rpc-registry' +import type { DroppedFileItem } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' +import { uploadFileSystemHandles } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' + +class MockFileHandle implements FileSystemHandle { + kind: 'file' | 'directory' + name: string + getFile?: () => Promise<{ text: () => Promise }> + values?: () => { [Symbol.asyncIterator]: () => AsyncGenerator } + + constructor(kind: 'file' | 'directory', name: string, content?: string, children?: MockFileHandle[]) { + this.kind = kind + this.name = name + + if (kind === 'file' && content) { + this.getFile = async (): Promise<{ text: () => Promise }> => ({ + text: async (): Promise => content, + }) + } + + if (kind === 'directory' && children) { + this.values = (): { [Symbol.asyncIterator]: () => AsyncGenerator } => ({ + [Symbol.asyncIterator]: async function* (): AsyncGenerator { + for (const child of children) { + yield child + } + }, + }) + } + } + + async isSameEntry(other: FileSystemHandle): Promise { + return this === other + } +} + +const asDroppedFileItem = (fileHandle: MockFileHandle): DroppedFileItem => { + return { + kind: 'file', + value: fileHandle as FileSystemFileHandle, + } +} + +test('upload single file', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return true + }, + 'FileSystem.writeFile'() { + return true + }, + }) + const fileHandle = new MockFileHandle('file', 'test.txt', 'content') + const result = await uploadFileSystemHandles('/', '/', [fileHandle]) + expect(result).toBe(true) + expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test.txt', 'content']]) +}) + +test('upload single dropped file item', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return true + }, + 'FileSystem.writeFile'() { + return true + }, + }) + const fileHandle = new MockFileHandle('file', 'test.txt', 'content') + const result = await uploadFileSystemHandles('/', '/', [asDroppedFileItem(fileHandle)]) + expect(result).toBe(true) + expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test.txt', 'content']]) +}) + +test('upload directory with files', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return true + }, + 'FileSystem.writeFile'() { + return true + }, + }) + const file1 = new MockFileHandle('file', 'file1.txt', 'content1') + const file2 = new MockFileHandle('file', 'file2.txt', 'content2') + const dir = new MockFileHandle('directory', 'dir', undefined, [file1, file2]) + const result = await uploadFileSystemHandles('/', '/', [dir]) + expect(result).toBe(true) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', '/dir'], + ['FileSystem.writeFile', '/dir/file1.txt', 'content1'], + ['FileSystem.writeFile', '/dir/file2.txt', 'content2'], + ]) +}) + +test('upload multiple files and directories', async () => { + using mockRpc = RendererWorker.registerMockRpc({ + 'FileSystem.mkdir'() { + return true + }, + 'FileSystem.writeFile'() { + return true + }, + }) + const file1 = new MockFileHandle('file', 'file1.txt', 'content1') + const file2 = new MockFileHandle('file', 'file2.txt', 'content2') + const dir1 = new MockFileHandle('directory', 'dir1', undefined, [file1]) + const dir2 = new MockFileHandle('directory', 'dir2', undefined, [file2]) + const result = await uploadFileSystemHandles('/', '/', [dir1, dir2]) + expect(result).toBe(true) + expect(mockRpc.invocations).toEqual([ + ['FileSystem.mkdir', '/dir1'], + ['FileSystem.writeFile', '/dir1/file1.txt', 'content1'], + ['FileSystem.mkdir', '/dir2'], + ['FileSystem.writeFile', '/dir2/file2.txt', 'content2'], + ]) +}) diff --git a/packages/explorer-view/test/ValidateFileName2.test.ts b/packages/explorer-view/test/ValidateFileName2.test.ts new file mode 100644 index 0000000..3ad2053 --- /dev/null +++ b/packages/explorer-view/test/ValidateFileName2.test.ts @@ -0,0 +1,79 @@ +import { test, expect } from '@jest/globals' +import * as ValidateFileName2 from '../src/parts/ValidateFileName2/ValidateFileName2.ts' + +test('validateFileName2 - empty name', () => { + const result = ValidateFileName2.validateFileName2('') + expect(result).toBe('A file or folder name must be provided.') +}) + +test('validateFileName2 - name starting with dot (allowed)', () => { + const result = ValidateFileName2.validateFileName2('.hidden') + expect(result).toBe('') +}) + +test('validateFileName2 - dotfile like .git (allowed)', () => { + const result = ValidateFileName2.validateFileName2('.git') + expect(result).toBe('') +}) + +test('validateFileName2 - dotfile like .editorconfig (allowed)', () => { + const result = ValidateFileName2.validateFileName2('.editorconfig') + expect(result).toBe('') +}) + +test('validateFileName2 - reserved name "." (not allowed)', () => { + const result = ValidateFileName2.validateFileName2('.') + expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +}) + +test('validateFileName2 - reserved name ".." (not allowed)', () => { + const result = ValidateFileName2.validateFileName2('..') + expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +}) + +test('validateFileName2 - reserved name "..." (not allowed)', () => { + const result = ValidateFileName2.validateFileName2('...') + expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +}) + +test('validateFileName2 - reserved name "../" (not allowed)', () => { + const result = ValidateFileName2.validateFileName2('../') + expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +}) + +test('validateFileName2 - name starting with "../" (not allowed)', () => { + const result = ValidateFileName2.validateFileName2('../file.txt') + expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +}) + +test('validateFileName2 - name starting with "../" folder (not allowed)', () => { + const result = ValidateFileName2.validateFileName2('../folder') + expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') +}) + +test('validateFileName2 - name starting with slash', () => { + const result = ValidateFileName2.validateFileName2('/file') + expect(result).toBe('A file or folder name cannot start with a slash.') +}) + +test('validateFileName2 - name starting with backslash', () => { + const result = ValidateFileName2.validateFileName2('\\file') + expect(result).toBe('A file or folder name cannot start with a backslash.') +}) + +test('validateFileName2 - valid name', () => { + const result = ValidateFileName2.validateFileName2('valid-file.txt') + expect(result).toBe('') +}) + +test('validateFileName2 - file already exists', () => { + const siblingFileNames = ['existing-file.txt', 'another-file.js'] + const result = ValidateFileName2.validateFileName2('existing-file.txt', siblingFileNames) + expect(result).toBe('A file or folder **existing-file.txt** already exists at this location. Please choose a different name.') +}) + +test('validateFileName2 - file does not exist', () => { + const siblingFileNames = ['existing-file.txt', 'another-file.js'] + const result = ValidateFileName2.validateFileName2('new-file.txt', siblingFileNames) + expect(result).toBe('') +}) diff --git a/packages/explorer-view/test/ValidateFolderCopy.test.ts b/packages/explorer-view/test/ValidateFolderCopy.test.ts new file mode 100644 index 0000000..3221fea --- /dev/null +++ b/packages/explorer-view/test/ValidateFolderCopy.test.ts @@ -0,0 +1,37 @@ +import { test, expect } from '@jest/globals' +import * as ValidateFolderCopy from '../src/parts/ValidateFolderCopy/ValidateFolderCopy.ts' + +test('should return null when copying folder to different location', () => { + const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder2') + expect(result).toBeNull() +}) + +test('should return null when copying file to different location', () => { + const result = ValidateFolderCopy.validateFolderCopy('test:///file.txt', 'test:///folder') + expect(result).toBeNull() +}) + +test('should return error when copying folder into its own subfolder', () => { + const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1/subfolder') + expect(result).toBe('Cannot copy folder folder1 into a subfolder of itself') +}) + +test('should return error when copying folder into nested subfolder', () => { + const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1/subfolder/nested') + expect(result).toBe('Cannot copy folder folder1 into a subfolder of itself') +}) + +test('should return error with Windows path separators', () => { + const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1\\subfolder') + expect(result).toBe('Cannot copy folder folder1 into a subfolder of itself') +}) + +test('should return null when paths are exactly the same', () => { + const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1') + expect(result).toBeNull() +}) + +test('should return null when target is parent of source', () => { + const result = ValidateFolderCopy.validateFolderCopy('test:///folder1/subfolder', 'test:///folder1') + expect(result).toBeNull() +}) diff --git a/packages/explorer-view/test/ValidateOperations.test.ts b/packages/explorer-view/test/ValidateOperations.test.ts new file mode 100644 index 0000000..a1e623b --- /dev/null +++ b/packages/explorer-view/test/ValidateOperations.test.ts @@ -0,0 +1,263 @@ +import { test, expect } from '@jest/globals' +import type { FileOperation } from '../src/parts/FileOperation/FileOperation.ts' +import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' +import * as ValidateOperations from '../src/parts/ValidateOperations/ValidateOperations.ts' + +test('should return empty array when no operations provided', () => { + const result = ValidateOperations.validateOperations([]) + expect(result).toEqual([]) +}) + +test('should return empty array when operations contain only non-copy operations', () => { + const operations: FileOperation[] = [ + { + path: '/home/user/file.txt', + text: 'content', + type: FileOperationType.CreateFile, + }, + { + path: '/home/user/folder', + type: FileOperationType.CreateFolder, + }, + { + from: '/home/user/old.txt', + path: '/home/user/new.txt', + type: FileOperationType.Rename, + }, + { + path: '/home/user/delete.txt', + type: FileOperationType.Remove, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual([]) +}) + +test('should return empty array when copy operations are valid', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder2', + type: FileOperationType.Copy, + }, + { + from: 'test:///file.txt', + path: 'test:///copied.txt', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual([]) +}) + +test('should return error when copying folder into its own subfolder', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder1/subfolder', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should return error when copying folder into nested subfolder', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder1/subfolder/nested', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should return error with Windows path separators', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder1\\subfolder', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should return empty array when copying file into folder', () => { + const operations: FileOperation[] = [ + { + from: 'test:///file.txt', + path: 'test:///folder/file.txt', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual([]) +}) + +test('should return empty array when copying folder to different location', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder2', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual([]) +}) + +test('should return empty array when copying folder to parent directory', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1/subfolder', + path: 'test:///folder1', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual([]) +}) + +test('should return empty array when paths are exactly the same', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder1', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual([]) +}) + +test('should return errors for all invalid operations when multiple operations', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder2', // valid + type: FileOperationType.Copy, + }, + { + from: 'test:///folder3', + path: 'test:///folder3/subfolder', // invalid + type: FileOperationType.Copy, + }, + { + from: 'test:///folder4', + path: 'test:///folder4/nested', // also invalid + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder3 into a subfolder of itself', 'Cannot copy folder folder4 into a subfolder of itself']) +}) + +test('should handle mixed operation types with invalid copy', () => { + const operations: FileOperation[] = [ + { + path: 'test:///file.txt', + text: 'content', + type: FileOperationType.CreateFile, + }, + { + from: 'test:///folder1', + path: 'test:///folder1/subfolder', // invalid + type: FileOperationType.Copy, + }, + { + from: 'test:///old.txt', + path: 'test:///new.txt', + type: FileOperationType.Rename, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should handle paths with trailing separators', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1/', + path: 'test:///folder1/subfolder/', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should handle mixed path separators', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder1\\subfolder', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should handle relative paths', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder1', + path: 'test:///folder1/subfolder', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should handle deep nested paths', () => { + const operations: FileOperation[] = [ + { + from: 'test:///a/b/c/d/e/folder1', + path: 'test:///a/b/c/d/e/folder1/subfolder', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) +}) + +test('should handle single character folder names', () => { + const operations: FileOperation[] = [ + { + from: 'test:///a', + path: 'test:///a/b', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder a into a subfolder of itself']) +}) + +test('should handle folder names with special characters', () => { + const operations: FileOperation[] = [ + { + from: 'test:///folder-name_123', + path: 'test:///folder-name_123/subfolder', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder folder-name_123 into a subfolder of itself']) +}) + +test('should handle empty folder names', () => { + const operations: FileOperation[] = [ + { + from: 'test:///', + path: 'test:///subfolder', + type: FileOperationType.Copy, + }, + ] + const result = ValidateOperations.validateOperations(operations) + expect(result).toEqual(['Cannot copy folder test: into a subfolder of itself']) +}) diff --git a/packages/explorer-view/test/getFileHandleText.test.ts b/packages/explorer-view/test/getFileHandleText.test.ts new file mode 100644 index 0000000..f49b2b7 --- /dev/null +++ b/packages/explorer-view/test/getFileHandleText.test.ts @@ -0,0 +1,15 @@ +import { test, expect, jest } from '@jest/globals' +import { getFileHandleText } from '../src/parts/GetFileHandleText/GetFileHandleText.ts' + +test('getFileHandleText returns file content as text', async () => { + const mockGetFile = jest.fn<() => Promise<{ text: () => Promise }>>().mockResolvedValue({ + text: jest.fn<() => Promise>().mockResolvedValue('test content'), + }) + const mockFileHandle = { + getFile: mockGetFile, + } as unknown as FileSystemFileHandle + + const result = await getFileHandleText(mockFileHandle) + expect(result).toBe('test content') + expect(mockGetFile).toHaveBeenCalled() +}) diff --git a/packages/explorer-view/tsconfig.json b/packages/explorer-view/tsconfig.json new file mode 100644 index 0000000..14c231f --- /dev/null +++ b/packages/explorer-view/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "lib": ["esnext", "webworker"], + "checkJs": true, + "target": "esnext", + "types": [], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "skipLibCheck": true, + "noEmit": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "assumeChangesOnlyAffectDirectDependencies": true, + "strict": true, + "noImplicitAny": true, + "composite": true, + "allowImportingTsExtensions": true, + "rootDir": ".", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src", "test"] +} diff --git a/packages/server/package-lock.json b/packages/server/package-lock.json new file mode 100644 index 0000000..bb29a73 --- /dev/null +++ b/packages/server/package-lock.json @@ -0,0 +1,2947 @@ +{ + "name": "@lvce-editor/explorer-view-server", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@lvce-editor/explorer-view-server", + "version": "0.0.0-dev", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@lvce-editor/server": "0.83.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "license": "MIT" + }, + "node_modules/@lvce-editor/assert": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@lvce-editor/assert/-/assert-1.5.1.tgz", + "integrity": "sha512-euS3PuVVjZy06bPFbgTz1yjQ0mY5BgWeYEDb9eQL2ncqYeap0ADy1D57nddlps1VkhHxj1g2ifXkLeIKLkQYJg==", + "license": "MIT" + }, + "node_modules/@lvce-editor/auth-process": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/auth-process/-/auth-process-1.6.0.tgz", + "integrity": "sha512-rbUt/aalA0g6qEYycmi/fj2ZC1YXiy6lgHyuGrz+NwqHI0PeSz8CQDleUSPQ2wk3yYz32fzw/CWinIEVLVpCSA==", + "license": "MIT", + "bin": { + "auth-process": "bin/oauthProcess.js" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/@lvce-editor/command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/command/-/command-2.0.0.tgz", + "integrity": "sha512-NZokXOACzuRoIpsHVHx+VhNQwM/QcQ4bl3wc8DgDM/+AxAVT2EU8S9cVQQedtJj94N35zmAB2To6Egm8aifOlw==", + "license": "MIT" + }, + "node_modules/@lvce-editor/constants": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/constants/-/constants-5.14.0.tgz", + "integrity": "sha512-eJvcdatVxKHYVtVhMOIULPo53uMNl6YCNztj65ejI4zVrP0qUspM2ymhpglyRoDnyZ+XtUVlMduCmSSq0fT6eQ==", + "license": "MIT" + }, + "node_modules/@lvce-editor/embeds-process": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/embeds-process/-/embeds-process-4.4.0.tgz", + "integrity": "sha512-odCuJeGo/yKntWBVT5voyETm+oJv4KPDEVn1Owq21CFP8N3lx2FXwUO7l92X65KH3t0T8zBgfyxKBaxF17dksw==", + "license": "MIT", + "optional": true, + "bin": { + "embeds-process": "bin/embedsProcess.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/extension-host-helper-process": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@lvce-editor/extension-host-helper-process/-/extension-host-helper-process-0.83.1.tgz", + "integrity": "sha512-OaAW43ZeuLuszCQKYTMtPlpAGABS5JIIbCBv+yDrg8WNbj6hYHsLV0d3DyjeGLInK3CqOiHBI2168IgtwlOUnA==", + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/rpc": "^6.4.0", + "@lvce-editor/verror": "^1.7.0", + "execa": "^9.6.1", + "got": "^15.0.5", + "minimist": "^1.2.8" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/@lvce-editor/file-system-process": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/file-system-process/-/file-system-process-5.1.0.tgz", + "integrity": "sha512-xRtwtnEjXnDJWBrw8i0C0duo5kpXzJVX3mU55SUGFnoL6JLocy7zAc5Xt3pu6FchF9H3r65Ns/e3DBc5HM50Zg==", + "license": "MIT", + "optional": true, + "dependencies": { + "trash": "^10.1.1", + "ws": "^8.20.0" + }, + "bin": { + "file-system-process": "bin/fileSystemProcess.js" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/@lvce-editor/file-watcher-process": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/file-watcher-process/-/file-watcher-process-3.6.0.tgz", + "integrity": "sha512-EqijIFxF8PoYWhnYpCjwueOz202vid4NpfX1KbW79hkVKOCTe7BlWg5z17K8BbEpP7F0VIUnpiy5mwOoMPoqMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@lvce-editor/assert": "^1.4.0", + "chokidar": "^4.0.3" + }, + "bin": { + "file-watcher-process": "bin/fileWatcherProcess.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/ipc": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/ipc/-/ipc-16.0.0.tgz", + "integrity": "sha512-POkqZlE9AVgQcrV2iwAUcNQ693XisdPMJyTb6hHVvUDFROadpfVY3sZIlk2MvcMjN8nvo/HKil4RLLf0U90Ygw==", + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/verror": "^1.7.0", + "@lvce-editor/web-socket-server": "^2.1.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/json-rpc": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/json-rpc/-/json-rpc-8.0.0.tgz", + "integrity": "sha512-mjeSYYd0qJ0Jz3vpEucBnikdbIFsdmewDX/EkVLHw7obYh0WUXr9f3u528nVAHskrUpb8/IsZY4ynJ0Uaar9bA==", + "license": "MIT" + }, + "node_modules/@lvce-editor/jsonc-parser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/jsonc-parser/-/jsonc-parser-1.5.0.tgz", + "integrity": "sha512-JIZ4ARYlkSa2snKgbgHR/twnLqf3kg0AvL34MS4DB/xmnjlurt5nOByRyoRifiOw/Vjttj7fXgiPxPaj6Ywh5w==", + "license": "MIT" + }, + "node_modules/@lvce-editor/network-process": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/network-process/-/network-process-5.2.0.tgz", + "integrity": "sha512-Kg4YY/c/tImt1LY4ZJTij8gex7Lg9r02/8G2T3igqr9HWq7nQMUym369XcjkIg4ArS0x7P6f6S65Y+kX443HKA==", + "license": "MIT", + "optional": true, + "dependencies": { + "execa": "^9.6.0", + "got": "^14.4.7", + "symlink-dir": "^6.0.5", + "tar-fs": "^3.0.10", + "tmp-promise": "^3.0.3", + "trash": "^9.0.0", + "ws": "^8.18.2" + }, + "bin": { + "network-process": "bin/networkProcess.js" + }, + "engines": { + "node": ">=22" + }, + "optionalDependencies": { + "open": "^10.1.2" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==", + "license": "MIT", + "optional": true, + "dependencies": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/got": { + "version": "14.6.6", + "resolved": "https://registry.npmjs.org/got/-/got-14.6.6.tgz", + "integrity": "sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@sindresorhus/is": "^7.0.1", + "byte-counter": "^0.1.0", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^13.0.12", + "decompress-response": "^10.0.0", + "form-data-encoder": "^4.0.2", + "http2-wrapper": "^2.2.1", + "keyv": "^5.5.3", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^4.0.1", + "responselike": "^4.0.2", + "type-fest": "^4.26.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "license": "MIT", + "optional": true + }, + "node_modules/@lvce-editor/network-process/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/move-file": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/move-file/-/move-file-3.1.0.tgz", + "integrity": "sha512-4aE3U7CCBWgrQlQDMq8da4woBWDGHioJFiOZ8Ie6Yq2uwYQ9V2kGhTz4x3u6Wc+OU17nw0yc3rJ/lQ4jIiPe3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "optional": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/trash": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/trash/-/trash-9.0.0.tgz", + "integrity": "sha512-6U3A0olN4C16iiPZvoF93AcZDNZtv/nI2bHb2m/sO3h/m8VPzg9tPdd3n3LVcYLWz7ui0AHaXYhIuRjzGW9ptg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@sindresorhus/chunkify": "^1.0.0", + "@stroncium/procfs": "^1.2.1", + "globby": "^7.1.1", + "is-path-inside": "^4.0.0", + "move-file": "^3.1.0", + "p-map": "^7.0.2", + "xdg-trashdir": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lvce-editor/network-process/node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lvce-editor/preload": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/preload/-/preload-1.5.0.tgz", + "integrity": "sha512-T9SHAahfrLK9I1ERukWZEeKa0zMRHBAZYOYJ08aaiQyNwYm/gNPDJwGnnV7K333i/MHYC4ISlzYh9VqIzywx3A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@lvce-editor/pretty-error": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/pretty-error/-/pretty-error-2.0.0.tgz", + "integrity": "sha512-esSIqbtOxI/KKIdLI30/cLg5Wq3u3QUnw3ShB5RcocMYzzAdBZrbfwPSVDpd+W+INu9CV+qpNF/bGLPllcrcpw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "lines-and-columns": "^2.0.4" + } + }, + "node_modules/@lvce-editor/preview-process": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/preview-process/-/preview-process-11.0.0.tgz", + "integrity": "sha512-3RcZTokj/dx7XF+yavaZnusRANoPHztt2RRRSY47MvG/O4MJQOuTXMBCOkAe15P1DXPzO7rz9l8sbgtTszOIWQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ws": "^8.18.2" + }, + "bin": { + "preview-process": "bin/previewProcess.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/pty-host": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/pty-host/-/pty-host-8.1.0.tgz", + "integrity": "sha512-RhaALocF9dTRbXfYctmWX23KFNf8R/mCRA8FSiBsCbJQ8zYTUiN5SUgMVBT3MsVS09kWfcOptFIAaq+1WEzexw==", + "license": "MIT", + "optional": true, + "bin": { + "pty-host": "bin/ptyHost.js" + }, + "optionalDependencies": { + "node-pty": "1.1.0-beta34" + } + }, + "node_modules/@lvce-editor/ripgrep": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/ripgrep/-/ripgrep-4.1.0.tgz", + "integrity": "sha512-J57lVXxRIbyuz1YwOi/hiUOMF6KDuOvht5OkhxVQOU971uv3j2t5bNdD6flq0hKmWESlr18p6sO0RTj8WMDIEA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@lvce-editor/verror": "^1.7.0", + "execa": "^9.6.0", + "extract-zip": "^2.0.1", + "fs-extra": "^11.3.2", + "path-exists": "^5.0.0", + "tempy": "^3.1.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/rpc": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/rpc/-/rpc-6.4.0.tgz", + "integrity": "sha512-AhIyFrPz9/9usLNSLNdMtHxSmrfYw4TfJXRMV19px/eYOv+Y20pEq3O31HtKejZaUVRUbPhhJ0EOa0z9YsGAcA==", + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/command": "^2.0.0", + "@lvce-editor/ipc": "^15.0.0", + "@lvce-editor/json-rpc": "^8.0.0" + } + }, + "node_modules/@lvce-editor/rpc-registry": { + "version": "9.25.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/rpc-registry/-/rpc-registry-9.25.0.tgz", + "integrity": "sha512-GCXNiGhRi6oZIoO/BU3v7pbxfZDyB26RBV3/uuzuZ+F4njhAiMySseH3J7Wj2QhgFzgd0Bj3Ejg7360GooqJVQ==", + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/constants": "^5.14.0", + "@lvce-editor/rpc": "^6.4.0" + } + }, + "node_modules/@lvce-editor/rpc/node_modules/@lvce-editor/ipc": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/ipc/-/ipc-15.0.0.tgz", + "integrity": "sha512-PY8HVhuShfGaTgTSgrsgwgv7Po3WPkgh9AlilgYull4yFPKYZphlGogMSudxq+IsdhKYjD7hdncUEoox+idXiQ==", + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "^1.5.1", + "@lvce-editor/verror": "^1.7.0", + "@lvce-editor/web-socket-server": "^2.1.0" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@lvce-editor/search-process": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/search-process/-/search-process-13.1.0.tgz", + "integrity": "sha512-A4W+vb0UPkh8ZpeFf06LKeU7uJDnvI5ZnV0jsxbaPdp6y3icWPxOp6aYYpZierRHKgApuzjlP/eXbgfdKCf7UQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@lvce-editor/constants": "^3.7.0", + "execa": "^9.6.0", + "ws": "^8.18.3" + }, + "bin": { + "search-process": "bin/searchProcess.js" + }, + "engines": { + "node": ">=24" + }, + "optionalDependencies": { + "@lvce-editor/ripgrep": "^4.0.0" + } + }, + "node_modules/@lvce-editor/search-process/node_modules/@lvce-editor/constants": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/constants/-/constants-3.7.0.tgz", + "integrity": "sha512-NTxt0cZlacI63ZryyoMFh1Nw717jyWpTIqnoaK7ssNBDjAWuEmIdNTcJq2ZyAtGkcJReuq1XHzbjAE5o44O0ow==", + "license": "MIT", + "optional": true + }, + "node_modules/@lvce-editor/server": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@lvce-editor/server/-/server-0.83.1.tgz", + "integrity": "sha512-wZzSWs1HrpwbbJazVF5FK7vDKp8xynskVNQEOSmSvoqbNUvU+fDlzLcpiHVlhcO9RIpNj/5zrHmA1zrLvRZc0Q==", + "license": "MIT", + "dependencies": { + "@lvce-editor/shared-process": "0.83.1", + "@lvce-editor/static-server": "0.83.1" + }, + "bin": { + "server": "bin/server.js" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/@lvce-editor/shared-process": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@lvce-editor/shared-process/-/shared-process-0.83.1.tgz", + "integrity": "sha512-XQu/tcdqqrYOpY16Sw0kVohakCs6s7ZC9/iQtMoTFLB3Fi/vcThjSICYwXlEPuuw2GjR5xSzcwZY+5GhLV54jA==", + "license": "MIT", + "dependencies": { + "@lvce-editor/assert": "1.5.1", + "@lvce-editor/auth-process": "1.6.0", + "@lvce-editor/extension-host-helper-process": "0.83.1", + "@lvce-editor/ipc": "16.0.0", + "@lvce-editor/json-rpc": "8.0.0", + "@lvce-editor/jsonc-parser": "1.5.0", + "@lvce-editor/pretty-error": "2.0.0", + "@lvce-editor/rpc-registry": "9.25.0", + "@lvce-editor/verror": "1.7.0", + "is-object": "^1.0.2", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=24" + }, + "optionalDependencies": { + "@lvce-editor/embeds-process": "4.4.0", + "@lvce-editor/file-system-process": "5.1.0", + "@lvce-editor/file-watcher-process": "3.6.0", + "@lvce-editor/network-process": "5.2.0", + "@lvce-editor/preload": "1.5.0", + "@lvce-editor/preview-process": "11.0.0", + "@lvce-editor/pty-host": "8.1.0", + "@lvce-editor/search-process": "13.1.0", + "@lvce-editor/typescript-compile-process": "5.1.0", + "open": "^11.0.0", + "tail": "^2.2.6", + "tmp-promise": "^3.0.3", + "trash": "^10.1.1" + } + }, + "node_modules/@lvce-editor/static-server": { + "version": "0.83.1", + "resolved": "https://registry.npmjs.org/@lvce-editor/static-server/-/static-server-0.83.1.tgz", + "integrity": "sha512-MOfwrBIKnQdnl0Q9mgCk6o9BXa1vXGwi5kNxlYhy62yqCnzhQpbkotHeoeLbrlplpDMIZ0mcEy7+5++bVrgCFA==", + "license": "MIT", + "engines": { + "node": ">=24" + } + }, + "node_modules/@lvce-editor/typescript-compile-process": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/typescript-compile-process/-/typescript-compile-process-5.1.0.tgz", + "integrity": "sha512-w/llmxs6hf9/r2sB1N+O61RqtFE93BTe7YhmlAByHeGnyKs8E476SlZA55Z/dRPb0QmqsowTzzEqp0HBlxsHQA==", + "license": "MIT", + "optional": true, + "bin": { + "typescript-compile-process": "bin/typescriptCompileProcess.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@lvce-editor/verror": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/verror/-/verror-1.7.0.tgz", + "integrity": "sha512-+LGuAEIC2L7pbvkyAQVWM2Go0dAy+UWEui28g07zNtZsCBhm+gusBK8PNwLJLV5Jay+TyUYuwLIbJdjLLzqEBg==", + "license": "MIT" + }, + "node_modules/@lvce-editor/web-socket-server": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/web-socket-server/-/web-socket-server-2.1.0.tgz", + "integrity": "sha512-Yldf6nJ4seaFaysYTkkLkOhuJQxkdyX/u01vk1X0dXi21882wMtQbDmYZoAg9rVGWbdBFDIdAJ99pFCAM8eUQA==", + "license": "MIT", + "dependencies": { + "ws": "^8.18.2" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "optional": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, + "node_modules/@sindresorhus/chunkify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/chunkify/-/chunkify-1.0.0.tgz", + "integrity": "sha512-YJOcVaEasXWcttXetXn0jd6Gtm9wFHQ1gViTPcxhESwkMCOoA4kwFsNr9EGcmsARGx7jXQZWmOR4zQotRcI9hw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/df": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/df/-/df-3.1.1.tgz", + "integrity": "sha512-SME/vtXaJcnQ/HpeV6P82Egy+jThn11IKfwW8+/XVoRD0rmPHVTeKMtww1oWdVnMykzVPjmrDN9S8NBndPEHCQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "execa": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sindresorhus/df/node_modules/execa": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", + "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", + "license": "MIT", + "optional": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^3.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": "^8.12.0 || >=9.7.0" + } + }, + "node_modules/@sindresorhus/df/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "optional": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/df/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/df/node_modules/npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "license": "MIT", + "optional": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sindresorhus/df/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/@sindresorhus/df/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-8.1.0.tgz", + "integrity": "sha512-2SX/1jW6CIMAiebvVv5ZInoCEuWQmMyBoJXXGC6Vjakjp/fpxP5eHs7/V6WKuPEIbuK06+VpjH+vjLQhr98rDQ==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stroncium/procfs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@stroncium/procfs/-/procfs-1.2.1.tgz", + "integrity": "sha512-X1Iui3FUNZP18EUvysTHxt+Avu2nlVzyf90YM8OYgP6SGzTzzX/0JgObfO1AQQDzuZtNNz29bVh8h5R97JrjxA==", + "license": "CC0-1.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "license": "MIT", + "optional": true, + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@zkochan/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@zkochan/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-GBf4ua7ogWTr7fATnzk/JLowZDBnBJMm8RkMaC/KcvxZ9gxbMWix0/jImd815LmqKyIHZ7h7lADRddGMdGBuCA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18.12" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "license": "MIT", + "optional": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "license": "Apache-2.0", + "optional": true, + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT", + "optional": true + }, + "node_modules/bare-events": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz", + "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==", + "license": "Apache-2.0", + "optional": true, + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz", + "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz", + "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.3.tgz", + "integrity": "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "b4a": "^1.8.1", + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz", + "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "optional": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/byte-counter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/byte-counter/-/byte-counter-0.1.0.tgz", + "integrity": "sha512-jheRLVMeUKrDBjVw2O5+k4EvR4t9wtxHL+bo/LxfkxsVeuGMy3a5SEGgXdAFA4FSzTrU8rQXQIrsZ3oBq5a0pQ==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "13.0.19", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-13.0.19.tgz", + "integrity": "sha512-SVXGH037+Mo1aIMO5B2UcleR43FGjFdN+M8JObSyEoQ2Mn4CODRWx28gN5jiTF0n5ItsgtIZfyargMNs8GX4kg==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.2.0", + "get-stream": "^9.0.1", + "http-cache-semantics": "^4.2.0", + "keyv": "^5.6.0", + "mimic-response": "^4.0.0", + "normalize-url": "^8.1.1", + "responselike": "^4.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "optional": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chunk-data": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chunk-data/-/chunk-data-0.1.0.tgz", + "integrity": "sha512-zFyPtyC0SZ6Zu79b9sOYtXZcgrsXe0RpePrzRyj52hYVFG1+Rk6rBqjjOEk+GNQwc3PIX+86teQMok970pod1g==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chunkify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chunkify/-/chunkify-5.0.0.tgz", + "integrity": "sha512-G8dj/3/Gm+1yL4oWSdwIxihZWFlgC4V2zYtIApacI0iPIRKBHlBGOGAiDUBZgrj4H8MBA8g8fPFwnJrWF3wl7Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT", + "optional": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-10.0.0.tgz", + "integrity": "sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==", + "license": "MIT", + "dependencies": { + "mimic-response": "^4.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "optional": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "license": "MIT", + "optional": true, + "dependencies": { + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "license": "MIT", + "optional": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dir-glob/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "optional": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT", + "optional": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "optional": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "optional": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/form-data-encoder": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.1.0.tgz", + "integrity": "sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", + "optional": true + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/got/-/got-15.0.5.tgz", + "integrity": "sha512-PMIMaZuYUCK43+Z9JWEXea4kkX2b3301m81D5TS6QpfG4PmNyirzEdO/Oa2OHAN4GsjnPfvWCWsshKN2rq4/gQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^8.0.0", + "byte-counter": "^0.1.0", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^13.0.18", + "chunk-data": "^0.1.0", + "decompress-response": "^10.0.0", + "http2-wrapper": "^2.2.1", + "keyv": "^5.6.0", + "lowercase-keys": "^4.0.1", + "responselike": "^4.0.2", + "type-fest": "^5.6.0", + "uint8array-extras": "^1.5.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC", + "optional": true + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC", + "optional": true + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "optional": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/lowercase-keys": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-4.0.1.tgz", + "integrity": "sha512-wI9Nui/L8VfADa/cr/7NQruaASk1k23/Uh1khQ02BCVYiiy8F4AhOGnQzJy3Fl/c44GnYSbZHv8g7EcG3kJ1Qg==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT", + "optional": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mount-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mount-point/-/mount-point-3.0.0.tgz", + "integrity": "sha512-jAhfD7ZCG+dbESZjcY1SdFVFqSJkh/yGbdsifHcPkvuLRO5ugK0Ssmd9jdATu29BTd4JiN+vkpMzVvsUgP3SZA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@sindresorhus/df": "^1.0.1", + "pify": "^2.3.0", + "pinkie-promise": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mount-point/node_modules/@sindresorhus/df": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/df/-/df-1.0.1.tgz", + "integrity": "sha512-1Hyp7NQnD/u4DSxR2DGW78TF9k7R0wZ8ev0BpMAIzA6yTQSHqNb5wTuvtcPYf4FWbVse2rW7RgDsyL8ua2vXHw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/move-file": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/move-file/-/move-file-4.1.0.tgz", + "integrity": "sha512-YE06K9XLIvMlqSfoZTl32qvbZLPgL70Za41wS8pEhsSOhy71xz2fn8J07nuz/LEEtPSuUzLUFGAJSx499eKDSw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, + "node_modules/node-pty": { + "version": "1.1.0-beta34", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta34.tgz", + "integrity": "sha512-RraDtX9RS1G1I5iO7e4YIOIA4arzd4ZVCD4mZr7+szaNupoTg9fxDCRr0EanqS0Qlzgm3PIdHNbPmblJguJuyg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^7.1.0" + } + }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "license": "MIT", + "optional": true, + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", + "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT", + "optional": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "license": "MIT", + "optional": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rename-overwrite": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/rename-overwrite/-/rename-overwrite-6.0.6.tgz", + "integrity": "sha512-bSbsw/VyMyDez6NJKxqURBCLRCm98uezWBi03UZCeEFccCNIthC6Jk5JazMjexOTdrYd4q/jIxTIwGtgk1k1gA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@zkochan/rimraf": "^3.0.2", + "fs-extra": "11.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/rename-overwrite/node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/responselike": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-4.0.2.tgz", + "integrity": "sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "optional": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/streamx": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz", + "integrity": "sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==", + "license": "MIT", + "optional": true, + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/symlink-dir": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/symlink-dir/-/symlink-dir-6.0.5.tgz", + "integrity": "sha512-xkihq5JPUZqxZbUOrz+fJprx5KZD0vPmesImGpoqFpPwmaFBpxBB4sl8GEwG2tE5/XVekSZw5I1D5NiwNvtwdQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "better-path-resolve": "^1.0.0", + "rename-overwrite": "^6.0.2" + }, + "bin": { + "symlink-dir": "dist/cli.js" + }, + "engines": { + "node": ">=18.12" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tail": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/tail/-/tail-2.2.6.tgz", + "integrity": "sha512-IQ6G4wK/t8VBauYiGPLx+d3fA5XjSVagjWV5SIYzvEvglbQjwEcukeYI68JOPpdydjxhZ9sIgzRlSmwSpphHyw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", + "license": "MIT", + "optional": true, + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tempy": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.2.0.tgz", + "integrity": "sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trash": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/trash/-/trash-10.1.1.tgz", + "integrity": "sha512-L/mu8sfblMwaS+exj1MxpmihlIRwVQyB6ieKuTTmBJG0lXWBPfx3pMGQG8i3NT/S8vvNZrflDUOp+j0o7Cnxzw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@stroncium/procfs": "^1.2.1", + "chunkify": "^5.0.0", + "globby": "^14.1.0", + "is-path-inside": "^4.0.0", + "move-file": "^4.1.0", + "p-map": "^7.0.3", + "powershell-utils": "^0.2.0", + "wsl-utils": "^0.4.0", + "xdg-trashdir": "^3.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/trash/node_modules/powershell-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.0.tgz", + "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/trash/node_modules/wsl-utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.4.0.tgz", + "integrity": "sha512-9YmF+2sFEd+T7TkwlmE337F0IVzfDvDknhtpBQxxXzEOfgPphGlFYpyx0cTuCIFj8/p+sqwBYAeGxOMNSzPPDA==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/trash/node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-fest": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT", + "optional": true + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "os-homedir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC", + "optional": true + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-trashdir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/xdg-trashdir/-/xdg-trashdir-3.1.0.tgz", + "integrity": "sha512-N1XQngeqMBoj9wM4ZFadVV2MymImeiFfYD+fJrNlcVcOHsJFFQe7n3b+aBoTPwARuq2HQxukfzVpQmAk1gN4sQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@sindresorhus/df": "^3.1.1", + "mount-point": "^3.0.0", + "user-home": "^2.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/xdg-trashdir/node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/packages/server/package.json b/packages/server/package.json new file mode 100644 index 0000000..4b6f5ee --- /dev/null +++ b/packages/server/package.json @@ -0,0 +1,16 @@ +{ + "name": "@lvce-editor/explorer-view-server", + "version": "0.0.0-dev", + "main": "index.js", + "type": "module", + "scripts": { + "postinstall": "node src/postinstall.js", + "dev": "node ./node_modules/@lvce-editor/server/bin/server.js --test-path=../e2e" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@lvce-editor/server": "0.83.1" + } +} diff --git a/packages/server/src/postinstall.js b/packages/server/src/postinstall.js new file mode 100644 index 0000000..03c4559 --- /dev/null +++ b/packages/server/src/postinstall.js @@ -0,0 +1,39 @@ +import { readFile, readdir, writeFile } from 'node:fs/promises' +import { join } from 'node:path' +import { pathToFileURL } from 'node:url' + +const __dirname = import.meta.dirname + +const root = join(__dirname, '..', '..', '..') + +export const getRemoteUrl = (path) => { + const url = pathToFileURL(path).toString().slice(8) + return `/remote/${url}` +} + +const nodeModulesPath = join(root, 'packages', 'server', 'node_modules') + +const workerPath = join(root, '.tmp', 'dist', 'dist', 'explorerViewWorkerMain.js') + +const serverStaticPath = join(nodeModulesPath, '@lvce-editor', 'static-server', 'static') + +const RE_COMMIT_HASH = /^[a-z\d]+$/ +const isCommitHash = (dirent) => { + return dirent.length === 7 && dirent.match(RE_COMMIT_HASH) +} + +const dirents = await readdir(serverStaticPath) +const commitHash = dirents.find(isCommitHash) || '' +const rendererWorkerMainPath = join(serverStaticPath, commitHash, 'packages', 'renderer-worker', 'dist', 'rendererWorkerMain.js') + +const content = await readFile(rendererWorkerMainPath, 'utf-8') + +const remoteUrl = getRemoteUrl(workerPath) +if (!content.includes('// const explorerWorkerUrl = ')) { + const occurrence = `const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\`` + const replacement = `// const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\` +const explorerWorkerUrl = \`${remoteUrl}\`` + + const newContent = content.replace(occurrence, replacement) + await writeFile(rendererWorkerMainPath, newContent) +} diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json new file mode 100644 index 0000000..571bd1d --- /dev/null +++ b/packages/server/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "lib": ["esnext"], + "checkJs": true, + "target": "esnext", + "types": ["node"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "skipLibCheck": true, + "noEmit": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "assumeChangesOnlyAffectDirectDependencies": true, + "strict": true, + "noImplicitAny": false, + "composite": true, + "allowImportingTsExtensions": true, + "rootDir": ".", + "noUnusedLocals": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src", "test"] +} diff --git a/scripts/update-dependencies.sh b/scripts/update-dependencies.sh new file mode 100644 index 0000000..5d86157 --- /dev/null +++ b/scripts/update-dependencies.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +cd $(dirname "$0") +cd .. + +command_exists(){ + command -v "$1" &> /dev/null +} + +if ! command_exists "ncu"; then + echo "npm-check-updates is not installed" + npm i -g npm-check-updates +else + echo "ncu is installed" +fi + +function updateDependencies { + echo "updating dependencies..." + OUTPUT=`ncu -u -x @types/node -x rollup -x lerna -x eslint -x @babel/preset-typescript` + SUB='All dependencies match the latest package versions' + if [[ "$OUTPUT" == *"$SUB"* ]]; then + echo "$OUTPUT" + else + rm -rf node_modules package-lock.json dist + npm install + fi +} + + updateDependencies && +cd packages/build && updateDependencies && cd ../.. && +cd packages/e2e && updateDependencies && cd ../.. && +cd packages/server && updateDependencies && cd ../.. && +cd packages/explorer-view && updateDependencies && cd ../.. && + +echo "Great Success!" + +sleep 2 \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1a3f1fd --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "files": [], + "include": [], + "references": [ + { + "path": "./packages/explorer-view" + }, + { + "path": "./packages/build" + }, + { + "path": "./packages/server" + }, + { + "path": "./packages/e2e" + } + ] +} From 568f4ff152da44c89272a91c863642ba7fe44369 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:27:28 +0200 Subject: [PATCH 02/17] updae --- packages/explorer-view/package.json | 8 ++++---- ...explorerViewWorkerMain.ts => pullRequestWorkerMain.ts} | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename packages/explorer-view/src/{explorerViewWorkerMain.ts => pullRequestWorkerMain.ts} (100%) diff --git a/packages/explorer-view/package.json b/packages/explorer-view/package.json index 38b3093..c1b5557 100644 --- a/packages/explorer-view/package.json +++ b/packages/explorer-view/package.json @@ -1,15 +1,15 @@ { - "name": "@lvce-editor/explorer-view", + "name": "@lvce-editor/pull-request-view", "version": "0.0.0-dev", - "description": "Explorer Worker", + "description": "Pull Request View", "repository": { "type": "git", - "url": "git+https://github.com/lvce-editor/explorer-view.git" + "url": "git+https://github.com/lvce-editor/pull-request-github.git" }, "license": "MIT", "author": "Lvce Editor", "type": "module", - "main": "src/explorerViewWorkerMain.ts", + "main": "src/pullRequestWorkerMain.ts", "scripts": { "build:watch": "cd ../../ && npm run build:watch", "dev": "cd ../../ && npm run dev", diff --git a/packages/explorer-view/src/explorerViewWorkerMain.ts b/packages/explorer-view/src/pullRequestWorkerMain.ts similarity index 100% rename from packages/explorer-view/src/explorerViewWorkerMain.ts rename to packages/explorer-view/src/pullRequestWorkerMain.ts From 9fe175721b19bca3bd704d413e84fde915579613 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:27:54 +0200 Subject: [PATCH 03/17] test --- .../explorer-view/test/AcceptCreate.test.ts | 274 ------------ .../test/AcceptCreateFile.test.ts | 51 --- .../explorer-view/test/AcceptEdit.test.ts | 204 --------- .../explorer-view/test/AcceptRename.test.ts | 228 ---------- .../test/AdjustScrollAfterPaste.test.ts | 80 ---- .../test/ApplyFileOperations.test.ts | 51 --- .../test/CanBeDroppedInto.test.ts | 59 --- .../explorer-view/test/CancelEdit.test.ts | 224 ---------- .../test/CancelTypeAhead.test.ts | 17 - packages/explorer-view/test/ClipBoard.test.ts | 34 -- .../explorer-view/test/CollapseAll.test.ts | 38 -- .../explorer-view/test/CommandMap.test.ts | 6 - .../test/CompareWithSelected.test.ts | 46 -- ...ComputeExplorerRenamedDirentUpdate.test.ts | 119 ----- .../explorer-view/test/ConfirmDelete.test.ts | 26 -- .../explorer-view/test/ConfirmPaste.test.ts | 25 -- .../test/CopyFilesElectron.test.ts | 30 -- packages/explorer-view/test/CopyPath.test.ts | 65 --- .../test/CopyRelativePath.test.ts | 85 ---- packages/explorer-view/test/Create2.test.ts | 20 - .../test/CreateDecorationMap.test.ts | 95 ---- .../test/CreateNestedPath.test.ts | 42 -- .../test/CreateUploadTree.test.ts | 106 ----- packages/explorer-view/test/Diff2.test.ts | 34 -- .../test/DiffEditingSelection.test.ts | 24 - packages/explorer-view/test/DiffFocus.test.ts | 45 -- .../explorer-view/test/DiffSelection.test.ts | 29 -- packages/explorer-view/test/DiffValue.test.ts | 31 -- .../explorer-view/test/EnsureUris.test.ts | 40 -- packages/explorer-view/test/ExpandAll.test.ts | 74 ---- .../test/ExpandRecursively.test.ts | 92 ---- .../test/ExplorerStrings.test.ts | 104 ----- .../explorer-view/test/FileSystem.test.ts | 100 ----- .../test/FilterByFocusWord.test.ts | 26 -- packages/explorer-view/test/Focus.test.ts | 16 - .../explorer-view/test/FocusFirst.test.ts | 78 ---- .../explorer-view/test/FocusIndex.test.ts | 169 ------- packages/explorer-view/test/FocusLast.test.ts | 80 ---- packages/explorer-view/test/FocusNext.test.ts | 110 ----- packages/explorer-view/test/FocusNone.test.ts | 16 - .../explorer-view/test/FocusPrevious.test.ts | 123 ------ .../test/GenerateUniqueName.test.ts | 143 ------ .../test/GetActionButtonVirtualDom.test.ts | 28 -- .../test/GetActionVirtualDom.test.ts | 26 -- .../explorer-view/test/GetActions.test.ts | 42 -- .../explorer-view/test/GetChevronType.test.ts | 32 -- .../test/GetChevronVirtualDom.test.ts | 16 - .../explorer-view/test/GetClickFn.test.ts | 52 --- packages/explorer-view/test/GetCss.test.ts | 119 ----- .../explorer-view/test/GetDragData.test.ts | 26 -- .../explorer-view/test/GetDragLabel.test.ts | 15 - .../explorer-view/test/GetDropHandler.test.ts | 14 - .../explorer-view/test/GetEditingIcon.test.ts | 121 ----- .../explorer-view/test/GetEditingType.test.ts | 13 - .../explorer-view/test/GetErrorCode.test.ts | 20 - .../test/GetErrorMessage.test.ts | 14 - .../test/GetErrorMessageDom.test.ts | 13 - .../explorer-view/test/GetExcluded.test.ts | 6 - .../test/GetExpandedDirents.test.ts | 27 -- .../test/GetExpandedType.test.ts | 28 -- .../test/GetExplorerItemVirtualDom.test.ts | 158 ------- .../test/GetExplorerMaxLineY.test.ts | 66 --- .../test/GetExplorerWelcomeVirtualDom.test.ts | 130 ------ .../explorer-view/test/GetFileArray.test.ts | 40 -- .../test/GetFileDecorations.test.ts | 166 ------- .../explorer-view/test/GetFileHandles.test.ts | 23 - .../test/GetFileIconVirtualDom.test.ts | 25 -- .../explorer-view/test/GetFileIcons.test.ts | 103 ----- .../test/GetFileOperations.test.ts | 45 -- .../test/GetFileOperationsCopy.test.ts | 87 ---- .../test/GetFileOperationsRename.test.ts | 16 - .../explorer-view/test/GetFilePaths.test.ts | 39 -- .../test/GetFittingIndex.test.ts | 41 -- .../test/GetFocusedIndexCancel.test.ts | 41 -- .../test/GetFriendlyErrorMessage.test.ts | 19 - .../test/GetIconVirtualDom.test.ts | 22 - packages/explorer-view/test/GetIndex.test.ts | 25 -- .../test/GetIndexFromPosition.test.ts | 302 ------------- .../explorer-view/test/GetInputDom.test.ts | 48 -- .../explorer-view/test/GetKeyBindings.test.ts | 7 - .../test/GetMenuEntries2.test.ts | 94 ---- .../test/GetMissingIconRequests.test.ts | 32 -- .../test/GetMouseActions.test.ts | 14 - .../GetNewChildDirentsForNewDirent.test.ts | 256 ----------- .../test/GetNewDirentsAccept.test.ts | 129 ------ .../test/GetNewDirentsForCancelRename.test.ts | 45 -- .../test/GetNewDirentsForNewDirent.test.ts | 238 ---------- .../test/GetNewDirentsForRename.test.ts | 45 -- .../test/GetNewDropTargets.test.ts | 32 -- .../test/GetNumberOfVisibleItems.test.ts | 26 -- .../test/GetPasteHandler.test.ts | 22 - packages/explorer-view/test/GetPath.test.ts | 86 ---- .../explorer-view/test/GetPathParts.test.ts | 98 ---- .../test/GetPathSeparator.test.ts | 16 - packages/explorer-view/test/GetPaths.test.ts | 20 - .../test/GetProtoMapInternal.test.ts | 211 --------- .../explorer-view/test/GetRenderer.test.ts | 32 -- .../test/GetRestoredDeltaY.test.ts | 14 - .../explorer-view/test/GetSavedRoot.test.ts | 6 - .../test/GetScrollBarVirtualDom.test.ts | 23 - .../explorer-view/test/GetSettings.test.ts | 75 ---- .../test/GetSiblingFileNames.test.ts | 97 ---- .../explorer-view/test/GetSymlinkType.test.ts | 18 - .../test/GetTreeItemIndent.test.ts | 18 - .../test/GetTreeItemIndentWithChevron.test.ts | 22 - .../test/GetVisibleExplorerItems.test.ts | 90 ---- .../test/HandleArrowLeft.test.ts | 122 ----- .../test/HandleArrowRight.test.ts | 111 ----- .../HandleArrowRightDirectoryExpanded.test.ts | 39 -- .../explorer-view/test/HandleBlur.test.ts | 71 --- .../test/HandleButtonClick.test.ts | 88 ---- .../explorer-view/test/HandleClickAt.test.ts | 83 ---- .../HandleClickCurrentButKeepFocus.test.ts | 11 - .../test/HandleClickDirectory.test.ts | 169 ------- .../test/HandleClickDirectoryExpanded.test.ts | 181 -------- .../HandleClickDirectoryExpanding.test.ts | 35 -- .../test/HandleClickOpenFolder.test.ts | 17 - .../test/HandleClickSymlink.test.ts | 67 --- .../test/HandleContextMenu.test.ts | 37 -- .../test/HandleContextMenuKeyboard.test.ts | 26 -- .../test/HandleContextMenuMouseAt.test.ts | 24 - .../explorer-view/test/HandleCopy.test.ts | 42 -- packages/explorer-view/test/HandleCut.test.ts | 37 -- .../test/HandleDoubleClick.test.ts | 198 --------- .../test/HandleDragLeave.test.ts | 9 - .../explorer-view/test/HandleDragOver.test.ts | 29 -- .../explorer-view/test/HandleDrop.test.ts | 98 ---- .../test/HandleDropRootDefault.test.ts | 199 --------- .../test/HandleDropRootElectron.test.ts | 82 ---- .../explorer-view/test/HandleEscape.test.ts | 17 - .../explorer-view/test/HandleFocus.test.ts | 27 -- .../test/HandleInputBlur.test.ts | 22 - .../explorer-view/test/HandleKeyDown.test.ts | 54 --- .../explorer-view/test/HandlePaste.test.ts | 204 --------- .../test/HandlePasteCopy.test.ts | 145 ------ .../test/HandlePointerDown.test.ts | 36 -- .../test/HandleRangeSelection.test.ts | 75 ---- .../explorer-view/test/HandleResize.test.ts | 63 --- .../test/HandleSelection.test.ts | 20 - .../explorer-view/test/HandleUpload.test.ts | 24 - .../explorer-view/test/HandleWheel.test.ts | 59 --- .../test/HandleWorkspaceChange.test.ts | 293 ------------ packages/explorer-view/test/IsAscii.test.ts | 20 - .../test/IsDirectoryHandle.test.ts | 13 - packages/explorer-view/test/IsEqual.test.ts | 30 -- .../explorer-view/test/IsExpanded.test.ts | 23 - .../test/IsExpandedDirectory.test.ts | 48 -- .../explorer-view/test/IsFileHandle.test.ts | 13 - .../explorer-view/test/IsSymbolicLink.test.ts | 59 --- .../explorer-view/test/IsTopLevel.test.ts | 25 -- .../test/IsUriWithinRoot.test.ts | 22 - .../explorer-view/test/LoadContent.test.ts | 134 ------ packages/explorer-view/test/Main.test.ts | 11 - .../explorer-view/test/MakeExpanded.test.ts | 34 -- packages/explorer-view/test/NewDirent.test.ts | 224 ---------- packages/explorer-view/test/NewFile.test.ts | 79 ---- packages/explorer-view/test/NewFolder.test.ts | 60 --- .../test/NormalizeDecorations.test.ts | 139 ------ .../test/OpenContainingFolder.test.ts | 19 - packages/explorer-view/test/OpenDiff.test.ts | 13 - packages/explorer-view/test/OpenUri.test.ts | 23 - .../explorer-view/test/OrderDirents.test.ts | 56 --- .../test/PasteShouldMove.test.ts | 73 --- packages/explorer-view/test/Path.test.ts | 25 -- packages/explorer-view/test/Refresh.test.ts | 290 ------------ .../test/RefreshChildDirents.test.ts | 55 --- .../explorer-view/test/RemoveDirent.test.ts | 417 ------------------ .../explorer-view/test/RenameDirent.test.ts | 89 ---- packages/explorer-view/test/Render2.test.ts | 51 --- .../explorer-view/test/RenderActions2.test.ts | 48 -- packages/explorer-view/test/RenderCss.test.ts | 308 ------------- .../explorer-view/test/RenderDragData.test.ts | 16 - .../test/RenderEditingSelection.test.ts | 16 - .../test/RenderEventListeners.test.ts | 7 - .../explorer-view/test/RenderFocus.test.ts | 43 -- .../test/RenderFocusContext.test.ts | 41 -- .../explorer-view/test/RenderItems.test.ts | 140 ------ .../explorer-view/test/RenderValue.test.ts | 51 --- .../test/RequestFileIcons.test.ts | 65 --- .../test/ResolveSymbolicLinks.test.ts | 186 -------- .../test/RestoreDirentType.test.ts | 18 - .../explorer-view/test/RestoreState.test.ts | 69 --- .../explorer-view/test/RevealItem.test.ts | 58 --- .../test/RevealItemHidden.test.ts | 57 --- .../test/RevealItemVisible.test.ts | 15 - packages/explorer-view/test/SaveState.test.ts | 57 --- .../explorer-view/test/ScrollInto.test.ts | 34 -- packages/explorer-view/test/SelectAll.test.ts | 24 - .../explorer-view/test/SelectDown.test.ts | 128 ------ .../test/SelectForCompare.test.ts | 32 -- .../explorer-view/test/SelectIndices.test.ts | 20 - packages/explorer-view/test/SelectUp.test.ts | 72 --- .../SendMessagePortToFileSystemWorker.test.ts | 77 ---- .../SendMessagePortToIconThemeWorker.test.ts | 77 ---- packages/explorer-view/test/SetDeltaY.test.ts | 102 ----- .../test/SortExplorerItems.test.ts | 61 --- packages/explorer-view/test/Terminate.test.ts | 9 - .../test/ToCollapsedDirent.test.ts | 92 ---- .../test/ToggleIndividualSelection.test.ts | 80 ---- .../explorer-view/test/TreeToArray.test.ts | 195 -------- .../test/UpdateDirentsAtPath.test.ts | 70 --- .../test/UpdateEditingValue.test.ts | 250 ----------- .../test/UpdateIconCache.test.ts | 33 -- .../explorer-view/test/UpdateIcons.test.ts | 75 ---- .../explorer-view/test/UpdateRoot.test.ts | 32 -- .../explorer-view/test/UpdateTree.test.ts | 45 -- .../test/UploadFileSystemHandles.test.ts | 117 ----- .../test/getFileHandleText.test.ts | 15 - 208 files changed, 14727 deletions(-) delete mode 100644 packages/explorer-view/test/AcceptCreate.test.ts delete mode 100644 packages/explorer-view/test/AcceptCreateFile.test.ts delete mode 100644 packages/explorer-view/test/AcceptEdit.test.ts delete mode 100644 packages/explorer-view/test/AcceptRename.test.ts delete mode 100644 packages/explorer-view/test/AdjustScrollAfterPaste.test.ts delete mode 100644 packages/explorer-view/test/ApplyFileOperations.test.ts delete mode 100644 packages/explorer-view/test/CanBeDroppedInto.test.ts delete mode 100644 packages/explorer-view/test/CancelEdit.test.ts delete mode 100644 packages/explorer-view/test/CancelTypeAhead.test.ts delete mode 100644 packages/explorer-view/test/ClipBoard.test.ts delete mode 100644 packages/explorer-view/test/CollapseAll.test.ts delete mode 100644 packages/explorer-view/test/CommandMap.test.ts delete mode 100644 packages/explorer-view/test/CompareWithSelected.test.ts delete mode 100644 packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts delete mode 100644 packages/explorer-view/test/ConfirmDelete.test.ts delete mode 100644 packages/explorer-view/test/ConfirmPaste.test.ts delete mode 100644 packages/explorer-view/test/CopyFilesElectron.test.ts delete mode 100644 packages/explorer-view/test/CopyPath.test.ts delete mode 100644 packages/explorer-view/test/CopyRelativePath.test.ts delete mode 100644 packages/explorer-view/test/Create2.test.ts delete mode 100644 packages/explorer-view/test/CreateDecorationMap.test.ts delete mode 100644 packages/explorer-view/test/CreateNestedPath.test.ts delete mode 100644 packages/explorer-view/test/CreateUploadTree.test.ts delete mode 100644 packages/explorer-view/test/Diff2.test.ts delete mode 100644 packages/explorer-view/test/DiffEditingSelection.test.ts delete mode 100644 packages/explorer-view/test/DiffFocus.test.ts delete mode 100644 packages/explorer-view/test/DiffSelection.test.ts delete mode 100644 packages/explorer-view/test/DiffValue.test.ts delete mode 100644 packages/explorer-view/test/EnsureUris.test.ts delete mode 100644 packages/explorer-view/test/ExpandAll.test.ts delete mode 100644 packages/explorer-view/test/ExpandRecursively.test.ts delete mode 100644 packages/explorer-view/test/ExplorerStrings.test.ts delete mode 100644 packages/explorer-view/test/FileSystem.test.ts delete mode 100644 packages/explorer-view/test/FilterByFocusWord.test.ts delete mode 100644 packages/explorer-view/test/Focus.test.ts delete mode 100644 packages/explorer-view/test/FocusFirst.test.ts delete mode 100644 packages/explorer-view/test/FocusIndex.test.ts delete mode 100644 packages/explorer-view/test/FocusLast.test.ts delete mode 100644 packages/explorer-view/test/FocusNext.test.ts delete mode 100644 packages/explorer-view/test/FocusNone.test.ts delete mode 100644 packages/explorer-view/test/FocusPrevious.test.ts delete mode 100644 packages/explorer-view/test/GenerateUniqueName.test.ts delete mode 100644 packages/explorer-view/test/GetActionButtonVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetActionVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetActions.test.ts delete mode 100644 packages/explorer-view/test/GetChevronType.test.ts delete mode 100644 packages/explorer-view/test/GetChevronVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetClickFn.test.ts delete mode 100644 packages/explorer-view/test/GetCss.test.ts delete mode 100644 packages/explorer-view/test/GetDragData.test.ts delete mode 100644 packages/explorer-view/test/GetDragLabel.test.ts delete mode 100644 packages/explorer-view/test/GetDropHandler.test.ts delete mode 100644 packages/explorer-view/test/GetEditingIcon.test.ts delete mode 100644 packages/explorer-view/test/GetEditingType.test.ts delete mode 100644 packages/explorer-view/test/GetErrorCode.test.ts delete mode 100644 packages/explorer-view/test/GetErrorMessage.test.ts delete mode 100644 packages/explorer-view/test/GetErrorMessageDom.test.ts delete mode 100644 packages/explorer-view/test/GetExcluded.test.ts delete mode 100644 packages/explorer-view/test/GetExpandedDirents.test.ts delete mode 100644 packages/explorer-view/test/GetExpandedType.test.ts delete mode 100644 packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetExplorerMaxLineY.test.ts delete mode 100644 packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetFileArray.test.ts delete mode 100644 packages/explorer-view/test/GetFileDecorations.test.ts delete mode 100644 packages/explorer-view/test/GetFileHandles.test.ts delete mode 100644 packages/explorer-view/test/GetFileIconVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetFileIcons.test.ts delete mode 100644 packages/explorer-view/test/GetFileOperations.test.ts delete mode 100644 packages/explorer-view/test/GetFileOperationsCopy.test.ts delete mode 100644 packages/explorer-view/test/GetFileOperationsRename.test.ts delete mode 100644 packages/explorer-view/test/GetFilePaths.test.ts delete mode 100644 packages/explorer-view/test/GetFittingIndex.test.ts delete mode 100644 packages/explorer-view/test/GetFocusedIndexCancel.test.ts delete mode 100644 packages/explorer-view/test/GetFriendlyErrorMessage.test.ts delete mode 100644 packages/explorer-view/test/GetIconVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetIndex.test.ts delete mode 100644 packages/explorer-view/test/GetIndexFromPosition.test.ts delete mode 100644 packages/explorer-view/test/GetInputDom.test.ts delete mode 100644 packages/explorer-view/test/GetKeyBindings.test.ts delete mode 100644 packages/explorer-view/test/GetMenuEntries2.test.ts delete mode 100644 packages/explorer-view/test/GetMissingIconRequests.test.ts delete mode 100644 packages/explorer-view/test/GetMouseActions.test.ts delete mode 100644 packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts delete mode 100644 packages/explorer-view/test/GetNewDirentsAccept.test.ts delete mode 100644 packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts delete mode 100644 packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts delete mode 100644 packages/explorer-view/test/GetNewDirentsForRename.test.ts delete mode 100644 packages/explorer-view/test/GetNewDropTargets.test.ts delete mode 100644 packages/explorer-view/test/GetNumberOfVisibleItems.test.ts delete mode 100644 packages/explorer-view/test/GetPasteHandler.test.ts delete mode 100644 packages/explorer-view/test/GetPath.test.ts delete mode 100644 packages/explorer-view/test/GetPathParts.test.ts delete mode 100644 packages/explorer-view/test/GetPathSeparator.test.ts delete mode 100644 packages/explorer-view/test/GetPaths.test.ts delete mode 100644 packages/explorer-view/test/GetProtoMapInternal.test.ts delete mode 100644 packages/explorer-view/test/GetRenderer.test.ts delete mode 100644 packages/explorer-view/test/GetRestoredDeltaY.test.ts delete mode 100644 packages/explorer-view/test/GetSavedRoot.test.ts delete mode 100644 packages/explorer-view/test/GetScrollBarVirtualDom.test.ts delete mode 100644 packages/explorer-view/test/GetSettings.test.ts delete mode 100644 packages/explorer-view/test/GetSiblingFileNames.test.ts delete mode 100644 packages/explorer-view/test/GetSymlinkType.test.ts delete mode 100644 packages/explorer-view/test/GetTreeItemIndent.test.ts delete mode 100644 packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts delete mode 100644 packages/explorer-view/test/GetVisibleExplorerItems.test.ts delete mode 100644 packages/explorer-view/test/HandleArrowLeft.test.ts delete mode 100644 packages/explorer-view/test/HandleArrowRight.test.ts delete mode 100644 packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts delete mode 100644 packages/explorer-view/test/HandleBlur.test.ts delete mode 100644 packages/explorer-view/test/HandleButtonClick.test.ts delete mode 100644 packages/explorer-view/test/HandleClickAt.test.ts delete mode 100644 packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts delete mode 100644 packages/explorer-view/test/HandleClickDirectory.test.ts delete mode 100644 packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts delete mode 100644 packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts delete mode 100644 packages/explorer-view/test/HandleClickOpenFolder.test.ts delete mode 100644 packages/explorer-view/test/HandleClickSymlink.test.ts delete mode 100644 packages/explorer-view/test/HandleContextMenu.test.ts delete mode 100644 packages/explorer-view/test/HandleContextMenuKeyboard.test.ts delete mode 100644 packages/explorer-view/test/HandleContextMenuMouseAt.test.ts delete mode 100644 packages/explorer-view/test/HandleCopy.test.ts delete mode 100644 packages/explorer-view/test/HandleCut.test.ts delete mode 100644 packages/explorer-view/test/HandleDoubleClick.test.ts delete mode 100644 packages/explorer-view/test/HandleDragLeave.test.ts delete mode 100644 packages/explorer-view/test/HandleDragOver.test.ts delete mode 100644 packages/explorer-view/test/HandleDrop.test.ts delete mode 100644 packages/explorer-view/test/HandleDropRootDefault.test.ts delete mode 100644 packages/explorer-view/test/HandleDropRootElectron.test.ts delete mode 100644 packages/explorer-view/test/HandleEscape.test.ts delete mode 100644 packages/explorer-view/test/HandleFocus.test.ts delete mode 100644 packages/explorer-view/test/HandleInputBlur.test.ts delete mode 100644 packages/explorer-view/test/HandleKeyDown.test.ts delete mode 100644 packages/explorer-view/test/HandlePaste.test.ts delete mode 100644 packages/explorer-view/test/HandlePasteCopy.test.ts delete mode 100644 packages/explorer-view/test/HandlePointerDown.test.ts delete mode 100644 packages/explorer-view/test/HandleRangeSelection.test.ts delete mode 100644 packages/explorer-view/test/HandleResize.test.ts delete mode 100644 packages/explorer-view/test/HandleSelection.test.ts delete mode 100644 packages/explorer-view/test/HandleUpload.test.ts delete mode 100644 packages/explorer-view/test/HandleWheel.test.ts delete mode 100644 packages/explorer-view/test/HandleWorkspaceChange.test.ts delete mode 100644 packages/explorer-view/test/IsAscii.test.ts delete mode 100644 packages/explorer-view/test/IsDirectoryHandle.test.ts delete mode 100644 packages/explorer-view/test/IsEqual.test.ts delete mode 100644 packages/explorer-view/test/IsExpanded.test.ts delete mode 100644 packages/explorer-view/test/IsExpandedDirectory.test.ts delete mode 100644 packages/explorer-view/test/IsFileHandle.test.ts delete mode 100644 packages/explorer-view/test/IsSymbolicLink.test.ts delete mode 100644 packages/explorer-view/test/IsTopLevel.test.ts delete mode 100644 packages/explorer-view/test/IsUriWithinRoot.test.ts delete mode 100644 packages/explorer-view/test/LoadContent.test.ts delete mode 100644 packages/explorer-view/test/Main.test.ts delete mode 100644 packages/explorer-view/test/MakeExpanded.test.ts delete mode 100644 packages/explorer-view/test/NewDirent.test.ts delete mode 100644 packages/explorer-view/test/NewFile.test.ts delete mode 100644 packages/explorer-view/test/NewFolder.test.ts delete mode 100644 packages/explorer-view/test/NormalizeDecorations.test.ts delete mode 100644 packages/explorer-view/test/OpenContainingFolder.test.ts delete mode 100644 packages/explorer-view/test/OpenDiff.test.ts delete mode 100644 packages/explorer-view/test/OpenUri.test.ts delete mode 100644 packages/explorer-view/test/OrderDirents.test.ts delete mode 100644 packages/explorer-view/test/PasteShouldMove.test.ts delete mode 100644 packages/explorer-view/test/Path.test.ts delete mode 100644 packages/explorer-view/test/Refresh.test.ts delete mode 100644 packages/explorer-view/test/RefreshChildDirents.test.ts delete mode 100644 packages/explorer-view/test/RemoveDirent.test.ts delete mode 100644 packages/explorer-view/test/RenameDirent.test.ts delete mode 100644 packages/explorer-view/test/Render2.test.ts delete mode 100644 packages/explorer-view/test/RenderActions2.test.ts delete mode 100644 packages/explorer-view/test/RenderCss.test.ts delete mode 100644 packages/explorer-view/test/RenderDragData.test.ts delete mode 100644 packages/explorer-view/test/RenderEditingSelection.test.ts delete mode 100644 packages/explorer-view/test/RenderEventListeners.test.ts delete mode 100644 packages/explorer-view/test/RenderFocus.test.ts delete mode 100644 packages/explorer-view/test/RenderFocusContext.test.ts delete mode 100644 packages/explorer-view/test/RenderItems.test.ts delete mode 100644 packages/explorer-view/test/RenderValue.test.ts delete mode 100644 packages/explorer-view/test/RequestFileIcons.test.ts delete mode 100644 packages/explorer-view/test/ResolveSymbolicLinks.test.ts delete mode 100644 packages/explorer-view/test/RestoreDirentType.test.ts delete mode 100644 packages/explorer-view/test/RestoreState.test.ts delete mode 100644 packages/explorer-view/test/RevealItem.test.ts delete mode 100644 packages/explorer-view/test/RevealItemHidden.test.ts delete mode 100644 packages/explorer-view/test/RevealItemVisible.test.ts delete mode 100644 packages/explorer-view/test/SaveState.test.ts delete mode 100644 packages/explorer-view/test/ScrollInto.test.ts delete mode 100644 packages/explorer-view/test/SelectAll.test.ts delete mode 100644 packages/explorer-view/test/SelectDown.test.ts delete mode 100644 packages/explorer-view/test/SelectForCompare.test.ts delete mode 100644 packages/explorer-view/test/SelectIndices.test.ts delete mode 100644 packages/explorer-view/test/SelectUp.test.ts delete mode 100644 packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts delete mode 100644 packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts delete mode 100644 packages/explorer-view/test/SetDeltaY.test.ts delete mode 100644 packages/explorer-view/test/SortExplorerItems.test.ts delete mode 100644 packages/explorer-view/test/Terminate.test.ts delete mode 100644 packages/explorer-view/test/ToCollapsedDirent.test.ts delete mode 100644 packages/explorer-view/test/ToggleIndividualSelection.test.ts delete mode 100644 packages/explorer-view/test/TreeToArray.test.ts delete mode 100644 packages/explorer-view/test/UpdateDirentsAtPath.test.ts delete mode 100644 packages/explorer-view/test/UpdateEditingValue.test.ts delete mode 100644 packages/explorer-view/test/UpdateIconCache.test.ts delete mode 100644 packages/explorer-view/test/UpdateIcons.test.ts delete mode 100644 packages/explorer-view/test/UpdateRoot.test.ts delete mode 100644 packages/explorer-view/test/UpdateTree.test.ts delete mode 100644 packages/explorer-view/test/UploadFileSystemHandles.test.ts delete mode 100644 packages/explorer-view/test/getFileHandleText.test.ts diff --git a/packages/explorer-view/test/AcceptCreate.test.ts b/packages/explorer-view/test/AcceptCreate.test.ts deleted file mode 100644 index 87338c6..0000000 --- a/packages/explorer-view/test/AcceptCreate.test.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { acceptCreate } from '../src/parts/AcceptCreate/AcceptCreate.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import * as ExplorerStrings from '../src/parts/ExplorerStrings/ExplorerStrings.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' - -test.skip('acceptCreate - empty file name', async () => { - const state: ExplorerState = { - ...createDefaultState(), - editingValue: '', - } - - const result = await acceptCreate(state, DirentType.File) - expect(result).toEqual({ - ...state, - editingErrorMessage: ExplorerStrings.fileOrFolderNameMustBeProvided(), - }) -}) - -test('acceptCreate - successful file creation', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.mkdir'() { - return - }, - 'FileSystem.readDirWithFileTypes'(path: string) { - if (path === 'memfs:///workspace') { - return [{ name: 'test', type: DirentType.Directory }] - } - if (path === 'memfs:///workspace/test') { - return [{ name: 'test.txt', type: DirentType.File }] - } - throw new Error(`unexpected file read ${path}`) - }, - 'FileSystem.writeFile'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return Array(2).fill('') - }, - 'Main.openUri'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 1, - editingValue: 'test.txt', - fileIconCache: {}, - focusedIndex: 0, - height: 100, - itemHeight: 20, - items: [ - { - depth: 0, - name: 'test', - path: 'memfs:///workspace/test', - selected: false, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'test.txt', - path: 'memfs:///workspace/test/test.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.EditingFile, - }, - ], - minLineY: 0, - root: 'memfs:///workspace', - } - - const result = await acceptCreate(state, DirentType.File) - expect(result).toEqual({ - ...state, - editingIndex: -1, - editingType: ExplorerEditingType.None, - focus: FocusId.List, - focusedIndex: 1, - items: [ - { - depth: 1, - icon: '', - name: 'test', - path: 'memfs:///workspace/test', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: 'test.txt', - path: 'memfs:///workspace/test/test.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ], - }) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', 'memfs:///workspace/test'], - ['FileSystem.writeFile', 'memfs:///workspace/test/test.txt', ''], - ['FileSystem.readDirWithFileTypes', 'memfs:///workspace'], - ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/test'], - ['Layout.handleWorkspaceRefresh'], - ['Main.openUri', 'memfs:///workspace/test/test.txt', true], - ]) -}) - -test('acceptCreate - successful folder creation does not open uri', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.mkdir'() { - return - }, - 'FileSystem.readDirWithFileTypes'(path: string) { - if (path === 'memfs:///workspace') { - return [{ name: 'test', type: DirentType.Directory }] - } - if (path === 'memfs:///workspace/test') { - return [{ name: 'newfolder', type: DirentType.Directory }] - } - throw new Error(`unexpected file read ${path}`) - }, - 'FileSystem.writeFile'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return Array(2).fill('') - }, - 'Main.openUri'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 1, - editingValue: 'newfolder', - fileIconCache: {}, - focusedIndex: 0, - height: 100, - itemHeight: 20, - items: [ - { - depth: 0, - name: 'test', - path: 'memfs:///workspace/test', - selected: false, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'newfolder', - path: 'memfs:///workspace/test/newfolder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.EditingFolder, - }, - ], - minLineY: 0, - root: 'memfs:///workspace', - } - - const result = await acceptCreate(state, DirentType.Directory) - expect(result.editingIndex).toBe(-1) - expect(result.editingType).toBe(ExplorerEditingType.None) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', 'memfs:///workspace/test'], - ['FileSystem.mkdir', 'memfs:///workspace/test/newfolder'], - ['FileSystem.readDirWithFileTypes', 'memfs:///workspace'], - ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/test'], - ['Layout.handleWorkspaceRefresh'], - ]) -}) - -test('acceptCreate - nested folder creation uses the file parent when a file is focused', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.mkdir'() { - return - }, - 'FileSystem.readDirWithFileTypes'(path: string) { - if (path === 'memfs:///workspace') { - return [ - { name: 'a', type: DirentType.Directory }, - { name: 'file1.txt', type: DirentType.File }, - ] - } - if (path === 'memfs:///workspace/a') { - return [{ name: 'b', type: DirentType.Directory }] - } - if (path === 'memfs:///workspace/a/b') { - return [{ name: 'c', type: DirentType.Directory }] - } - throw new Error(`unexpected file read ${path}`) - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return Array(5).fill('') - }, - 'Main.openUri'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 1, - editingValue: 'a/b/c', - fileIconCache: {}, - focusedIndex: 0, - height: 100, - itemHeight: 20, - items: [ - { - depth: 0, - icon: '', - name: 'file1.txt', - path: 'memfs:///workspace/file1.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - { - depth: 0, - icon: '', - name: '', - path: 'memfs:///workspace', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.EditingFolder, - }, - ], - minLineY: 0, - pathSeparator: '/', - root: 'memfs:///workspace', - } - - await acceptCreate(state, DirentType.Directory) - - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', 'memfs:///workspace/a'], - ['FileSystem.mkdir', 'memfs:///workspace/a/b'], - ['FileSystem.mkdir', 'memfs:///workspace/a/b/c'], - ['FileSystem.readDirWithFileTypes', 'memfs:///workspace'], - ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/a'], - ['FileSystem.readDirWithFileTypes', 'memfs:///workspace/a/b'], - ['Layout.handleWorkspaceRefresh'], - ]) -}) diff --git a/packages/explorer-view/test/AcceptCreateFile.test.ts b/packages/explorer-view/test/AcceptCreateFile.test.ts deleted file mode 100644 index d885f34..0000000 --- a/packages/explorer-view/test/AcceptCreateFile.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { acceptCreateFile } from '../src/parts/AcceptCreateFile/AcceptCreateFile.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' - -test('acceptCreateFile', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.createFile'() {}, - 'FileSystem.readDirWithFileTypes'(...params: any[]) { - const path = params[0] - if (path === '/test') { - return [{ name: 'folder1', type: DirentType.Directory }] - } - return [] - }, - 'FileSystem.writeFile'() {}, - 'IconTheme.getFolderIcon'() { - return 'folder-icon' - }, - 'IconTheme.getIcons'() { - return ['folder-icon'] - }, - 'Main.openUri'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingValue: 'test.txt', - items: [ - { - depth: 0, - name: 'test', - path: 'test', - selected: false, - type: 1, - }, - ], - root: '/test', - } - const newState = await acceptCreateFile(state) - expect(newState.editingIndex).toBe(-1) - expect(newState.editingType).toBe(0) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.writeFile', 'test/test.txt', ''], - ['Layout.handleWorkspaceRefresh'], - ['Main.openUri', 'test/test.txt', true], - ]) -}) diff --git a/packages/explorer-view/test/AcceptEdit.test.ts b/packages/explorer-view/test/AcceptEdit.test.ts deleted file mode 100644 index bd66557..0000000 --- a/packages/explorer-view/test/AcceptEdit.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import * as ViewletExplorerAcceptEdit from '../src/parts/AcceptEdit/AcceptEdit.ts' -import * as ViewletExplorer from '../src/parts/Create/Create.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import * as FileSystem from '../src/parts/FileSystem/FileSystem.ts' -import * as PathSeparatorType from '../src/parts/PathSeparatorType/PathSeparatorType.ts' - -test.skip('acceptEdit - rename', async () => { - // @ts-ignore - FileSystem.rename.mockImplementation(() => {}) - const state: ExplorerState = { - ...ViewletExplorer.create(1, '', 0, 0, 0, 0, [], 0), - deltaY: 0, - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'b.txt', - focusedIndex: 0, - height: 600, - items: [ - { - depth: 1, - icon: '', - name: 'a.txt', - path: '/test/a.txt', - posInSet: 1, - setSize: 1, - type: DirentType.File, - }, - ], - maxLineY: 2, - minLineY: 1, - pathSeparator: PathSeparatorType.Slash, - root: '/test', - top: 0, - } - expect(await ViewletExplorerAcceptEdit.acceptEdit(state)).toMatchObject({ - items: [ - { - depth: 1, - icon: '', - name: 'b.txt', - path: '/test/b.txt', - posInSet: 1, - setSize: 1, - type: DirentType.File, - }, - ], - }) - expect(FileSystem.rename).toHaveBeenCalledTimes(1) - expect(FileSystem.rename).toHaveBeenCalledWith('/test/a.txt', '/test/b.txt') -}) - -test.skip('acceptEdit - rename - nested file', async () => { - // @ts-ignore - FileSystem.rename.mockImplementation(() => {}) - const state: ExplorerState = { - ...ViewletExplorer.create(1, '', 0, 0, 0, 0, [], 0), - deltaY: 0, - editingIndex: 1, - editingType: ExplorerEditingType.Rename, - editingValue: 'c.txt', - focusedIndex: 0, - height: 600, - items: [ - { - depth: 1, - icon: '', - name: 'a', - path: '/test/a', - posInSet: 1, - setSize: 1, - type: DirentType.Directory, - }, - { - depth: 2, - icon: '', - name: 'b.txt', - path: '/test/a/b.txt', - posInSet: 1, - setSize: 1, - type: DirentType.File, - }, - ], - maxLineY: 2, - minLineY: 1, - pathSeparator: PathSeparatorType.Slash, - root: '/test', - top: 0, - } - expect(await ViewletExplorerAcceptEdit.acceptEdit(state)).toMatchObject({ - focusedIndex: 1, - items: [ - { - depth: 1, - icon: '', - name: 'a', - path: '/test/a', - posInSet: 1, - setSize: 1, - type: DirentType.Directory, - }, - { - depth: 2, - icon: '', - name: 'c.txt', - path: '/test/a/c.txt', - posInSet: 1, - setSize: 1, - type: DirentType.File, - }, - ], - }) -}) - -test.skip('acceptEdit - create - insert folder', async () => { - // @ts-ignore - FileSystem.mkdir.mockImplementation(() => {}) - const state: ExplorerState = { - ...ViewletExplorer.create(1, '', 0, 0, 0, 0, [], 0), - deltaY: 0, - editingIndex: 0, - editingType: ExplorerEditingType.CreateFolder, - editingValue: 'c', - focusedIndex: -1, - height: 600, - items: [ - { - depth: 1, - icon: '', - name: 'a', - path: '/test/a', - posInSet: 1, - setSize: 3, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'b', - path: '/test/b', - posInSet: 2, - setSize: 3, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'd', - path: '/test/d', - posInSet: 3, - setSize: 3, - type: DirentType.Directory, - }, - ], - maxLineY: 2, - minLineY: 1, - pathSeparator: PathSeparatorType.Slash, - root: '/test', - top: 0, - } - expect(await ViewletExplorerAcceptEdit.acceptEdit(state)).toMatchObject({ - focusedIndex: 2, - items: [ - { - depth: 1, - icon: '', - name: 'a', - path: '/test/a', - posInSet: 1, - setSize: 4, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'b', - path: '/test/b', - posInSet: 2, - setSize: 4, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'c', - path: '/test/c', - posInSet: 3, - setSize: 4, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'd', - path: '/test/d', - posInSet: 3, // TODO should be 4 - setSize: 3, // TODO should be 4 - type: DirentType.Directory, - }, - ], - }) -}) diff --git a/packages/explorer-view/test/AcceptRename.test.ts b/packages/explorer-view/test/AcceptRename.test.ts deleted file mode 100644 index 0aa1c98..0000000 --- a/packages/explorer-view/test/AcceptRename.test.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { acceptRename } from '../src/parts/AcceptRename/AcceptRename.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import * as PathSeparatorType from '../src/parts/PathSeparatorType/PathSeparatorType.ts' - -test.skip('acceptRename - basic file rename', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'b.txt', type: DirentType.File }, - { name: 'c.txt', type: DirentType.File }, - ] - }, - 'FileSystem.rename'() { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'b.txt', - items: [ - { depth: 0, name: 'a.txt', path: '/test/a.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'c.txt', path: '/test/c.txt', selected: false, type: DirentType.File }, - ], - pathSeparator: PathSeparatorType.Slash, - } - - const result = await acceptRename(state) - expect(result.items).toHaveLength(2) - expect(result.items[0].name).toBe('b.txt') - expect(result.items[0].path).toBe('/test/b.txt') - expect(result.items[1].name).toBe('c.txt') - expect(result.focusedIndex).toBe(0) - expect(result.editingIndex).toBe(-1) - expect(result.editingType).toBe(ExplorerEditingType.None) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['FileSystem.rename', '/test/a.txt', '/test/b.txt'], - ['FileSystem.readDirWithFileTypes', '/test'], - ]), - ) -}) - -test.skip('acceptRename - folder rename', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'folder2', type: DirentType.Directory }, - { name: 'file.txt', type: DirentType.File }, - ] - }, - 'FileSystem.rename'() { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'folder2', - items: [ - { depth: 0, name: 'folder1', path: '/test/folder1', selected: false, type: DirentType.Directory }, - { depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }, - ], - pathSeparator: PathSeparatorType.Slash, - } - - const result = await acceptRename(state) - expect(result.items).toHaveLength(2) - expect(result.items[0].name).toBe('folder2') - expect(result.items[0].path).toBe('/test/folder2') - expect(result.items[1].name).toBe('file.txt') - expect(result.focusedIndex).toBe(0) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['FileSystem.rename', '/test/folder1', '/test/folder2'], - ['FileSystem.readDirWithFileTypes', '/test'], - ]), - ) -}) - -test.skip('acceptRename - nested file rename', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'b.txt', type: DirentType.File }, - { name: 'c.txt', type: DirentType.File }, - ] - }, - 'FileSystem.rename'() { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 1, - editingType: ExplorerEditingType.Rename, - editingValue: 'b.txt', - items: [ - { depth: 0, name: 'folder', path: '/test/folder', selected: false, type: DirentType.Directory }, - { depth: 1, name: 'a.txt', path: '/test/folder/a.txt', selected: false, type: DirentType.File }, - { depth: 1, name: 'c.txt', path: '/test/folder/c.txt', selected: false, type: DirentType.File }, - ], - pathSeparator: PathSeparatorType.Slash, - } - - const result = await acceptRename(state) - expect(result.items).toHaveLength(3) - expect(result.items[0].name).toBe('folder') - expect(result.items[1].name).toBe('b.txt') - expect(result.items[1].path).toBe('/test/folder/b.txt') - expect(result.items[2].name).toBe('c.txt') - expect(result.focusedIndex).toBe(1) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['FileSystem.rename', '/test/folder/a.txt', '/test/folder/b.txt'], - ['FileSystem.readDirWithFileTypes', '/test/folder'], - ]), - ) -}) - -test.skip('acceptRename - preserves nested items', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [{ name: 'folder2', type: DirentType.Directory }] - }, - 'FileSystem.rename'() { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'folder2', - items: [ - { depth: 0, name: 'folder1', path: '/test/folder1', selected: false, type: DirentType.Directory }, - { depth: 1, name: 'nested.txt', path: '/test/folder1/nested.txt', selected: false, type: DirentType.File }, - ], - pathSeparator: PathSeparatorType.Slash, - } - - const result = await acceptRename(state) - expect(result.items).toHaveLength(2) - expect(result.items[0].name).toBe('folder2') - expect(result.items[0].path).toBe('/test/folder2') - expect(result.items[1].name).toBe('nested.txt') - expect(result.items[1].path).toBe('/test/folder2/nested.txt') - expect(result.focusedIndex).toBe(0) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['FileSystem.rename', '/test/folder1', '/test/folder2'], - ['FileSystem.readDirWithFileTypes', '/test'], - ]), - ) -}) - -test.skip('acceptRename - handles rename error', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.rename'() { - return Promise.reject(new Error('rename failed')) - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'b.txt', - items: [{ depth: 0, name: 'a.txt', path: '/test/a.txt', selected: false, type: DirentType.File }], - pathSeparator: PathSeparatorType.Slash, - } - - const result = await acceptRename(state) - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([['FileSystem.rename', '/test/a.txt', '/test/b.txt']]) -}) - -test.skip('acceptRename - maintains sorting order', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'b.txt', type: DirentType.File }, - { name: 'folder', type: DirentType.Directory }, - { name: 'z.txt', type: DirentType.File }, - ] - }, - 'FileSystem.rename'() { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'b.txt', - items: [ - { depth: 0, name: 'a.txt', path: '/test/a.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'folder', path: '/test/folder', selected: false, type: DirentType.Directory }, - { depth: 0, name: 'z.txt', path: '/test/z.txt', selected: false, type: DirentType.File }, - ], - pathSeparator: PathSeparatorType.Slash, - } - - const result = await acceptRename(state) - expect(result.items).toHaveLength(3) - expect(result.items[0].name).toBe('b.txt') - expect(result.items[1].name).toBe('folder') - expect(result.items[2].name).toBe('z.txt') - expect(result.focusedIndex).toBe(0) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['FileSystem.rename', '/test/a.txt', '/test/b.txt'], - ['FileSystem.readDirWithFileTypes', '/test'], - ]), - ) -}) diff --git a/packages/explorer-view/test/AdjustScrollAfterPaste.test.ts b/packages/explorer-view/test/AdjustScrollAfterPaste.test.ts deleted file mode 100644 index 7074f3c..0000000 --- a/packages/explorer-view/test/AdjustScrollAfterPaste.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { adjustScrollAfterPaste } from '../src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' - -test('should adjust scroll when focused index is below minLineY', () => { - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 100, - height: 100, - itemHeight: 20, - maxLineY: 10, - minLineY: 5, - } - - const result = adjustScrollAfterPaste(state, 2) - - expect(result.focusedIndex).toBe(2) - expect(result.focused).toBe(true) - expect(result.minLineY).toBe(0) - expect(result.maxLineY).toBe(5) - expect(result.deltaY).toBe(0) -}) - -test('should adjust scroll when focused index is above maxLineY', () => { - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 100, - height: 100, - itemHeight: 20, - maxLineY: 10, - minLineY: 5, - } - - const result = adjustScrollAfterPaste(state, 15) - - expect(result.focusedIndex).toBe(15) - expect(result.focused).toBe(true) - expect(result.minLineY).toBe(13) - expect(result.maxLineY).toBe(18) - expect(result.deltaY).toBe(260) -}) - -test('should not adjust scroll when focused index is within viewport', () => { - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 100, - height: 100, - itemHeight: 20, - maxLineY: 10, - minLineY: 5, - } - - const result = adjustScrollAfterPaste(state, 7) - - expect(result.focusedIndex).toBe(7) - expect(result.focused).toBe(true) - expect(result.minLineY).toBe(5) - expect(result.maxLineY).toBe(10) - expect(result.deltaY).toBe(100) -}) - -test('should handle edge case with odd viewport size', () => { - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 100, - height: 120, - itemHeight: 20, - maxLineY: 11, // Odd size: 6 items - minLineY: 5, - } - - const result = adjustScrollAfterPaste(state, 2) - - expect(result.focusedIndex).toBe(2) - expect(result.focused).toBe(true) - expect(result.minLineY).toBe(-1) - expect(result.maxLineY).toBe(5) - expect(result.deltaY).toBe(-20) -}) diff --git a/packages/explorer-view/test/ApplyFileOperations.test.ts b/packages/explorer-view/test/ApplyFileOperations.test.ts deleted file mode 100644 index 45eafd1..0000000 --- a/packages/explorer-view/test/ApplyFileOperations.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { FileOperation } from '../src/parts/FileOperation/FileOperation.ts' -import { applyFileOperations } from '../src/parts/ApplyFileOperations/ApplyFileOperations.ts' -import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' - -test('should apply empty operations', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() {}, - 'FileSystem.writeFile'() {}, - }) - const operations: readonly FileOperation[] = [] - await applyFileOperations(operations) - expect(mockRpc.invocations).toEqual([]) -}) - -test('should create folder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() {}, - 'FileSystem.writeFile'() {}, - }) - const operations: readonly FileOperation[] = [{ path: '/test/folder', type: FileOperationType.CreateFolder }] - await applyFileOperations(operations) - expect(mockRpc.invocations).toEqual([['FileSystem.mkdir', '/test/folder']]) -}) - -test('should create file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() {}, - 'FileSystem.writeFile'() {}, - }) - const operations: readonly FileOperation[] = [{ path: '/test/file.txt', text: 'content', type: FileOperationType.CreateFile }] - await applyFileOperations(operations) - expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test/file.txt', 'content']]) -}) - -test('should apply multiple operations in sequence', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() {}, - 'FileSystem.writeFile'() {}, - }) - const operations: readonly FileOperation[] = [ - { path: '/test/folder', type: FileOperationType.CreateFolder }, - { path: '/test/folder/file.txt', text: 'content', type: FileOperationType.CreateFile }, - ] - await applyFileOperations(operations) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', '/test/folder'], - ['FileSystem.writeFile', '/test/folder/file.txt', 'content'], - ]) -}) diff --git a/packages/explorer-view/test/CanBeDroppedInto.test.ts b/packages/explorer-view/test/CanBeDroppedInto.test.ts deleted file mode 100644 index 7d82625..0000000 --- a/packages/explorer-view/test/CanBeDroppedInto.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as CanBeDroppedInto from '../src/parts/CanBeDroppedInto/CanBeDroppedInto.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' - -test('canBeDroppedInto - directory', () => { - const item: ExplorerItem = { - depth: 0, - name: 'directory', - path: '/directory', - selected: false, - type: DirentType.Directory, - } - expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(true) -}) - -test('canBeDroppedInto - directory expanded', () => { - const item: ExplorerItem = { - depth: 0, - name: 'directory', - path: '/directory', - selected: false, - type: DirentType.DirectoryExpanded, - } - expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(true) -}) - -test('canBeDroppedInto - directory expanding', () => { - const item: ExplorerItem = { - depth: 0, - name: 'directory', - path: '/directory', - selected: false, - type: DirentType.DirectoryExpanding, - } - expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(true) -}) - -test('canBeDroppedInto - file', () => { - const item: ExplorerItem = { - depth: 0, - name: 'file.txt', - path: '/file.txt', - selected: false, - type: DirentType.File, - } - expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(false) -}) - -test('canBeDroppedInto - unknown type', () => { - const item: ExplorerItem = { - depth: 0, - name: 'unknown', - path: '/unknown', - selected: false, - type: 999_999, - } - expect(CanBeDroppedInto.canBeDroppedInto(item)).toBe(false) -}) diff --git a/packages/explorer-view/test/CancelEdit.test.ts b/packages/explorer-view/test/CancelEdit.test.ts deleted file mode 100644 index 0dc8706..0000000 --- a/packages/explorer-view/test/CancelEdit.test.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { cancelEdit } from '../src/parts/CancelEdit/CancelEdit.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' - -test('cancelEdit', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 1, - editingType: ExplorerEditingType.CreateFile, - editingValue: 'test.txt', - } - - const result = await cancelEdit(state) - expect(result).toEqual({ - ...state, - editingIndex: -1, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: true, - focusedIndex: -1, - }) - expect(mockRpc.invocations).toEqual([]) -}) - -test('cancelEdit - removes editing items', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 1, - editingType: ExplorerEditingType.CreateFile, - editingValue: 'test.txt', - items: [ - { - depth: 0, - icon: '', - name: 'file1.txt', - path: '/file1.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - { - depth: 0, - icon: '', - name: 'test.txt', - path: '/test.txt', - posInSet: 2, - selected: false, - setSize: 1, - type: DirentType.EditingFile, - }, - { - depth: 0, - icon: '', - name: 'newfolder', - path: '/newfolder', - posInSet: 3, - selected: false, - setSize: 1, - type: DirentType.EditingFolder, - }, - ], - } - - const result = await cancelEdit(state) - expect(result.items).toHaveLength(1) - expect(result.items[0].type).toBe(DirentType.File) - expect(result).toEqual({ - ...state, - editingIndex: -1, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: true, - focusedIndex: 0, - items: [state.items[0]], - }) - expect(mockRpc.invocations).toEqual([]) -}) - -test('cancelEdit - rename file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'test.txt', - items: [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.EditingFile, - }, - ], - } - - const result = await cancelEdit(state) - expect(result).toEqual({ - ...state, - editingIndex: -1, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: true, - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - }, - ], - }) - expect(mockRpc.invocations).toEqual([]) -}) - -test('cancelEdit - rename folder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'test', - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.EditingFolder, - }, - ], - } - - const result = await cancelEdit(state) - expect(result).toEqual({ - ...state, - editingIndex: -1, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: true, - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - }, - ], - }) - expect(mockRpc.invocations).toEqual([]) -}) - -test('cancelEdit - create file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 1, - editingType: ExplorerEditingType.CreateFile, - editingValue: 'test.txt', - items: [ - { - depth: 0, - name: 'file1.txt', - path: '/file1.txt', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.EditingFile, - }, - ], - } - - const result = await cancelEdit(state) - expect(result.items).toHaveLength(1) - expect(result.items[0].type).toBe(DirentType.File) - expect(result).toEqual({ - ...state, - editingIndex: -1, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: true, - focusedIndex: 0, - items: [state.items[0]], - }) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/CancelTypeAhead.test.ts b/packages/explorer-view/test/CancelTypeAhead.test.ts deleted file mode 100644 index ff3d038..0000000 --- a/packages/explorer-view/test/CancelTypeAhead.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { cancelTypeAhead } from '../src/parts/CancelTypeAhead/CancelTypeAhead.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' - -test('cancelTypeAhead - clears focusWord only', () => { - const initialState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 2, - focusWord: 'abc', - } - - const result = cancelTypeAhead(initialState) - - expect(result.focusWord).toBe('') - expect(result.focusedIndex).toBe(2) -}) diff --git a/packages/explorer-view/test/ClipBoard.test.ts b/packages/explorer-view/test/ClipBoard.test.ts deleted file mode 100644 index b3e84ae..0000000 --- a/packages/explorer-view/test/ClipBoard.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as ClipBoard from '../src/parts/ClipBoard/ClipBoard.ts' - -test('writeText', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'() {}, - }) - await ClipBoard.writeText('test text') - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'test text']]) -}) - -test('readNativeFiles', async () => { - const expectedResult = { - files: ['/test/file1.txt', '/test/file2.txt'], - type: 'copy', - } - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return expectedResult - }, - }) - const result = await ClipBoard.readNativeFiles() - expect(result).toEqual(expectedResult) - expect(mockRpc.invocations).toEqual([['ClipBoard.readNativeFiles']]) -}) - -test('writeNativeFiles', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeNativeFiles'() {}, - }) - await ClipBoard.writeNativeFiles('copy', ['/test/file.txt']) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'copy', ['/test/file.txt']]]) -}) diff --git a/packages/explorer-view/test/CollapseAll.test.ts b/packages/explorer-view/test/CollapseAll.test.ts deleted file mode 100644 index e8fd104..0000000 --- a/packages/explorer-view/test/CollapseAll.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { collapseAll } from '../src/parts/CollapseAll/CollapseAll.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' - -test('collapseAll - empty state', async () => { - const state: ExplorerState = createDefaultState() - const result = await collapseAll(state) - expect(result).toEqual(state) -}) - -test('collapseAll - with nested items', async () => { - const state: ExplorerState = { - ...createDefaultState(), - fileIconCache: { - '/folder1': 'icon', - '/folder1/file1.txt': 'icon', - '/folder2': 'icon', - '/folder2/file2.txt': 'icon', - }, - items: [ - { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }, - { depth: 2, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: DirentType.File }, - { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: DirentType.Directory }, - { depth: 2, name: 'file2.txt', path: '/folder2/file2.txt', selected: false, type: DirentType.File }, - ], - } - - const result = await collapseAll(state) - expect(result).toEqual({ - ...state, - items: [ - { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }, - { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: DirentType.Directory }, - ], - }) -}) diff --git a/packages/explorer-view/test/CommandMap.test.ts b/packages/explorer-view/test/CommandMap.test.ts deleted file mode 100644 index abb67c4..0000000 --- a/packages/explorer-view/test/CommandMap.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as CommandMap from '../src/parts/CommandMap/CommandMap.ts' - -test('commandMap', () => { - expect(typeof CommandMap.commandMap).toBe('object') -}) diff --git a/packages/explorer-view/test/CompareWithSelected.test.ts b/packages/explorer-view/test/CompareWithSelected.test.ts deleted file mode 100644 index 6de1abd..0000000 --- a/packages/explorer-view/test/CompareWithSelected.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { compareWithSelected } from '../src/parts/CompareWithSelected/CompareWithSelected.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' - -test('compareWithSelected - opens diff for selected and focused file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Main.openUri'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - compareSourceUri: '/a.txt', - focusedIndex: 1, - items: [ - { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'b.txt', path: '/b.txt', selected: false, type: DirentType.File }, - ], - } - - const result = await compareWithSelected(state) - - expect(mockRpc.invocations).toEqual([['Main.openUri', 'diff:///a.txt<->/b.txt', true]]) - expect(result).toEqual({ - ...state, - compareSourceUri: '', - }) -}) - -test('compareWithSelected - ignores same focused file', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - - const state: ExplorerState = { - ...createDefaultState(), - compareSourceUri: '/a.txt', - focusedIndex: 0, - items: [{ depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }], - } - - const result = await compareWithSelected(state) - - expect(mockRpc.invocations).toEqual([]) - expect(result).toBe(state) -}) diff --git a/packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts b/packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts deleted file mode 100644 index b6d6869..0000000 --- a/packages/explorer-view/test/ComputeExplorerRenamedDirentUpdate.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { Tree } from '../src/parts/Tree/Tree.ts' -import { computeExplorerRenamedDirentUpdate } from '../src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts' - -test('computeExplorerRenamedDirentUpdate - basic rename', () => { - const root = '/' - const parentPath = '/parent' - const oldUri = '/parent/old' - const newUri = '/parent/new' - const children: ExplorerItem[] = [ - { - depth: 1, - icon: '', - name: 'child1', - path: '/parent/child1', - posInSet: 1, - selected: false, - setSize: 2, - type: 1, - }, - { - depth: 1, - icon: '', - name: 'child2', - path: '/parent/child2', - posInSet: 2, - selected: false, - setSize: 2, - type: 1, - }, - ] - const tree: Tree = { - 'parent/old': [ - { - name: 'nested', - type: 1, - }, - ], - } - - const result = computeExplorerRenamedDirentUpdate(root, parentPath, oldUri, children, tree, newUri) - - expect(result).toEqual({ - parent: children, - 'parent/new': tree['parent/old'], - }) -}) - -test('computeExplorerRenamedDirentUpdate - empty tree', () => { - const root = '/' - const parentPath = '/parent' - const oldUri = '/parent/old' - const newUri = '/parent/new' - const children: ExplorerItem[] = [] - const tree: Tree = {} - - const result = computeExplorerRenamedDirentUpdate(root, parentPath, oldUri, children, tree, newUri) - - expect(result).toEqual({ - parent: [], - 'parent/new': [], - }) -}) - -test('computeExplorerRenamedDirentUpdate - deep nested rename', () => { - const root = '/' - const parentPath = '/' - const oldUri = '/old' - const newUri = '/new' - const children: ExplorerItem[] = [ - { - depth: 1, - icon: '', - name: 'old', - path: '/old', - posInSet: 1, - selected: false, - setSize: 1, - type: 1, - }, - ] - const tree: Tree = { - old: [ - { - name: 'level1', - type: 1, - }, - ], - 'old/level1': [ - { - name: 'level2', - type: 1, - }, - ], - 'old/level1/level2': [ - { - name: 'level3', - type: 1, - }, - ], - 'old/level1/level2/level3': [ - { - name: 'file.txt', - type: 2, - }, - ], - } - - const result = computeExplorerRenamedDirentUpdate(root, parentPath, oldUri, children, tree, newUri) - - expect(result).toEqual({ - '': children, - new: tree['old'], - 'new/level1': tree['old/level1'], - 'new/level1/level2': tree['old/level1/level2'], - 'new/level1/level2/level3': tree['old/level1/level2/level3'], - }) -}) diff --git a/packages/explorer-view/test/ConfirmDelete.test.ts b/packages/explorer-view/test/ConfirmDelete.test.ts deleted file mode 100644 index e00642b..0000000 --- a/packages/explorer-view/test/ConfirmDelete.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { confirmDelete } from '../src/parts/ConfirmDelete/ConfirmDelete.ts' - -test('confirmDelete - single file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'() { - return true - }, - }) - const result = await confirmDelete(['/test/file.txt']) - expect(result).toBe(true) - expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to delete "/test/file.txt"?', undefined]]) -}) - -test('confirmDelete - multiple files', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'() { - return false - }, - }) - - const result = await confirmDelete(['/test/file1.txt', '/test/file2.txt', '/test/file3.txt']) - expect(result).toBe(false) - expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to delete 3 items?', undefined]]) -}) diff --git a/packages/explorer-view/test/ConfirmPaste.test.ts b/packages/explorer-view/test/ConfirmPaste.test.ts deleted file mode 100644 index 0cdc4b9..0000000 --- a/packages/explorer-view/test/ConfirmPaste.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { confirmPaste } from '../src/parts/ConfirmPaste/ConfirmPaste.ts' - -test('confirmPaste returns true when user confirms', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'() { - return true - }, - }) - const result = await confirmPaste() - expect(result).toBe(true) - expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to paste these files?', undefined]]) -}) - -test('confirmPaste returns false when user cancels', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'() { - return false - }, - }) - const result = await confirmPaste() - expect(result).toBe(false) - expect(mockRpc.invocations).toEqual([['ConfirmPrompt.prompt', 'Are you sure you want to paste these files?', undefined]]) -}) diff --git a/packages/explorer-view/test/CopyFilesElectron.test.ts b/packages/explorer-view/test/CopyFilesElectron.test.ts deleted file mode 100644 index d0dcf9b..0000000 --- a/packages/explorer-view/test/CopyFilesElectron.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { DroppedArgs } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' -import { copyFilesElectron } from '../src/parts/CopyFilesElectron/CopyFilesElectron.ts' - -test('copyFilesElectron', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.copy'() { - return undefined - }, - 'FileSystem.getPathSeparator'() { - return '/' - }, - }) - - const root = '/test' - const fileHandles: DroppedArgs = [ - { kind: 'file', value: { kind: 'file', name: 'file1.txt' } as FileSystemFileHandle }, - { kind: 'file', value: { kind: 'file', name: 'file2.txt' } as FileSystemFileHandle }, - ] - const files: readonly File[] = [] - const paths = ['/source/file1.txt', '/source/file2.txt'] - - await copyFilesElectron(root, fileHandles, files, paths) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.getPathSeparator', '/test'], - ['FileSystem.copy', '/source/file1.txt', '/test/file1.txt'], - ['FileSystem.copy', '/source/file2.txt', '/test/file2.txt'], - ]) -}) diff --git a/packages/explorer-view/test/CopyPath.test.ts b/packages/explorer-view/test/CopyPath.test.ts deleted file mode 100644 index 21208f7..0000000 --- a/packages/explorer-view/test/CopyPath.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { copyPath } from '../src/parts/CopyPath/CopyPath.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' - -test('copyPath - writes absolute path of focused dirent to clipboard', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'(text: string) { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }], - } - - const result = await copyPath(state) - - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', '/test/file.txt']]) -}) - -test('copyPath - writes workspace path when no focused dirent', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'(text: string) { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [], - root: 'memfs:///workspace', - } - - const result = await copyPath(state) - - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'memfs:///workspace']]) -}) - -test('copyPath - writes workspace path when focused index is out of bounds', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'(text: string) { - return - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 2, - items: [{ depth: 0, name: 'file.txt', path: 'memfs:///workspace/file.txt', selected: false, type: DirentType.File }], - root: 'memfs:///workspace', - } - - const result = await copyPath(state) - - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'memfs:///workspace']]) -}) diff --git a/packages/explorer-view/test/CopyRelativePath.test.ts b/packages/explorer-view/test/CopyRelativePath.test.ts deleted file mode 100644 index 18d5970..0000000 --- a/packages/explorer-view/test/CopyRelativePath.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { copyRelativePath } from '../src/parts/CopyRelativePath/CopyRelativePath.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' - -test('copyRelativePath - copies relative path of focused dirent', async (): Promise => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }], - } - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'() {}, - }) - const result = await copyRelativePath(state) - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'test/file.txt']]) -}) - -test('copyRelativePath - returns state when no focused dirent', async (): Promise => { - const state = createDefaultState() - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'() {}, - }) - const result = await copyRelativePath(state) - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test('copyRelativePath - slices first character from path', async (): Promise => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'file.txt', path: '/single', selected: false, type: DirentType.File }], - } - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'() {}, - }) - await copyRelativePath(state) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'single']]) -}) - -test('copyRelativePath - handles nested paths correctly', async (): Promise => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'file.txt', path: '/a/b/c/file.txt', selected: false, type: DirentType.File }], - } - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'() {}, - }) - await copyRelativePath(state) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'a/b/c/file.txt']]) -}) - -test('copyRelativePath - strips workspace root prefix from runtime paths', async (): Promise => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'file.txt', path: 'memfs:///workspace/a/b.txt', selected: false, type: DirentType.File }], - pathSeparator: '/', - root: 'memfs:///workspace', - } - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'() {}, - }) - await copyRelativePath(state) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeText', 'a/b.txt']]) -}) - -test('copyRelativePath - returns state after writing to clipboard', async (): Promise => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }], - } - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeText'() {}, - }) - const result = await copyRelativePath(state) - expect(result).toBe(state) - expect(mockRpc.invocations).toHaveLength(1) -}) diff --git a/packages/explorer-view/test/Create2.test.ts b/packages/explorer-view/test/Create2.test.ts deleted file mode 100644 index 7bb1236..0000000 --- a/packages/explorer-view/test/Create2.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { expect, test } from '@jest/globals' -import { create2 } from '../src/parts/Create2/Create2.ts' -import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' - -test('create2', () => { - const uid = 1 - const uri = 'test' - const x = 0 - const y = 0 - const width = 100 - const height = 200 - const args = {} - const parentUid = 0 - const platform = 0 - - create2(uid, uri, x, y, width, height, args, parentUid, platform) - - const state = ExplorerStates.get(uid) - expect(state).toBeDefined() -}) diff --git a/packages/explorer-view/test/CreateDecorationMap.test.ts b/packages/explorer-view/test/CreateDecorationMap.test.ts deleted file mode 100644 index ea78b95..0000000 --- a/packages/explorer-view/test/CreateDecorationMap.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDecorationMap } from '../src/parts/CreateDecorationMap/CreateDecorationMap.ts' - -test('createDecorationMap - creates map from single decoration', () => { - const decorations = [{ decoration: 'modified', uri: '/home/user/file.txt' }] - const result = createDecorationMap(decorations) - expect(result).toEqual({ - 'file:///home/user/file.txt': 'modified', - }) -}) - -test('createDecorationMap - creates map from multiple decorations', () => { - const decorations = [ - { decoration: 'modified', uri: '/home/user/file1.txt' }, - { decoration: 'added', uri: '/home/user/file2.txt' }, - { decoration: 'deleted', uri: '/home/user/file3.txt' }, - ] - const result = createDecorationMap(decorations) - expect(result).toEqual({ - 'file:///home/user/file1.txt': 'modified', - 'file:///home/user/file2.txt': 'added', - 'file:///home/user/file3.txt': 'deleted', - }) -}) - -test('createDecorationMap - handles URIs that are already URIs', () => { - const decorations = [ - { decoration: 'modified', uri: 'file:///home/user/file1.txt' }, - { decoration: 'added', uri: 'https://example.com/file.txt' }, - ] - const result = createDecorationMap(decorations) - expect(result).toEqual({ - 'file:///home/user/file1.txt': 'modified', - 'https://example.com/file.txt': 'added', - }) -}) - -test('createDecorationMap - handles empty array', () => { - const decorations: readonly any[] = [] - const result = createDecorationMap(decorations) - expect(result).toEqual({}) - expect(Object.getPrototypeOf(result)).toBe(null) -}) - -test('createDecorationMap - uses Object.create(null) for prototype-less map', () => { - const decorations = [{ decoration: 'modified', uri: '/home/user/file.txt' }] - const result = createDecorationMap(decorations) - expect(Object.getPrototypeOf(result)).toBe(null) - expect('toString' in result).toBe(false) -}) - -test('createDecorationMap - handles mixed paths and URIs', () => { - const decorations = [ - { decoration: 'modified', uri: '/absolute/path.txt' }, - { decoration: 'added', uri: 'file:///already/uri.txt' }, - { decoration: 'deleted', uri: 'https://example.com/file.txt' }, - ] - const result = createDecorationMap(decorations) - expect(result).toEqual({ - 'file:///absolute/path.txt': 'modified', - 'file:///already/uri.txt': 'added', - 'https://example.com/file.txt': 'deleted', - }) -}) - -test('createDecorationMap - handles duplicate URIs (last one wins)', () => { - const decorations = [ - { decoration: 'modified', uri: '/home/user/file.txt' }, - { decoration: 'added', uri: '/home/user/file.txt' }, - ] - const result = createDecorationMap(decorations) - expect(result).toEqual({ - 'file:///home/user/file.txt': 'added', - }) -}) - -test('createDecorationMap - handles empty decoration strings', () => { - const decorations = [ - { decoration: '', uri: '/home/user/file1.txt' }, - { decoration: 'modified', uri: '/home/user/file2.txt' }, - ] - const result = createDecorationMap(decorations) - expect(result).toEqual({ - 'file:///home/user/file1.txt': '', - 'file:///home/user/file2.txt': 'modified', - }) -}) - -test('createDecorationMap - handles root path', () => { - const decorations = [{ decoration: 'modified', uri: '/' }] - const result = createDecorationMap(decorations) - expect(result).toEqual({ - 'file:///': 'modified', - }) -}) diff --git a/packages/explorer-view/test/CreateNestedPath.test.ts b/packages/explorer-view/test/CreateNestedPath.test.ts deleted file mode 100644 index 9aa2b47..0000000 --- a/packages/explorer-view/test/CreateNestedPath.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { createNestedPath } from '../src/parts/CreateNestedPath/CreateNestedPath.ts' - -test('createNestedPath - creates all directories', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return - }, - }) - const root = '/a' - await createNestedPath(root, '/a/b/c', '/') - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', '/ab'], - ['FileSystem.mkdir', '/ab/c'], - ]) -}) - -test('createNestedPath - handles existing directories', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return Promise.reject(new Error('Directory already exists')) - }, - }) - const root = '/a' - await createNestedPath(root, '/a/b/c', '/') - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', '/ab'], - ['FileSystem.mkdir', '/ab/c'], - ]) -}) - -test('createNestedPath - propagates other errors', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return Promise.reject(new Error('Permission denied')) - }, - }) - const root = '/a' - await expect(createNestedPath(root, '/a/b/c', '/')).rejects.toThrow('Permission denied') - expect(mockRpc.invocations).toEqual([['FileSystem.mkdir', '/ab']]) -}) diff --git a/packages/explorer-view/test/CreateUploadTree.test.ts b/packages/explorer-view/test/CreateUploadTree.test.ts deleted file mode 100644 index 81c398a..0000000 --- a/packages/explorer-view/test/CreateUploadTree.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createUploadTree } from '../src/parts/CreateUploadTree/CreateUploadTree.ts' - -test('createUploadTree with files', async (): Promise => { - const fileHandle = { - async getFile(): Promise<{ text(): Promise }> { - return { - async text(): Promise { - return 'file content' - }, - } - }, - isSameEntry: async (): Promise => false, - kind: 'file', - name: 'test.txt', - } as FileSystemHandle - - const result = await createUploadTree('root', [fileHandle]) - expect(result).toEqual({ - 'test.txt': 'file content', - }) -}) - -test('createUploadTree with directories', async (): Promise => { - const fileHandle = { - async getFile(): Promise<{ text(): Promise }> { - return { - async text(): Promise { - return 'file content' - }, - } - }, - isSameEntry: async (): Promise => false, - kind: 'file', - name: 'test.txt', - } as FileSystemHandle - - const directoryHandle = { - isSameEntry: async (): Promise => false, - kind: 'directory', - name: 'dir', - values(): { [Symbol.asyncIterator](): AsyncGenerator } { - return { - [Symbol.asyncIterator]: async function* (): AsyncGenerator { - yield fileHandle - }, - } - }, - } as FileSystemHandle - - const result = await createUploadTree('root', [directoryHandle]) - expect(result).toEqual({ - dir: { - 'test.txt': 'file content', - }, - }) -}) - -test('createUploadTree with mixed content', async (): Promise => { - const fileHandle1 = { - async getFile(): Promise<{ text(): Promise }> { - return { - async text(): Promise { - return 'file content 1' - }, - } - }, - isSameEntry: async (): Promise => false, - kind: 'file', - name: 'test1.txt', - } as FileSystemHandle - - const fileHandle2 = { - async getFile(): Promise<{ text(): Promise }> { - return { - async text(): Promise { - return 'file content 2' - }, - } - }, - isSameEntry: async (): Promise => false, - kind: 'file', - name: 'test2.txt', - } as FileSystemHandle - - const directoryHandle = { - isSameEntry: async (): Promise => false, - kind: 'directory', - name: 'dir', - values(): { [Symbol.asyncIterator](): AsyncGenerator } { - return { - [Symbol.asyncIterator]: async function* (): AsyncGenerator { - yield fileHandle2 - }, - } - }, - } as FileSystemHandle - - const result = await createUploadTree('root', [fileHandle1, directoryHandle]) - expect(result).toEqual({ - dir: { - 'test2.txt': 'file content 2', - }, - 'test1.txt': 'file content 1', - }) -}) diff --git a/packages/explorer-view/test/Diff2.test.ts b/packages/explorer-view/test/Diff2.test.ts deleted file mode 100644 index 3b97a1f..0000000 --- a/packages/explorer-view/test/Diff2.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { diff2 } from '../src/parts/Diff2/Diff2.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' -import { set } from '../src/parts/ExplorerStates/ExplorerStates.ts' - -test('diff2 - empty states', () => { - const uid = 1 - const oldState: ExplorerState = createDefaultState() - const newState: ExplorerState = { - ...oldState, - items: [], - } - set(uid, oldState, newState) - const result = diff2(uid) - expect(result).toEqual([12]) -}) - -test('diff2 - different states', () => { - const uid = 2 - const oldState: ExplorerState = { - ...createDefaultState(), - items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: DirentType.File }], - } - const newState: ExplorerState = { - ...oldState, - items: [{ depth: 0, name: 'file2.txt', path: '/file2.txt', selected: false, type: DirentType.File }], - } - ExplorerStates.set(uid, oldState, newState) - const result = diff2(uid) - expect(result).toEqual([12]) -}) diff --git a/packages/explorer-view/test/DiffEditingSelection.test.ts b/packages/explorer-view/test/DiffEditingSelection.test.ts deleted file mode 100644 index c8755e7..0000000 --- a/packages/explorer-view/test/DiffEditingSelection.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { diffEditingSelection } from '../src/parts/DiffEditingSelection/DiffEditingSelection.ts' - -test('diffEditingSelection - returns undefined when selection is the same', () => { - const state: ExplorerState = { - ...createDefaultState(), - editingSelectionEnd: 5, - editingSelectionStart: 0, - } - const result = diffEditingSelection(state, 0, 5) - expect(result).toBe(undefined) -}) - -test('diffEditingSelection - returns new selection when different', () => { - const state: ExplorerState = { - ...createDefaultState(), - editingSelectionEnd: 5, - editingSelectionStart: 0, - } - const result = diffEditingSelection(state, 1, 6) - expect(result).toEqual({ end: 6, start: 1 }) -}) diff --git a/packages/explorer-view/test/DiffFocus.test.ts b/packages/explorer-view/test/DiffFocus.test.ts deleted file mode 100644 index b542a67..0000000 --- a/packages/explorer-view/test/DiffFocus.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { expect, test } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { isEqual } from '../src/parts/DiffFocus/DiffFocus.ts' - -test('isEqual should return true when focused and focus are equal', () => { - const oldState = { - ...createDefaultState(), - focus: 1, - focused: true, - } - const newState = { - ...createDefaultState(), - focus: 1, - focused: true, - } - expect(isEqual(oldState, newState)).toBe(true) -}) - -test('isEqual should return false when focused differs', () => { - const oldState = { - ...createDefaultState(), - focus: 1, - focused: true, - } - const newState = { - ...createDefaultState(), - focus: 1, - focused: false, - } - expect(isEqual(oldState, newState)).toBe(false) -}) - -test('isEqual should return false when focus differs', () => { - const oldState = { - ...createDefaultState(), - focus: 1, - focused: true, - } - const newState = { - ...createDefaultState(), - focus: 2, - focused: true, - } - expect(isEqual(oldState, newState)).toBe(false) -}) diff --git a/packages/explorer-view/test/DiffSelection.test.ts b/packages/explorer-view/test/DiffSelection.test.ts deleted file mode 100644 index adbec21..0000000 --- a/packages/explorer-view/test/DiffSelection.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { isEqual } from '../src/parts/DiffSelection/DiffSelection.ts' - -test('isEqual - same selection', () => { - const state: ExplorerState = { - ...createDefaultState(), - editingSelectionEnd: 5, - editingSelectionStart: 0, - } - const result = isEqual(state, state) - expect(result).toBe(true) -}) - -test('isEqual - different selection', () => { - const oldState: ExplorerState = { - ...createDefaultState(), - editingSelectionEnd: 5, - editingSelectionStart: 0, - } - const newState: ExplorerState = { - ...createDefaultState(), - editingSelectionEnd: 6, - editingSelectionStart: 1, - } - const result = isEqual(oldState, newState) - expect(result).toBe(false) -}) diff --git a/packages/explorer-view/test/DiffValue.test.ts b/packages/explorer-view/test/DiffValue.test.ts deleted file mode 100644 index 91b4455..0000000 --- a/packages/explorer-view/test/DiffValue.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { isEqual } from '../src/parts/DiffValue/DiffValue.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' - -test('isEqual - same focus and editing value', () => { - const state1 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } - const state2 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } - - expect(isEqual(state1, state2)).toBe(true) -}) - -test('isEqual - different focus', () => { - const state1 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } - const state2 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.List } - expect(isEqual(state1, state2)).toBe(true) -}) - -test('isEqual - different editing value', () => { - const state1 = { ...createDefaultState(), editingValue: 'test1', focus: FocusId.Input } - const state2 = { ...createDefaultState(), editingValue: 'test2', focus: FocusId.Input } - - expect(isEqual(state1, state2)).toBe(false) -}) - -test('isEqual - new focus is list', () => { - const state1 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.Input } - const state2 = { ...createDefaultState(), editingValue: 'test', focus: FocusId.List } - - expect(isEqual(state1, state2)).toBe(true) -}) diff --git a/packages/explorer-view/test/EnsureUris.test.ts b/packages/explorer-view/test/EnsureUris.test.ts deleted file mode 100644 index 0ae1e68..0000000 --- a/packages/explorer-view/test/EnsureUris.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { test, expect } from '@jest/globals' -import { ensureUri, ensureUris } from '../src/parts/EnsureUris/EnsureUris.ts' - -test('ensureUri - adds file:// prefix to paths starting with /', () => { - expect(ensureUri('/home/user/file.txt')).toBe('file:///home/user/file.txt') - expect(ensureUri('/')).toBe('file:///') - expect(ensureUri('/path/to/directory/')).toBe('file:///path/to/directory/') -}) - -test('ensureUri - returns string as-is if it does not start with /', () => { - expect(ensureUri('file:///home/user/file.txt')).toBe('file:///home/user/file.txt') - expect(ensureUri('https://example.com/file.txt')).toBe('https://example.com/file.txt') - expect(ensureUri('relative/path/file.txt')).toBe('relative/path/file.txt') - expect(ensureUri('')).toBe('') -}) - -test('ensureUris - processes array of strings', () => { - const input = ['/home/user/file1.txt', '/home/user/file2.txt', 'file:///already/uri.txt'] - const result = ensureUris(input) - expect(result).toEqual(['file:///home/user/file1.txt', 'file:///home/user/file2.txt', 'file:///already/uri.txt']) -}) - -test('ensureUris - handles empty array', () => { - const result = ensureUris([]) - expect(result).toEqual([]) -}) - -test('ensureUris - handles mixed paths and URIs', () => { - const input = ['/absolute/path.txt', 'file:///already/uri.txt', 'https://example.com/file.txt', '/another/path'] - const result = ensureUris(input) - expect(result).toEqual(['file:///absolute/path.txt', 'file:///already/uri.txt', 'https://example.com/file.txt', 'file:///another/path']) -}) - -test('ensureUris - preserves readonly array type', () => { - const input: readonly string[] = ['/path1', '/path2'] - const result = ensureUris(input) - expect(result).toEqual(['file:///path1', 'file:///path2']) - // Verify it returns a readonly array - expect(Object.isFrozen(result) || Array.isArray(result)).toBe(true) -}) diff --git a/packages/explorer-view/test/ExpandAll.test.ts b/packages/explorer-view/test/ExpandAll.test.ts deleted file mode 100644 index fa6455f..0000000 --- a/packages/explorer-view/test/ExpandAll.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { expandAll } from '../src/parts/ExpandAll/ExpandAll.ts' - -test('expandAll - no focused item', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file1', path: '/dir1/file1', type: DirentType.File }, - { name: 'file2', path: '/dir1/file2', type: DirentType.File }, - ] - }, - 'IconTheme.getFileIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getFolderIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getIcons'() { - return ['icon1', 'icon2'] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - } - const result = await expandAll(state) - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test('expandAll - expand directories at same depth', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file1', path: '/dir1/file1', type: DirentType.File }, - { name: 'file2', path: '/dir1/file2', type: DirentType.File }, - ] - }, - 'IconTheme.getFileIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getFolderIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getIcons'() { - return ['icon1', 'icon2'] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 0, name: 'dir1', path: '/dir1', selected: false, type: DirentType.Directory }, - { depth: 0, name: 'dir2', path: '/dir2', selected: false, type: DirentType.Directory }, - ], - } - - const result = await expandAll(state) - - expect(result.items).toHaveLength(6) - expect(result.items[0].type).toBe(DirentType.DirectoryExpanded) - expect(result.items[1].type).toBe(DirentType.File) - expect(result.items[2].name).toBe('file2') - expect(result.items[3].name).toBe('dir2') - expect(result.fileIconCache).toBeDefined() - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/dir1'], - ['FileSystem.readDirWithFileTypes', '/dir2'], - ]) -}) diff --git a/packages/explorer-view/test/ExpandRecursively.test.ts b/packages/explorer-view/test/ExpandRecursively.test.ts deleted file mode 100644 index 4f99fe6..0000000 --- a/packages/explorer-view/test/ExpandRecursively.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { Directory, File } from '../src/parts/DirentType/DirentType.ts' -import { expandRecursively } from '../src/parts/ExpandRecursively/ExpandRecursively.ts' - -test.skip('expand root directory', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [ - { isSymbolicLink: false, name: 'file1.txt', type: 'file' }, - { isSymbolicLink: false, name: 'dir1', type: 'directory' }, - ] - }, - 'IconTheme.getFileIcon'() { - return 'file-icon' - }, - 'IconTheme.getFolderIcon'() { - return 'folder-icon' - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: File }, - { depth: 0, name: 'dir1', path: '/test/dir1', selected: false, type: Directory }, - ], - root: '/test', - } - const newState = await expandRecursively(state) - expect(newState.items).toHaveLength(2) - expect(newState.items[0].name).toBe('file1.txt') - expect(newState.items[1].name).toBe('dir1') - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('expand focused directory', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [ - { isSymbolicLink: false, name: 'file1.txt', type: 'file' }, - { isSymbolicLink: false, name: 'file2.txt', type: 'file' }, - ] - }, - 'IconTheme.getFileIcon'() { - return 'file-icon' - }, - 'IconTheme.getFolderIcon'() { - return 'folder-icon' - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 0, name: 'dir1', path: '/test/dir1', selected: false, type: Directory }, - { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: File }, - ], - } - const newState = await expandRecursively(state) - expect(newState.items).toHaveLength(2) - expect(newState.items[0].name).toBe('file1.txt') - expect(newState.items[1].name).toBe('file2.txt') - expect(mockRpc.invocations).toEqual([]) -}) - -test('do not expand file', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: File, - }, - ], - } - const newState = await expandRecursively(state) - expect(newState.items).toHaveLength(1) - expect(newState.items[0].type).toBe(File) -}) diff --git a/packages/explorer-view/test/ExplorerStrings.test.ts b/packages/explorer-view/test/ExplorerStrings.test.ts deleted file mode 100644 index 10c46ae..0000000 --- a/packages/explorer-view/test/ExplorerStrings.test.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as ExplorerStrings from '../src/parts/ExplorerStrings/ExplorerStrings.ts' - -test('newFile', () => { - expect(ExplorerStrings.newFile()).toBe('New File...') -}) - -test('newFolder', () => { - expect(ExplorerStrings.newFolder()).toBe('New Folder...') -}) - -test('openContainingFolder', () => { - expect(ExplorerStrings.openContainingFolder()).toBe('Open Containing Folder') -}) - -test('openInIntegratedTerminal', () => { - expect(ExplorerStrings.openInIntegratedTerminal()).toBe('Open in integrated Terminal') -}) - -test('cut', () => { - expect(ExplorerStrings.cut()).toBe('Cut') -}) - -test('copy', () => { - expect(ExplorerStrings.copy()).toBe('Copy') -}) - -test('paste', () => { - expect(ExplorerStrings.paste()).toBe('Paste') -}) - -test('copyPath', () => { - expect(ExplorerStrings.copyPath()).toBe('Copy Path') -}) - -test('copyRelativePath', () => { - expect(ExplorerStrings.copyRelativePath()).toBe('Copy Relative Path') -}) - -test('rename', () => { - expect(ExplorerStrings.rename()).toBe('Rename') -}) - -test('deleteItem', () => { - expect(ExplorerStrings.deleteItem()).toBe('Delete') -}) - -test('refresh', () => { - expect(ExplorerStrings.refresh()).toBe('Refresh Explorer') -}) - -test('collapseAll', () => { - expect(ExplorerStrings.collapseAll()).toBe('Collapse All Folders in Explorer') -}) - -test('explorer', () => { - expect(ExplorerStrings.explorer()).toBe('Explorer') -}) - -test('filesExplorer', () => { - expect(ExplorerStrings.filesExplorer()).toBe('Files Explorer') -}) - -test('youHaveNotYetOpenedAFolder', () => { - expect(ExplorerStrings.youHaveNotYetOpenedAFolder()).toBe('You have not yet opened a folder.') -}) - -test('openFolder', () => { - expect(ExplorerStrings.openFolder()).toBe('Open folder') -}) - -test('openAnotherFolder', () => { - expect(ExplorerStrings.openAnotherFolder()).toBe('Open another folder') -}) - -test('noFolderOpen', () => { - expect(ExplorerStrings.noFolderOpen()).toBe('No Folder Open') -}) - -test('fileOrFolderNameMustBeProvided', () => { - expect(ExplorerStrings.fileOrFolderNameMustBeProvided()).toBe('A file or folder name must be provided.') -}) - -test('typeAFileName', () => { - expect(ExplorerStrings.typeAFileName()).toBe('Type file name. Press Enter to confirm or Escape to cancel.') -}) - -test('fileNameCannotStartWithSlash', () => { - expect(ExplorerStrings.fileNameCannotStartWithSlash()).toBe('A file or folder name cannot start with a slash.') -}) - -test('fileOrFolderAlreadyExists', () => { - expect(ExplorerStrings.fileOrFolderAlreadyExists('test-file.txt')).toBe( - 'A file or folder **test-file.txt** already exists at this location. Please choose a different name.', - ) -}) - -test('theNameIsNotValid', () => { - expect(ExplorerStrings.theNameIsNotValid()).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -}) - -test('leadingOrTrailingWhitespaceDetected', () => { - expect(ExplorerStrings.leadingOrTrailingWhitespaceDetected()).toBe('Leading or trailing whitespace detected in file or folder name.') -}) diff --git a/packages/explorer-view/test/FileSystem.test.ts b/packages/explorer-view/test/FileSystem.test.ts deleted file mode 100644 index 66750eb..0000000 --- a/packages/explorer-view/test/FileSystem.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as FileSystem from '../src/parts/FileSystem/FileSystem.ts' - -test('readDirWithFileTypes', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file.txt', type: 1 }, - { name: 'folder', type: 2 }, - ] - }, - }) - - const result = await FileSystem.readDirWithFileTypes('/test') - expect(result).toEqual([ - { name: 'file.txt', type: 1 }, - { name: 'folder', type: 2 }, - ]) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) -}) - -test('writeFile', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.writeFile'() { - return undefined - }, - }) - - await expect(FileSystem.writeFile('/test/file.txt', 'content')).resolves.toBeUndefined() - expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test/file.txt', 'content']]) -}) - -test('remove', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.remove'() { - return undefined - }, - }) - - await expect(FileSystem.remove('/test/file.txt')).resolves.toBeUndefined() - expect(mockRpc.invocations).toEqual([['FileSystem.remove', '/test/file.txt']]) -}) - -test('mkdir', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return undefined - }, - }) - - await expect(FileSystem.mkdir('/test/newfolder')).resolves.toBeUndefined() - expect(mockRpc.invocations).toEqual([['FileSystem.mkdir', '/test/newfolder']]) -}) - -test('rename', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.rename'() { - return undefined - }, - }) - - await expect(FileSystem.rename('/test/old.txt', '/test/new.txt')).resolves.toBeUndefined() - expect(mockRpc.invocations).toEqual([['FileSystem.rename', '/test/old.txt', '/test/new.txt']]) -}) - -test('copy', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.copy'() { - return undefined - }, - }) - - await expect(FileSystem.copy('/test/source.txt', '/test/dest.txt')).resolves.toBeUndefined() - expect(mockRpc.invocations).toEqual([['FileSystem.copy', '/test/source.txt', '/test/dest.txt']]) -}) - -test('getRealPath', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getRealPath'() { - return '/real/path' - }, - }) - - const path = await FileSystem.getRealPath('/test/link') - expect(path).toBe('/real/path') - expect(mockRpc.invocations).toEqual([['FileSystem.getRealPath', '/test/link']]) -}) - -test('getPathSeparator', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - }) - - const result = await FileSystem.getPathSeparator('/') - expect(result).toBe('/') - expect(mockRpc.invocations).toEqual([['FileSystem.getPathSeparator', '/']]) -}) diff --git a/packages/explorer-view/test/FilterByFocusWord.test.ts b/packages/explorer-view/test/FilterByFocusWord.test.ts deleted file mode 100644 index 6481ec5..0000000 --- a/packages/explorer-view/test/FilterByFocusWord.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect, test } from '@jest/globals' -import { filterByFocusWord } from '../src/parts/FilterByFocusWord/FilterByFocusWord.ts' - -test('filterByFocusWord - basic match', () => { - const items = ['apple', 'banana', 'cherry'] - expect(filterByFocusWord(items, -1, 'b')).toBe(1) -}) - -test('filterByFocusWord - no match', () => { - const items = ['apple', 'banana', 'cherry'] - expect(filterByFocusWord(items, -1, 'x')).toBe(-1) -}) - -test('filterByFocusWord - cycle through matches', () => { - const items = ['apple', 'banana', 'berry'] - // First match - expect(filterByFocusWord(items, -1, 'b')).toBe(1) - // Next match after current focus - expect(filterByFocusWord(items, 1, 'b')).toBe(2) - // Wrap around to first match - expect(filterByFocusWord(items, 2, 'b')).toBe(1) -}) - -test('filterByFocusWord - empty items', () => { - expect(filterByFocusWord([], -1, 'a')).toBe(-1) -}) diff --git a/packages/explorer-view/test/Focus.test.ts b/packages/explorer-view/test/Focus.test.ts deleted file mode 100644 index cbf6280..0000000 --- a/packages/explorer-view/test/Focus.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' -import { focus } from '../src/parts/Focus/Focus.js' - -test('focus - assigns focus if not present', () => { - const state = { ...createDefaultState(), focus: undefined as unknown as number } - const result = focus(state) - expect(result.focus).toBeDefined() - expect(result).not.toBe(state) -}) - -test('focus - does not change state if focus present', () => { - const state = { ...createDefaultState(), focus: 123 } - const result = focus(state) - expect(result).toBe(state) -}) diff --git a/packages/explorer-view/test/FocusFirst.test.ts b/packages/explorer-view/test/FocusFirst.test.ts deleted file mode 100644 index 7111541..0000000 --- a/packages/explorer-view/test/FocusFirst.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ViewletExplorerFocusFirst from '../src/parts/FocusFirst/FocusFirst.ts' - -test('focusFirst', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - height: 600, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - posInSet: 0, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusFirst.focusFirst(state)).toMatchObject({ - focusedIndex: 0, - }) -}) - -test('focusFirst - no dirents', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - height: 600, - items: [], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusFirst.focusFirst(state)).toBe(state) -}) - -test('focusFirst - focus already at first', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - height: 600, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - posInSet: 0, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusFirst.focusFirst(state)).toBe(state) -}) diff --git a/packages/explorer-view/test/FocusIndex.test.ts b/packages/explorer-view/test/FocusIndex.test.ts deleted file mode 100644 index 916a1d6..0000000 --- a/packages/explorer-view/test/FocusIndex.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ViewletExplorerFocusIndex from '../src/parts/FocusIndex/FocusIndex.ts' - -test('focusIndex - scroll up', () => { - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 0, - focusedIndex: 1, - height: 600, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - selected: false, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - selected: true, - type: DirentType.File, - }, - ], - maxLineY: 2, - minLineY: 1, - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusIndex.focusIndex(state, 0)).toMatchObject({ - focusedIndex: 0, - items: [ - { - selected: false, - }, - { - selected: false, - }, - ], - maxLineY: 1, - minLineY: 0, - }) -}) - -test('focusIndex - scroll down', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - selected: true, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - ], - maxLineY: 1, - minLineY: 0, - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusIndex.focusIndex(state, 1)).toMatchObject({ - focusedIndex: 1, - items: [ - { - selected: false, - }, - { - selected: false, - }, - ], - maxLineY: 2, - minLineY: 1, - }) -}) - -test('focusIndex - focus container', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - selected: true, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - ], - maxLineY: 1, - minLineY: 0, - } - expect(ViewletExplorerFocusIndex.focusIndex(state, -1)).toMatchObject({ - focusedIndex: -1, - items: [ - { - selected: false, - }, - { - selected: false, - }, - ], - maxLineY: 1, - minLineY: 0, - }) -}) - -test('focusIndex - unselects all other items', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - selected: true, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - selected: true, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.js', - path: '/index.js', - selected: true, - type: DirentType.File, - }, - ], - maxLineY: 3, - minLineY: 0, - } - expect(ViewletExplorerFocusIndex.focusIndex(state, 1)).toMatchObject({ - focusedIndex: 1, - items: [ - { - selected: false, - }, - { - selected: false, - }, - { - selected: false, - }, - ], - }) -}) diff --git a/packages/explorer-view/test/FocusLast.test.ts b/packages/explorer-view/test/FocusLast.test.ts deleted file mode 100644 index 68e879e..0000000 --- a/packages/explorer-view/test/FocusLast.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import * as ViewletExplorer from '../src/parts/Create/Create.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ViewletExplorerFocusLast from '../src/parts/FocusLast/FocusLast.ts' - -test('focusLast', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - height: 600, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - posInSet: 0, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusLast.focusLast(state)).toMatchObject({ - focusedIndex: 1, - }) -}) - -test('focusLast - no dirents', () => { - const state: ExplorerState = { - // @ts-ignore - ...ViewletExplorer.create(1), - focusedIndex: -1, - items: [], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusLast.focusLast(state)).toMatchObject({ - focusedIndex: -1, - }) -}) - -test('focusLast - focus already at last', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - items: [ - { - depth: 1, - name: 'index.css', - path: '/index.css', - posInSet: 0, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 1, - name: 'index.html', - path: '/index.html', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusLast.focusLast(state)).toBe(state) -}) diff --git a/packages/explorer-view/test/FocusNext.test.ts b/packages/explorer-view/test/FocusNext.test.ts deleted file mode 100644 index 76e0b9d..0000000 --- a/packages/explorer-view/test/FocusNext.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ViewletExplorerFocusNext from '../src/parts/FocusNext/FocusNext.ts' - -test('focusNext', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - height: 600, - items: [ - { - depth: 0, - name: 'index.css', - path: '/index.css', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'test-folder', - path: '/test-folder', - selected: false, - type: DirentType.Directory, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusNext.focusNext(state)).toMatchObject({ - focusedIndex: 1, - }) -}) - -test('focusNext - when no focus', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - height: 600, - items: [ - { - depth: 0, - name: 'index.css', - path: '/index.css', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'test-folder', - path: '/test-folder', - selected: false, - type: DirentType.Directory, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusNext.focusNext(state)).toMatchObject({ - focusedIndex: 0, - }) -}) - -test('focusNext - at end', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 2, - height: 600, - items: [ - { - depth: 0, - name: 'index.css', - path: '/index.css', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'test-folder', - path: '/test-folder', - selected: false, - type: DirentType.Directory, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusNext.focusNext(state)).toMatchObject({ - focusedIndex: 2, - }) -}) diff --git a/packages/explorer-view/test/FocusNone.test.ts b/packages/explorer-view/test/FocusNone.test.ts deleted file mode 100644 index 1253fe0..0000000 --- a/packages/explorer-view/test/FocusNone.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { focusNone } from '../src/parts/FocusNone/FocusNone.ts' - -test('should return state if focusedIndex is -1', () => { - const state: ExplorerState = { ...createDefaultState(), focusedIndex: -1 } - const result = focusNone(state) - expect(result).toBe(state) -}) - -test('should call focusIndex if focusedIndex is not -1', () => { - const state: ExplorerState = { ...createDefaultState(), focusedIndex: 2 } - const result = focusNone(state) - expect(result.focusedIndex).toBe(-1) -}) diff --git a/packages/explorer-view/test/FocusPrevious.test.ts b/packages/explorer-view/test/FocusPrevious.test.ts deleted file mode 100644 index 45cb98c..0000000 --- a/packages/explorer-view/test/FocusPrevious.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ViewletExplorerFocusPrevious from '../src/parts/FocusPrevious/FocusPrevious.ts' - -test('focusPrevious', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - height: 600, - items: [ - { - depth: 0, - name: 'index.css', - path: '/index.css', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'test-folder', - path: '/test-folder', - selected: false, - type: DirentType.Directory, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ - focusedIndex: 0, - }) -}) - -test('focusPrevious - at start', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - height: 600, - items: [ - { - depth: 0, - name: 'index.css', - path: '/index.css', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'test-folder', - path: '/test-folder', - selected: false, - type: DirentType.Directory, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ - focusedIndex: 0, - }) -}) - -test('focusPrevious - when no focus', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - height: 600, - items: [ - { - depth: 0, - name: 'index.css', - path: '/index.css', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'index.html', - path: '/index.html', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - name: 'test-folder', - path: '/test-folder', - selected: false, - type: DirentType.Directory, - }, - ], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ - focusedIndex: 2, - }) -}) - -test('focusPrevious - when no focus and no dirents', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - height: 600, - items: [], - root: '/home/test-user/test-path', - } - expect(ViewletExplorerFocusPrevious.focusPrevious(state)).toMatchObject({ - focusedIndex: -1, - }) -}) diff --git a/packages/explorer-view/test/GenerateUniqueName.test.ts b/packages/explorer-view/test/GenerateUniqueName.test.ts deleted file mode 100644 index 5fa16e8..0000000 --- a/packages/explorer-view/test/GenerateUniqueName.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { expect, test } from '@jest/globals' -import { generateUniqueName } from '../src/parts/GenerateUniqueName/GenerateUniqueName.ts' - -test('generateUniqueName - no conflict', () => { - const result = generateUniqueName('file.txt', ['/test/other.txt'], '/test') - expect(result).toBe('file.txt') -}) - -test('generateUniqueName - single conflict', () => { - const result = generateUniqueName('file.txt', ['/test/file.txt'], '/test') - expect(result).toBe('file copy.txt') -}) - -test('generateUniqueName - multiple conflicts', () => { - const result = generateUniqueName('file.txt', ['/test/file.txt', '/test/file copy.txt'], '/test') - expect(result).toBe('file copy 1.txt') -}) - -test('generateUniqueName - multiple numbered conflicts', () => { - const result = generateUniqueName('file.txt', ['/test/file.txt', '/test/file copy.txt', '/test/file copy 1.txt', '/test/file copy 2.txt'], '/test') - expect(result).toBe('file copy 3.txt') -}) - -test('generateUniqueName - file without extension', () => { - const result = generateUniqueName('README', ['/test/README'], '/test') - expect(result).toBe('README copy') -}) - -test('generateUniqueName - file without extension multiple conflicts', () => { - const result = generateUniqueName('README', ['/test/README', '/test/README copy', '/test/README copy 1'], '/test') - expect(result).toBe('README copy 2') -}) - -test('generateUniqueName - file starting with dot', () => { - const result = generateUniqueName('.gitignore', ['/test/.gitignore'], '/test') - expect(result).toBe('.gitignore copy') -}) - -test('generateUniqueName - file ending with dot', () => { - const result = generateUniqueName('file.', ['/test/file.'], '/test') - expect(result).toBe('file. copy') -}) - -test('generateUniqueName - file with multiple dots', () => { - const result = generateUniqueName('file.backup.txt', ['/test/file.backup.txt'], '/test') - expect(result).toBe('file.backup copy.txt') -}) - -test('generateUniqueName - file with only dot', () => { - const result = generateUniqueName('.', ['/test/.'], '/test') - expect(result).toBe('. copy') -}) - -test('generateUniqueName - empty filename', () => { - const result = generateUniqueName('', ['/test/'], '/test') - expect(result).toBe(' copy') -}) - -test('generateUniqueName - filename with spaces', () => { - const result = generateUniqueName('my file.txt', ['/test/my file.txt'], '/test') - expect(result).toBe('my file copy.txt') -}) - -test('generateUniqueName - filename with special characters', () => { - const result = generateUniqueName('file@#$%.txt', ['/test/file@#$%.txt'], '/test') - expect(result).toBe('file@#$% copy.txt') -}) - -test('generateUniqueName - filename with numbers', () => { - const result = generateUniqueName('file123.txt', ['/test/file123.txt'], '/test') - expect(result).toBe('file123 copy.txt') -}) - -test('generateUniqueName - filename that looks like a copy', () => { - const result = generateUniqueName('file copy.txt', ['/test/file copy.txt'], '/test') - expect(result).toBe('file copy copy.txt') -}) - -test('generateUniqueName - filename that looks like a numbered copy', () => { - const result = generateUniqueName('file copy 1.txt', ['/test/file copy 1.txt'], '/test') - expect(result).toBe('file copy 1 copy.txt') -}) - -test('generateUniqueName - complex extension', () => { - const result = generateUniqueName('file.tar.gz', ['/test/file.tar.gz'], '/test') - expect(result).toBe('file.tar copy.gz') -}) - -test('generateUniqueName - hidden file with extension', () => { - const result = generateUniqueName('.config.json', ['/test/.config.json'], '/test') - expect(result).toBe('.config copy.json') -}) - -test('generateUniqueName - very long filename', () => { - const longName = 'a'.repeat(100) + '.txt' - const result = generateUniqueName(longName, [`/test/${longName}`], '/test') - expect(result).toBe('a'.repeat(100) + ' copy.txt') -}) - -test('generateUniqueName - unicode filename', () => { - const result = generateUniqueName('café.txt', ['/test/café.txt'], '/test') - expect(result).toBe('café copy.txt') -}) - -test('generateUniqueName - filename with emoji', () => { - const result = generateUniqueName('file🚀.txt', ['/test/file🚀.txt'], '/test') - expect(result).toBe('file🚀 copy.txt') -}) - -test('generateUniqueName - case sensitive', () => { - const result = generateUniqueName('File.txt', ['/test/file.txt'], '/test') - expect(result).toBe('File.txt') -}) - -test('generateUniqueName - different root path', () => { - const result = generateUniqueName('file.txt', ['/different/file.txt'], '/test') - expect(result).toBe('file.txt') -}) - -test('generateUniqueName - root path with trailing slash', () => { - const result = generateUniqueName('file.txt', ['/test/file.txt'], '/test/') - expect(result).toBe('file copy.txt') -}) - -test('generateUniqueName - multiple conflicts with gaps', () => { - const result = generateUniqueName('file.txt', ['/test/file.txt', '/test/file copy.txt', '/test/file copy 3.txt'], '/test') - expect(result).toBe('file copy 1.txt') -}) - -test('generateUniqueName - filename with copy in middle', () => { - const result = generateUniqueName('copyfile.txt', ['/test/copyfile.txt'], '/test') - expect(result).toBe('copyfile copy.txt') -}) - -test('generateUniqueName - filename ending with copy', () => { - const result = generateUniqueName('mycopy.txt', ['/test/mycopy.txt'], '/test') - expect(result).toBe('mycopy copy.txt') -}) - -test('generateUniqueName - filename with copy and number', () => { - const result = generateUniqueName('filecopy1.txt', ['/test/filecopy1.txt'], '/test') - expect(result).toBe('filecopy1 copy.txt') -}) diff --git a/packages/explorer-view/test/GetActionButtonVirtualDom.test.ts b/packages/explorer-view/test/GetActionButtonVirtualDom.test.ts deleted file mode 100644 index 12c941a..0000000 --- a/packages/explorer-view/test/GetActionButtonVirtualDom.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as ActionType from '../src/parts/ActionType/ActionType.ts' -import * as GetActionButtonVirtualDom from '../src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts' - -test('getActionButtonVirtualDom', () => { - const action = { - command: 'newFile', - icon: 'NewFile', - id: 'New File', - name: 'NewFile', - type: ActionType.Button, - } - expect(GetActionButtonVirtualDom.getActionButtonVirtualDom(action)).toEqual([ - { - childCount: 1, - className: 'IconButton', - name: 'NewFile', - title: 'New File', - type: 1, - }, - { - childCount: 0, - className: 'MaskIcon MaskIconNewFile', - role: 'none', - type: 4, - }, - ]) -}) diff --git a/packages/explorer-view/test/GetActionVirtualDom.test.ts b/packages/explorer-view/test/GetActionVirtualDom.test.ts deleted file mode 100644 index 43e6d2e..0000000 --- a/packages/explorer-view/test/GetActionVirtualDom.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ViewletAction } from '../src/parts/ViewletAction/ViewletAction.ts' -import * as ActionType from '../src/parts/ActionType/ActionType.ts' -import { getActionVirtualDom } from '../src/parts/GetActionVirtualDom/GetActionVirtualDom.ts' - -test('getActionVirtualDom - button action', () => { - const action: ViewletAction = { - command: 'test.command', - icon: 'test-icon', - id: 'test-button', - type: ActionType.Button, - } - const result = getActionVirtualDom(action) - expect(result).toHaveLength(2) - expect(result[0].type).toBe(1) -}) - -test('getActionVirtualDom - unknown action type', () => { - const action: ViewletAction = { - command: 'test.command', - id: 'test-unknown', - type: 999, // Using a number that's not defined in ActionType - } - const result = getActionVirtualDom(action) - expect(result).toEqual([]) -}) diff --git a/packages/explorer-view/test/GetActions.test.ts b/packages/explorer-view/test/GetActions.test.ts deleted file mode 100644 index 4be0973..0000000 --- a/packages/explorer-view/test/GetActions.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as ActionType from '../src/parts/ActionType/ActionType.ts' -import * as ViewletExplorerStrings from '../src/parts/ExplorerStrings/ExplorerStrings.ts' -import * as GetActions from '../src/parts/GetActions/GetActions.ts' -import * as MaskIcon from '../src/parts/MaskIcon/MaskIcon.ts' - -test('getActions - with root', () => { - expect(GetActions.getActions('/test-root')).toEqual([ - { - command: 'newFile', - icon: MaskIcon.NewFile, - id: ViewletExplorerStrings.newFile(), - name: 'NewFile', - type: ActionType.Button, - }, - { - command: 'newFolder', - icon: MaskIcon.NewFolder, - id: ViewletExplorerStrings.newFolder(), - name: 'NewFolder', - type: ActionType.Button, - }, - { - command: 'refresh', - icon: MaskIcon.Refresh, - id: ViewletExplorerStrings.refresh(), - name: 'Refresh', - type: ActionType.Button, - }, - { - command: 'collapseAll', - icon: MaskIcon.CollapseAll, - id: ViewletExplorerStrings.collapseAll(), - name: 'CollapseAll', - type: ActionType.Button, - }, - ]) -}) - -test('getActions - no root', () => { - expect(GetActions.getActions('')).toEqual([]) -}) diff --git a/packages/explorer-view/test/GetChevronType.test.ts b/packages/explorer-view/test/GetChevronType.test.ts deleted file mode 100644 index f31f4a4..0000000 --- a/packages/explorer-view/test/GetChevronType.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as ChevronType from '../src/parts/ChevronType/ChevronType.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as GetChevronType from '../src/parts/GetChevronType/GetChevronType.ts' - -test('getChevronType - chevrons disabled', () => { - expect(GetChevronType.getChevronType(DirentType.Directory, false)).toBe(ChevronType.None) -}) - -test('getChevronType - directory', () => { - expect(GetChevronType.getChevronType(DirentType.Directory, true)).toBe(ChevronType.Right) -}) - -test('getChevronType - directory expanded', () => { - expect(GetChevronType.getChevronType(DirentType.DirectoryExpanded, true)).toBe(ChevronType.Down) -}) - -test('getChevronType - directory expanding', () => { - expect(GetChevronType.getChevronType(DirentType.DirectoryExpanding, true)).toBe(ChevronType.Down) -}) - -test('getChevronType - file', () => { - expect(GetChevronType.getChevronType(DirentType.File, true)).toBe(ChevronType.None) -}) - -test('getChevronType - symlink file', () => { - expect(GetChevronType.getChevronType(DirentType.SymLinkFile, true)).toBe(ChevronType.None) -}) - -test('getChevronType - unknown type', () => { - expect(GetChevronType.getChevronType(999_999, true)).toBe(ChevronType.None) -}) diff --git a/packages/explorer-view/test/GetChevronVirtualDom.test.ts b/packages/explorer-view/test/GetChevronVirtualDom.test.ts deleted file mode 100644 index d23ec90..0000000 --- a/packages/explorer-view/test/GetChevronVirtualDom.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as ChevronDownVirtualDom from '../src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts' -import * as ChevronRightVirtualDom from '../src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts' -import * as GetChevronVirtualDom from '../src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts' - -test('getChevronVirtualDom - no chevron', () => { - expect(GetChevronVirtualDom.getChevronVirtualDom(0)).toEqual([]) -}) - -test('getChevronVirtualDom - right chevron', () => { - expect(GetChevronVirtualDom.getChevronVirtualDom(1)).toEqual([ChevronRightVirtualDom.chevronRightVirtualDom]) -}) - -test('getChevronVirtualDom - down chevron', () => { - expect(GetChevronVirtualDom.getChevronVirtualDom(2)).toEqual([ChevronDownVirtualDom.chevronDownVirtualDom]) -}) diff --git a/packages/explorer-view/test/GetClickFn.test.ts b/packages/explorer-view/test/GetClickFn.test.ts deleted file mode 100644 index cbf8c12..0000000 --- a/packages/explorer-view/test/GetClickFn.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as GetClickFn from '../src/parts/GetClickFn/GetClickFn.ts' -import * as HandleClickDirectory from '../src/parts/HandleClickDirectory/HandleClickDirectory.ts' -import * as HandleClickDirectoryExpanded from '../src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' -import * as HandleClickDirectoryExpanding from '../src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts' -import * as HandleClickFile from '../src/parts/HandleClickFile/HandleClickFile.ts' -import * as HandleClickSymlink from '../src/parts/HandleClickSymlink/HandleClickSymlink.ts' - -test('getClickFn - file', () => { - expect(GetClickFn.getClickFn(DirentType.File)).toBe(HandleClickFile.handleClickFile) -}) - -test('getClickFn - symlink file', () => { - expect(GetClickFn.getClickFn(DirentType.SymLinkFile)).toBe(HandleClickFile.handleClickFile) -}) - -test('getClickFn - directory', () => { - expect(GetClickFn.getClickFn(DirentType.Directory)).toBe(HandleClickDirectory.handleClickDirectory) -}) - -test('getClickFn - symlink folder', () => { - expect(GetClickFn.getClickFn(DirentType.SymLinkFolder)).toBe(HandleClickDirectory.handleClickDirectory) -}) - -test('getClickFn - directory expanding', () => { - expect(GetClickFn.getClickFn(DirentType.DirectoryExpanding)).toBe(HandleClickDirectoryExpanding.handleClickDirectoryExpanding) -}) - -test('getClickFn - directory expanded', () => { - expect(GetClickFn.getClickFn(DirentType.DirectoryExpanded)).toBe(HandleClickDirectoryExpanded.handleClickDirectoryExpanded) -}) - -test('getClickFn - symlink', () => { - expect(GetClickFn.getClickFn(DirentType.Symlink)).toBe(HandleClickSymlink.handleClickSymLink) -}) - -test('getClickFn - character device', () => { - expect(() => GetClickFn.getClickFn(DirentType.CharacterDevice)).toThrow('Cannot open character device files') -}) - -test('getClickFn - block device', () => { - expect(() => GetClickFn.getClickFn(DirentType.BlockDevice)).toThrow('Cannot open block device files') -}) - -test('getClickFn - socket', () => { - expect(() => GetClickFn.getClickFn(DirentType.Socket)).toThrow('Cannot open socket files') -}) - -test('getClickFn - unknown type', () => { - expect(() => GetClickFn.getClickFn(999_999)).toThrow('unsupported dirent type 999999') -}) diff --git a/packages/explorer-view/test/GetCss.test.ts b/packages/explorer-view/test/GetCss.test.ts deleted file mode 100644 index abe63dc..0000000 --- a/packages/explorer-view/test/GetCss.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { test, expect } from '@jest/globals' -import { getCss } from '../src/parts/GetCss/GetCss.ts' - -test('getCss - basic scrollBarHeight and empty indents', () => { - const scrollBarHeight = 20 - const scrollBarTop = 0 - const uniqueIndents: readonly number[] = [] - const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) - expect(result).toBe(`.Explorer { - --ScrollBarThumbHeight: 20px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 0px; - --ErrorMessageLeft: 0px; - --ErrorMessageWidth: 0px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -}`) -}) - -test('getCss - with single indent', () => { - const scrollBarHeight = 15 - const scrollBarTop = 0 - const uniqueIndents: readonly number[] = [10] - const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) - expect(result).toBe(`.Explorer { - --ScrollBarThumbHeight: 15px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 0px; - --ErrorMessageLeft: 0px; - --ErrorMessageWidth: 0px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-10 { - padding-left: 10px; -}`) -}) - -test('getCss - with multiple indents', () => { - const scrollBarHeight = 25 - const scrollBarTop = 0 - const uniqueIndents: readonly number[] = [0, 20, 40] - const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) - expect(result).toBe(`.Explorer { - --ScrollBarThumbHeight: 25px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 0px; - --ErrorMessageLeft: 0px; - --ErrorMessageWidth: 0px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-0 { - padding-left: 0px; -} -.Indent-20 { - padding-left: 20px; -} -.Indent-40 { - padding-left: 40px; -}`) -}) - -test('getCss - with zero scrollBarHeight', () => { - const scrollBarHeight = 0 - const scrollBarTop = 0 - const uniqueIndents: readonly number[] = [5, 10] - const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) - expect(result).toBe(`.Explorer { - --ScrollBarThumbHeight: 0px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 0px; - --ErrorMessageLeft: 0px; - --ErrorMessageWidth: 0px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-5 { - padding-left: 5px; -} -.Indent-10 { - padding-left: 10px; -}`) -}) - -test('getCss - with large indents', () => { - const scrollBarHeight = 30 - const scrollBarTop = 0 - const uniqueIndents: readonly number[] = [100, 200, 300] - const result = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, 0, 0, 0) - expect(result).toBe(`.Explorer { - --ScrollBarThumbHeight: 30px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 0px; - --ErrorMessageLeft: 0px; - --ErrorMessageWidth: 0px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-100 { - padding-left: 100px; -} -.Indent-200 { - padding-left: 200px; -} -.Indent-300 { - padding-left: 300px; -}`) -}) diff --git a/packages/explorer-view/test/GetDragData.test.ts b/packages/explorer-view/test/GetDragData.test.ts deleted file mode 100644 index adaf71a..0000000 --- a/packages/explorer-view/test/GetDragData.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { test, expect } from '@jest/globals' -import { getDragData } from '../src/parts/GetDragData/GetDragData.js' - -test('getDragData - single url', () => { - const urls: string[] = ['/a.txt'] - const result = getDragData(urls) - expect(result.items[0]).toEqual({ data: 'file:///a.txt', type: 'text/uri-list' }) - expect(result.items[1]).toEqual({ data: 'file:///a.txt', type: 'text/plain' }) - expect(result.label).toBe('a.txt') -}) - -test('getDragData - multiple urls', () => { - const urls: string[] = ['/a.txt', '/b.txt'] - const result = getDragData(urls) - expect(result.items[0]).toEqual({ data: 'file:///a.txt\nfile:///b.txt', type: 'text/uri-list' }) - expect(result.items[1]).toEqual({ data: 'file:///a.txt\nfile:///b.txt', type: 'text/plain' }) - expect(result.label).toBe('2') -}) - -test('getDragData - empty', () => { - const urls: string[] = [] - const result = getDragData(urls) - expect(result.items[0]).toEqual({ data: '', type: 'text/uri-list' }) - expect(result.items[1]).toEqual({ data: '', type: 'text/plain' }) - expect(result.label).toBe('0') -}) diff --git a/packages/explorer-view/test/GetDragLabel.test.ts b/packages/explorer-view/test/GetDragLabel.test.ts deleted file mode 100644 index 442d536..0000000 --- a/packages/explorer-view/test/GetDragLabel.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect } from '@jest/globals' -import { getDragLabel } from '../src/parts/GetDragLabel/GetDragLabel.js' - -test('getDragLabel - single url', () => { - expect(getDragLabel(['file:///a.txt'])).toBe('a.txt') -}) - -test('getDragLabel - multiple urls', () => { - expect(getDragLabel(['file:///a.txt', 'file:///b.txt'])).toBe('2') - expect(getDragLabel(['file:///a.txt', 'file:///b.txt', 'file:///c.txt'])).toBe('3') -}) - -test('getDragLabel - empty', () => { - expect(getDragLabel([])).toBe('0') -}) diff --git a/packages/explorer-view/test/GetDropHandler.test.ts b/packages/explorer-view/test/GetDropHandler.test.ts deleted file mode 100644 index 8145367..0000000 --- a/packages/explorer-view/test/GetDropHandler.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { expect, test } from '@jest/globals' -import { getDropHandler } from '../src/parts/GetDropHandler/GetDropHandler.ts' -import * as HandleDropIndex from '../src/parts/HandleDropIndex/HandleDropIndex.ts' -import * as HandleDropRoot from '../src/parts/HandleDropRoot/HandleDropRoot.ts' - -test('get root drop handler', () => { - const handler = getDropHandler(-1) - expect(handler).toBe(HandleDropRoot.handleDropRoot) -}) - -test('get index drop handler', () => { - const handler = getDropHandler(0) - expect(handler).toBe(HandleDropIndex.handleDropIndex) -}) diff --git a/packages/explorer-view/test/GetEditingIcon.test.ts b/packages/explorer-view/test/GetEditingIcon.test.ts deleted file mode 100644 index 6627760..0000000 --- a/packages/explorer-view/test/GetEditingIcon.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import * as GetEditingIcon from '../src/parts/GetEditingIcon/GetEditingIcon.ts' - -test('getEditingIcon - CreateFile', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return 'file-icon' - }, - }) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.CreateFile, 'test.txt') - expect(result).toBe('file-icon') - expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) -}) - -test('getEditingIcon - CreateFolder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFolderIcon'() { - return 'folder-icon' - }, - }) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.CreateFolder, 'test-folder') - expect(result).toBe('folder-icon') - expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) -}) - -test('getEditingIcon - Rename File', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return 'file-icon' - }, - }) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test.txt', DirentType.File) - expect(result).toBe('file-icon') - expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) -}) - -test('getEditingIcon - Rename EditingFile', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return 'file-icon' - }, - }) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test.txt', DirentType.EditingFile) - expect(result).toBe('file-icon') - expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) -}) - -test('getEditingIcon - Rename Directory', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFolderIcon'() { - return 'folder-icon' - }, - }) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test-folder', DirentType.Directory) - expect(result).toBe('folder-icon') - expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) -}) - -test('getEditingIcon - Rename EditingFolder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFolderIcon'() { - return 'folder-icon' - }, - }) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test-folder', DirentType.EditingFolder) - expect(result).toBe('folder-icon') - expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) -}) - -test('getEditingIcon - Rename EditingDirectoryExpanded', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFolderIcon'() { - return 'folder-icon' - }, - }) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test-folder', DirentType.EditingDirectoryExpanded) - expect(result).toBe('folder-icon') - expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test-folder' }]]) -}) - -test('getEditingIcon - Rename with unsupported dirent type', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test', DirentType.Symlink) - expect(result).toBe('') - expect(mockRpc.invocations).toEqual([]) -}) - -test('getEditingIcon - Rename without dirent type', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.Rename, 'test') - expect(result).toBe('') - expect(mockRpc.invocations).toEqual([]) -}) - -test('getEditingIcon - None editing type', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - - const result = await GetEditingIcon.getEditingIcon(ExplorerEditingType.None, 'test') - expect(result).toBe('') - expect(mockRpc.invocations).toEqual([]) -}) - -test('getEditingIcon - unknown editing type', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - - const result = await GetEditingIcon.getEditingIcon(999, 'test') - expect(result).toBe('') - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/GetEditingType.test.ts b/packages/explorer-view/test/GetEditingType.test.ts deleted file mode 100644 index 047e6e7..0000000 --- a/packages/explorer-view/test/GetEditingType.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { test, expect } from '@jest/globals' -import { DELTA_EDITING } from '../src/parts/DeltaEditing/DeltaEditing.ts' -import { getEditingType } from '../src/parts/GetEditingType/GetEditingType.ts' - -test('should add DELTA_EDITING if direntType < DELTA_EDITING', () => { - const result = getEditingType(1) - expect(result).toBe(1 + DELTA_EDITING) -}) - -test('should return direntType if direntType >= DELTA_EDITING', () => { - const result = getEditingType(DELTA_EDITING) - expect(result).toBe(DELTA_EDITING) -}) diff --git a/packages/explorer-view/test/GetErrorCode.test.ts b/packages/explorer-view/test/GetErrorCode.test.ts deleted file mode 100644 index d31060b..0000000 --- a/packages/explorer-view/test/GetErrorCode.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetErrorCode from '../src/parts/GetErrorCode/GetErrorCode.ts' - -test('getErrorCode - returns code from object error', () => { - const error = { - code: 'ENOENT', - } - expect(GetErrorCode.getErrorCode(error)).toBe('ENOENT') -}) - -test('getErrorCode - returns empty string for error without string code', () => { - const error = { - code: 404, - } - expect(GetErrorCode.getErrorCode(error)).toBe('') -}) - -test('getErrorCode - returns empty string for null', () => { - expect(GetErrorCode.getErrorCode(null)).toBe('') -}) diff --git a/packages/explorer-view/test/GetErrorMessage.test.ts b/packages/explorer-view/test/GetErrorMessage.test.ts deleted file mode 100644 index 32b7c88..0000000 --- a/packages/explorer-view/test/GetErrorMessage.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetErrorMessage from '../src/parts/GetErrorMessage/GetErrorMessage.ts' - -test('getErrorMessage - returns message from Error instance', () => { - expect(GetErrorMessage.getErrorMessage(new Error('Failed to load'))).toBe('Failed to load') -}) - -test('getErrorMessage - returns string error as is', () => { - expect(GetErrorMessage.getErrorMessage('Failed to load')).toBe('Failed to load') -}) - -test('getErrorMessage - returns fallback for unknown error', () => { - expect(GetErrorMessage.getErrorMessage({ message: 'Hidden' })).toBe('Unknown error') -}) diff --git a/packages/explorer-view/test/GetErrorMessageDom.test.ts b/packages/explorer-view/test/GetErrorMessageDom.test.ts deleted file mode 100644 index d33c1ec..0000000 --- a/packages/explorer-view/test/GetErrorMessageDom.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { test, expect } from '@jest/globals' -import { getErrorMessageDom } from '../src/parts/GetErrorMessageDom/GetErrorMessageDom.ts' - -test('should return empty array for empty error message', () => { - const result = getErrorMessageDom('') - expect(result).toEqual([]) -}) - -test('should return dom nodes for non-empty error message', () => { - const result = getErrorMessageDom('Error!') - expect(Array.isArray(result)).toBe(true) - expect(result.length).toBeGreaterThan(0) -}) diff --git a/packages/explorer-view/test/GetExcluded.test.ts b/packages/explorer-view/test/GetExcluded.test.ts deleted file mode 100644 index 16499bb..0000000 --- a/packages/explorer-view/test/GetExcluded.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetExcluded from '../src/parts/GetExcluded/GetExcluded.ts' - -test('getExcluded - returns empty array by default', () => { - expect(GetExcluded.getExcluded()).toEqual([]) -}) diff --git a/packages/explorer-view/test/GetExpandedDirents.test.ts b/packages/explorer-view/test/GetExpandedDirents.test.ts deleted file mode 100644 index 55b2d89..0000000 --- a/packages/explorer-view/test/GetExpandedDirents.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import { Directory, DirectoryExpanded, File } from '../src/parts/DirentType/DirentType.ts' -import { getExpandedDirents } from '../src/parts/GetExpandedDirents/GetExpandedDirents.ts' - -test('getExpandedDirents - empty array', () => { - const items: readonly ExplorerItem[] = [] - expect(getExpandedDirents(items)).toHaveLength(0) -}) - -test('getExpandedDirents - no expanded items', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: Directory }, - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, - ] - expect(getExpandedDirents(items)).toHaveLength(0) -}) - -test('getExpandedDirents - with expanded items', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, - ] - const result = getExpandedDirents(items) - expect(result).toHaveLength(1) - expect(result[0].name).toBe('folder1') -}) diff --git a/packages/explorer-view/test/GetExpandedType.test.ts b/packages/explorer-view/test/GetExpandedType.test.ts deleted file mode 100644 index 8f05e91..0000000 --- a/packages/explorer-view/test/GetExpandedType.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExpandedType from '../src/parts/ExpandedType/ExpandedType.ts' -import * as GetExpandedType from '../src/parts/GetExpandedType/GetExpandedType.ts' - -test('getExpandedType - directory', () => { - expect(GetExpandedType.getExpandedType(DirentType.Directory)).toBe(ExpandedType.Collapsed) -}) - -test('getExpandedType - directory expanding', () => { - expect(GetExpandedType.getExpandedType(DirentType.DirectoryExpanding)).toBe(ExpandedType.Expanded) -}) - -test('getExpandedType - directory expanded', () => { - expect(GetExpandedType.getExpandedType(DirentType.DirectoryExpanded)).toBe(ExpandedType.Expanded) -}) - -test('getExpandedType - file', () => { - expect(GetExpandedType.getExpandedType(DirentType.File)).toBe(ExpandedType.None) -}) - -test('getExpandedType - symlink file', () => { - expect(GetExpandedType.getExpandedType(DirentType.SymLinkFile)).toBe(ExpandedType.None) -}) - -test('getExpandedType - unknown type', () => { - expect(GetExpandedType.getExpandedType(999_999)).toBe(ExpandedType.None) -}) diff --git a/packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts b/packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts deleted file mode 100644 index 1421d64..0000000 --- a/packages/explorer-view/test/GetExplorerItemVirtualDom.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { VisibleExplorerItem } from '../src/parts/VisibleExplorerItem/VisibleExplorerItem.ts' -import { getExplorerItemVirtualDom } from '../src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts' - -test('basic item', () => { - const item: VisibleExplorerItem = { - ariaExpanded: undefined, - chevron: 0, - className: '', - depth: 1, - hasEditingError: false, - icon: 'file', - id: '1', - indent: 0, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'test.txt', - path: '/test.txt', - posInSet: 1, - selected: false, - setSize: 2, - } - const dom = getExplorerItemVirtualDom(item) - expect(dom).toHaveLength(4) - expect(dom[0].type).toBe(4) - expect(dom[0].role).toBe('treeitem') - expect(dom[0].ariaLabel).toBe('test.txt') - expect(dom[0].title).toBe('/test.txt') -}) - -test('file uri item removes file scheme from title', () => { - const item: VisibleExplorerItem = { - ariaExpanded: undefined, - chevron: 0, - className: '', - depth: 1, - hasEditingError: false, - icon: 'file', - id: '1', - indent: 0, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'test.txt', - path: 'file:///test.txt', - posInSet: 1, - selected: false, - setSize: 2, - } - const dom = getExplorerItemVirtualDom(item) - expect(dom[0].title).toBe('/test.txt') -}) - -test('non-file uri item keeps scheme in title', () => { - const item: VisibleExplorerItem = { - ariaExpanded: undefined, - chevron: 0, - className: '', - depth: 1, - hasEditingError: false, - icon: 'file', - id: '1', - indent: 0, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'test.txt', - path: 'memfs:///test.txt', - posInSet: 1, - selected: false, - setSize: 2, - } - const dom = getExplorerItemVirtualDom(item) - expect(dom[0].title).toBe('memfs:///test.txt') -}) - -test('item with chevron', () => { - const item: VisibleExplorerItem = { - ariaExpanded: 'true', - chevron: 1, - className: '', - depth: 1, - hasEditingError: false, - icon: 'folder', - id: '1', - indent: 0, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'test', - path: '/test', - posInSet: 1, - selected: false, - setSize: 2, - } - const dom = getExplorerItemVirtualDom(item) - expect(dom).toHaveLength(5) - expect(dom[0].type).toBe(4) - expect(dom[0].role).toBe('treeitem') - expect(dom[0].ariaLabel).toBe('test') -}) - -test('item in editing state', () => { - const item: VisibleExplorerItem = { - ariaExpanded: undefined, - chevron: 0, - className: '', - depth: 1, - hasEditingError: false, - icon: 'file', - id: '1', - indent: 0, - index: 0, - isCut: false, - isEditing: true, - isIgnored: false, - name: 'test.txt', - path: '/test.txt', - posInSet: 1, - selected: false, - setSize: 2, - } - const dom = getExplorerItemVirtualDom(item) - expect(dom).toHaveLength(3) - expect(dom[0].type).toBe(4) - expect(dom[0].role).toBe('treeitem') -}) - -test('item with error', () => { - const item: VisibleExplorerItem = { - ariaExpanded: undefined, - chevron: 0, - className: '', - depth: 1, - hasEditingError: true, - icon: 'file', - id: '1', - indent: 0, - index: 0, - isCut: false, - isEditing: true, - isIgnored: false, - name: 'test.txt', - path: '/test.txt', - posInSet: 1, - selected: false, - setSize: 2, - } - const dom = getExplorerItemVirtualDom(item) - expect(dom).toHaveLength(3) - expect(dom[0].type).toBe(4) - expect(dom[0].role).toBe('treeitem') -}) diff --git a/packages/explorer-view/test/GetExplorerMaxLineY.test.ts b/packages/explorer-view/test/GetExplorerMaxLineY.test.ts deleted file mode 100644 index f66f2d9..0000000 --- a/packages/explorer-view/test/GetExplorerMaxLineY.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetExplorerMaxLineY from '../src/parts/GetMaxLineY/GetMaxLineY.ts' - -test('getExplorerMaxLineY - basic functionality', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 10)).toBe(6) -}) - -test('getExplorerMaxLineY - with offset minLineY', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(50, 100, 20, 10)).toBe(56) -}) - -test('getExplorerMaxLineY - direntsLength smaller than visible items', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 200, 20, 3)).toBe(3) -}) - -test('getExplorerMaxLineY - direntsLength larger than visible items', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 20)).toBe(6) -}) - -test('getExplorerMaxLineY - exact fit', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 6)).toBe(6) -}) - -test('getExplorerMaxLineY - zero height', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 0, 20, 10)).toBe(0) -}) - -test('getExplorerMaxLineY - zero itemHeight', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 0, 10)).toBe(0) -}) - -test('getExplorerMaxLineY - negative height', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, -100, 20, 10)).toBe(0) -}) - -test('getExplorerMaxLineY - negative itemHeight', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, -20, 10)).toBe(0) -}) - -test('getExplorerMaxLineY - zero direntsLength', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 100, 20, 0)).toBe(0) -}) - -test('getExplorerMaxLineY - small height with small itemHeight', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 10, 5, 10)).toBe(3) -}) - -test('getExplorerMaxLineY - large height with small itemHeight', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 1000, 10, 50)).toBe(50) -}) - -test('getExplorerMaxLineY - partial height division', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 75, 20, 10)).toBe(5) -}) - -test('getExplorerMaxLineY - negative minLineY', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(-10, 100, 20, 10)).toBe(-4) -}) - -test('getExplorerMaxLineY - very small height', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 1, 20, 10)).toBe(2) -}) - -test('getExplorerMaxLineY - height smaller than itemHeight', () => { - expect(GetExplorerMaxLineY.getExplorerMaxLineY(0, 10, 20, 10)).toBe(2) -}) diff --git a/packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts b/packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts deleted file mode 100644 index 7f48843..0000000 --- a/packages/explorer-view/test/GetExplorerWelcomeVirtualDom.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' -import { dropTargetFull } from '../src/parts/DropTargetFull/DropTargetFull.ts' -import * as GetExplorerWelcomeVirtualDom from '../src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts' - -test('getExplorerWelcomeVirtualDom - wide', () => { - expect(GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(true, [])).toEqual([ - { - childCount: 1, - className: 'Viewlet Explorer', - onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, - onDragLeave: DomEventListenerFunctions.HandleDragLeave, - onDragOver: DomEventListenerFunctions.HandleDragOver, - onDrop: DomEventListenerFunctions.HandleDrop, - tabIndex: 0, - type: 4, - }, - { - childCount: 2, - className: 'Welcome', - type: 4, - }, - { - childCount: 1, - className: 'WelcomeMessage', - type: 50, - }, - { - childCount: 0, - text: 'You have not yet opened a folder.', - type: 12, - }, - { - childCount: 1, - className: 'Button ButtonPrimary ButtonWide', - name: 'OpenFolder', - onClick: DomEventListenerFunctions.HandleClickOpenFolder, - type: 1, - }, - { - childCount: 0, - text: 'Open folder', - type: 12, - }, - ]) -}) - -test('getExplorerWelcomeVirtualDom - narrow', () => { - expect(GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(false, [])).toEqual([ - { - childCount: 1, - className: 'Viewlet Explorer', - onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, - onDragLeave: DomEventListenerFunctions.HandleDragLeave, - onDragOver: DomEventListenerFunctions.HandleDragOver, - onDrop: DomEventListenerFunctions.HandleDrop, - tabIndex: 0, - type: 4, - }, - { - childCount: 2, - className: 'Welcome', - type: 4, - }, - { - childCount: 1, - className: 'WelcomeMessage', - type: 50, - }, - { - childCount: 0, - text: 'You have not yet opened a folder.', - type: 12, - }, - { - childCount: 1, - className: 'Button ButtonPrimary ButtonNarrow', - name: 'OpenFolder', - onClick: DomEventListenerFunctions.HandleClickOpenFolder, - type: 1, - }, - { - childCount: 0, - text: 'Open folder', - type: 12, - }, - ]) -}) - -test('getExplorerWelcomeVirtualDom - drop target', () => { - expect(GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(true, dropTargetFull)).toEqual([ - { - childCount: 1, - className: 'Viewlet Explorer DropTarget', - onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, - onDragLeave: DomEventListenerFunctions.HandleDragLeave, - onDragOver: DomEventListenerFunctions.HandleDragOver, - onDrop: DomEventListenerFunctions.HandleDrop, - tabIndex: 0, - type: 4, - }, - { - childCount: 2, - className: 'Welcome', - type: 4, - }, - { - childCount: 1, - className: 'WelcomeMessage', - type: 50, - }, - { - childCount: 0, - text: 'You have not yet opened a folder.', - type: 12, - }, - { - childCount: 1, - className: 'Button ButtonPrimary ButtonWide', - name: 'OpenFolder', - onClick: DomEventListenerFunctions.HandleClickOpenFolder, - type: 1, - }, - { - childCount: 0, - text: 'Open folder', - type: 12, - }, - ]) -}) diff --git a/packages/explorer-view/test/GetFileArray.test.ts b/packages/explorer-view/test/GetFileArray.test.ts deleted file mode 100644 index 5c59b1e..0000000 --- a/packages/explorer-view/test/GetFileArray.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { test, expect } from '@jest/globals' -import { getFileArray } from '../src/parts/GetFileArray/GetFileArray.ts' - -class MockFileList implements FileList { - private files: File[] = [] - - constructor(files: File[] = []) { - this.files = files - } - - get length(): number { - return this.files.length - } - - item(index: number): File | null { - return this.files[index] || null - } - - [Symbol.iterator](): any { - return this.files[Symbol.iterator]() - } - - [index: number]: File -} - -test('getFileArray converts FileList to array', () => { - const mockFile = new File(['test'], 'test.txt') - const mockFileList = new MockFileList([mockFile]) - - const result = getFileArray(mockFileList) - expect(result).toHaveLength(1) - expect(result[0]).toBe(mockFile) -}) - -test('getFileArray handles empty FileList', () => { - const mockFileList = new MockFileList() - - const result = getFileArray(mockFileList) - expect(result).toHaveLength(0) -}) diff --git a/packages/explorer-view/test/GetFileDecorations.test.ts b/packages/explorer-view/test/GetFileDecorations.test.ts deleted file mode 100644 index 64169ee..0000000 --- a/packages/explorer-view/test/GetFileDecorations.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { test, expect, jest } from '@jest/globals' -import { SourceControlWorker } from '@lvce-editor/rpc-registry' -import type { FileDecoration } from '../src/parts/FileDecoration/FileDecoration.ts' - -test.skip('getFileDecorations - returns empty array when decorationsEnabled is false', async () => { - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['/file1.txt'], false, '', 0) - expect(result).toEqual([]) -}) - -test('getFileDecorations - returns empty array when no provider IDs', async () => { - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) - expect(result).toEqual([]) - expect(mockRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0]]) -}) - -test.skip('getFileDecorations - returns decorations for single file', async () => { - const decorations: FileDecoration[] = [{ decoration: 'modified', uri: 'file:///file1.txt' }] - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return ['git'] - }, - 'SourceControl.getFileDecorations'() { - return decorations - }, - }) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) - expect(result).toEqual(decorations) - expect(mockRpc.invocations).toEqual([ - ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], - ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', '', 0]], - ]) -}) - -test.skip('getFileDecorations - converts paths to URIs', async () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///file1.txt' }, - { decoration: 'added', uri: 'file:///file2.txt' }, - ] - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return ['git'] - }, - 'SourceControl.getFileDecorations'() { - return decorations - }, - }) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['/file1.txt', '/file2.txt'], true, '', 0) - expect(result).toEqual(decorations) - expect(mockRpc.invocations).toEqual([ - ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], - ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', 'file:///file2.txt', '', 0]], - ]) -}) - -test.skip('getFileDecorations - handles URIs that are already URIs', async () => { - const decorations: FileDecoration[] = [{ decoration: 'modified', uri: 'file:///file1.txt' }] - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return ['git'] - }, - 'SourceControl.getFileDecorations'() { - return decorations - }, - }) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['file:///file1.txt'], true, '', 0) - expect(result).toEqual(decorations) - expect(mockRpc.invocations).toEqual([ - ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], - ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', '', 0]], - ]) -}) - -test.skip('getFileDecorations - uses first provider ID when multiple are available', async () => { - const decorations: FileDecoration[] = [{ decoration: 'modified', uri: 'file:///file1.txt' }] - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return ['git', 'svn', 'hg'] - }, - 'SourceControl.getFileDecorations'() { - return decorations - }, - }) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) - expect(result).toEqual(decorations) - expect(mockRpc.invocations).toEqual([ - ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], - ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt', '', 0]], - ]) -}) - -test('getFileDecorations - returns empty array when getEnabledProviderIds throws', async () => { - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - throw new Error('Provider error') - }, - }) - - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) - expect(result).toEqual([]) - expect(mockRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0]]) - expect(consoleErrorSpy).toHaveBeenCalled() - - consoleErrorSpy.mockRestore() -}) - -test('getFileDecorations - returns empty array when getFileDecorations throws', async () => { - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return ['git'] - }, - 'SourceControl.getFileDecorations'() { - throw new Error('Decorations error') - }, - }) - - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', ['/file1.txt'], true, '', 0) - expect(result).toEqual([]) - expect(mockRpc.invocations).toEqual([ - ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], - ['SourceControl.getFileDecorations', 'git', ['file:///file1.txt'], '', 0], - ]) - expect(consoleErrorSpy).toHaveBeenCalled() - - consoleErrorSpy.mockRestore() -}) - -test('getFileDecorations - handles empty URIs array', async () => { - using mockRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return ['git'] - }, - 'SourceControl.getFileDecorations'() { - return [] - }, - }) - - const { getFileDecorations } = await import('../src/parts/GetFileDecorations/GetFileDecorations.ts') - const result = await getFileDecorations('file', '/root', [], true, '', 0) - expect(result).toEqual([]) - expect(mockRpc.invocations).toEqual([ - ['SourceControl.getEnabledProviderIds', 'file', '/root', '', 0], - ['SourceControl.getFileDecorations', 'git', [], '', 0], - ]) -}) diff --git a/packages/explorer-view/test/GetFileHandles.test.ts b/packages/explorer-view/test/GetFileHandles.test.ts deleted file mode 100644 index a642439..0000000 --- a/packages/explorer-view/test/GetFileHandles.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { getFileHandles } from '../src/parts/GetFileHandles/GetFileHandles.ts' - -class MockFileHandle { - constructor(public name: string) {} -} - -test('getFileHandles', async () => { - const fileIds = [1, 2, 3] - const mockFiles = [new MockFileHandle('file1'), new MockFileHandle('file2'), new MockFileHandle('file3')] - - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystemHandle.getFileHandles'() { - return mockFiles - }, - }) - - const result = await getFileHandles(fileIds) - expect(result).toBe(mockFiles) - expect(result[0]).toBeInstanceOf(MockFileHandle) - expect(mockRpc.invocations).toEqual([['FileSystemHandle.getFileHandles', fileIds]]) -}) diff --git a/packages/explorer-view/test/GetFileIconVirtualDom.test.ts b/packages/explorer-view/test/GetFileIconVirtualDom.test.ts deleted file mode 100644 index 12b85b6..0000000 --- a/packages/explorer-view/test/GetFileIconVirtualDom.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as AriaRoles from '../src/parts/AriaRoles/AriaRoles.ts' -import * as ClassNames from '../src/parts/ClassNames/ClassNames.ts' -import * as GetFileIconVirtualDom from '../src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts' -import * as VirtualDomElements from '../src/parts/VirtualDomElements/VirtualDomElements.ts' - -test('getFileIconVirtualDom - with icon path', () => { - expect(GetFileIconVirtualDom.getFileIconVirtualDom('/icons/file.svg')).toEqual({ - childCount: 0, - className: ClassNames.FileIcon, - role: AriaRoles.None, - src: '/icons/file.svg', - type: VirtualDomElements.Img, - }) -}) - -test('getFileIconVirtualDom - empty icon path', () => { - expect(GetFileIconVirtualDom.getFileIconVirtualDom('')).toEqual({ - childCount: 0, - className: ClassNames.FileIcon, - role: AriaRoles.None, - src: '', - type: VirtualDomElements.Img, - }) -}) diff --git a/packages/explorer-view/test/GetFileIcons.test.ts b/packages/explorer-view/test/GetFileIcons.test.ts deleted file mode 100644 index bb72046..0000000 --- a/packages/explorer-view/test/GetFileIcons.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { test, expect } from '@jest/globals' -import { IconThemeWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { FileIconCache } from '../src/parts/FileIconCache/FileIconCache.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as GetFileIcons from '../src/parts/GetFileIcons/GetFileIcons.ts' - -test('getFileIcons - empty dirents', async () => { - using mockRpc = IconThemeWorker.registerMockRpc({}) - - const result = await GetFileIcons.getFileIcons([], {}) - expect(result).toEqual({ - icons: [], - newFileIconCache: {}, - }) - expect(mockRpc.invocations).toEqual([]) -}) - -test('getFileIcons - all cached', async () => { - using mockRpc = IconThemeWorker.registerMockRpc({}) - - const dirents: readonly ExplorerItem[] = [ - { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'b', path: '/b', selected: false, type: DirentType.Directory }, - ] - const cache: FileIconCache = { - '/a.txt': 'cached-a', - '/b': 'cached-b', - } - const result = await GetFileIcons.getFileIcons(dirents, cache) - expect(result).toEqual({ - icons: ['cached-a', 'cached-b'], - newFileIconCache: cache, - }) - expect(mockRpc.invocations).toEqual([]) -}) - -test('getFileIcons - none cached', async () => { - const dirents: readonly ExplorerItem[] = [ - { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'b', path: '/b', selected: false, type: DirentType.Directory }, - ] - - using mockRpc = IconThemeWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return ['file-icon', 'folder-icon'] - }, - }) - - const result = await GetFileIcons.getFileIcons(dirents, {}) - expect(result).toEqual({ - icons: ['file-icon', 'folder-icon'], - newFileIconCache: { - '/a.txt': 'file-icon', - '/b': 'folder-icon', - }, - }) - expect(mockRpc.invocations).toEqual([ - [ - 'IconTheme.getIcons', - [ - { name: 'a.txt', type: 1 }, - { name: 'b', type: 2 }, - ], - ], - ]) -}) - -test('getFileIcons - mixed cache', async () => { - const dirents: readonly ExplorerItem[] = [ - { depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'b', path: '/b', selected: false, type: DirentType.Directory }, - { depth: 0, name: 'c.txt', path: '/c.txt', selected: false, type: DirentType.File }, - ] - const cache: FileIconCache = { - '/a.txt': 'cached-a', - } - - using mockRpc = IconThemeWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return ['folder-icon', 'file-icon'] - }, - }) - - const result = await GetFileIcons.getFileIcons(dirents, cache) - expect(result).toEqual({ - icons: ['cached-a', 'folder-icon', 'file-icon'], - newFileIconCache: { - '/a.txt': 'cached-a', - '/b': 'folder-icon', - '/c.txt': 'file-icon', - }, - }) - expect(mockRpc.invocations).toEqual([ - [ - 'IconTheme.getIcons', - [ - { name: 'b', type: 2 }, - { name: 'c.txt', type: 1 }, - ], - ], - ]) -}) diff --git a/packages/explorer-view/test/GetFileOperations.test.ts b/packages/explorer-view/test/GetFileOperations.test.ts deleted file mode 100644 index f0c258f..0000000 --- a/packages/explorer-view/test/GetFileOperations.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' -import { getFileOperations } from '../src/parts/GetFileOperations/GetFileOperations.ts' - -test('getFileOperations - empty tree', () => { - const root = '/test' - const uploadTree = {} - expect(getFileOperations(root, uploadTree)).toEqual([]) -}) - -test('getFileOperations - single file', () => { - const root = '/test' - const uploadTree = { - 'file.txt': 'content', - } - expect(getFileOperations(root, uploadTree)).toEqual([{ path: '/test/file.txt', text: 'content', type: FileOperationType.CreateFile }]) -}) - -test('getFileOperations - single folder', () => { - const root = '/test' - const uploadTree = { - folder: {}, - } - expect(getFileOperations(root, uploadTree)).toEqual([{ path: '/test/folder', type: FileOperationType.CreateFolder }]) -}) - -test.skip('getFileOperations - nested structure', () => { - const root = '/test' - const uploadTree = { - 'file3.txt': 'content3', - folder1: { - 'file1.txt': 'content1', - subfolder: { - 'file2.txt': 'content2', - }, - }, - } - expect(getFileOperations(root, uploadTree)).toEqual([ - { path: '/test/folder1', type: FileOperationType.CreateFolder }, - { path: '/test/folder1/file1.txt', text: 'content1', type: FileOperationType.CreateFile }, - { path: '/test/folder1/subfolder', type: FileOperationType.CreateFolder }, - { path: '/test/folder1/subfolder/file2.txt', text: 'content2', type: FileOperationType.CreateFile }, - { path: '/test/file3.txt', text: 'content3', type: FileOperationType.CreateFile }, - ]) -}) diff --git a/packages/explorer-view/test/GetFileOperationsCopy.test.ts b/packages/explorer-view/test/GetFileOperationsCopy.test.ts deleted file mode 100644 index a2b2802..0000000 --- a/packages/explorer-view/test/GetFileOperationsCopy.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' -import { getFileOperationsCopy } from '../src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts' - -test('getFileOperationsCopy - no conflicts', () => { - const root = '/test' - const existingUris = ['/test/existing.txt'] - const files = ['/source/file.txt'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file.txt', type: FileOperationType.Copy }]) -}) - -test('getFileOperationsCopy - single conflict', () => { - const root = '/test' - const existingUris = ['/test/file.txt'] - const files = ['/source/file.txt'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file copy.txt', type: FileOperationType.Copy }]) -}) - -test('getFileOperationsCopy - multiple conflicts', () => { - const root = '/test' - const existingUris = ['/test/file.txt', '/test/file copy.txt'] - const files = ['/source/file.txt'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file copy 1.txt', type: FileOperationType.Copy }]) -}) - -test('getFileOperationsCopy - multiple numbered conflicts', () => { - const root = '/test' - const existingUris = ['/test/file.txt', '/test/file copy.txt', '/test/file copy 1.txt', '/test/file copy 2.txt'] - const files = ['/source/file.txt'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file copy 3.txt', type: FileOperationType.Copy }]) -}) - -test('getFileOperationsCopy - file without extension', () => { - const root = '/test' - const existingUris = ['/test/README'] - const files = ['/source/README'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([{ from: '/source/README', path: '/test/README copy', type: FileOperationType.Copy }]) -}) - -test('getFileOperationsCopy - file without extension multiple conflicts', () => { - const root = '/test' - const existingUris = ['/test/README', '/test/README copy', '/test/README copy 1'] - const files = ['/source/README'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([{ from: '/source/README', path: '/test/README copy 2', type: FileOperationType.Copy }]) -}) - -test('getFileOperationsCopy - multiple files with conflicts', () => { - const root = '/test' - const existingUris = ['/test/file1.txt', '/test/file2.txt'] - const files = ['/source/file1.txt', '/source/file2.txt'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([ - { from: '/source/file1.txt', path: '/test/file1 copy.txt', type: FileOperationType.Copy }, - { from: '/source/file2.txt', path: '/test/file2 copy.txt', type: FileOperationType.Copy }, - ]) -}) - -test('getFileOperationsCopy - empty existingUris', () => { - const root = '/test' - const existingUris: readonly string[] = [] - const files = ['/source/file.txt'] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([{ from: '/source/file.txt', path: '/test/file.txt', type: FileOperationType.Copy }]) -}) - -test('getFileOperationsCopy - empty files', () => { - const root = '/test' - const existingUris = ['/test/existing.txt'] - const files: readonly string[] = [] - - const result = getFileOperationsCopy(root, existingUris, files, root) - expect(result).toEqual([]) -}) diff --git a/packages/explorer-view/test/GetFileOperationsRename.test.ts b/packages/explorer-view/test/GetFileOperationsRename.test.ts deleted file mode 100644 index 5ab7478..0000000 --- a/packages/explorer-view/test/GetFileOperationsRename.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { test, expect } from '@jest/globals' -import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' -import { getFileOperationsRename } from '../src/parts/GetFileOperationsRename/GetFileOperationsRename.ts' - -test('should return rename operation', () => { - const ops = getFileOperationsRename('/folder/old.txt', 'new.txt') - expect(ops).toHaveLength(1) - expect(ops[0].type).toBe(FileOperationType.Rename) - expect(ops).toEqual([ - { - from: '/folder/old.txt', - path: '/folder/new.txt', - type: 4, - }, - ]) -}) diff --git a/packages/explorer-view/test/GetFilePaths.test.ts b/packages/explorer-view/test/GetFilePaths.test.ts deleted file mode 100644 index 9f6028d..0000000 --- a/packages/explorer-view/test/GetFilePaths.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { getFilePaths } from '../src/parts/GetFilePaths/GetFilePaths.ts' -import * as PlatformType from '../src/parts/PlatformType/PlatformType.ts' - -test('getFilePaths - non-electron platform', async () => { - const files = [new File([], 'test.txt')] - const paths = await getFilePaths(files, PlatformType.Web) - expect(paths).toEqual(['']) -}) - -test('getFilePaths - electron platform', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystemHandle.getFilePathElectron'() { - return '/path/to/file' - }, - }) - - const files = [new File([], 'test.txt')] - const paths = await getFilePaths(files, PlatformType.Electron) - expect(paths).toEqual(['/path/to/file']) - expect(mockRpc.invocations).toEqual([['FileSystemHandle.getFilePathElectron', files[0]]]) -}) - -test('getFilePaths - multiple files', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystemHandle.getFilePathElectron'() { - return '/path/to/file' - }, - }) - - const files = [new File([], 'test1.txt'), new File([], 'test2.txt')] - const paths = await getFilePaths(files, PlatformType.Electron) - expect(paths).toEqual(['/path/to/file', '/path/to/file']) - expect(mockRpc.invocations).toEqual([ - ['FileSystemHandle.getFilePathElectron', files[0]], - ['FileSystemHandle.getFilePathElectron', files[1]], - ]) -}) diff --git a/packages/explorer-view/test/GetFittingIndex.test.ts b/packages/explorer-view/test/GetFittingIndex.test.ts deleted file mode 100644 index 0fa04b3..0000000 --- a/packages/explorer-view/test/GetFittingIndex.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getFittingIndex } from '../src/parts/GetFittingIndex/GetFittingIndex.ts' - -test('getFittingIndex returns the focused folder index', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.Directory }, - { depth: 0, name: 'file.txt', path: '/file.txt', selected: false, type: DirentType.File }, - ] - - expect(getFittingIndex(items, 0)).toBe(0) -}) - -test('getFittingIndex returns the closest parent folder before a focused file', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.DirectoryExpanded }, - { depth: 1, name: 'file-a.txt', path: '/folder/file-a.txt', selected: false, type: DirentType.File }, - { depth: 1, name: 'file-b.txt', path: '/folder/file-b.txt', selected: false, type: DirentType.File }, - ] - - expect(getFittingIndex(items, 2)).toBe(0) -}) - -test('getFittingIndex treats symlink folders as valid insertion targets', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'link', path: '/link', selected: false, type: DirentType.SymLinkFolder }, - { depth: 0, name: 'file.txt', path: '/file.txt', selected: false, type: DirentType.File }, - ] - - expect(getFittingIndex(items, 1)).toBe(0) -}) - -test('getFittingIndex returns -1 when there is no folder at or before the start index', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'file-a.txt', path: '/file-a.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'file-b.txt', path: '/file-b.txt', selected: false, type: DirentType.File }, - ] - - expect(getFittingIndex(items, 1)).toBe(-1) -}) diff --git a/packages/explorer-view/test/GetFocusedIndexCancel.test.ts b/packages/explorer-view/test/GetFocusedIndexCancel.test.ts deleted file mode 100644 index 4e97a87..0000000 --- a/packages/explorer-view/test/GetFocusedIndexCancel.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { expect, test } from '@jest/globals' -import { getFocusedIndexCancel } from '../src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts' - -test('getFocusedIndexCancel - clamps index to last remaining item when edited placeholder was removed', () => { - const items = [ - { - depth: 0, - name: 'file1.txt', - path: '/file1.txt', - selected: false, - type: 2, - }, - ] - - const result = getFocusedIndexCancel(items, 1) - - expect(result).toBe(0) -}) - -test('getFocusedIndexCancel - returns original editing index when still in bounds', () => { - const items = [ - { - depth: 0, - name: 'file1.txt', - path: '/file1.txt', - selected: false, - type: 2, - }, - { - depth: 0, - name: 'file2.txt', - path: '/file2.txt', - selected: false, - type: 2, - }, - ] - - const result = getFocusedIndexCancel(items, 1) - - expect(result).toBe(1) -}) diff --git a/packages/explorer-view/test/GetFriendlyErrorMessage.test.ts b/packages/explorer-view/test/GetFriendlyErrorMessage.test.ts deleted file mode 100644 index a1b37d7..0000000 --- a/packages/explorer-view/test/GetFriendlyErrorMessage.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetFriendlyErrorMessage from '../src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts' - -test('getFriendlyErrorMessage - maps permission errors', () => { - expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Access denied', 'EACCES')).toBe('permission was denied') - expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Access denied', 'EPERM')).toBe('permission was denied') -}) - -test('getFriendlyErrorMessage - maps busy error', () => { - expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Busy', 'EBUSY')).toBe('the folder is currently in use') -}) - -test('getFriendlyErrorMessage - returns explicit message for unknown code', () => { - expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('Custom failure', 'UNKNOWN')).toBe('Custom failure') -}) - -test('getFriendlyErrorMessage - returns generic fallback for empty message', () => { - expect(GetFriendlyErrorMessage.getFriendlyErrorMessage('', 'UNKNOWN')).toBe('an unexpected error occurred') -}) diff --git a/packages/explorer-view/test/GetIconVirtualDom.test.ts b/packages/explorer-view/test/GetIconVirtualDom.test.ts deleted file mode 100644 index 5a6aee7..0000000 --- a/packages/explorer-view/test/GetIconVirtualDom.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as AriaRoles from '../src/parts/AriaRoles/AriaRoles.ts' -import * as GetIconVirtualDom from '../src/parts/GetIconVirtualDom/GetIconVirtualDom.ts' -import * as VirtualDomElements from '../src/parts/VirtualDomElements/VirtualDomElements.ts' - -test('getIconVirtualDom - with icon', () => { - expect(GetIconVirtualDom.getIconVirtualDom('File')).toEqual({ - childCount: 0, - className: 'MaskIcon MaskIconFile', - role: AriaRoles.None, - type: VirtualDomElements.Div, - }) -}) - -test('getIconVirtualDom - with custom element type', () => { - expect(GetIconVirtualDom.getIconVirtualDom('Folder', VirtualDomElements.Div)).toEqual({ - childCount: 0, - className: 'MaskIcon MaskIconFolder', - role: AriaRoles.None, - type: VirtualDomElements.Div, - }) -}) diff --git a/packages/explorer-view/test/GetIndex.test.ts b/packages/explorer-view/test/GetIndex.test.ts deleted file mode 100644 index 635f45a..0000000 --- a/packages/explorer-view/test/GetIndex.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import { getIndex } from '../src/parts/GetIndex/GetIndex.ts' - -test('getIndex - finds item', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, - { depth: 0, name: 'b', path: '/b', selected: true, type: 2 }, - { depth: 0, name: 'c', path: '/c', selected: false, type: 1 }, - ] - expect(getIndex(items, '/b')).toBe(1) -}) - -test('getIndex - item not found', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, - { depth: 0, name: 'b', path: '/b', selected: false, type: 2 }, - ] - expect(getIndex(items, '/not-found')).toBe(-1) -}) - -test('getIndex - empty array', () => { - const items: readonly ExplorerItem[] = [] - expect(getIndex(items, '/any')).toBe(-1) -}) diff --git a/packages/explorer-view/test/GetIndexFromPosition.test.ts b/packages/explorer-view/test/GetIndexFromPosition.test.ts deleted file mode 100644 index 071b4f8..0000000 --- a/packages/explorer-view/test/GetIndexFromPosition.test.ts +++ /dev/null @@ -1,302 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { getIndexFromPosition } from '../src/parts/GetIndexFromPosition/GetIndexFromPosition.ts' - -test('getIndexFromPosition', () => { - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - confirmPaste: false, - cutItems: [], - deltaY: 0, - dropTargets: [], - editingErrorMessage: '', - editingIcon: '', - editingIndex: -1, - editingSelectionEnd: 0, - editingSelectionStart: 0, - editingType: 0, - editingValue: '', - excluded: [], - fileIconCache: { - 'test:///virtual-dom/.git': 'test://file-icons/folder_type_git.svg', - 'test:///virtual-dom/.git/branches': 'test://file-icons/default_folder.svg', - 'test:///virtual-dom/.git/COMMIT_EDITMSG': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/config': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/description': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/FETCH_HEAD': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/HEAD': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/hooks': 'test://file-icons/folder_type_hook.svg', - 'test:///virtual-dom/.git/index': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/info': 'test://file-icons/default_folder.svg', - 'test:///virtual-dom/.git/logs': 'test://file-icons/folder_type_log.svg', - 'test:///virtual-dom/.git/objects': 'test://file-icons/default_folder.svg', - 'test:///virtual-dom/.git/ORIG_HEAD': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/packed-refs': 'test://file-icons/default_file.svg', - 'test:///virtual-dom/.git/refs': 'test://file-icons/default_folder.svg', - 'test:///virtual-dom/.git/rr-cache': 'test://file-icons/default_folder.svg', - 'test:///virtual-dom/.github': 'test://file-icons/folder_type_github.svg', - 'test:///virtual-dom/.gitignore': 'test://file-icons/file_type_git.svg', - 'test:///virtual-dom/.gitpod.Dockerfile': 'test://file-icons/file_type_docker.svg', - 'test:///virtual-dom/.gitpod.yml': 'test://file-icons/file_type_gitpod.svg', - 'test:///virtual-dom/.nvmrc': 'test://file-icons/file_type_node.svg', - 'test:///virtual-dom/.vscode': 'test://file-icons/folder_type_vscode.svg', - 'test:///virtual-dom/dist': 'test://file-icons/folder_type_dist.svg', - 'test:///virtual-dom/eslint.config.js': 'test://file-icons/file_type_eslint.svg', - 'test:///virtual-dom/lerna.json': 'test://file-icons/file_type_lerna.svg', - 'test:///virtual-dom/LICENSE': 'test://file-icons/file_type_license.svg', - 'test:///virtual-dom/node_modules': 'test://file-icons/folder_type_node.svg', - 'test:///virtual-dom/package-lock.json': 'test://file-icons/file_type_npm.svg', - 'test:///virtual-dom/package.json': 'test://file-icons/file_type_npm.svg', - 'test:///virtual-dom/packages': 'test://file-icons/folder_type_package.svg', - 'test:///virtual-dom/README.md': 'test://file-icons/file_type_markdown.svg', - 'test:///virtual-dom/scripts': 'test://file-icons/folder_type_script.svg', - 'test:///virtual-dom/tsconfig.json': 'test://file-icons/file_type_tsconfig.svg', - 'test:///virtual-dom/virtual-dom-worker': 'test://file-icons/default_folder.svg', - }, - finalDeltaY: 0, - focus: 0, - focused: false, - focusedIndex: 0, - focusWord: '', - focusWordTimeout: 800, - handleOffset: 0, - height: 964, - hoverIndex: -1, - icons: [ - 'test://file-icons/folder_type_git.svg', - 'test://file-icons/folder_type_github.svg', - 'test://file-icons/folder_type_vscode.svg', - 'test://file-icons/folder_type_dist.svg', - 'test://file-icons/folder_type_node.svg', - 'test://file-icons/folder_type_package.svg', - 'test://file-icons/folder_type_script.svg', - 'test://file-icons/default_folder.svg', - 'test://file-icons/file_type_git.svg', - 'test://file-icons/file_type_docker.svg', - 'test://file-icons/file_type_gitpod.svg', - 'test://file-icons/file_type_node.svg', - 'test://file-icons/file_type_license.svg', - 'test://file-icons/file_type_markdown.svg', - 'test://file-icons/file_type_eslint.svg', - 'test://file-icons/file_type_lerna.svg', - 'test://file-icons/file_type_npm.svg', - 'test://file-icons/file_type_npm.svg', - 'test://file-icons/file_type_tsconfig.svg', - ], - inputSource: 0, - isPointerDown: false, - itemHeight: 22, - items: [ - { - depth: 1, - icon: '', - name: '.git', - path: 'test:///virtual-dom/.git', - posInSet: 1, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: '.github', - path: 'test:///virtual-dom/.github', - posInSet: 2, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: '.vscode', - path: 'test:///virtual-dom/.vscode', - posInSet: 3, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: 'dist', - path: 'test:///virtual-dom/dist', - posInSet: 4, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: 'node_modules', - path: 'test:///virtual-dom/node_modules', - posInSet: 5, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: 'packages', - path: 'test:///virtual-dom/packages', - posInSet: 6, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: 'scripts', - path: 'test:///virtual-dom/scripts', - posInSet: 7, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: 'virtual-dom-worker', - path: 'test:///virtual-dom/virtual-dom-worker', - posInSet: 8, - selected: false, - setSize: 19, - type: 3, - }, - { - depth: 1, - icon: '', - name: '.gitignore', - path: 'test:///virtual-dom/.gitignore', - posInSet: 9, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: '.gitpod.Dockerfile', - path: 'test:///virtual-dom/.gitpod.Dockerfile', - posInSet: 10, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: '.gitpod.yml', - path: 'test:///virtual-dom/.gitpod.yml', - posInSet: 11, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: '.nvmrc', - path: 'test:///virtual-dom/.nvmrc', - posInSet: 12, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'LICENSE', - path: 'test:///virtual-dom/LICENSE', - posInSet: 13, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'README.md', - path: 'test:///virtual-dom/README.md', - posInSet: 14, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'eslint.config.js', - path: 'test:///virtual-dom/eslint.config.js', - posInSet: 15, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'lerna.json', - path: 'test:///virtual-dom/lerna.json', - posInSet: 16, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'package-lock.json', - path: 'test:///virtual-dom/package-lock.json', - posInSet: 17, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'package.json', - path: 'test:///virtual-dom/package.json', - posInSet: 18, - selected: false, - setSize: 19, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'tsconfig.json', - path: 'test:///virtual-dom/tsconfig.json', - posInSet: 19, - selected: false, - setSize: 19, - type: 7, - }, - ], - maxLineY: 19, - minLineY: 0, - parentUid: 43, - pasteShouldMove: false, - pathSeparator: '/', - platform: 2, - pointerDownIndex: -1, - root: 'test:///virtual-dom', - scrollBarActive: false, - scrollBarHeight: 0, - sourceControlIgnoredUris: [], - uid: 44, - useChevrons: true, - version: 0, - width: 170, - x: 29, - y: 1671, - } - expect(getIndexFromPosition(state, 988, 1700)).toBe(1) -}) diff --git a/packages/explorer-view/test/GetInputDom.test.ts b/packages/explorer-view/test/GetInputDom.test.ts deleted file mode 100644 index 14d8755..0000000 --- a/packages/explorer-view/test/GetInputDom.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as ClassNames from '../src/parts/ClassNames/ClassNames.ts' -import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' -import { getInputDom } from '../src/parts/GetInputDom/GetInputDom.ts' -import * as InputName from '../src/parts/InputName/InputName.ts' -import * as VirtualDomElements from '../src/parts/VirtualDomElements/VirtualDomElements.ts' - -test('getInputDom - without error', () => { - const result = getInputDom(true, false) - expect(result).toEqual([ - { - ariaLabel: 'Type file name. Press Enter to confirm or Escape to cancel.', - autocapitalize: 'off', - autocomplete: 'off', - autocorrect: 'off', - childCount: 0, - className: `ExplorerInputBox`, - id: 'ExplorerInput', - name: InputName.ExplorerInput, - onBlur: DomEventListenerFunctions.HandleInputBlur, - onClick: DomEventListenerFunctions.HandleInputClick, - onInput: DomEventListenerFunctions.HandleEditingInput, - spellcheck: 'false', - type: VirtualDomElements.Input, - }, - ]) -}) - -test('getInputDom - with error', () => { - const result = getInputDom(true, true) - expect(result).toEqual([ - { - ariaLabel: 'Type file name. Press Enter to confirm or Escape to cancel.', - autocapitalize: 'off', - autocomplete: 'off', - autocorrect: 'off', - childCount: 0, - className: expect.stringContaining(ClassNames.InputBox), - id: 'ExplorerInput', - name: InputName.ExplorerInput, - onBlur: DomEventListenerFunctions.HandleInputBlur, - onClick: DomEventListenerFunctions.HandleInputClick, - onInput: DomEventListenerFunctions.HandleEditingInput, - spellcheck: 'false', - type: VirtualDomElements.Input, - }, - ]) -}) diff --git a/packages/explorer-view/test/GetKeyBindings.test.ts b/packages/explorer-view/test/GetKeyBindings.test.ts deleted file mode 100644 index adfe23b..0000000 --- a/packages/explorer-view/test/GetKeyBindings.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { expect, test } from '@jest/globals' -import { getKeyBindings } from '../src/parts/GetKeyBindings/GetKeyBindings.ts' - -test('getKeyBindings', () => { - const keyBindings = getKeyBindings() - expect(keyBindings).toBeDefined() -}) diff --git a/packages/explorer-view/test/GetMenuEntries2.test.ts b/packages/explorer-view/test/GetMenuEntries2.test.ts deleted file mode 100644 index ea1d5dd..0000000 --- a/packages/explorer-view/test/GetMenuEntries2.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { set } from '../src/parts/ExplorerStates/ExplorerStates.ts' -import { getMenuEntries2 } from '../src/parts/GetMenuEntries2/GetMenuEntries2.ts' - -test('getMenuEntries2 - root', () => { - const uid = 1 - const state: ExplorerState = createDefaultState() - set(uid, state, state) - const menuEntries = getMenuEntries2(state) - expect(menuEntries.length).toBeGreaterThan(0) -}) - -test('getMenuEntries2 - directory', () => { - const uid = 1 - const item: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: true, - type: DirentType.Directory, - } - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [item], - } - set(uid, state, state) - const menuEntries = getMenuEntries2(state) - expect(menuEntries.length).toBeGreaterThan(0) -}) - -test('getMenuEntries2 - file', () => { - const uid = 1 - const item: ExplorerItem = { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - } - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [item], - } - set(uid, state, state) - const menuEntries = getMenuEntries2(state) - expect(menuEntries.length).toBeGreaterThan(0) -}) - -test('getMenuEntries2 - file shows select for compare by default', () => { - const uid = 1 - const item: ExplorerItem = { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - } - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [item], - } - set(uid, state, state) - const menuEntries = getMenuEntries2(state) - expect(menuEntries.some((entry) => entry.id === 'selectForCompare')).toBe(true) - expect(menuEntries.some((entry) => entry.id === 'compareWithSelected')).toBe(false) -}) - -test('getMenuEntries2 - file shows compare with selected for different file', () => { - const uid = 1 - const item: ExplorerItem = { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - } - const state: ExplorerState = { - ...createDefaultState(), - compareSourceUri: '/other.txt', - focusedIndex: 0, - items: [item], - } - set(uid, state, state) - const menuEntries = getMenuEntries2(state) - expect(menuEntries.some((entry) => entry.id === 'compareWithSelected')).toBe(true) - expect(menuEntries.some((entry) => entry.id === 'selectForCompare')).toBe(false) -}) diff --git a/packages/explorer-view/test/GetMissingIconRequests.test.ts b/packages/explorer-view/test/GetMissingIconRequests.test.ts deleted file mode 100644 index 400f9df..0000000 --- a/packages/explorer-view/test/GetMissingIconRequests.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { FileIconCache } from '../src/parts/FileIconCache/FileIconCache.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as GetMissingIconRequests from '../src/parts/GetMissingIconRequests/GetMissingIconRequests.ts' - -test('getMissingIconRequests - empty list', () => { - const dirents: readonly ExplorerItem[] = [] - const cache: FileIconCache = {} - expect(GetMissingIconRequests.getMissingIconRequests(dirents, cache)).toEqual([]) -}) - -test('getMissingIconRequests - all in cache', () => { - const dirents: readonly ExplorerItem[] = [{ depth: 0, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }] - const cache: FileIconCache = { - '/test/file.txt': 'icon', - } - expect(GetMissingIconRequests.getMissingIconRequests(dirents, cache)).toEqual([]) -}) - -test('getMissingIconRequests - some missing', () => { - const dirents: readonly ExplorerItem[] = [ - { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'file2.txt', path: '/test/file2.txt', selected: false, type: DirentType.File }, - ] - const cache: FileIconCache = { - '/test/file1.txt': 'icon', - } - expect(GetMissingIconRequests.getMissingIconRequests(dirents, cache)).toEqual([ - { name: 'file2.txt', path: '/test/file2.txt', type: DirentType.File }, - ]) -}) diff --git a/packages/explorer-view/test/GetMouseActions.test.ts b/packages/explorer-view/test/GetMouseActions.test.ts deleted file mode 100644 index cb2e1ff..0000000 --- a/packages/explorer-view/test/GetMouseActions.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { test, expect } from '@jest/globals' -import { getMouseActions } from '../src/parts/GetMouseActions/GetMouseActions.ts' - -test('should return mouse actions array', () => { - const actions = getMouseActions() - expect(Array.isArray(actions)).toBe(true) - expect(actions.length).toBeGreaterThan(0) - for (const action of actions) { - expect(action).toHaveProperty('description') - expect(action).toHaveProperty('button') - expect(action).toHaveProperty('command') - expect(action).toHaveProperty('when') - } -}) diff --git a/packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts b/packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts deleted file mode 100644 index f61b36a..0000000 --- a/packages/explorer-view/test/GetNewChildDirentsForNewDirent.test.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getNewChildDirentsForNewDirent } from '../src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts' - -test.skip('getNewChildDirentsForNewDirent - empty directory', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const items = [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - ] - - const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.File) - - expect(result).toEqual([ - { - depth: 2, - icon: '', - name: '', - path: '', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ]) - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('getNewChildDirentsForNewDirent - directory with existing children', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const items = [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/root/folder/file1.txt', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: 'file2.txt', - path: '/root/folder/file2.txt', - posInSet: 2, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ] - - const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.File) - - expect(result).toEqual([ - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/root/folder/file1.txt', - posInSet: 1, - selected: false, - setSize: 3, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: 'file2.txt', - path: '/root/folder/file2.txt', - posInSet: 2, - selected: false, - setSize: 3, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: '', - path: '', - posInSet: 3, - selected: false, - setSize: 3, - type: DirentType.File, - }, - ]) - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('getNewChildDirentsForNewDirent - directory with no children', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const items = [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - ] - - const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.DirectoryExpanded) - - expect(result).toEqual([ - { - depth: 2, - icon: '', - name: '', - path: '', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - ]) - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('getNewChildDirentsForNewDirent - different dirent types', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const items = [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/root/folder/file1.txt', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: 'folder1', - path: '/root/folder/folder1', - posInSet: 2, - selected: false, - setSize: 2, - type: DirentType.DirectoryExpanded, - }, - ] - - const result = await getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.SymLinkFolder) - - expect(result).toEqual([ - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/root/folder/file1.txt', - posInSet: 1, - selected: false, - setSize: 4, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: 'folder1', - path: '/root/folder/folder1', - posInSet: 2, - selected: false, - setSize: 4, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: '', - path: '', - posInSet: 3, - selected: false, - setSize: 4, - type: DirentType.SymLinkFolder, - }, - ]) - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('getNewChildDirentsForNewDirent - error case', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - throw new Error('Failed to read directory') - }, - }) - - const items = [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - ] - - await expect(getNewChildDirentsForNewDirent(items, 2, '/root/folder', DirentType.File)).rejects.toThrow('Failed to read directory') - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/GetNewDirentsAccept.test.ts b/packages/explorer-view/test/GetNewDirentsAccept.test.ts deleted file mode 100644 index a0c6776..0000000 --- a/packages/explorer-view/test/GetNewDirentsAccept.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getNewDirentsAccept } from '../src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts' - -test('getNewDirentsAccept - create file in root', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.writeFile'() { - return - }, - }) - - const items: readonly ExplorerItem[] = [] - const editingValue = 'test.txt' - const focusedIndex = -1 - const root = '/root' - const pathSeparator = '/' - const newDirentType = DirentType.File - const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) - expect(result.dirents).toHaveLength(1) - expect(result.dirents[0]).toEqual({ - depth: 1, - icon: '', - name: 'test.txt', - path: '/root/test.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }) - expect(result.newFocusedIndex).toBe(0) - expect(mockRpc.invocations).toEqual([]) -}) - -test('getNewDirentsAccept - create file in subfolder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.writeFile'() { - return - }, - }) - - const newDirentType = DirentType.File - - const editingValue = 'test.txt' - const focusedIndex = 0 - const root = '/root' - const pathSeparator = '/' - const items = [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: 2, - }, - ] - - const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) - - expect(result.dirents).toHaveLength(2) - expect(result.dirents[1]).toEqual({ - depth: 2, - icon: '', - name: 'test.txt', - path: '/root/folder/test.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }) - expect(result.newFocusedIndex).toBe(1) - expect(mockRpc.invocations).toEqual([]) -}) - -test('getNewDirentsAccept - create nested file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return - }, - 'FileSystem.writeFile'() { - return - }, - }) - - const items: readonly ExplorerItem[] = [] - const editingValue = 'a/b/c/test.txt' - const focusedIndex = -1 - const root = '/root' - const pathSeparator = '/' - const newDirentType = DirentType.File - const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) - expect(result.dirents).toHaveLength(1) - expect(result.dirents[0]).toEqual({ - depth: 1, - icon: '', - name: 'a/b/c/test.txt', - path: '/root/a/b/c/test.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }) - expect(result.newFocusedIndex).toBe(0) - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('getNewDirentsAccept - handle error', async () => { - RendererWorker.registerMockRpc({ - 'FileSystem.writeFile'() { - return Promise.reject(new Error('Failed to create file')) - }, - }) - - const editingValue = 'test.txt' - const focusedIndex = -1 - const root = '/root' - const pathSeparator = '/' - const items: readonly ExplorerItem[] = [] - const newDirentType = DirentType.File - - const result = getNewDirentsAccept(items, focusedIndex, editingValue, root, pathSeparator, newDirentType) - - expect(result.dirents).toEqual(items) - expect(result.newFocusedIndex).toBe(focusedIndex) -}) diff --git a/packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts b/packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts deleted file mode 100644 index ffbe02e..0000000 --- a/packages/explorer-view/test/GetNewDirentsForCancelRename.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getNewDirentsForCancelRename } from '../src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts' - -test('getNewDirentsForCancelRename - file', () => { - const items = [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.EditingFile, - }, - ] - const result = getNewDirentsForCancelRename(items, 0) - expect(result).toHaveLength(1) - expect(result[0]).toEqual({ - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - }) -}) - -test('getNewDirentsForCancelRename - folder', () => { - const items = [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.EditingFolder, - }, - ] - const result = getNewDirentsForCancelRename(items, 0) - expect(result).toHaveLength(1) - expect(result[0]).toEqual({ - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - }) -}) diff --git a/packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts b/packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts deleted file mode 100644 index 92774c4..0000000 --- a/packages/explorer-view/test/GetNewDirentsForNewDirent.test.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getNewDirentsForNewDirent } from '../src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts' - -test('getNewDirentsForNewDirent - folder with existing children', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const defaultState = createDefaultState() - const state: ExplorerState = { - ...defaultState, - focusedIndex: 0, - items: [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/root/folder/file1.txt', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: 'file2.txt', - path: '/root/folder/file2.txt', - posInSet: 2, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ], - } - const root = '/root' - - const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) - - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/root/folder/file1.txt', - posInSet: 1, - selected: false, - setSize: 4, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: 'file2.txt', - path: '/root/folder/file2.txt', - posInSet: 2, - selected: false, - setSize: 4, - type: DirentType.File, - }, - { - depth: 2, - icon: '', - name: '', - path: '/root/folder', - posInSet: 3, - selected: false, - setSize: 4, - type: DirentType.File, - }, - ]) - expect(mockRpc.invocations).toEqual([]) -}) - -test('getNewDirentsForNewDirent - folder without children', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const defaultState = createDefaultState() - const state: ExplorerState = { - ...defaultState, - focusedIndex: 0, - items: [ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - ], - } - - const root = '/root' - - const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) - - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: '', - path: '/root/folder', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ]) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/root/folder']]) -}) - -test('getNewDirentsForNewDirent - no items', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const defaultState = createDefaultState() - const state: ExplorerState = { - ...defaultState, - focusedIndex: -1, - items: [], - } - const root = '/root' - - const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) - - expect(result).toEqual([ - { - depth: 0, - icon: '', - name: '', - path: '/root', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ]) - expect(mockRpc.invocations).toEqual([]) -}) - -test('getNewDirentsForNewDirent - focusedIndex -1 with existing items', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const defaultState = createDefaultState() - const state: ExplorerState = { - ...defaultState, - focusedIndex: -1, - items: [ - { - depth: 0, - icon: '', - name: 'file1.txt', - path: '/root/file1.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ], - } - const root = '/root' - - const result = await getNewDirentsForNewDirent(state.items, state.focusedIndex, DirentType.File, root) - - expect(result).toEqual([ - { - depth: 0, - icon: '', - name: 'file1.txt', - path: '/root/file1.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - { - depth: 0, - icon: '', - name: '', - path: '/root', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ]) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/GetNewDirentsForRename.test.ts b/packages/explorer-view/test/GetNewDirentsForRename.test.ts deleted file mode 100644 index 5cc8bcf..0000000 --- a/packages/explorer-view/test/GetNewDirentsForRename.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getNewDirentsForRename } from '../src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts' - -test('getNewDirentsForRename - file', () => { - const items = [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - }, - ] - const result = getNewDirentsForRename(items, 0) - expect(result).toHaveLength(1) - expect(result[0]).toEqual({ - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.EditingFile, - }) -}) - -test('getNewDirentsForRename - folder', () => { - const items = [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - }, - ] - const result = getNewDirentsForRename(items, 0) - expect(result).toHaveLength(1) - expect(result[0]).toEqual({ - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.EditingFolder, - }) -}) diff --git a/packages/explorer-view/test/GetNewDropTargets.test.ts b/packages/explorer-view/test/GetNewDropTargets.test.ts deleted file mode 100644 index deaaa49..0000000 --- a/packages/explorer-view/test/GetNewDropTargets.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getNewDropTargets } from '../src/parts/GetNewDropTargets/GetNewDropTargets.ts' - -test('getNewDropTargets - index -1', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [], - } - const result = getNewDropTargets(state, -1) - expect(result).toEqual([-1]) -}) - -test('getNewDropTargets - cannot be dropped into', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - const result = getNewDropTargets(state, 0) - expect(result).toEqual([-1, 0, 1]) -}) - -test('getNewDropTargets - can be dropped into', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], - } - const result = getNewDropTargets(state, 0) - expect(result).toEqual([0]) -}) diff --git a/packages/explorer-view/test/GetNumberOfVisibleItems.test.ts b/packages/explorer-view/test/GetNumberOfVisibleItems.test.ts deleted file mode 100644 index 4b45d6c..0000000 --- a/packages/explorer-view/test/GetNumberOfVisibleItems.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetNumberOfVisibleItems from '../src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts' - -test('getNumberOfVisibleItems - empty state', () => { - expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(600, 22)).toBe(29) -}) - -test('getNumberOfVisibleItems - partial height', () => { - expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(100, 22)).toBe(6) -}) - -test('getNumberOfVisibleItems - exact division', () => { - expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(88, 22)).toBe(5) -}) - -test('getNumberOfVisibleItems - small height', () => { - expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(10, 22)).toBe(2) -}) - -test('getNumberOfVisibleItems - zero height', () => { - expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(0, 22)).toBe(0) -}) - -test('getNumberOfVisibleItems - negative height', () => { - expect(GetNumberOfVisibleItems.getNumberOfVisibleItems(-100, 22)).toBe(0) -}) diff --git a/packages/explorer-view/test/GetPasteHandler.test.ts b/packages/explorer-view/test/GetPasteHandler.test.ts deleted file mode 100644 index 339240d..0000000 --- a/packages/explorer-view/test/GetPasteHandler.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetPasteHandler from '../src/parts/GetPasteHandler/GetPasteHandler.ts' -import * as HandlePasteCopy from '../src/parts/HandlePasteCopy/HandlePasteCopy.ts' -import * as HandlePasteCut from '../src/parts/HandlePasteCut/HandlePasteCut.ts' -import * as HandlePasteNone from '../src/parts/HandlePasteNone/HandlePasteNone.ts' -import * as NativeFileTypes from '../src/parts/NativeFileTypes/NativeFileTypes.ts' - -test('getPasteHandler - none', () => { - expect(GetPasteHandler.getPasteHandler(NativeFileTypes.None)).toBe(HandlePasteNone.handlePasteNone) -}) - -test('getPasteHandler - copy', () => { - expect(GetPasteHandler.getPasteHandler(NativeFileTypes.Copy)).toBe(HandlePasteCopy.handlePasteCopy) -}) - -test('getPasteHandler - cut', () => { - expect(GetPasteHandler.getPasteHandler(NativeFileTypes.Cut)).toBe(HandlePasteCut.handlePasteCut) -}) - -test('getPasteHandler - invalid type', () => { - expect(() => GetPasteHandler.getPasteHandler('invalid')).toThrow('unexpected native paste type: invalid') -}) diff --git a/packages/explorer-view/test/GetPath.test.ts b/packages/explorer-view/test/GetPath.test.ts deleted file mode 100644 index 3c0304f..0000000 --- a/packages/explorer-view/test/GetPath.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import { File } from '../src/parts/DirentType/DirentType.ts' -import * as GetPath from '../src/parts/GetPath/GetPath.ts' - -test('getPath - file dirent', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'test.txt', - path: '/test/test.txt', - selected: true, - type: 1, - } - expect(GetPath.getPath(dirent)).toBe('/test/test.txt') -}) - -test('getPath - directory dirent', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'folder', - path: '/test/folder', - selected: false, - type: 2, - } - expect(GetPath.getPath(dirent)).toBe('/test/folder') -}) - -test('getPath - nested path', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'file.js', - path: '/test/folder/subfolder/file.js', - selected: false, - type: 1, - } - expect(GetPath.getPath(dirent)).toBe('/test/folder/subfolder/file.js') -}) - -test('getPath - root path', () => { - const dirent: ExplorerItem = { - depth: 0, - name: '', - path: '/', - selected: false, - type: 2, - } - expect(GetPath.getPath(dirent)).toBe('/') -}) - -test('getPath - empty path', () => { - const dirent: ExplorerItem = { - depth: 0, - name: '', - path: '', - selected: false, - type: 2, - } - expect(GetPath.getPath(dirent)).toBe('') -}) - -test('getPath - with spaces in path', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'my file.txt', - path: '/test/my folder/my file.txt', - selected: true, - type: 1, - } - expect(GetPath.getPath(dirent)).toBe('/test/my folder/my file.txt') -}) - -test('getPath - with special characters in path', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'file@test.txt', - path: '/test/folder#1/file@test.txt', - selected: true, - type: 1, - } - expect(GetPath.getPath(dirent)).toBe('/test/folder#1/file@test.txt') -}) - -test('getPath', () => { - const item = { depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: File } - expect(GetPath.getPath(item)).toBe('/test.txt') -}) diff --git a/packages/explorer-view/test/GetPathParts.test.ts b/packages/explorer-view/test/GetPathParts.test.ts deleted file mode 100644 index 4c1c92d..0000000 --- a/packages/explorer-view/test/GetPathParts.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetPathParts from '../src/parts/GetPathParts/GetPathParts.ts' -import * as PathSeparatorType from '../src/parts/PathSeparatorType/PathSeparatorType.ts' - -test('getPathParts - empty path', () => { - expect(GetPathParts.getPathParts('', '', PathSeparatorType.Slash)).toEqual([]) -}) - -test('getPathParts - root path', () => { - expect(GetPathParts.getPathParts('/', '/', PathSeparatorType.Slash)).toEqual([]) -}) - -test('getPathParts - single level', () => { - expect(GetPathParts.getPathParts('/root', '/root/folder', PathSeparatorType.Slash)).toEqual([ - { - depth: 0, - expanded: true, - path: '/root', - pathSeparator: '/', - root: '/root', - }, - ]) -}) - -test('getPathParts - multiple levels', () => { - expect(GetPathParts.getPathParts('/root', '/root/folder/subfolder/file.txt', PathSeparatorType.Slash)).toEqual([ - { - depth: 0, - expanded: true, - path: '/root', - pathSeparator: '/', - root: '/root', - }, - { - depth: 1, - expanded: true, - path: '/root/folder', - pathSeparator: '/', - root: '/root', - }, - { - depth: 2, - expanded: true, - path: '/root/folder/subfolder', - pathSeparator: '/', - root: '/root', - }, - ]) -}) - -test('getPathParts - path equals root', () => { - expect(GetPathParts.getPathParts('/root', '/root', PathSeparatorType.Slash)).toEqual([]) -}) - -test('getPathParts - trailing slash', () => { - expect(GetPathParts.getPathParts('/root', '/root/folder/', PathSeparatorType.Slash)).toEqual([ - { - depth: 0, - expanded: true, - path: '/root', - pathSeparator: '/', - root: '/root', - }, - { - depth: 1, - expanded: true, - path: '/root/folder', - pathSeparator: '/', - root: '/root', - }, - ]) -}) - -test('getPathParts - multiple slashes', () => { - expect(GetPathParts.getPathParts('/root', '/root/folder//subfolder', PathSeparatorType.Slash)).toEqual([ - { - depth: 0, - expanded: true, - path: '/root', - pathSeparator: '/', - root: '/root', - }, - { - depth: 1, - expanded: true, - path: '/root/folder', - pathSeparator: '/', - root: '/root', - }, - { - depth: 2, - expanded: true, - path: '/root/folder/', - pathSeparator: '/', - root: '/root', - }, - ]) -}) diff --git a/packages/explorer-view/test/GetPathSeparator.test.ts b/packages/explorer-view/test/GetPathSeparator.test.ts deleted file mode 100644 index 27ccd51..0000000 --- a/packages/explorer-view/test/GetPathSeparator.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as GetPathSeparator from '../src/parts/GetPathSeparator/GetPathSeparator.ts' - -test('getPathSeparator - delegates to file system module', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - }) - - const result = await GetPathSeparator.getPathSeparator('/workspace') - - expect(result).toBe('/') - expect(mockRpc.invocations).toEqual([['FileSystem.getPathSeparator', '/workspace']]) -}) diff --git a/packages/explorer-view/test/GetPaths.test.ts b/packages/explorer-view/test/GetPaths.test.ts deleted file mode 100644 index 013c63a..0000000 --- a/packages/explorer-view/test/GetPaths.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import { Directory, File } from '../src/parts/DirentType/DirentType.ts' -import { getPaths } from '../src/parts/GetPaths/GetPaths.ts' - -test('getPaths - empty array', () => { - const items: readonly ExplorerItem[] = [] - expect(getPaths(items)).toHaveLength(0) -}) - -test('getPaths - with items', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: Directory }, - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, - ] - const result = getPaths(items) - expect(result).toHaveLength(2) - expect(result[0]).toBe('/folder1') - expect(result[1]).toBe('/file1.txt') -}) diff --git a/packages/explorer-view/test/GetProtoMapInternal.test.ts b/packages/explorer-view/test/GetProtoMapInternal.test.ts deleted file mode 100644 index 9e49ac1..0000000 --- a/packages/explorer-view/test/GetProtoMapInternal.test.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { RawDirent } from '../src/parts/RawDirent/RawDirent.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getProtoMapInternal } from '../src/parts/GetProtoMapInternal/GetProtoMapInternal.ts' - -test('getProtoMapInternal - empty directory', () => { - const root = '/root' - const pathToDirents = { - '/root': [], - } - const expandedPaths: string[] = [] - const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) - expect(result).toEqual([]) -}) - -test('getProtoMapInternal - directory with files', () => { - const root = '/root' - const pathToDirents: Record = { - '/root': [ - { name: 'file1.txt', type: DirentType.File }, - { name: 'file2.txt', type: DirentType.File }, - ], - } - const expandedPaths: string[] = [] - const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'file1.txt', - path: '/root/file1.txt', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.File, - }, - { - depth: 1, - icon: '', - name: 'file2.txt', - path: '/root/file2.txt', - posInSet: 2, - selected: false, - setSize: 2, - type: DirentType.File, - }, - ]) -}) - -test('getProtoMapInternal - directory with subdirectories', () => { - const root = '/root' - const pathToDirents: Record = { - '/root': [ - { name: 'folder1', type: DirentType.Directory }, - { name: 'folder2', type: DirentType.Directory }, - ], - '/root/folder1': [{ name: 'file1.txt', type: DirentType.File }], - '/root/folder2': [{ name: 'file2.txt', type: DirentType.File }], - } - const expandedPaths: string[] = ['/root/folder1'] - const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'folder1', - path: '/root/folder1', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/root/folder1/file1.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - { - depth: 1, - icon: '', - name: 'folder2', - path: '/root/folder2', - posInSet: 2, - selected: false, - setSize: 2, - type: DirentType.Directory, - }, - { - depth: 2, - icon: '', - name: 'file2.txt', - path: '/root/folder2/file2.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: 7, - }, - ]) -}) - -test('getProtoMapInternal - directory with different file types', () => { - const root = '/root' - const pathToDirents: Record = { - '/root': [ - { name: 'file.txt', type: DirentType.File }, - { name: 'symlink.txt', type: DirentType.SymLinkFile }, - { name: 'folder', type: DirentType.Directory }, - { name: 'symlink-folder', type: DirentType.SymLinkFolder }, - ], - } - const expandedPaths: string[] = [] - const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'file.txt', - path: '/root/file.txt', - posInSet: 1, - selected: false, - setSize: 4, - type: DirentType.File, - }, - { - depth: 1, - icon: '', - name: 'symlink.txt', - path: '/root/symlink.txt', - posInSet: 2, - selected: false, - setSize: 4, - type: DirentType.SymLinkFile, - }, - { - depth: 1, - icon: '', - name: 'folder', - path: '/root/folder', - posInSet: 3, - selected: false, - setSize: 4, - type: DirentType.Directory, - }, - { - depth: 1, - icon: '', - name: 'symlink-folder', - path: '/root/symlink-folder', - posInSet: 4, - selected: false, - setSize: 4, - type: DirentType.SymLinkFolder, - }, - ]) -}) - -test('getProtoMapInternal - non-existent directory', () => { - const root = '/root' - const pathToDirents = {} - const expandedPaths: string[] = [] - const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) - expect(result).toEqual([]) -}) - -test('getProtoMapInternal - nested directory structure', () => { - const root = '/root' - const pathToDirents: Record = { - '/root': [{ name: 'folder1', type: DirentType.Directory }], - '/root/folder1': [{ name: 'folder2', type: DirentType.Directory }], - '/root/folder1/folder2': [{ name: 'file.txt', type: DirentType.File }], - } - const expandedPaths: string[] = ['/root/folder1', '/root/folder1/folder2'] - const result = getProtoMapInternal(root, pathToDirents, expandedPaths, 1) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'folder1', - path: '/root/folder1', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 2, - icon: '', - name: 'folder2', - path: '/root/folder1/folder2', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 3, - icon: '', - name: 'file.txt', - path: '/root/folder1/folder2/file.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ]) -}) diff --git a/packages/explorer-view/test/GetRenderer.test.ts b/packages/explorer-view/test/GetRenderer.test.ts deleted file mode 100644 index 04928b1..0000000 --- a/packages/explorer-view/test/GetRenderer.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { test, expect } from '@jest/globals' -import * as DiffType from '../src/parts/DiffType/DiffType.ts' -import { getRenderer } from '../src/parts/GetRenderer/GetRenderer.ts' - -test('should return RenderItems for RenderItems diffType', () => { - const renderer = getRenderer(DiffType.RenderItems) - expect(typeof renderer).toBe('function') -}) - -test('should return RenderFocus for RenderFocus diffType', () => { - const renderer = getRenderer(DiffType.RenderFocus) - expect(typeof renderer).toBe('function') -}) - -test('should return RenderFocusContext for RenderFocusContext diffType', () => { - const renderer = getRenderer(DiffType.RenderFocusContext) - expect(typeof renderer).toBe('function') -}) - -test('should return RenderValue for RenderValue diffType', () => { - const renderer = getRenderer(DiffType.RenderValue) - expect(typeof renderer).toBe('function') -}) - -test('should return RenderEditingSelection for RenderSelection diffType', () => { - const renderer = getRenderer(DiffType.RenderSelection) - expect(typeof renderer).toBe('function') -}) - -test('should throw for unknown diffType', () => { - expect(() => getRenderer(9999)).toThrow('unknown renderer') -}) diff --git a/packages/explorer-view/test/GetRestoredDeltaY.test.ts b/packages/explorer-view/test/GetRestoredDeltaY.test.ts deleted file mode 100644 index 6ccbc30..0000000 --- a/packages/explorer-view/test/GetRestoredDeltaY.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetRestoredDeltaY from '../src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts' - -test('getRestoredDeltaY - returns saved deltaY when it is numeric', () => { - expect(GetRestoredDeltaY.getRestoredDeltaY({ deltaY: 42 })).toBe(42) -}) - -test('getRestoredDeltaY - returns 0 when deltaY is missing', () => { - expect(GetRestoredDeltaY.getRestoredDeltaY({})).toBe(0) -}) - -test('getRestoredDeltaY - returns 0 when state is undefined', () => { - expect(GetRestoredDeltaY.getRestoredDeltaY(undefined)).toBe(0) -}) diff --git a/packages/explorer-view/test/GetSavedRoot.test.ts b/packages/explorer-view/test/GetSavedRoot.test.ts deleted file mode 100644 index 75cae89..0000000 --- a/packages/explorer-view/test/GetSavedRoot.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetSavedRoot from '../src/parts/GetSavedRoot/GetSavedRoot.ts' - -test('getSavedRoot - returns workspace path', () => { - expect(GetSavedRoot.getSavedRoot({ root: '/stale-workspace' }, '/workspace')).toBe('/workspace') -}) diff --git a/packages/explorer-view/test/GetScrollBarVirtualDom.test.ts b/packages/explorer-view/test/GetScrollBarVirtualDom.test.ts deleted file mode 100644 index 870e47f..0000000 --- a/packages/explorer-view/test/GetScrollBarVirtualDom.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { expect, test } from '@jest/globals' -import { getScrollBarVirtualDom } from '../src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts' - -test('getScrollBarVirtualDom - no scrollbar when height is 0', () => { - const dom = getScrollBarVirtualDom(0) - expect(dom).toEqual([]) -}) - -test('getScrollBarVirtualDom - renders scrollbar', () => { - const dom = getScrollBarVirtualDom(100) - expect(dom).toEqual([ - { - childCount: 1, - className: 'ScrollBar ScrollBarSmall', - type: 4, - }, - { - childCount: 0, - className: 'ScrollBarThumb', - type: 4, - }, - ]) -}) diff --git a/packages/explorer-view/test/GetSettings.test.ts b/packages/explorer-view/test/GetSettings.test.ts deleted file mode 100644 index 568f87c..0000000 --- a/packages/explorer-view/test/GetSettings.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { getSettings } from '../src/parts/GetSettings/GetSettings.ts' - -test('getSettings - useChevrons true', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Preferences.get'() { - return undefined - }, - }) - const settings = await getSettings() - expect(settings).toEqual({ - confirmDelete: false, - confirmPaste: false, - sourceControlDecorations: true, - useChevrons: true, - }) - expect(mockRpc.invocations).toEqual([ - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ]) -}) - -test('getSettings - useChevrons false', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Preferences.get'(settingName: string) { - if (settingName === 'explorer.useChevrons') { - return false - } - if (settingName === 'explorer.confirmdelete') { - return true - } - if (settingName === 'explorer.sourceControlDecorations') { - return false - } - return undefined - }, - }) - const settings = await getSettings() - expect(settings).toEqual({ - confirmDelete: false, - confirmPaste: false, - sourceControlDecorations: false, - useChevrons: false, - }) - expect(mockRpc.invocations).toEqual([ - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ]) -}) - -test('getSettings - useChevrons undefined', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Preferences.get'() { - return undefined - }, - }) - const settings = await getSettings() - expect(settings).toEqual({ - confirmDelete: false, - confirmPaste: false, - sourceControlDecorations: true, - useChevrons: true, - }) - expect(mockRpc.invocations).toEqual([ - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ]) -}) diff --git a/packages/explorer-view/test/GetSiblingFileNames.test.ts b/packages/explorer-view/test/GetSiblingFileNames.test.ts deleted file mode 100644 index 685b6be..0000000 --- a/packages/explorer-view/test/GetSiblingFileNames.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as GetSiblingFileNames from '../src/parts/GetSiblingFileNames/GetSiblingFileNames.ts' - -test('getSiblingFileNames - root level files', () => { - const items: readonly ExplorerItem[] = [ - { - depth: 0, - icon: '', - name: 'file1.txt', - path: '/root/file1.txt', - posInSet: 0, - selected: false, - setSize: 2, - type: 1, - }, - { - depth: 0, - icon: '', - name: 'file2.txt', - path: '/root/file2.txt', - posInSet: 1, - selected: false, - setSize: 2, - type: 1, - }, - { - depth: 1, - icon: '', - name: 'file3.txt', - path: '/root/folder/file3.txt', - posInSet: 0, - selected: false, - setSize: 1, - type: 1, - }, - ] - - const result = GetSiblingFileNames.getSiblingFileNames(items, 0, '/root', '/') - expect(result).toEqual(['file1.txt', 'file2.txt']) -}) - -test('getSiblingFileNames - folder level files', () => { - const items: readonly ExplorerItem[] = [ - { - depth: 0, - icon: '', - name: 'file1.txt', - path: '/root/file1.txt', - posInSet: 0, - selected: false, - setSize: 1, - type: 1, - }, - { - depth: 1, - icon: '', - name: 'file2.txt', - path: '/root/folder/file2.txt', - posInSet: 0, - selected: false, - setSize: 2, - type: 1, - }, - { - depth: 1, - icon: '', - name: 'file3.txt', - path: '/root/folder/file3.txt', - posInSet: 1, - selected: false, - setSize: 2, - type: 1, - }, - ] - - const result = GetSiblingFileNames.getSiblingFileNames(items, 1, '/root', '/') - expect(result).toEqual(['file2.txt', 'file3.txt']) -}) - -test('getSiblingFileNames - no siblings', () => { - const items: readonly ExplorerItem[] = [ - { - depth: 0, - icon: '', - name: 'file1.txt', - path: '/root/file1.txt', - posInSet: 0, - selected: false, - setSize: 1, - type: 1, - }, - ] - - const result = GetSiblingFileNames.getSiblingFileNames(items, 0, '/root', '/') - expect(result).toEqual(['file1.txt']) -}) diff --git a/packages/explorer-view/test/GetSymlinkType.test.ts b/packages/explorer-view/test/GetSymlinkType.test.ts deleted file mode 100644 index 7448fbc..0000000 --- a/packages/explorer-view/test/GetSymlinkType.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { test, expect } from '@jest/globals' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { getSymlinkType } from '../src/parts/GetSymlinkType/GetSymlinkType.ts' - -test('getSymlinkType - File', () => { - expect(getSymlinkType(DirentType.File)).toBe(DirentType.SymLinkFile) -}) - -test('getSymlinkType - Directory', () => { - expect(getSymlinkType(DirentType.Directory)).toBe(DirentType.SymLinkFolder) -}) - -test('getSymlinkType - Default', () => { - expect(getSymlinkType(DirentType.BlockDevice)).toBe(DirentType.Symlink) - expect(getSymlinkType(DirentType.CharacterDevice)).toBe(DirentType.Symlink) - expect(getSymlinkType(DirentType.Socket)).toBe(DirentType.Symlink) - expect(getSymlinkType(DirentType.Unknown)).toBe(DirentType.Symlink) -}) diff --git a/packages/explorer-view/test/GetTreeItemIndent.test.ts b/packages/explorer-view/test/GetTreeItemIndent.test.ts deleted file mode 100644 index 5590bbb..0000000 --- a/packages/explorer-view/test/GetTreeItemIndent.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetTreeItemIndent from '../src/parts/GetTreeItemIndent/GetTreeItemIndent.ts' - -test('getTreeItemIndent - depth 0', () => { - expect(GetTreeItemIndent.getTreeItemIndent(0)).toBe(0) -}) - -test('getTreeItemIndent - depth 1', () => { - expect(GetTreeItemIndent.getTreeItemIndent(1)).toBe(12) -}) - -test('getTreeItemIndent - depth 2', () => { - expect(GetTreeItemIndent.getTreeItemIndent(2)).toBe(24) -}) - -test('getTreeItemIndent - depth 3', () => { - expect(GetTreeItemIndent.getTreeItemIndent(3)).toBe(36) -}) diff --git a/packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts b/packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts deleted file mode 100644 index 35295c5..0000000 --- a/packages/explorer-view/test/GetTreeItemIndentWithChevron.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as GetTreeItemIndentWithChevron from '../src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts' - -test('getTreeItemIndentWithChevron - depth 0', () => { - const chevron = 0 - expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(0, chevron)).toBe(26) -}) - -test('getTreeItemIndentWithChevron - depth 1', () => { - const chevron = 0 - expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(1, chevron)).toBe(34) -}) - -test('getTreeItemIndentWithChevron - depth 2', () => { - const chevron = 0 - expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(2, chevron)).toBe(42) -}) - -test('getTreeItemIndentWithChevron - depth 3', () => { - const chevron = 0 - expect(GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron(3, chevron)).toBe(50) -}) diff --git a/packages/explorer-view/test/GetVisibleExplorerItems.test.ts b/packages/explorer-view/test/GetVisibleExplorerItems.test.ts deleted file mode 100644 index b7589e5..0000000 --- a/packages/explorer-view/test/GetVisibleExplorerItems.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { FileDecoration } from '../src/parts/FileDecoration/FileDecoration.ts' -import { getVisibleExplorerItems } from '../src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts' - -test('getVisibleExplorerItems - basic', () => { - const items: ExplorerItem[] = [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: 0, - }, - ] - const editingIcon = '' - const decorations: readonly FileDecoration[] = [] - const result = getVisibleExplorerItems(items, 0, 1, 0, -1, '', ['icon'], true, [], editingIcon, [], [], decorations) - expect(result).toHaveLength(1) - expect(result[0]).toMatchObject({ - ariaExpanded: undefined, - chevron: 0, - depth: 0, - hasEditingError: false, - icon: 'icon', - id: 'TreeItemActive', - indent: 26, - isEditing: false, - name: 'test', - path: '/test', - }) -}) - -test('getVisibleExplorerItems - editing', () => { - const items: ExplorerItem[] = [ - { - depth: 0, - name: 'test', - path: '/test', - selected: true, - type: 0, - }, - ] - const editingIcon = '' - const decorations: readonly FileDecoration[] = [] - const result = getVisibleExplorerItems(items, 0, 1, 0, 0, 'error', ['icon'], true, [], editingIcon, [], [], decorations) - expect(result).toHaveLength(1) - expect(result[0]).toMatchObject({ - hasEditingError: true, - isEditing: true, - }) -}) - -test('getVisibleExplorerItems - new item', () => { - const items: readonly ExplorerItem[] = [] - const editingIcon = '' - const decorations: readonly FileDecoration[] = [] - - const result = getVisibleExplorerItems(items, 0, 1, -1, -1, 'error', [], true, [], editingIcon, [], [], decorations) - expect(result).toHaveLength(0) - // expect(result[0]).toMatchObject({ - // depth: 3, - // name: 'new', - // path: '/test/new', - // isEditing: true, - // hasEditingError: true, - // }) -}) - -test('getVisibleExplorerItems - ignored item is dimmed', () => { - const items: ExplorerItem[] = [ - { - depth: 0, - name: 'ignored.txt', - path: '/ignored.txt', - selected: false, - type: 0, - }, - ] - const editingIcon = '' - const ignored = ['/ignored.txt'] - const decorations: readonly FileDecoration[] = [] - - const result = getVisibleExplorerItems(items, 0, 1, 0, -1, '', ['icon'], true, [], editingIcon, [], ignored, decorations) - expect(result).toHaveLength(1) - expect(result[0]).toMatchObject({ - isCut: false, - isIgnored: true, - }) -}) diff --git a/packages/explorer-view/test/HandleArrowLeft.test.ts b/packages/explorer-view/test/HandleArrowLeft.test.ts deleted file mode 100644 index 856e628..0000000 --- a/packages/explorer-view/test/HandleArrowLeft.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleArrowLeft } from '../src/parts/HandleArrowLeft/HandleArrowLeft.ts' - -test('handleArrowLeft - no focused item', () => { - const state: ExplorerState = { ...createDefaultState(), focusedIndex: -1 } - const result = handleArrowLeft(state) - expect(result).toBe(state) -}) - -test('handleArrowLeft - directory', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - }, - ], - } - const result = handleArrowLeft(state) - expect(result).toBeDefined() -}) - -test('handleArrowLeft - file', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - }, - ], - } - const result = handleArrowLeft(state) - expect(result).toBeDefined() -}) - -test('handleArrowLeft - symlink file', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.SymLinkFile, - }, - ], - } - const result = handleArrowLeft(state) - expect(result).toBeDefined() -}) - -test('handleArrowLeft - expanded directory', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 0, - // @ts-ignore - expanded: true, - level: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.DirectoryExpanded, - }, - ], - } - const result = handleArrowLeft(state) - expect(result).toBeDefined() -}) - -test('handleArrowLeft - expanding directory', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.DirectoryExpanding, - }, - ], - } - const result = handleArrowLeft(state) - expect(result).toBeDefined() -}) - -test('handleArrowLeft - symlink folder', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.SymLinkFolder, - }, - ], - } - const result = handleArrowLeft(state) - expect(result).toBeDefined() -}) diff --git a/packages/explorer-view/test/HandleArrowRight.test.ts b/packages/explorer-view/test/HandleArrowRight.test.ts deleted file mode 100644 index 15fec10..0000000 --- a/packages/explorer-view/test/HandleArrowRight.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleArrowRight } from '../src/parts/HandleArrowRight/HandleArrowRight.ts' - -test('handleArrowRight - no focused item', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - } - const result = await handleArrowRight(state) - expect(result).toBe(state) -}) - -test('handleArrowRight - file', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - const result = await handleArrowRight(state) - expect(result).toBe(state) -}) - -test.skip('handleArrowRight - directory', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], - } - const result = await handleArrowRight(state) - expect(result).not.toBe(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test('handleArrowRight - symlink file', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.SymLinkFile }], - } - const result = await handleArrowRight(state) - expect(result).toBe(state) -}) - -test.skip('handleArrowRight - symlink folder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.SymLinkFolder }], - } - const result = await handleArrowRight(state) - expect(result).not.toBe(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('handleArrowRight - directory expanded', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.DirectoryExpanded }], - } - const result = await handleArrowRight(state) - expect(result).not.toBe(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test.skip('handleArrowRight - symlink', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getRealPath'() { - return '/real/path' - }, - 'FileSystem.stat'() { - return { isDirectory: (): boolean => false } - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Symlink }], - } - const result = await handleArrowRight(state) - expect(result).not.toBe(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test('handleArrowRight - invalid type', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: 999 }], - } - await expect(handleArrowRight(state)).rejects.toThrow('unsupported file type 999') -}) diff --git a/packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts b/packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts deleted file mode 100644 index 0eb22bd..0000000 --- a/packages/explorer-view/test/HandleArrowRightDirectoryExpanded.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleArrowRightDirectoryExpanded } from '../src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts' - -test.skip('handleArrowRightDirectoryExpanded - last item', () => { - const state: ExplorerState = createDefaultState() - const dirent = { depth: 0 } - const result = handleArrowRightDirectoryExpanded(state, dirent) - expect(result).toBe(state) -}) - -test('handleArrowRightDirectoryExpanded - next item has higher depth', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 1 }, - ], - } - const dirent = { depth: 0 } - const result = handleArrowRightDirectoryExpanded(state, dirent) - expect(result.focusedIndex).toBe(1) -}) - -test('handleArrowRightDirectoryExpanded - next item has same depth', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 0, name: 'a', path: '/a', selected: false, type: 1 }, - { depth: 0, name: 'b', path: '/b', selected: false, type: 1 }, - ], - } - const dirent = { depth: 0 } - const result = handleArrowRightDirectoryExpanded(state, dirent) - expect(result).toBe(state) -}) diff --git a/packages/explorer-view/test/HandleBlur.test.ts b/packages/explorer-view/test/HandleBlur.test.ts deleted file mode 100644 index 8bd3d4d..0000000 --- a/packages/explorer-view/test/HandleBlur.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import { handleBlur } from '../src/parts/HandleBlur/HandleBlur.ts' - -test('handleBlur - when not editing, sets focused to false', async () => { - const state: ExplorerState = createDefaultState() - const newState = await handleBlur(state) - expect(newState.focused).toBe(false) -}) - -test.skip('handleBlur - when editing, keeps state unchanged', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.writeFile'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return Array(1).fill('') - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.CreateFile, - editingValue: 'created.txt', - items: [ - { - depth: 0, - name: '1', - path: '1', - selected: false, - type: DirentType.File, - }, - ], - } - const newState = await handleBlur(state) - expect(newState).toEqual({ - ...state, - editingIndex: -1, - editingType: 0, - fileIconCache: { - '1': '', - '1/created.txt': '', - }, - focus: 1, - focusedIndex: 1, - icons: ['', ''], - maxLineY: 2, - }) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.getPathSeparator'], - ['FileSystem.writeFile', '1/created.txt', ''], - ['IconTheme.getFileIcon', { depth: 0, name: '1', path: '1', selected: false, type: DirentType.File }], - [ - 'IconTheme.getIcons', - [ - { depth: 0, name: '1', path: '1', selected: false, type: DirentType.File }, - { depth: 0, name: 'created.txt', path: '1/created.txt', selected: false, type: DirentType.File }, - ], - ], - ]) -}) diff --git a/packages/explorer-view/test/HandleButtonClick.test.ts b/packages/explorer-view/test/HandleButtonClick.test.ts deleted file mode 100644 index 0c4f702..0000000 --- a/packages/explorer-view/test/HandleButtonClick.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import { handleButtonClick } from '../src/parts/HandleButtonClick/HandleButtonClick.ts' -import * as InputName from '../src/parts/InputName/InputName.ts' - -test('handleButtonClick - CollapseAll', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - items: [ - { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.DirectoryExpanded }, - { depth: 2, name: 'file1', path: '/folder1/file1', selected: false, type: DirentType.File }, - { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: DirentType.DirectoryExpanded }, - ], - } - const newState = await handleButtonClick(state, InputName.CollapseAll) - expect(newState.items).toHaveLength(2) - expect(newState.items[0].name).toBe('folder1') - expect(newState.items[1].name).toBe('folder2') - expect(newState.focusedIndex).toBe(0) -}) - -test('handleButtonClick - NewFile', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }], - } - const newState = await handleButtonClick(state, InputName.NewFile) - expect(newState.editingType).toBe(ExplorerEditingType.CreateFile) - expect(newState.editingIndex).toBeGreaterThanOrEqual(0) - expect(newState.editingValue).toBe('') -}) - -test('handleButtonClick - NewFolder', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 1, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }], - } - const newState = await handleButtonClick(state, InputName.NewFolder) - expect(newState.editingType).toBe(ExplorerEditingType.CreateFolder) - expect(newState.editingIndex).toBeGreaterThanOrEqual(0) - expect(newState.editingValue).toBe('') -}) - -test('handleButtonClick - Refresh', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readdir'() { - return [] - }, - 'FileSystem.stat'() { - return DirentType.File - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return Array(1).fill('') - }, - }) - - const state = createDefaultState() - const newState = await handleButtonClick(state, InputName.Refresh) - expect(newState.items).toBeDefined() -}) - -test('handleButtonClick - unknown button name returns state unchanged', async () => { - const state = createDefaultState() - const newState = await handleButtonClick(state, 'UnknownButton') - expect(newState).toBe(state) -}) diff --git a/packages/explorer-view/test/HandleClickAt.test.ts b/packages/explorer-view/test/HandleClickAt.test.ts deleted file mode 100644 index ebbc58d..0000000 --- a/packages/explorer-view/test/HandleClickAt.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleClickAt } from '../src/parts/HandleClickAt/HandleClickAt.ts' -import { LeftClick } from '../src/parts/MouseEventType/MouseEventType.ts' - -test.skip('handleClickAt - left click without shift', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - ], - } - const result = await handleClickAt(state, false, LeftClick, false, false, 0, 0) - expect(result).toBeDefined() -}) - -test.skip('handleClickAt - shift click with no selection', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - ], - } - const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) - expect(result).toBeDefined() -}) - -test('handleClickAt - shift click with existing selection', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) - expect(result).toBeDefined() -}) - -test('handleClickAt - non left click', async () => { - const state: ExplorerState = createDefaultState() - const shiftKey = false - const ctrlKey = false - const result = await handleClickAt(state, false, 2, ctrlKey, shiftKey, 0, 0) - expect(result).toBe(state) -}) - -test('handleClickAt - left click', async () => { - const state: ExplorerState = createDefaultState() - const shiftKey = false - const ctrlKey = false - const result = await handleClickAt(state, false, LeftClick, ctrlKey, shiftKey, 0, 0) - expect(result).toBeDefined() -}) - -test.skip('handleClickAt - shift click with no selection', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - ], - } - const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) - expect(result).toBeDefined() -}) - -test('handleClickAt - shift click with existing selection', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const result = await handleClickAt(state, false, LeftClick, false, true, 0, 0) - expect(result).toBeDefined() -}) diff --git a/packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts b/packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts deleted file mode 100644 index 17422ae..0000000 --- a/packages/explorer-view/test/HandleClickCurrentButKeepFocus.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { test, expect, jest } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleClickCurrentButKeepFocus } from '../src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts' - -test('handleClickCurrentButKeepFocus', async () => { - const state = createDefaultState() - const spy = jest.spyOn(console, 'warn').mockImplementation(() => {}) - const newState = await handleClickCurrentButKeepFocus(state) - expect(newState).toBeDefined() - expect(spy).toHaveBeenCalledTimes(1) -}) diff --git a/packages/explorer-view/test/HandleClickDirectory.test.ts b/packages/explorer-view/test/HandleClickDirectory.test.ts deleted file mode 100644 index 6215e53..0000000 --- a/packages/explorer-view/test/HandleClickDirectory.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' -import { handleClickDirectory } from '../src/parts/HandleClickDirectory/HandleClickDirectory.ts' - -test('handleClickDirectory - updates state with focus', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }, - { isDirectory: false, isSymbolicLink: false, name: 'child2', path: '/test/child2' }, - ] - }, - }) - - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const state: ExplorerState = { - ...createDefaultState(), - items: [dirent], - } - const index = 0 - const keepFocus = true - - const newState = await handleClickDirectory(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(3) - expect(newState.items[0]).toBe(dirent) - expect(newState.items[1].name).toBe('child1') - expect(newState.items[2].name).toBe('child2') - expect(newState.focusedIndex).toBe(0) - expect(newState.focused).toBe(true) - expect(newState.focus).toBe(FocusId.List) - expect(dirent.type).toBe(DirentType.DirectoryExpanded) - expect(dirent.icon).toBe('') -}) - -test('handleClickDirectory - updates state without focus', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }, - { isDirectory: false, isSymbolicLink: false, name: 'child2', path: '/test/child2' }, - ] - }, - }) - - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const state: ExplorerState = { - ...createDefaultState(), - items: [dirent], - } - const index = 0 - const keepFocus = false - - const newState = await handleClickDirectory(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(3) - expect(newState.focusedIndex).toBe(0) - expect(newState.focused).toBe(false) - expect(newState.focus).toBe(FocusId.List) - expect(dirent.type).toBe(DirentType.DirectoryExpanded) - expect(dirent.icon).toBe('') -}) - -test('handleClickDirectory - with empty child dirents', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const state: ExplorerState = { - ...createDefaultState(), - items: [dirent], - } - const index = 0 - const keepFocus = true - - const newState = await handleClickDirectory(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(1) - expect(newState.items[0]).toBe(dirent) - expect(newState.focusedIndex).toBe(0) - expect(newState.focused).toBe(true) - expect(dirent.type).toBe(DirentType.DirectoryExpanded) - expect(dirent.icon).toBe('') -}) - -test('handleClickDirectory - with multiple items in state', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [{ isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'other', path: '/other', selected: false, type: DirentType.File }, - { depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }, - { depth: 0, name: 'another', path: '/another', selected: false, type: DirentType.File }, - ], - } - const dirent = state.items[1] - const index = 1 - const keepFocus = true - - const newState = await handleClickDirectory(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(4) - expect(newState.items[0].name).toBe('other') - expect(newState.items[1]).toBe(dirent) - expect(newState.items[2].name).toBe('child1') - expect(newState.items[3].name).toBe('another') - expect(newState.focusedIndex).toBe(1) - expect(newState.focused).toBe(true) - expect(dirent.type).toBe(DirentType.DirectoryExpanded) - expect(dirent.icon).toBe('') -}) - -test('handleClickDirectory - dirent not found in items', async () => { - using _mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [{ isDirectory: false, isSymbolicLink: false, name: 'child1', path: '/test/child1' }] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [{ depth: 0, name: 'other', path: '/other', selected: false, type: DirentType.File }], - } - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const index = 0 - const keepFocus = true - - const newState = await handleClickDirectory(state, dirent, index, keepFocus) - - // Should return original state when dirent not found - expect(newState).toBe(state) -}) diff --git a/packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts b/packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts deleted file mode 100644 index f0aba8a..0000000 --- a/packages/explorer-view/test/HandleClickDirectoryExpanded.test.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleClickDirectoryExpanded } from '../src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' - -test.skip('collapse expanded directory', async () => { - const state: ExplorerState = createDefaultState() - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const index = 0 - const keepFocus = true - - const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(1) - expect(newState.focusedIndex).toBe(0) - expect(newState.focused).toBe(true) -}) - -test('collapse expanded directory with children', async () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const child1: ExplorerItem = { - depth: 1, - name: 'child1', - path: '/test/child1', - selected: false, - type: DirentType.File, - } - const child2: ExplorerItem = { - depth: 1, - name: 'child2', - path: '/test/child2', - selected: false, - type: DirentType.File, - } - const state: ExplorerState = { - ...createDefaultState(), - fileIconCache: { - '/test/': '', - '/test/child1': '', - '/test/child2': '', - }, - items: [dirent, child1, child2], - } - const index = 0 - const keepFocus = true - - const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(1) - expect(newState.focusedIndex).toBe(0) - expect(newState.focused).toBe(true) -}) - -test('collapse expanded directory with many items preserves icons', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const dirent = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const items = [dirent] - const fileIconCache: Record = { '/test/': 'folder-icon' } - - // Add 10 items with unique icons - for (let i = 0; i < 10; i++) { - const child: ExplorerItem = { - depth: 1, - name: `child${i}`, - path: `/test/child${i}`, - selected: false, - type: DirentType.File, - } - items.push(child) - fileIconCache[`/test/child${i}`] = `icon-${i}` - } - - const state: ExplorerState = { - ...createDefaultState(), - fileIconCache, - items, - } - const index = 0 - const keepFocus = true - - const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(1) - expect(newState.focusedIndex).toBe(0) - expect(newState.focused).toBe(true) - expect(newState.fileIconCache['/test/']).toBe('folder-icon') - expect(mockRpc.invocations).toEqual([]) -}) - -test('collapse expanded directory with scroll position adjustment', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const otherFolder: ExplorerItem = { - depth: 0, - name: '1', - path: '/1', - selected: false, - type: DirentType.Directory, - } - - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const items: ExplorerItem[] = [otherFolder, dirent] - const fileIconCache: Record = { - '/1': 'folder-icon-1', - '/test': 'folder-icon-2', - } - - // Add 10 items with unique icons - for (let i = 0; i < 5; i++) { - const child: ExplorerItem = { - depth: 1, - name: `child${i}`, - path: `/test/child${i}`, - selected: false, - type: DirentType.File, - } - items.push(child) - fileIconCache[`/test/child${i}`] = `icon-${i}` - } - - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 20, // User has scrolled down - fileIconCache, - height: 100, - itemHeight: 20, - items, - maxLineY: 6, - minLineY: 1, - } - const index = 1 - const keepFocus = true - - const newState = await handleClickDirectoryExpanded(state, dirent, index, keepFocus) - - expect(newState.items).toHaveLength(2) - expect(newState.focusedIndex).toBe(1) - expect(newState.focused).toBe(true) - expect(newState.minLineY).toBe(0) - expect(newState.maxLineY).toBe(2) - // After collapsing, since only one item remains and it fits in viewport, - // scroll position should be reset to 0 - expect(newState.deltaY).toBe(0) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts b/packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts deleted file mode 100644 index e74ef95..0000000 --- a/packages/explorer-view/test/HandleClickDirectoryExpanding.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleClickDirectoryExpanding } from '../src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts' - -test('handleClickDirectoryExpanding - updates state with focus', async () => { - const state: ExplorerState = createDefaultState() - const dirent = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.File, - } - const newState = await handleClickDirectoryExpanding(state, dirent, 1, true) - expect(newState.focusedIndex).toBe(1) - expect(newState.focused).toBe(true) - expect(dirent.type).toBe(DirentType.Directory) -}) - -test('handleClickDirectoryExpanding - updates state without focus', async () => { - const state: ExplorerState = createDefaultState() - const dirent = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.File, - } - const newState = await handleClickDirectoryExpanding(state, dirent, 2, false) - expect(newState.focusedIndex).toBe(2) - expect(newState.focused).toBe(false) - expect(dirent.type).toBe(DirentType.Directory) -}) diff --git a/packages/explorer-view/test/HandleClickOpenFolder.test.ts b/packages/explorer-view/test/HandleClickOpenFolder.test.ts deleted file mode 100644 index 91526a2..0000000 --- a/packages/explorer-view/test/HandleClickOpenFolder.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleClickOpenFolder } from '../src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts' - -test('handleClickOpenFolder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Dialog.openFolder'() { - return - }, - }) - - const state = createDefaultState() - const newState = await handleClickOpenFolder(state) - expect(newState).toBe(state) - expect(mockRpc.invocations).toEqual([['Dialog.openFolder']]) -}) diff --git a/packages/explorer-view/test/HandleClickSymlink.test.ts b/packages/explorer-view/test/HandleClickSymlink.test.ts deleted file mode 100644 index 3431ea7..0000000 --- a/packages/explorer-view/test/HandleClickSymlink.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleClickSymLink } from '../src/parts/HandleClickSymlink/HandleClickSymlink.ts' - -test('handleClickSymLink - file symlink', async () => { - const state: ExplorerState = createDefaultState() - const dirent: ExplorerItem = { - depth: 0, - name: 'symlink', - path: '/test/symlink', - selected: false, - type: DirentType.Symlink, - } - const index = 0 - - const mockRealPath = '/test/real-file' - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getRealPath'() { - return mockRealPath - }, - 'FileSystem.stat'() { - return DirentType.File - }, - 'Main.openUri'() { - return undefined - }, - }) - - await handleClickSymLink(state, dirent, index) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.getRealPath', '/test/symlink'], - ['FileSystem.stat', '/test/real-file'], - ['Main.openUri', '/test/symlink', true], - ]) -}) - -test('handleClickSymLink - unsupported type', async () => { - const state: ExplorerState = createDefaultState() - const dirent: ExplorerItem = { - depth: 0, - name: 'symlink', - path: '/test/symlink', - selected: false, - type: DirentType.Symlink, - } - const index = 0 - - const mockRealPath = '/test/real-file' - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getRealPath'() { - return mockRealPath - }, - 'FileSystem.stat'() { - return DirentType.Directory - }, - }) - - await expect(handleClickSymLink(state, dirent, index)).rejects.toThrow('unsupported file type') - expect(mockRpc.invocations).toEqual([ - ['FileSystem.getRealPath', '/test/symlink'], - ['FileSystem.stat', '/test/real-file'], - ]) -}) diff --git a/packages/explorer-view/test/HandleContextMenu.test.ts b/packages/explorer-view/test/HandleContextMenu.test.ts deleted file mode 100644 index 6d63355..0000000 --- a/packages/explorer-view/test/HandleContextMenu.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleContextMenu } from '../src/parts/HandleContextMenu/HandleContextMenu.ts' -import { Keyboard } from '../src/parts/MouseEventType/MouseEventType.ts' - -test('handleContextMenu - keyboard', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ContextMenu.show2'() { - return - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const state = createDefaultState() - const newState = await handleContextMenu(state, Keyboard, 0, 0) - expect(newState).toBeDefined() - expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 0, 20, { menuId: 4 }]]) -}) - -test('handleContextMenu - mouse', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ContextMenu.show2'() { - return - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const state = createDefaultState() - const newState = await handleContextMenu(state, 2, 100, 100) - expect(newState).toBeDefined() - expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 100, 100, { menuId: 4 }]]) -}) diff --git a/packages/explorer-view/test/HandleContextMenuKeyboard.test.ts b/packages/explorer-view/test/HandleContextMenuKeyboard.test.ts deleted file mode 100644 index c5811bc..0000000 --- a/packages/explorer-view/test/HandleContextMenuKeyboard.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as HandleContextMenuKeyboard from '../src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts' - -test('handleContextMenuKeyboard', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ContextMenu.show2'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 2, - itemHeight: 20, - minLineY: 0, - x: 100, - y: 200, - } - const result = await HandleContextMenuKeyboard.handleContextMenuKeyboard(state) - expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 100, 260, { menuId: 4 }]]) - expect(result).toEqual({ - ...state, - focused: false, - }) -}) diff --git a/packages/explorer-view/test/HandleContextMenuMouseAt.test.ts b/packages/explorer-view/test/HandleContextMenuMouseAt.test.ts deleted file mode 100644 index 5007946..0000000 --- a/packages/explorer-view/test/HandleContextMenuMouseAt.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as HandleContextMenuMouseAt from '../src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts' - -test('handleContextMenuMouseAt', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ContextMenu.show2'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - itemHeight: 20, - minLineY: 0, - uid: 1, - x: 0, - y: 0, - } - const result = await HandleContextMenuMouseAt.handleContextMenuMouseAt(state, 100, 200) - expect(mockRpc.invocations).toEqual([['ContextMenu.show2', 1, 4, 100, 200, { menuId: 4 }]]) - expect(result).toEqual({ ...state, focused: false, focusedIndex: -1 }) -}) diff --git a/packages/explorer-view/test/HandleCopy.test.ts b/packages/explorer-view/test/HandleCopy.test.ts deleted file mode 100644 index b4a318e..0000000 --- a/packages/explorer-view/test/HandleCopy.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { expect, jest, test } from '@jest/globals' -import { RendererWorker as RpcRendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleCopy } from '../src/parts/HandleCopy/HandleCopy.ts' - -test('handleCopy - with focused dirent', async () => { - using mockRpc = RpcRendererWorker.registerMockRpc({ - 'ClipBoard.writeNativeFiles'() {}, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - const result = await handleCopy(state) - - expect(mockRpc.invocations).toEqual(expect.arrayContaining([['ClipBoard.writeNativeFiles', 'copy', ['/test.txt']]])) - expect(result).toEqual({ - ...state, - pasteShouldMove: false, - }) -}) - -test('handleCopy - without focused dirent', async () => { - using mockRpc = RpcRendererWorker.registerMockRpc({ - 'ClipBoard.writeNativeFiles'() {}, - }) - const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - items: [], - } - const result = await handleCopy(state) - expect(mockRpc.invocations).toEqual([]) - expect(result).toBe(state) - expect(spy).toHaveBeenCalledTimes(1) - expect(spy).toHaveBeenCalledWith('[ViewletExplorer/handleCopy] no dirent selected') - spy.mockRestore() -}) diff --git a/packages/explorer-view/test/HandleCut.test.ts b/packages/explorer-view/test/HandleCut.test.ts deleted file mode 100644 index b30fe06..0000000 --- a/packages/explorer-view/test/HandleCut.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleCut } from '../src/parts/HandleCut/HandleCut.ts' - -test('handleCut - with focused dirent', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeNativeFiles'() {}, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - const result = await handleCut(state) - - expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'cut', ['/test.txt']]]) - expect(result).toEqual({ - ...state, - cutItems: ['/test.txt'], - pasteShouldMove: true, - }) -}) - -test('handleCut - without focused dirent', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - items: [], - } - const result = await handleCut(state) - expect(mockRpc.invocations).toEqual([]) - expect(result).toBe(state) -}) diff --git a/packages/explorer-view/test/HandleDoubleClick.test.ts b/packages/explorer-view/test/HandleDoubleClick.test.ts deleted file mode 100644 index c073be9..0000000 --- a/packages/explorer-view/test/HandleDoubleClick.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import { handleDoubleClick } from '../src/parts/HandleDoubleClick/HandleDoubleClick.ts' - -test('handleDoubleClick - double click on empty area creates new file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() { - return undefined - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'(requests: readonly any[]) { - return requests.map((param) => { - if (param.type === 2) { - return `folder-icon` - } - return `file-icon` - }) - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - itemHeight: 20, - items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], - maxLineY: 1, - minLineY: 0, - y: 0, - } - - // Double click on empty area (position that doesn't match any item) - const result = await handleDoubleClick(state, 0, 100) - expect(result).toEqual({ - ...state, - editingIndex: 1, - editingType: ExplorerEditingType.CreateFile, - editingValue: '', - focus: 2, - focusedIndex: 1, - items: [ - { - depth: 0, - name: 'testfolder', - path: '/testfolder', - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 1, - icon: '', - name: '', - path: '/testfolder', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.EditingFile, - }, - ], - visibleExplorerItems: expect.anything(), - }) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/testfolder']]) -}) - -test('handleDoubleClick - double click on item returns same state', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - itemHeight: 20, - items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], - maxLineY: 1, - minLineY: 0, - y: 0, - } - - // Double click on item (position that matches an item) - const result = await handleDoubleClick(state, 0, 10) - expect(result).toBe(state) -}) - -test('handleDoubleClick - double click on item with multiple items returns same state', async () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - itemHeight: 20, - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirentType.Directory }, - { depth: 0, name: 'folder2', path: '/folder2', selected: false, type: DirentType.Directory }, - ], - maxLineY: 2, - minLineY: 0, - y: 0, - } - - // Double click on first item - const result = await handleDoubleClick(state, 0, 10) - expect(result).toBe(state) - - // Double click on second item - const result2 = await handleDoubleClick(state, 0, 30) - expect(result2).toBe(state) -}) - -test('handleDoubleClick - double click on empty area with scrolled state creates new file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() { - return undefined - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'(requests: readonly any[]) { - return requests.map((param) => { - if (param.type === 2) { - return `folder-icon` - } - return `file-icon` - }) - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - itemHeight: 20, - items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], - maxLineY: 1, - minLineY: 0, - y: 0, - } - - // Double click on empty area with scrolled position - const result = await handleDoubleClick(state, 0, 100) - expect(result).toEqual({ - ...state, - editingIndex: 1, - editingType: ExplorerEditingType.CreateFile, - editingValue: '', - focus: 2, - focusedIndex: 1, - items: [ - { - depth: 0, - name: 'testfolder', - path: '/testfolder', - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 1, - icon: '', - name: '', - path: '/testfolder', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.EditingFile, - }, - ], - visibleExplorerItems: expect.anything(), - }) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/testfolder']]) -}) diff --git a/packages/explorer-view/test/HandleDragLeave.test.ts b/packages/explorer-view/test/HandleDragLeave.test.ts deleted file mode 100644 index 373d5a5..0000000 --- a/packages/explorer-view/test/HandleDragLeave.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleDragLeave } from '../src/parts/HandleDragLeave/HandleDragLeave.ts' - -test('handleDragLeave returns state unchanged', () => { - const state = createDefaultState() - const result = handleDragLeave(state) - expect(result).toBe(state) -}) diff --git a/packages/explorer-view/test/HandleDragOver.test.ts b/packages/explorer-view/test/HandleDragOver.test.ts deleted file mode 100644 index 9fc0afa..0000000 --- a/packages/explorer-view/test/HandleDragOver.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleDragOver } from '../src/parts/HandleDragOver/HandleDragOver.ts' - -test.skip('handleDragOver - returns same state when drop targets are equal', () => { - const state: ExplorerState = { - ...createDefaultState(), - dropTargets: [1, 2], - } - const result = handleDragOver(state, 100, 100) - expect(result).toBe(state) -}) - -test('handleDragOver - returns new state when drop targets change', () => { - const state: ExplorerState = { - ...createDefaultState(), - dropTargets: [1], - } - const result = handleDragOver(state, 200, 200) - expect(result).not.toBe(state) - expect(result.dropTargets).not.toEqual(state.dropTargets) -}) - -test.skip('handleDragOver - throws error for invalid coordinates', () => { - const state = createDefaultState() - expect(() => handleDragOver(state, Number.NaN, 100)).toThrow() - expect(() => handleDragOver(state, 100, Number.NaN)).toThrow() -}) diff --git a/packages/explorer-view/test/HandleDrop.test.ts b/packages/explorer-view/test/HandleDrop.test.ts deleted file mode 100644 index 1426e86..0000000 --- a/packages/explorer-view/test/HandleDrop.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleDrop } from '../src/parts/HandleDrop/HandleDrop.ts' - -class MockFile implements File { - constructor( - public name: string, - public path: string, - public size: number = 0, - public type: string = 'text/plain', - public lastModified: number = 0, - public webkitRelativePath: string = '', - ) {} - - async arrayBuffer(): Promise { - return new ArrayBuffer(0) - } - - slice(): Blob { - return new Blob() - } - - stream(): ReadableStream> { - return new ReadableStream() - } - - async text(): Promise { - return '' - } - - async bytes(): Promise> { - return new Uint8Array(0) - } -} - -class MockFileList implements FileList { - private files: readonly File[] - - constructor(files: readonly File[]) { - this.files = files - } - - get length(): number { - return this.files.length - } - - item(index: number): File | null { - return this.files[index] || null - } - - [index: number]: File - - // @ts-ignore - [Symbol.iterator](): Iterator { - return this.files[Symbol.iterator]() - } -} - -test('handleDrop - successful drop', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystemHandle.getFileHandles'() { - return [] - }, - 'IconTheme.getIcons'() { - return [''] - }, - }) - - const state = createDefaultState() - const fileList = new MockFileList([new MockFile('test.txt', '/test.txt')]) - - // @ts-ignore - const result = await handleDrop(state, 0, 0, [1], fileList) - expect(result).toBeDefined() - expect(mockRpc.invocations).toEqual([ - ['FileSystemHandle.getFileHandles', [1]], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('handleDrop - error case', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystemHandle.getFileHandles'() { - throw new Error('test error') - }, - }) - - const state = createDefaultState() - const fileList = new MockFileList([new MockFile('test.txt', '/test.txt')]) - - // @ts-ignore - await expect(handleDrop(state, 0, 0, [1], fileList)).rejects.toThrow(new Error('Failed to drop files: test error')) - expect(mockRpc.invocations).toEqual([['FileSystemHandle.getFileHandles', [1]]]) -}) diff --git a/packages/explorer-view/test/HandleDropRootDefault.test.ts b/packages/explorer-view/test/HandleDropRootDefault.test.ts deleted file mode 100644 index c0fa1a8..0000000 --- a/packages/explorer-view/test/HandleDropRootDefault.test.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker, SourceControlWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import type { DroppedArgs } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleDrop } from '../src/parts/HandleDropRootDefault/HandleDropRootDefault.ts' - -test('handleDropRootDefault opens dropped folder as workspace when workspace is empty', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [{ isDirectory: false, isFile: true, name: 'inside.txt' }] - }, - 'PersistentFileHandle.addHandle'() { - return undefined - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return 'html://dropped-folder' - }, - 'Workspace.setPath'() { - return undefined - }, - }) - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - root: '', - } - const fileHandle = { - kind: 'directory', - name: 'dropped-folder', - } as FileSystemDirectoryHandle - const fileHandles: DroppedArgs = [fileHandle] - - const result = await handleDrop(state, fileHandles, [], []) - - expect(result.root).toBe('html://dropped-folder') - expect(result.dropTargets).toEqual([]) - expect(result.items).toHaveLength(1) - expect(mockRpc.invocations).toEqual([ - ['PersistentFileHandle.addHandle', 'dropped-folder', fileHandle], - ['Workspace.setPath', 'html://dropped-folder'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', 'html://dropped-folder'], - ['FileSystem.readDirWithFileTypes', 'html://dropped-folder'], - ]) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) - -test('handleDropRootDefault opens first dropped folder as workspace when two folders are dropped into empty workspace', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [{ isDirectory: false, isFile: true, name: 'inside.txt' }] - }, - 'PersistentFileHandle.addHandle'() { - return undefined - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return 'html://first-folder' - }, - 'Workspace.setPath'() { - return undefined - }, - }) - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - root: '', - } - const firstFolderHandle = { - kind: 'directory', - name: 'first-folder', - } as FileSystemDirectoryHandle - const secondFolderHandle = { - kind: 'directory', - name: 'second-folder', - } as FileSystemDirectoryHandle - const fileHandles: DroppedArgs = [firstFolderHandle, secondFolderHandle] - - const result = await handleDrop(state, fileHandles, [], []) - - expect(result.root).toBe('html://first-folder') - expect(result.dropTargets).toEqual([]) - expect(result.items).toHaveLength(1) - expect(mockRpc.invocations).toEqual([ - ['PersistentFileHandle.addHandle', 'first-folder', firstFolderHandle], - ['Workspace.setPath', 'html://first-folder'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', 'html://first-folder'], - ['FileSystem.readDirWithFileTypes', 'html://first-folder'], - ]) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) - -test('handleDropRootDefault ignores dropped file when workspace is empty', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - const state: ExplorerState = { - ...createDefaultState(), - root: '', - } - const fileHandle = { - kind: 'file', - name: 'dropped-file.txt', - } as FileSystemFileHandle - const fileHandles: DroppedArgs = [fileHandle] - - const result = await handleDrop(state, fileHandles, [], []) - - expect(result.root).toBe('') - expect(result.dropTargets).toEqual([]) - expect(result.items).toEqual([]) - expect(mockRpc.invocations).toEqual([]) -}) - -test('handleDropRootDefault opens dropped folder as workspace when file and folder are dropped into empty workspace', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [{ isDirectory: false, isFile: true, name: 'folder-inside.txt' }] - }, - 'PersistentFileHandle.addHandle'() { - return undefined - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return 'html://dropped-folder' - }, - 'Workspace.setPath'() { - return undefined - }, - }) - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - root: '', - } - const fileHandle = { - kind: 'file', - name: 'dropped-file.txt', - } as FileSystemFileHandle - const directoryHandle = { - kind: 'directory', - name: 'dropped-folder', - } as FileSystemDirectoryHandle - const fileHandles: DroppedArgs = [fileHandle, directoryHandle] - - const result = await handleDrop(state, fileHandles, [], []) - - expect(result.root).toBe('html://dropped-folder') - expect(result.dropTargets).toEqual([]) - expect(result.items).toHaveLength(1) - expect(mockRpc.invocations).toEqual([ - ['PersistentFileHandle.addHandle', 'dropped-folder', directoryHandle], - ['Workspace.setPath', 'html://dropped-folder'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', 'html://dropped-folder'], - ['FileSystem.readDirWithFileTypes', 'html://dropped-folder'], - ]) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/HandleDropRootElectron.test.ts b/packages/explorer-view/test/HandleDropRootElectron.test.ts deleted file mode 100644 index 198f5e2..0000000 --- a/packages/explorer-view/test/HandleDropRootElectron.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker, SourceControlWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import type { DroppedArgs } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleDrop } from '../src/parts/HandleDropRootElectron/HandleDropRootElectron.ts' - -test('handleDropRootElectron opens dropped folder as workspace when workspace is empty', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [{ isDirectory: false, isFile: true, name: 'inside.txt' }] - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/home/simon/dotfiles' - }, - 'Workspace.setPath'() { - return undefined - }, - }) - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - root: '', - } - const fileHandle = { - kind: 'directory', - name: 'dotfiles', - } as FileSystemDirectoryHandle - const fileHandles: DroppedArgs = [fileHandle] - - const result = await handleDrop(state, fileHandles, [], ['/home/simon/dotfiles']) - - expect(result.root).toBe('/home/simon/dotfiles') - expect(result.dropTargets).toEqual([]) - expect(result.items).toHaveLength(1) - expect(mockRpc.invocations).toEqual([ - ['Workspace.setPath', '/home/simon/dotfiles'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/home/simon/dotfiles'], - ['FileSystem.readDirWithFileTypes', '/home/simon/dotfiles'], - ]) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) - -test('handleDropRootElectron ignores dropped file when workspace is empty', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - const state: ExplorerState = { - ...createDefaultState(), - dropTargets: [0], - root: '', - } - const fileHandles: DroppedArgs = [ - { - kind: 'file', - value: { - kind: 'file', - name: 'dropped-file.txt', - } as FileSystemFileHandle, - }, - ] - - const result = await handleDrop(state, fileHandles, [], ['/home/simon/dropped-file.txt']) - - expect(result.root).toBe('') - expect(result.dropTargets).toEqual([]) - expect(result.items).toEqual([]) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/HandleEscape.test.ts b/packages/explorer-view/test/HandleEscape.test.ts deleted file mode 100644 index b69d825..0000000 --- a/packages/explorer-view/test/HandleEscape.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleEscape } from '../src/parts/HandleEscape/HandleEscape.ts' - -test('handleEscape - clears cutItems and keeps other state', async () => { - const initialState: ExplorerState = { - ...createDefaultState(), - cutItems: ['/a/b.txt', '/c/d.txt'], - focusedIndex: 1, - } - - const result = await handleEscape(initialState) - - expect(result.cutItems).toEqual([]) - expect(result.focusedIndex).toBe(1) -}) diff --git a/packages/explorer-view/test/HandleFocus.test.ts b/packages/explorer-view/test/HandleFocus.test.ts deleted file mode 100644 index b83ae25..0000000 --- a/packages/explorer-view/test/HandleFocus.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' -import { handleFocus } from '../src/parts/HandleFocus/HandleFocus.ts' - -test('handleFocus keeps input focus while editing', async () => { - const state = { - ...createDefaultState(), - editingIndex: 1, - focus: FocusId.Input, - } - - const result = await handleFocus(state) - - expect(result).toBe(state) -}) - -test('handleFocus switches to list focus when not editing', async () => { - const state = createDefaultState() - - const result = await handleFocus(state) - - expect(result).toEqual({ - ...state, - focus: FocusId.List, - }) -}) diff --git a/packages/explorer-view/test/HandleInputBlur.test.ts b/packages/explorer-view/test/HandleInputBlur.test.ts deleted file mode 100644 index ed40ac1..0000000 --- a/packages/explorer-view/test/HandleInputBlur.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleInputBlur } from '../src/parts/HandleInputBlur/HandleInputBlur.ts' - -test('should cancel edit if there is an error message', async () => { - const state: ExplorerState = { ...createDefaultState(), editingErrorMessage: 'error', editingValue: 'foo' } - const result = await handleInputBlur(state) - expect(result.editingValue).toBe('foo') -}) - -test('should cancel edit if editing value is empty', async () => { - const state: ExplorerState = { ...createDefaultState(), editingErrorMessage: '', editingValue: '' } - const result = await handleInputBlur(state) - expect(result.editingValue).toBe('') -}) - -test('should accept edit if no error and value present', async () => { - const state: ExplorerState = { ...createDefaultState(), editingErrorMessage: '', editingType: 0, editingValue: 'foo' } - const result = await handleInputBlur(state) - expect(result.editingValue).toBe('foo') -}) diff --git a/packages/explorer-view/test/HandleKeyDown.test.ts b/packages/explorer-view/test/HandleKeyDown.test.ts deleted file mode 100644 index 7249289..0000000 --- a/packages/explorer-view/test/HandleKeyDown.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleKeyDown } from '../src/parts/HandleKeyDown/HandleKeyDown.ts' - -test.skip('handleKeyDown - empty state', () => { - const state = createDefaultState() - const newState = handleKeyDown(state, 'a') - expect(newState.focusWord).toBe('a') - expect(newState.focusedIndex).toBe(0) -}) - -test.skip('handleKeyDown - with items', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'apple', path: '/apple', selected: false, type: 0 }, - { depth: 0, name: 'banana', path: '/banana', selected: false, type: 0 }, - { depth: 0, name: 'cherry', path: '/cherry', selected: false, type: 0 }, - ], - } - const newState = handleKeyDown(state, 'b') - expect(newState.focusWord).toBe('b') - expect(newState.focusedIndex).toBe(1) -}) - -test.skip('handleKeyDown - no match', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'apple', path: '/apple', selected: false, type: 0 }, - { depth: 0, name: 'banana', path: '/banana', selected: false, type: 0 }, - { depth: 0, name: 'cherry', path: '/cherry', selected: false, type: 0 }, - ], - } - const newState = handleKeyDown(state, 'x') - expect(newState.focusWord).toBe('x') - expect(newState.focusedIndex).toBe(0) -}) - -test.skip('handleKeyDown - multiple characters', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'apple', path: '/apple', selected: false, type: 0 }, - { depth: 0, name: 'banana', path: '/banana', selected: false, type: 0 }, - { depth: 0, name: 'cherry', path: '/cherry', selected: false, type: 0 }, - ], - } - let newState = handleKeyDown(state, 'b') - newState = handleKeyDown(newState, 'a') - expect(newState.focusWord).toBe('ba') - expect(newState.focusedIndex).toBe(1) -}) diff --git a/packages/explorer-view/test/HandlePaste.test.ts b/packages/explorer-view/test/HandlePaste.test.ts deleted file mode 100644 index b29c30b..0000000 --- a/packages/explorer-view/test/HandlePaste.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handlePaste } from '../src/parts/HandlePaste/HandlePaste.ts' -import * as NativeFileTypes from '../src/parts/NativeFileTypes/NativeFileTypes.ts' - -test('should handle paste with no files (none type)', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return { - files: [], - type: NativeFileTypes.None, - } - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handlePaste(initialState) - - expect(result).toBe(initialState) - expect(mockRpc.invocations).toEqual([['ClipBoard.readNativeFiles']]) -}) - -test('should handle paste with copy type', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return { - files: ['/source/file1.txt', '/source/file2.txt'], - type: NativeFileTypes.Copy, - } - }, - 'FileSystem.copy'() {}, - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getIcons'() { - return [''] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handlePaste(initialState) - - expect(result).toBeDefined() - expect(result).toHaveProperty('items') - expect(result).toHaveProperty('icons') - expect(mockRpc.invocations).toEqual([ - ['ClipBoard.readNativeFiles'], - ['FileSystem.copy', '/source/file1.txt', '/file1.txt'], - ['FileSystem.copy', '/source/file2.txt', '/file2.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('should handle paste with cut type', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return { - files: ['/source/file1.txt', '/source/file2.txt'], - type: NativeFileTypes.Cut, - } - }, - 'FileSystem.copy'() {}, - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.rename'() {}, - 'IconTheme.getIcons'() { - return [''] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handlePaste(initialState) - - expect(result).toBeDefined() - expect(result).toHaveProperty('items') - expect(result).toHaveProperty('icons') - expect(mockRpc.invocations).toEqual([ - ['ClipBoard.readNativeFiles'], - ['FileSystem.copy', '/source/file1.txt', '/file1.txt'], - ['FileSystem.copy', '/source/file2.txt', '/file2.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('should handle paste with multiple files', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return { - files: ['/source/file1.txt', '/source/file2.txt', '/source/folder1', '/source/folder2/file3.txt'], - type: NativeFileTypes.Copy, - } - }, - 'FileSystem.copy'() {}, - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getIcons'() { - return [''] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handlePaste(initialState) - - expect(result).toBeDefined() - expect(result).toHaveProperty('items') - expect(result).toHaveProperty('icons') - expect(mockRpc.invocations).toEqual([ - ['ClipBoard.readNativeFiles'], - ['FileSystem.copy', '/source/file1.txt', '/file1.txt'], - ['FileSystem.copy', '/source/file2.txt', '/file2.txt'], - ['FileSystem.copy', '/source/folder1', '/folder1'], - ['FileSystem.copy', '/source/folder2/file3.txt', '/file3.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('should handle paste with empty files array', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return { - files: [], - type: NativeFileTypes.Copy, - } - }, - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getIcons'() { - return [''] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handlePaste(initialState) - - expect(result).toBeDefined() - expect(result).toHaveProperty('items') - expect(result).toHaveProperty('icons') - expect(mockRpc.invocations).toEqual([['ClipBoard.readNativeFiles'], ['FileSystem.readDirWithFileTypes', '/']]) -}) - -test('should preserve state properties when handling paste', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return { - files: ['/source/file.txt'], - type: NativeFileTypes.Copy, - } - }, - 'FileSystem.copy'() {}, - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getIcons'() { - return [''] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handlePaste(initialState) - - expect(result).toBeDefined() - expect(result).toHaveProperty('items') - expect(result).toHaveProperty('icons') - expect(mockRpc.invocations).toEqual([ - ['ClipBoard.readNativeFiles'], - ['FileSystem.copy', '/source/file.txt', '/file.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) diff --git a/packages/explorer-view/test/HandlePasteCopy.test.ts b/packages/explorer-view/test/HandlePasteCopy.test.ts deleted file mode 100644 index 26c847d..0000000 --- a/packages/explorer-view/test/HandlePasteCopy.test.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handlePasteCopy } from '../src/parts/HandlePasteCopy/HandlePasteCopy.ts' - -test('should focus on first newly created file after paste copy', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.copy'() { - return undefined - }, - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'index.js', type: DirentType.File }, - { name: 'index copy.js', type: DirentType.File }, - ] - }, - 'IconTheme.getIcons'() { - return ['', ''] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'index.js', path: '/test/index.js', selected: false, type: DirentType.File }], - root: '/test', - } - - const nativeFiles = { - files: ['/source/index.js'], - source: 'gnomeCopiedFiles' as const, - type: 'copy' as const, - } - - const result = await handlePasteCopy(initialState, nativeFiles) - - expect(result).toBeDefined() - expect(result.items).toHaveLength(2) - const focusedItem = result.items[result.focusedIndex] - expect(focusedItem.path).toBe('/test/index copy.js') - expect(result.focused).toBe(true) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.copy', '/source/index.js', '/test/index copy.js'], - ['FileSystem.readDirWithFileTypes', '/test'], - ]) -}) - -test('should handle paste copy with multiple files and focus on first', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.copy'() { - return undefined - }, - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file1.txt', type: DirentType.File }, - { name: 'file1 copy.txt', type: DirentType.File }, - { name: 'file2.txt', type: DirentType.File }, - { name: 'file2 copy.txt', type: DirentType.File }, - ] - }, - 'IconTheme.getIcons'() { - return ['', '', '', ''] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 0, name: 'file1.txt', path: '/test/file1.txt', selected: false, type: DirentType.File }, - { depth: 0, name: 'file2.txt', path: '/test/file2.txt', selected: false, type: DirentType.File }, - ], - root: '/test', - } - - const nativeFiles = { - files: ['/source/file1.txt', '/source/file2.txt'], - source: 'gnomeCopiedFiles' as const, - type: 'copy' as const, - } - - const result = await handlePasteCopy(initialState, nativeFiles) - - expect(result).toBeDefined() - expect(result.items).toHaveLength(4) - const focusedItem = result.items[result.focusedIndex] - expect(focusedItem.path).toBe('/test/file1 copy.txt') - expect(result.focused).toBe(true) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.copy', '/source/file1.txt', '/test/file1 copy.txt'], - ['FileSystem.copy', '/source/file2.txt', '/test/file2 copy.txt'], - ['FileSystem.readDirWithFileTypes', '/test'], - ]) -}) - -test('should handle paste copy with empty files array', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getIcons'() { - return [] - }, - 'Preferences.get'() { - return false - }, - }) - - const initialState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [], - root: '/test', - } - - const nativeFiles = { - files: [], - source: 'gnomeCopiedFiles' as const, - type: 'copy' as const, - } - - const result = await handlePasteCopy(initialState, nativeFiles) - - expect(result).toBeDefined() - expect(result.items).toHaveLength(0) - expect(result.focusedIndex).toBe(0) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) -}) diff --git a/packages/explorer-view/test/HandlePointerDown.test.ts b/packages/explorer-view/test/HandlePointerDown.test.ts deleted file mode 100644 index bae2bc3..0000000 --- a/packages/explorer-view/test/HandlePointerDown.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' -import { handlePointerDown } from '../src/parts/HandlePointerDown/HandlePointerDown.ts' -import * as MouseEventType from '../src/parts/MouseEventType/MouseEventType.ts' - -test('left click outside items', () => { - const state = createDefaultState() - const result = handlePointerDown(state, MouseEventType.LeftClick, 100, 100) - expect(result).toEqual({ - ...state, - focus: FocusId.List, - focused: true, - focusedIndex: -1, - }) -}) - -test.skip('right click outside items', () => { - const state = createDefaultState() - const result = handlePointerDown(state, 2, 100, 100) - expect(result).toEqual({ - ...state, - focusedIndex: -1, - }) -}) - -test('left click on item', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - const result = handlePointerDown(state, MouseEventType.LeftClick, 0, 0) - expect(result).toEqual(state) -}) diff --git a/packages/explorer-view/test/HandleRangeSelection.test.ts b/packages/explorer-view/test/HandleRangeSelection.test.ts deleted file mode 100644 index 0eec359..0000000 --- a/packages/explorer-view/test/HandleRangeSelection.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleRangeSelection } from '../src/parts/HandleRangeSelection/HandleRangeSelection.ts' - -const createItem = (name: string, selected: boolean): ExplorerItem => ({ - depth: 0, - name, - path: `/${name}`, - selected, - type: 0, -}) - -test('handleRangeSelection - forward range', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const newState = handleRangeSelection(state, 0, 2) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(true) -}) - -test('handleRangeSelection - backward range', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - expect(() => handleRangeSelection(state, 2, 0)).toThrow(new Error('startIndex must be less than or equal to endIndex')) -}) - -test('handleRangeSelection - preserve existing selections', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: true, type: 0 }, - ], - } - const newState = handleRangeSelection(state, 0, 2) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(true) -}) - -test('selects items in range', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [createItem('a', false), createItem('b', false), createItem('c', false), createItem('d', false)], - } - - const newState = handleRangeSelection(state, 1, 2) - - expect(newState.items).toEqual([createItem('a', false), createItem('b', true), createItem('c', true), createItem('d', false)]) -}) - -test('throws error when startIndex > endIndex', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [createItem('a', false), createItem('b', false)], - } - - expect(() => handleRangeSelection(state, 1, 0)).toThrow('startIndex must be less than or equal to endIndex') -}) diff --git a/packages/explorer-view/test/HandleResize.test.ts b/packages/explorer-view/test/HandleResize.test.ts deleted file mode 100644 index 00b44a3..0000000 --- a/packages/explorer-view/test/HandleResize.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleResize } from '../src/parts/HandleResize/HandleResize.ts' - -test('handleResize updates dimensions, viewport lines and scrollbarHeight', () => { - const items: readonly ExplorerItem[] = Array.from({ length: 10 }, (_, index) => ({ - depth: 0, - name: `file-${index}`, - path: `/file-${index}`, - selected: false, - type: 1, - })) - const state: ExplorerState = { - ...createDefaultState(), - itemHeight: 20, - items, - } - - const result = handleResize(state, { height: 100, width: 300 }) - - expect(result).toEqual({ - ...state, - height: 100, - maxLineY: 6, - minLineY: 0, - scrollBarHeight: 50, - width: 300, - }) -}) - -test('handleResize clamps deltaY when viewport gets larger', () => { - const items: readonly ExplorerItem[] = Array.from({ length: 10 }, (_, index) => ({ - depth: 0, - name: `file-${index}`, - path: `/file-${index}`, - selected: false, - type: 1, - })) - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 180, - height: 20, - itemHeight: 20, - items, - maxLineY: 1, - minLineY: 9, - } - - const result = handleResize(state, { height: 120, width: 300 }) - - expect(result.deltaY).toBe(80) - expect(result.minLineY).toBe(4) - expect(result.maxLineY).toBe(11) - expect(result.scrollBarHeight).toBe(72) -}) - -test('handleResize returns same state for invalid dimensions', () => { - const state: ExplorerState = createDefaultState() - const result = handleResize(state, { height: Number.NaN, width: 200 }) - expect(result).toBe(state) -}) diff --git a/packages/explorer-view/test/HandleSelection.test.ts b/packages/explorer-view/test/HandleSelection.test.ts deleted file mode 100644 index b8161bf..0000000 --- a/packages/explorer-view/test/HandleSelection.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' -import { handleSelection } from '../src/parts/HandleSelection/HandleSelection.js' - -test('handleSelection toggles selection of item at index', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, - { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, - { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, - ], - } - - const newState = handleSelection(state, 1) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[2].selected).toBe(false) -}) diff --git a/packages/explorer-view/test/HandleUpload.test.ts b/packages/explorer-view/test/HandleUpload.test.ts deleted file mode 100644 index b96ed65..0000000 --- a/packages/explorer-view/test/HandleUpload.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker as RpcRendererWorker } from '@lvce-editor/rpc-registry' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleUpload } from '../src/parts/HandleUpload/HandleUpload.ts' - -test('should upload a file', async () => { - using mockRpc = RpcRendererWorker.registerMockRpc({ - 'FileSystem.writeFile'(...args: any[]) { - // Mock implementation - }, - }) - const state = createDefaultState() - const file = { name: 'test.txt', text: (): string => 'hello' } - const dirents = [{ file, type: 1 }] - await handleUpload(state, dirents) - expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', expect.stringContaining('test.txt'), 'hello']]) -}) - -test('should do nothing for empty dirents', async () => { - using mockRpc = RpcRendererWorker.registerMockRpc({}) - const state = createDefaultState() - await handleUpload(state, []) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/HandleWheel.test.ts b/packages/explorer-view/test/HandleWheel.test.ts deleted file mode 100644 index 688add2..0000000 --- a/packages/explorer-view/test/HandleWheel.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleWheel } from '../src/parts/HandleWheel/HandleWheel.ts' - -test('handleWheel calls SetDeltaY with correct delta', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 10, - height: 50, - itemHeight: 20, - items: [ - { depth: 0, name: 'test1', path: '/test1', selected: false, type: 1 }, - { depth: 0, name: 'test2', path: '/test2', selected: false, type: 1 }, - { depth: 0, name: 'test3', path: '/test3', selected: false, type: 1 }, - { depth: 0, name: 'test4', path: '/test4', selected: false, type: 1 }, - { depth: 0, name: 'test5', path: '/test5', selected: false, type: 1 }, - ], - } - const result = await handleWheel(state, 0, 5) - expect(result.deltaY).toBe(15) - expect(mockRpc.invocations).toEqual([]) -}) - -test('handleWheel with negative delta', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - deltaY: 10, - height: 50, - itemHeight: 20, - items: [ - { depth: 0, name: 'test1', path: '/test1', selected: false, type: 1 }, - { depth: 0, name: 'test2', path: '/test2', selected: false, type: 1 }, - { depth: 0, name: 'test3', path: '/test3', selected: false, type: 1 }, - { depth: 0, name: 'test4', path: '/test4', selected: false, type: 1 }, - { depth: 0, name: 'test5', path: '/test5', selected: false, type: 1 }, - ], - } - const result = await handleWheel(state, 0, -3) - expect(result.deltaY).toBe(7) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/HandleWorkspaceChange.test.ts b/packages/explorer-view/test/HandleWorkspaceChange.test.ts deleted file mode 100644 index f1d533d..0000000 --- a/packages/explorer-view/test/HandleWorkspaceChange.test.ts +++ /dev/null @@ -1,293 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker, SourceControlWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { handleWorkspaceChange } from '../src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts' - -test('should update state with new workspace path and load content', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/workspace/path' - }, - }) - - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handleWorkspaceChange(initialState) - - expect(result.root).toBe('/new/workspace/path') - expect(result).toHaveProperty('items') - expect(result).toHaveProperty('icons') - expect(result).toHaveProperty('fileIconCache') - expect(result).toHaveProperty('minLineY') - expect(result).toHaveProperty('deltaY') - expect(result).toHaveProperty('maxLineY') - expect(result).toHaveProperty('pathSeparator') - expect(result).toHaveProperty('excluded') - expect(result).toHaveProperty('useChevrons') - expect(mockRpc.invocations).toEqual([ - ['Workspace.getPath'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/new/workspace/path'], - ['FileSystem.readDirWithFileTypes', '/new/workspace/path'], - ]) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) - -test('should preserve state properties when updating workspace', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Preferences.get'() { - return true - }, - 'Workspace.getPath'() { - return '/another/workspace' - }, - }) - - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handleWorkspaceChange(initialState) - - expect(result.uid).toBe(initialState.uid) - expect(result.parentUid).toBe(initialState.parentUid) - expect(result.focusedIndex).toBe(initialState.focusedIndex) - expect(result.focused).toBe(initialState.focused) - expect(result.hoverIndex).toBe(initialState.hoverIndex) - expect(result.x).toBe(initialState.x) - expect(result.y).toBe(initialState.y) - expect(result.width).toBe(initialState.width) - expect(result.height).toBe(initialState.height) - expect(result.version).toBe(initialState.version) - expect(result.editingIndex).toBe(initialState.editingIndex) - expect(result.itemHeight).toBe(initialState.itemHeight) - expect(result.platform).toBe(initialState.platform) - expect(result.focus).toBe(initialState.focus) - expect(result.inputSource).toBe(initialState.inputSource) - expect(result.focusWord).toBe(initialState.focusWord) - expect(result.focusWordTimeout).toBe(initialState.focusWordTimeout) - expect(result.finalDeltaY).toBe(initialState.finalDeltaY) - expect(result.scrollBarHeight).toBe(initialState.scrollBarHeight) - expect(result.handleOffset).toBe(initialState.handleOffset) - expect(result.scrollBarActive).toBe(initialState.scrollBarActive) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['Workspace.getPath'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/another/workspace'], - ['FileSystem.readDirWithFileTypes', '/another/workspace'], - ]), - ) - expect(mockSourceControlRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', '', '/another/workspace', '', 0]]) -}) - -test('should handle workspace path change with existing content', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [ - { isDirectory: false, isFile: true, name: 'file1.txt' }, - { isDirectory: true, isFile: false, name: 'folder1' }, - ] - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/changed/workspace/path' - }, - }) - - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handleWorkspaceChange(initialState) - - expect(result.root).toBe('/changed/workspace/path') - expect(result.items).toHaveLength(2) - expect(result.pathSeparator).toBe('/') - expect(result.useChevrons).toBe(false) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['Workspace.getPath'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/changed/workspace/path'], - ['FileSystem.readDirWithFileTypes', '/changed/workspace/path'], - ]), - ) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) - -test('should handle workspace path change with chevrons enabled', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Preferences.get'() { - return true - }, - 'Workspace.getPath'() { - return '/chevron/workspace' - }, - }) - - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handleWorkspaceChange(initialState) - - expect(result.root).toBe('/chevron/workspace') - expect(result.useChevrons).toBe(true) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['Workspace.getPath'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/chevron/workspace'], - ['FileSystem.readDirWithFileTypes', '/chevron/workspace'], - ]), - ) - expect(mockSourceControlRpc.invocations).toEqual([['SourceControl.getEnabledProviderIds', '', '/chevron/workspace', '', 0]]) -}) - -test('should handle different path separators', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '\\' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return 'C:\\windows\\workspace' - }, - }) - - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handleWorkspaceChange(initialState) - - expect(result.root).toBe('C:\\windows\\workspace') - expect(result.pathSeparator).toBe('\\') - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['Workspace.getPath'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', 'C:\\windows\\workspace'], - ['FileSystem.readDirWithFileTypes', 'C:\\windows\\workspace'], - ]), - ) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) - -test('should set load error state when reading folder fails', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - const error = Object.assign(new Error('Permission denied'), { - code: 'EACCES', - }) - throw error - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/restricted/workspace' - }, - }) - - const mockSourceControlRpc = SourceControlWorker.registerMockRpc({ - 'SourceControl.getEnabledProviderIds'() { - return [] - }, - }) - - const initialState: ExplorerState = createDefaultState() - const result = await handleWorkspaceChange(initialState) - - expect(result.root).toBe('/restricted/workspace') - expect(result.hasError).toBe(true) - expect(result.errorCode).toBe('EACCES') - expect(result.errorMessage).toBe('permission was denied') - expect(result.items).toEqual([]) - expect(mockRpc.invocations).toEqual( - expect.arrayContaining([ - ['Workspace.getPath'], - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/restricted/workspace'], - ['FileSystem.readDirWithFileTypes', '/restricted/workspace'], - ]), - ) - expect(mockSourceControlRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/IsAscii.test.ts b/packages/explorer-view/test/IsAscii.test.ts deleted file mode 100644 index 8939116..0000000 --- a/packages/explorer-view/test/IsAscii.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { test, expect } from '@jest/globals' -import { isAscii } from '../src/parts/IsAscii/IsAscii.js' - -test('isAscii - lowercase ascii', () => { - expect(isAscii('a')).toBe(true) - expect(isAscii('z')).toBe(true) -}) - -test('isAscii - uppercase ascii', () => { - expect(isAscii('A')).toBe(false) - expect(isAscii('Z')).toBe(false) -}) - -test('isAscii - non-ascii', () => { - expect(isAscii('ä')).toBe(false) - expect(isAscii('1')).toBe(false) - expect(isAscii('-')).toBe(false) - expect(isAscii(' ')).toBe(false) - expect(isAscii('')).toBe(false) -}) diff --git a/packages/explorer-view/test/IsDirectoryHandle.test.ts b/packages/explorer-view/test/IsDirectoryHandle.test.ts deleted file mode 100644 index e3893d0..0000000 --- a/packages/explorer-view/test/IsDirectoryHandle.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { test, expect } from '@jest/globals' -import { isDirectoryHandle } from '../src/parts/IsDirectoryHandle/IsDirectoryHandle.ts' - -test('isDirectoryHandle', () => { - const fileHandle = { - kind: 'file', - } as FileSystemHandle - const directoryHandle = { - kind: 'directory', - } as FileSystemHandle - expect(isDirectoryHandle(fileHandle)).toBe(false) - expect(isDirectoryHandle(directoryHandle)).toBe(true) -}) diff --git a/packages/explorer-view/test/IsEqual.test.ts b/packages/explorer-view/test/IsEqual.test.ts deleted file mode 100644 index cbdd666..0000000 --- a/packages/explorer-view/test/IsEqual.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as IsEqual from '../src/parts/IsEqual/IsEqual.ts' - -test('isEqual - empty arrays', () => { - expect(IsEqual.isEqual([], [])).toBe(true) -}) - -test('isEqual - arrays with same elements', () => { - expect(IsEqual.isEqual([1, 2, 3], [1, 2, 3])).toBe(true) -}) - -test('isEqual - arrays with different elements', () => { - expect(IsEqual.isEqual([1, 2, 3], [1, 2, 4])).toBe(false) -}) - -test('isEqual - arrays with different lengths', () => { - expect(IsEqual.isEqual([1, 2], [1, 2, 3])).toBe(false) -}) - -test('isEqual - arrays with same elements in different order', () => { - expect(IsEqual.isEqual([1, 2, 3], [3, 2, 1])).toBe(false) -}) - -test('isEqual - arrays with string elements', () => { - expect(IsEqual.isEqual(['a', 'b', 'c'], ['a', 'b', 'c'])).toBe(true) -}) - -test('isEqual - arrays with mixed elements', () => { - expect(IsEqual.isEqual([1, 'b', true], [1, 'b', true])).toBe(true) -}) diff --git a/packages/explorer-view/test/IsExpanded.test.ts b/packages/explorer-view/test/IsExpanded.test.ts deleted file mode 100644 index 090ed11..0000000 --- a/packages/explorer-view/test/IsExpanded.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { test, expect } from '@jest/globals' -import { Directory, DirectoryExpanded, DirectoryExpanding, File } from '../src/parts/DirentType/DirentType.ts' -import { isExpanded } from '../src/parts/IsExpanded/IsExpanded.ts' - -test('isExpanded - DirectoryExpanded', () => { - const item = { depth: 0, name: 'test', path: '/test', selected: false, type: DirectoryExpanded } - expect(isExpanded(item)).toBe(true) -}) - -test('isExpanded - DirectoryExpanding', () => { - const item = { depth: 0, name: 'test', path: '/test', selected: false, type: DirectoryExpanding } - expect(isExpanded(item)).toBe(true) -}) - -test('isExpanded - Directory', () => { - const item = { depth: 0, name: 'test', path: '/test', selected: false, type: Directory } - expect(isExpanded(item)).toBe(false) -}) - -test('isExpanded - File', () => { - const item = { depth: 0, name: 'test', path: '/test', selected: false, type: File } - expect(isExpanded(item)).toBe(false) -}) diff --git a/packages/explorer-view/test/IsExpandedDirectory.test.ts b/packages/explorer-view/test/IsExpandedDirectory.test.ts deleted file mode 100644 index b33142b..0000000 --- a/packages/explorer-view/test/IsExpandedDirectory.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as IsExpandedDirectory from '../src/parts/IsExpandedDirectory/IsExpandedDirectory.ts' - -test('isExpandedDirectory - expanded directory', () => { - const item: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.DirectoryExpanded, - } - expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(true) -}) - -test('isExpandedDirectory - collapsed directory', () => { - const item: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(false) -}) - -test('isExpandedDirectory - expanding directory', () => { - const item: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.DirectoryExpanding, - } - expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(false) -}) - -test('isExpandedDirectory - file', () => { - const item: ExplorerItem = { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - } - expect(IsExpandedDirectory.isExpandedDirectory(item)).toBe(false) -}) diff --git a/packages/explorer-view/test/IsFileHandle.test.ts b/packages/explorer-view/test/IsFileHandle.test.ts deleted file mode 100644 index 5cf80a8..0000000 --- a/packages/explorer-view/test/IsFileHandle.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { test, expect } from '@jest/globals' -import { isFileHandle } from '../src/parts/IsFileHandle/IsFileHandle.ts' - -test('isFileHandle', () => { - const fileHandle = { - kind: 'file', - } as FileSystemHandle - const directoryHandle = { - kind: 'directory', - } as FileSystemHandle - expect(isFileHandle(fileHandle)).toBe(true) - expect(isFileHandle(directoryHandle)).toBe(false) -}) diff --git a/packages/explorer-view/test/IsSymbolicLink.test.ts b/packages/explorer-view/test/IsSymbolicLink.test.ts deleted file mode 100644 index 82bab5d..0000000 --- a/packages/explorer-view/test/IsSymbolicLink.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as IsSymbolicLink from '../src/parts/IsSymbolicLink/IsSymbolicLink.ts' - -test('isSymbolicLink - symlink', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'symlink', - path: '/symlink', - selected: false, - type: DirentType.Symlink, - } - expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(true) -}) - -test('isSymbolicLink - file', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'file.txt', - path: '/file.txt', - selected: false, - type: DirentType.File, - } - expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) -}) - -test('isSymbolicLink - directory', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'directory', - path: '/directory', - selected: false, - type: DirentType.Directory, - } - expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) -}) - -test('isSymbolicLink - symlink file', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'symlink-file', - path: '/symlink-file', - selected: false, - type: DirentType.SymLinkFile, - } - expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) -}) - -test('isSymbolicLink - symlink folder', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'symlink-folder', - path: '/symlink-folder', - selected: false, - type: DirentType.SymLinkFolder, - } - expect(IsSymbolicLink.isSymbolicLink(dirent)).toBe(false) -}) diff --git a/packages/explorer-view/test/IsTopLevel.test.ts b/packages/explorer-view/test/IsTopLevel.test.ts deleted file mode 100644 index 8fc4748..0000000 --- a/packages/explorer-view/test/IsTopLevel.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as IsTopLevel from '../src/parts/IsTopLevel/IsTopLevel.ts' - -test('isTopLevel - depth 1', () => { - const dirent: ExplorerItem = { - depth: 1, - name: '', - path: '', - selected: false, - type: 0, - } - expect(IsTopLevel.isTopLevel(dirent)).toBe(true) -}) - -test('isTopLevel - depth 2', () => { - const dirent = { - depth: 2, - name: '', - path: '', - selected: false, - type: 0, - } - expect(IsTopLevel.isTopLevel(dirent)).toBe(false) -}) diff --git a/packages/explorer-view/test/IsUriWithinRoot.test.ts b/packages/explorer-view/test/IsUriWithinRoot.test.ts deleted file mode 100644 index c95d936..0000000 --- a/packages/explorer-view/test/IsUriWithinRoot.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { test, expect } from '@jest/globals' -import { isUriWithinRoot } from '../src/parts/IsUriWithinRoot/IsUriWithinRoot.ts' - -test('isUriWithinRoot returns true for exact root match', () => { - expect(isUriWithinRoot('/root', '/root', '/')).toBe(true) -}) - -test('isUriWithinRoot returns true for child uri', () => { - expect(isUriWithinRoot('/root', '/root/folder/file.txt', '/')).toBe(true) -}) - -test('isUriWithinRoot returns false for uri outside root', () => { - expect(isUriWithinRoot('/root', '/other/file.txt', '/')).toBe(false) -}) - -test('isUriWithinRoot returns false for matching prefix without separator', () => { - expect(isUriWithinRoot('/root', '/rooted/file.txt', '/')).toBe(false) -}) - -test('isUriWithinRoot supports roots that already end with the path separator', () => { - expect(isUriWithinRoot('/root/', '/root/folder/file.txt', '/')).toBe(true) -}) diff --git a/packages/explorer-view/test/LoadContent.test.ts b/packages/explorer-view/test/LoadContent.test.ts deleted file mode 100644 index d9cde44..0000000 --- a/packages/explorer-view/test/LoadContent.test.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { Directory, File } from '../src/parts/DirentType/DirentType.ts' -import { loadContent } from '../src/parts/LoadContent/LoadContent.ts' - -test('loadContent clamps restored deltaY to 0 when content is shorter after reload', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'folder1', type: Directory }, - { name: 'folder2', type: Directory }, - ] - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/workspace' - }, - }) - const state: ExplorerState = createDefaultState() - - const result = await loadContent(state, { - deltaY: 4800, - expandedPaths: [], - minLineY: 240, - root: '/workspace', - }) - - expect({ - deltaY: result.deltaY, - items: result.items, - minLineY: result.minLineY, - }).toEqual({ - deltaY: 0, - items: [ - { - depth: 1, - icon: '', - name: 'folder1', - path: '/workspace/folder1', - posInSet: 1, - setSize: 2, - type: Directory, - }, - { - depth: 1, - icon: '', - name: 'folder2', - path: '/workspace/folder2', - posInSet: 2, - setSize: 2, - type: Directory, - }, - ], - minLineY: 0, - }) - expect(mockRpc.invocations).toEqual([ - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/workspace'], - ['FileSystem.readDirWithFileTypes', '/workspace'], - ]) -}) - -test('loadContent clamps restored deltaY to maxDeltaY when content is still scrollable', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file1', type: File }, - { name: 'file2', type: File }, - { name: 'file3', type: File }, - { name: 'file4', type: File }, - { name: 'file5', type: File }, - { name: 'file6', type: File }, - { name: 'file7', type: File }, - { name: 'file8', type: File }, - ] - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/workspace' - }, - }) - const state: ExplorerState = createDefaultState() - - const result = await loadContent(state, { - deltaY: 4800, - expandedPaths: [], - minLineY: 240, - root: '/workspace', - }) - - expect({ - deltaY: result.deltaY, - items: result.items, - minLineY: result.minLineY, - }).toEqual({ - deltaY: 60, - items: [ - { depth: 1, icon: '', name: 'file1', path: '/workspace/file1', posInSet: 1, setSize: 8, type: File }, - { depth: 1, icon: '', name: 'file2', path: '/workspace/file2', posInSet: 2, setSize: 8, type: File }, - { depth: 1, icon: '', name: 'file3', path: '/workspace/file3', posInSet: 3, setSize: 8, type: File }, - { depth: 1, icon: '', name: 'file4', path: '/workspace/file4', posInSet: 4, setSize: 8, type: File }, - { depth: 1, icon: '', name: 'file5', path: '/workspace/file5', posInSet: 5, setSize: 8, type: File }, - { depth: 1, icon: '', name: 'file6', path: '/workspace/file6', posInSet: 6, setSize: 8, type: File }, - { depth: 1, icon: '', name: 'file7', path: '/workspace/file7', posInSet: 7, setSize: 8, type: File }, - { depth: 1, icon: '', name: 'file8', path: '/workspace/file8', posInSet: 8, setSize: 8, type: File }, - ], - minLineY: 3, - }) - expect(mockRpc.invocations).toEqual([ - ['Preferences.get', 'explorer.useChevrons'], - ['Preferences.get', 'explorer.confirmdelete'], - ['Preferences.get', 'explorer.confirmpaste'], - ['Preferences.get', 'explorer.sourceControlDecorations'], - ['Workspace.getPath'], - ['FileSystem.getPathSeparator', '/workspace'], - ['FileSystem.readDirWithFileTypes', '/workspace'], - ]) -}) diff --git a/packages/explorer-view/test/Main.test.ts b/packages/explorer-view/test/Main.test.ts deleted file mode 100644 index 8f5562c..0000000 --- a/packages/explorer-view/test/Main.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { expect, test } from '@jest/globals' -import { mockWorkerGlobalRpc } from '@lvce-editor/rpc' -import { main } from '../src/parts/Main/Main.ts' - -test('main', async () => { - const { dispose, start } = mockWorkerGlobalRpc() - const mainPromise = main() - start() - await expect(mainPromise).resolves.toBeUndefined() - dispose() -}) diff --git a/packages/explorer-view/test/MakeExpanded.test.ts b/packages/explorer-view/test/MakeExpanded.test.ts deleted file mode 100644 index 024c61b..0000000 --- a/packages/explorer-view/test/MakeExpanded.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { makeExpanded } from '../src/parts/MakeExpanded/MakeExpanded.ts' - -test('makeExpanded - directory', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.Directory, - } - const result = makeExpanded(dirent) - expect(result).toEqual({ - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: DirentType.DirectoryExpanded, - }) -}) - -test('makeExpanded - file', () => { - const dirent: ExplorerItem = { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - } - const result = makeExpanded(dirent) - expect(result).toEqual(dirent) -}) diff --git a/packages/explorer-view/test/NewDirent.test.ts b/packages/explorer-view/test/NewDirent.test.ts deleted file mode 100644 index 05ae7b1..0000000 --- a/packages/explorer-view/test/NewDirent.test.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { newDirent } from '../src/parts/NewDirent/NewDirent.ts' - -const handleFileIcons = (requests: readonly any[]): readonly string[] => { - return requests.map((param) => { - if (param.type === 2) { - return `folder-icon` - } - return `file-icon` - }) -} - -test('newDirent sets focus and updates state when no item is focused', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() {}, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'(...params: any[]) { - return handleFileIcons(params[0]) - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - items: [], - } - const mockEditingType = 1 - - const result = await newDirent(mockState, mockEditingType) - expect(mockRpc.invocations).toEqual([]) - expect(result).toEqual({ - ...mockState, - editingIndex: 0, - editingType: mockEditingType, - editingValue: '', - focus: 2, - focusedIndex: 0, - items: [ - { - depth: 0, - icon: '', - name: '', - path: '/', - posInSet: 1, - selected: false, - setSize: 1, - type: 107, - }, - ], - }) -}) - -test('newDirent handles directory click when focused item is a directory', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() {}, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'(...params: any[]) { - return handleFileIcons(params[0]) - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], - } - const mockEditingType = 1 - - const result = await newDirent(mockState, mockEditingType) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) - expect(result).toEqual({ - ...mockState, - editingIndex: 1, - editingType: mockEditingType, - editingValue: '', - focus: 2, - focusedIndex: 1, - items: [ - { depth: 0, name: 'test', path: '/test', selected: false, setSize: 1, type: DirentType.DirectoryExpanded }, - { - depth: 1, - icon: '', - name: '', - path: '/test', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.EditingFile, - }, - ], - visibleExplorerItems: expect.anything(), - }) -}) - -test('newDirent updates state when focused item is not a directory', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() {}, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'(...params: any[]) { - return handleFileIcons(params[0]) - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - const mockEditingType = 1 - - const result = await newDirent(mockState, mockEditingType) - expect(mockRpc.invocations).toEqual([]) - expect(result).toEqual({ - ...mockState, - editingIndex: 1, - editingType: mockEditingType, - editingValue: '', - focus: 2, - focusedIndex: 1, - items: [ - { - depth: 0, - name: 'test.txt', - path: '/test.txt', - selected: false, - type: DirentType.File, - }, - { - depth: 0, - icon: '', - name: '', - path: '/', - posInSet: 1, - selected: false, - setSize: 1, - type: DirentType.EditingFile, - }, - ], - visibleExplorerItems: expect.anything(), - }) -}) - -test('newDirent expands a closed folder when creating a file inside it', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() {}, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'(...params: any[]) { - return handleFileIcons(params[0]) - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.Directory }], - } - const mockEditingType = 1 - - const result = await newDirent(mockState, mockEditingType) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/folder']]) - // The folder should be expanded (type changed to DirectoryExpanded) - expect(result.items[0].type).toBe(DirentType.DirectoryExpanded) - expect(result.editingIndex).toBe(1) - expect(result.items[1].type).toBe(DirentType.EditingFile) -}) diff --git a/packages/explorer-view/test/NewFile.test.ts b/packages/explorer-view/test/NewFile.test.ts deleted file mode 100644 index 1561a5e..0000000 --- a/packages/explorer-view/test/NewFile.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import { newFile } from '../src/parts/NewFile/NewFile.ts' - -test('newFile', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() { - return undefined - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'(requests: readonly any[]) { - return requests.map((param) => { - if (param.type === 2) { - return `folder-icon` - } - return `file-icon` - }) - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'testfolder', path: '/testfolder', selected: false, type: DirentType.Directory }], - maxLineY: 1, - } - - const result = await newFile(state) - expect(result).toEqual({ - ...state, - editingIndex: 1, - editingType: ExplorerEditingType.CreateFile, - editingValue: '', - focus: 2, - focusedIndex: 1, - items: [ - { - depth: 0, - name: 'testfolder', - path: '/testfolder', - selected: false, - setSize: 1, - type: DirentType.DirectoryExpanded, - }, - { - depth: 1, - icon: '', - name: '', - path: '/testfolder', - posInSet: 1, - selected: false, - setSize: 2, - type: DirentType.EditingFile, - }, - ], - visibleExplorerItems: expect.anything(), - }) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/testfolder']]) -}) diff --git a/packages/explorer-view/test/NewFolder.test.ts b/packages/explorer-view/test/NewFolder.test.ts deleted file mode 100644 index ecffcc0..0000000 --- a/packages/explorer-view/test/NewFolder.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import { newFolder } from '../src/parts/NewFolder/NewFolder.ts' - -test('newFolder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.getPathSeparator'() { - return '/' - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'Focus.setFocus'() { - return undefined - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [''] - }, - 'Preferences.get'() { - return false - }, - 'Workspace.getPath'() { - return '/new/path' - }, - }) - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - items: [], - } - - const result = await newFolder(mockState) - expect(result).toEqual({ - ...mockState, - editingIndex: 0, - editingType: ExplorerEditingType.CreateFolder, - editingValue: '', - focus: 2, - focusedIndex: 0, - items: [ - { - depth: 0, - icon: '', - name: '', - path: '/', - posInSet: 1, - selected: false, - setSize: 1, - type: 103, - }, - ], - }) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/NormalizeDecorations.test.ts b/packages/explorer-view/test/NormalizeDecorations.test.ts deleted file mode 100644 index 6dd721f..0000000 --- a/packages/explorer-view/test/NormalizeDecorations.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { FileDecoration } from '../src/parts/FileDecoration/FileDecoration.ts' -import { normalizeDecorations } from '../src/parts/NormalizeDecorations/NormalizeDecorations.ts' - -test('normalizeDecorations - returns empty array when input is null', () => { - const result = normalizeDecorations(null as any) - expect(result).toEqual([]) -}) - -test('normalizeDecorations - returns empty array when input is undefined', () => { - const result = normalizeDecorations(undefined as any) - expect(result).toEqual([]) -}) - -test('normalizeDecorations - returns empty array when input is not an array', () => { - const result = normalizeDecorations('not an array' as any) - expect(result).toEqual([]) -}) - -test('normalizeDecorations - returns empty array when input is an empty array', () => { - const result = normalizeDecorations([]) - expect(result).toEqual([]) -}) - -test('normalizeDecorations - filters out invalid decorations (null)', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - null as any, - { decoration: 'added', uri: 'file:///test2.txt' }, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 'file:///test2.txt' }, - ]) -}) - -test('normalizeDecorations - filters out invalid decorations (undefined)', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - undefined as any, - { decoration: 'added', uri: 'file:///test2.txt' }, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 'file:///test2.txt' }, - ]) -}) - -test('normalizeDecorations - filters out decorations with missing decoration property', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - { uri: 'file:///test2.txt' } as any, - { decoration: 'added', uri: 'file:///test3.txt' }, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 'file:///test3.txt' }, - ]) -}) - -test('normalizeDecorations - filters out decorations with missing uri property', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added' } as any, - { decoration: 'deleted', uri: 'file:///test3.txt' }, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'deleted', uri: 'file:///test3.txt' }, - ]) -}) - -test('normalizeDecorations - filters out decorations with non-string decoration property', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 123, uri: 'file:///test2.txt' } as any, - { decoration: 'added', uri: 'file:///test3.txt' }, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 'file:///test3.txt' }, - ]) -}) - -test('normalizeDecorations - filters out decorations with non-string uri property', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 123 } as any, - { decoration: 'deleted', uri: 'file:///test3.txt' }, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'deleted', uri: 'file:///test3.txt' }, - ]) -}) - -test('normalizeDecorations - returns all valid decorations', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 'file:///test2.txt' }, - { decoration: 'deleted', uri: 'file:///test3.txt' }, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 'file:///test2.txt' }, - { decoration: 'deleted', uri: 'file:///test3.txt' }, - ]) -}) - -test('normalizeDecorations - handles mixed valid and invalid decorations', () => { - const decorations: FileDecoration[] = [ - { decoration: 'modified', uri: 'file:///test.txt' }, - null as any, - { decoration: 'added', uri: 'file:///test2.txt' }, - undefined as any, - { decoration: 'deleted' } as any, - { decoration: 'renamed', uri: 'file:///test3.txt' }, - { uri: 'file:///test4.txt' } as any, - ] - const result = normalizeDecorations(decorations) - expect(result).toEqual([ - { decoration: 'modified', uri: 'file:///test.txt' }, - { decoration: 'added', uri: 'file:///test2.txt' }, - { decoration: 'renamed', uri: 'file:///test3.txt' }, - ]) -}) - -test('normalizeDecorations - returns empty array when all decorations are invalid', () => { - const decorations: FileDecoration[] = [null as any, undefined as any, { decoration: 'added' } as any, { uri: 'file:///test.txt' } as any] - const result = normalizeDecorations(decorations) - expect(result).toEqual([]) -}) diff --git a/packages/explorer-view/test/OpenContainingFolder.test.ts b/packages/explorer-view/test/OpenContainingFolder.test.ts deleted file mode 100644 index 5b324e8..0000000 --- a/packages/explorer-view/test/OpenContainingFolder.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker as RpcRendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { openContainingFolder } from '../src/parts/OpenContainingFolder/OpenContainingFolder.ts' - -test('openContainingFolder', async () => { - using mockRpc = RpcRendererWorker.registerMockRpc({ - 'OpenNativeFolder.openNativeFolder'() {}, - }) - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: 1 }], - } - const result = await openContainingFolder(mockState) - expect(mockRpc.invocations).toEqual(expect.arrayContaining([['OpenNativeFolder.openNativeFolder', '']])) - expect(result).toBe(mockState) -}) diff --git a/packages/explorer-view/test/OpenDiff.test.ts b/packages/explorer-view/test/OpenDiff.test.ts deleted file mode 100644 index b75a5c2..0000000 --- a/packages/explorer-view/test/OpenDiff.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { openDiff } from '../src/parts/OpenDiff/OpenDiff.ts' - -test('openDiff opens file diff uri', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Main.openUri'() {}, - }) - - await openDiff('/left.txt', '/right.txt', true) - - expect(mockRpc.invocations).toEqual([['Main.openUri', 'diff:///left.txt<->/right.txt', true]]) -}) diff --git a/packages/explorer-view/test/OpenUri.test.ts b/packages/explorer-view/test/OpenUri.test.ts deleted file mode 100644 index a1cba7a..0000000 --- a/packages/explorer-view/test/OpenUri.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { openUri } from '../src/parts/OpenUri/OpenUri.ts' - -test('openUri calls ParentRpc.invoke with correct parameters', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Main.openUri'() {}, - }) - const mockUri = 'file:///test.txt' - const mockFocus = true - await openUri(mockUri, mockFocus) - expect(mockRpc.invocations).toEqual([['Main.openUri', mockUri, mockFocus]]) -}) - -test('openUri calls ParentRpc.invoke with focus false', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'Main.openUri'() {}, - }) - const mockUri = 'file:///test.txt' - const mockFocus = false - await openUri(mockUri, mockFocus) - expect(mockRpc.invocations).toEqual([['Main.openUri', mockUri, mockFocus]]) -}) diff --git a/packages/explorer-view/test/OrderDirents.test.ts b/packages/explorer-view/test/OrderDirents.test.ts deleted file mode 100644 index 99e6f95..0000000 --- a/packages/explorer-view/test/OrderDirents.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import { orderDirents } from '../src/parts/OrderDirents/OrderDirents.ts' - -test('empty array returns empty array', () => { - expect(orderDirents([])).toEqual([]) -}) - -test('orders single top level item', () => { - const input: readonly ExplorerItem[] = [{ depth: 1, name: 'file1', path: '/file1', selected: false, type: 1 }] - expect(orderDirents(input)).toEqual(input) -}) - -test('orders multiple top level items', () => { - const input: readonly ExplorerItem[] = [ - { depth: 1, name: 'file2', path: '/file2', selected: false, type: 1 }, - { depth: 1, name: 'file1', path: '/file1', selected: false, type: 1 }, - ] - const expected = [ - { depth: 1, name: 'file2', path: '/file2', selected: false, type: 1 }, - { depth: 1, name: 'file1', path: '/file1', selected: false, type: 1 }, - ] - expect(orderDirents(input)).toEqual(expected) -}) - -test('orders nested items correctly', () => { - const input: readonly ExplorerItem[] = [ - { depth: 2, name: 'file1', path: '/folder1/file1', selected: false, type: 1 }, - { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, - { depth: 2, name: 'file2', path: '/folder2/file2', selected: false, type: 1 }, - { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, - ] - const expected = [ - { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, - { depth: 2, name: 'file1', path: '/folder1/file1', selected: false, type: 1 }, - { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, - { depth: 2, name: 'file2', path: '/folder2/file2', selected: false, type: 1 }, - ] - expect(orderDirents(input)).toEqual(expected) -}) - -test('orders deeply nested items correctly', () => { - const input: readonly ExplorerItem[] = [ - { depth: 3, name: 'file1', path: '/folder1/subfolder/file1', selected: false, type: 1 }, - { depth: 2, name: 'subfolder', path: '/folder1/subfolder', selected: false, type: 2 }, - { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, - { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, - ] - const expected = [ - { depth: 1, name: 'folder1', path: '/folder1', selected: false, type: 2 }, - { depth: 2, name: 'subfolder', path: '/folder1/subfolder', selected: false, type: 2 }, - { depth: 3, name: 'file1', path: '/folder1/subfolder/file1', selected: false, type: 1 }, - { depth: 1, name: 'folder2', path: '/folder2', selected: false, type: 2 }, - ] - expect(orderDirents(input)).toEqual(expected) -}) diff --git a/packages/explorer-view/test/PasteShouldMove.test.ts b/packages/explorer-view/test/PasteShouldMove.test.ts deleted file mode 100644 index abcde8c..0000000 --- a/packages/explorer-view/test/PasteShouldMove.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { handleCopy } from '../src/parts/HandleCopy/HandleCopy.ts' -import { handleCut } from '../src/parts/HandleCut/HandleCut.ts' -import { handlePaste } from '../src/parts/HandlePaste/HandlePaste.ts' - -test('pasteShouldMove should be true after cut operation', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeNativeFiles'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - - const result = await handleCut(state) - - expect(result.pasteShouldMove).toBe(true) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'cut', ['/test.txt']]]) -}) - -test('pasteShouldMove should be false after copy operation', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'ClipBoard.writeNativeFiles'() {}, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - - const result = await handleCopy(state) - - expect(result.pasteShouldMove).toBe(false) - expect(mockRpc.invocations).toEqual([['ClipBoard.writeNativeFiles', 'copy', ['/test.txt']]]) -}) - -test('pasteShouldMove should be reset to false after paste operation', async () => { - RendererWorker.registerMockRpc({ - 'ClipBoard.readNativeFiles'() { - return { - files: ['/source/file.txt'], - type: 'copy', - } - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.rename'() {}, - 'IconTheme.getIcons'() { - return [''] - }, - 'Preferences.get'() { - return false - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, // No item focused, use root as target - pasteShouldMove: true, // Simulate state after cut operation - } - - const result = await handlePaste(state) - - expect(result.pasteShouldMove).toBe(false) -}) diff --git a/packages/explorer-view/test/Path.test.ts b/packages/explorer-view/test/Path.test.ts deleted file mode 100644 index a8b2785..0000000 --- a/packages/explorer-view/test/Path.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { test, expect } from '@jest/globals' -import { dirname, join, getBaseName } from '../src/parts/Path/Path.ts' - -test('dirname returns parent directory', () => { - expect(dirname('/', '/home/user/file.txt')).toBe('/home/user') - expect(dirname('/', '/home/user/')).toBe('/home/user') - expect(dirname('/', '/home/user')).toBe('/home') - expect(dirname('/', 'file.txt')).toBe('file.txt') - expect(dirname('/', '/')).toBe('') -}) - -test('join combines path parts', () => { - expect(join('/', 'home', 'user', 'file.txt')).toBe('home/user/file.txt') - expect(join('/', 'home', 'user', '')).toBe('home/user/') - expect(join('/', 'home', 'user')).toBe('home/user') - expect(join('/', '', 'home', 'user')).toBe('/home/user') -}) - -test('getBaseName returns last path component', () => { - expect(getBaseName('/', '/home/user/file.txt')).toBe('file.txt') - expect(getBaseName('/', '/home/user/')).toBe('') - expect(getBaseName('/', '/home/user')).toBe('user') - expect(getBaseName('/', 'file.txt')).toBe('file.txt') - expect(getBaseName('/', '/')).toBe('') -}) diff --git a/packages/explorer-view/test/Refresh.test.ts b/packages/explorer-view/test/Refresh.test.ts deleted file mode 100644 index 1b0b366..0000000 --- a/packages/explorer-view/test/Refresh.test.ts +++ /dev/null @@ -1,290 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { DirectoryExpanded, File } from '../src/parts/DirentType/DirentType.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { refresh } from '../src/parts/Refresh/Refresh.ts' - -test('refresh - empty state', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = createDefaultState() - const result = await refresh(state) - expect(result.items).toHaveLength(0) - expect(result.icons).toHaveLength(0) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/']]) -}) - -test('refresh - with top level items', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file1', type: DirentType.File }, - { name: 'file2', type: DirentType.File }, - ] - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = createDefaultState() - const result = await refresh(state) - expect(result.items).toHaveLength(2) - expect(result.items[0].name).toBe('file1') - expect(result.items[1].name).toBe('file2') - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/']]) -}) - -test('refresh - preserve expanded folder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'(_path: string) { - if (_path === '/') { - return [{ name: 'folder1', type: DirentType.Directory }] - } - if (_path === '/folder1') { - return [ - { name: 'file1.txt', type: 'file' }, - { name: 'file2.txt', type: 'file' }, - ] - } - return [] - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, - { depth: 1, name: 'file2.txt', path: '/folder1/file2.txt', selected: false, type: File }, - ], - } - - const result = await refresh(state) - expect(result.items).toHaveLength(3) - expect(result.items[0].name).toBe('folder1') - expect(result.items[0].type).toBe(DirectoryExpanded) - expect(result.items[1].name).toBe('file1.txt') - expect(result.items[2].name).toBe('file2.txt') - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/'], - ['FileSystem.readDirWithFileTypes', '/folder1'], - ]) -}) - -test('refresh - remove expanded folder that no longer exists', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [{ name: 'file1.txt', type: DirentType.File }] - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, - ], - } - - const result = await refresh(state) - expect(result.items).toHaveLength(1) - expect(result.items[0].name).toBe('file1.txt') - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/'], - ['FileSystem.readDirWithFileTypes', '/folder1'], - ]) -}) - -test('refresh - nested expanded folders', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'(path: string) { - if (path === '/') { - return [{ name: 'folder1', type: DirentType.Directory }] - } - if (path === '/folder1') { - return [{ name: 'folder2', type: DirentType.Directory }] - } - if (path === '/folder1/folder2') { - return [{ name: 'file1.txt', type: DirentType.File }] - } - return [] - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 1, name: 'folder2', path: '/folder1/folder2', selected: false, type: DirectoryExpanded }, - { depth: 2, name: 'file1.txt', path: '/folder1/folder2/file1.txt', selected: false, type: File }, - ], - } - - const result = await refresh(state) - expect(result.items).toHaveLength(3) - expect(result.items[0].name).toBe('folder1') - expect(result.items[0].type).toBe(DirectoryExpanded) - expect(result.items[1].name).toBe('folder2') - expect(result.items[1].type).toBe(DirectoryExpanded) - expect(result.items[2].name).toBe('file1.txt') - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/'], - ['FileSystem.readDirWithFileTypes', '/folder1'], - ['FileSystem.readDirWithFileTypes', '/folder1/folder2'], - ]) -}) - -test('refresh - preserve directory types', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'(path: string) { - if (path === '/') { - return [ - { name: 'folder1', type: DirentType.Directory }, - { name: 'file1.txt', type: DirentType.File }, - ] - } - if (path === '/folder1') { - return [ - { name: 'subfolder', type: DirentType.Directory }, - { name: 'file2.txt', type: DirentType.File }, - ] - } - if (path === '/folder1/subfolder') { - return [{ name: 'file3.txt', type: DirentType.File }] - } - return [] - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 1, name: 'subfolder', path: '/folder1/subfolder', selected: false, type: DirectoryExpanded }, - { depth: 2, name: 'file3.txt', path: '/folder1/subfolder/file3.txt', selected: false, type: File }, - { depth: 1, name: 'file2.txt', path: '/folder1/file2.txt', selected: false, type: File }, - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, - ], - } - - const result = await refresh(state) - expect(result.items).toHaveLength(5) - expect(result.items[0].name).toBe('folder1') - expect(result.items[0].type).toBe(DirectoryExpanded) - expect(result.items[1].name).toBe('subfolder') - expect(result.items[1].type).toBe(DirectoryExpanded) - expect(result.items[2].name).toBe('file3.txt') - expect(result.items[2].type).toBe(File) - expect(result.items[3].name).toBe('file2.txt') - expect(result.items[3].type).toBe(File) - expect(result.items[4].name).toBe('file1.txt') - expect(result.items[4].type).toBe(File) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/'], - ['FileSystem.readDirWithFileTypes', '/folder1'], - ['FileSystem.readDirWithFileTypes', '/folder1/subfolder'], - ]) -}) - -test('refresh - check filesystem response', async () => { - const methodCalls: string[] = [] - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'(path: string) { - methodCalls.push('FileSystem.readDirWithFileTypes') - if (path === '/') { - return [ - { name: 'folder1', type: DirentType.Directory }, - { name: 'file1.txt', type: DirentType.File }, - ] - } - return [] - }, - 'IconTheme.getFileIcon'() { - methodCalls.push('IconTheme.getFileIcon') - return '' - }, - 'IconTheme.getFolderIcon'() { - methodCalls.push('IconTheme.getFolderIcon') - return '' - }, - 'IconTheme.getIcons'() { - methodCalls.push('IconTheme.getIcons') - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, - ], - } - - const result = await refresh(state) - expect(methodCalls).toContain('FileSystem.readDirWithFileTypes') - expect(result.items[0].type).toBe(DirectoryExpanded) - expect(result.items[1].type).toBe(File) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/'], - ['FileSystem.readDirWithFileTypes', '/folder1'], - ]) -}) diff --git a/packages/explorer-view/test/RefreshChildDirents.test.ts b/packages/explorer-view/test/RefreshChildDirents.test.ts deleted file mode 100644 index cfbd2dc..0000000 --- a/packages/explorer-view/test/RefreshChildDirents.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { Directory, DirectoryExpanded } from '../src/parts/DirentType/DirentType.ts' -import { refreshChildDirents } from '../src/parts/RefreshChildDirents/RefreshChildDirents.ts' - -test('refreshChildDirents - basic', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file1.txt', type: 'file' }, - { name: 'folder1', type: 'directory' }, - ] - }, - }) - - const folder = { depth: 0, name: 'test', path: '/test', selected: false, type: Directory } - const result = await refreshChildDirents(folder, '/', []) - expect(result).toHaveLength(2) - expect(result[0].name).toBe('file1.txt') - expect(result[0].path).toBe('/test/file1.txt') - expect(result[0].depth).toBe(1) - expect(result[1].name).toBe('folder1') - expect(result[1].path).toBe('/test/folder1') - expect(result[1].depth).toBe(1) - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/test']]) -}) - -test('refreshChildDirents - with expanded folder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'(path?: string) { - if (path === '/test') { - return [{ name: 'folder1', type: 'directory' }] - } - if (path === '/test/folder1') { - return [{ name: 'file1.txt', type: 'file' }] - } - return [] - }, - }) - - const folder = { depth: 0, name: 'test', path: '/test', selected: false, type: Directory } - const result = await refreshChildDirents(folder, '/', ['/test/folder1']) - expect(result).toHaveLength(2) - expect(result[0].name).toBe('folder1') - expect(result[0].path).toBe('/test/folder1') - expect(result[0].type).toBe(DirectoryExpanded) - expect(result[0].depth).toBe(1) - expect(result[1].name).toBe('file1.txt') - expect(result[1].path).toBe('/test/folder1/file1.txt') - expect(result[1].depth).toBe(2) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/test'], - ['FileSystem.readDirWithFileTypes', '/test/folder1'], - ]) -}) diff --git a/packages/explorer-view/test/RemoveDirent.test.ts b/packages/explorer-view/test/RemoveDirent.test.ts deleted file mode 100644 index 727b874..0000000 --- a/packages/explorer-view/test/RemoveDirent.test.ts +++ /dev/null @@ -1,417 +0,0 @@ -import { test, expect } from '@jest/globals' -import { jest } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { Directory, DirectoryExpanded, File } from '../src/parts/DirentType/DirentType.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { removeDirent } from '../src/parts/RemoveDirent/RemoveDirent.ts' - -test('removeDirent - removes focused item', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(0) - expect(result.focusedIndex).toBe(-1) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.remove', '/file1.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('removeDirent - removes multiple selected items', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [ - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: true, type: File }, - { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, - ], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(0) - expect(result.focusedIndex).toBe(-1) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.remove', '/file1.txt'], - ['FileSystem.remove', '/file2.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('removeDirent - removes focused item and selected items', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [ - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, - { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, - { depth: 0, name: 'file3.txt', path: '/file3.txt', selected: true, type: File }, - ], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(0) - expect(result.focusedIndex).toBe(-1) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.remove', '/file1.txt'], - ['FileSystem.remove', '/file2.txt'], - ['FileSystem.remove', '/file3.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('remove file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [{ name: 'folder1', type: DirentType.Directory }] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 1, - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: Directory }, - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }, - ], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(1) - expect(result.items[0].name).toBe('folder1') - expect(result.focusedIndex).toBe(0) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.remove', '/file1.txt'], - ['FileSystem.readDirWithFileTypes', '/'], - ]) -}) - -test('remove folder with children', async () => { - RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, - ], - root: '/', - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(0) - expect(result.focusedIndex).toBe(-1) -}) - -test('remove file from expanded folder', async () => { - RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'(path: string) { - if (path === '/') { - return [{ name: 'folder1', type: DirentType.Directory }] - } - if (path === '/folder1') { - return [] - } - return [] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 1, - items: [ - { depth: 0, name: 'folder1', path: '/folder1', selected: false, type: DirectoryExpanded }, - { depth: 1, name: 'file1.txt', path: '/folder1/file1.txt', selected: false, type: File }, - ], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(1) - expect(result.items[0].name).toBe('folder1') - expect(result.items[0].type).toBe(DirectoryExpanded) - expect(result.focusedIndex).toBe(0) -}) - -test.skip('removeDirent - with confirmation enabled and user confirms', async () => { - RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'(_message?: string) { - return true - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(0) - expect(result.focusedIndex).toBe(-1) -}) - -test.skip('removeDirent - with confirmation enabled and user cancels', async () => { - RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'(_message?: string) { - return false - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [ - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: true, type: File }, - { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, - ], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(2) - expect(result.focusedIndex).toBe(0) -}) - -test('removeDirent - shows error message when file operation fails', async () => { - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) - const confirmFn = jest.fn() - confirmFn.mockImplementation(() => true) - RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'(message?: string) { - return confirmFn(message) - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - throw new Error('Permission denied') - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], - } - - const result = await removeDirent(state) - expect(result).toBe(state) - expect(confirmFn).toHaveBeenCalledWith('Error: Permission denied') - expect(consoleErrorSpy).toHaveBeenCalledTimes(1) - expect(consoleErrorSpy).toHaveBeenCalledWith( - expect.objectContaining({ - message: expect.stringContaining('Failed to apply file operations: Permission denied'), - }), - ) - consoleErrorSpy.mockRestore() -}) - -test('removeDirent - shows error message for multiple files when operation fails', async () => { - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) - const confirmFn = jest.fn() - confirmFn.mockImplementation(() => true) - RendererWorker.registerMockRpc({ - 'ConfirmPrompt.prompt'(message?: string) { - return confirmFn(message) - }, - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - throw new Error('Access denied') - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [ - { depth: 0, name: 'file1.txt', path: '/file1.txt', selected: true, type: File }, - { depth: 0, name: 'file2.txt', path: '/file2.txt', selected: true, type: File }, - ], - } - - const result = await removeDirent(state) - expect(result).toBe(state) - expect(confirmFn).toHaveBeenCalledWith('Error: Access denied') - expect(consoleErrorSpy).toHaveBeenCalledTimes(1) - expect(consoleErrorSpy).toHaveBeenCalledWith( - expect.objectContaining({ - message: expect.stringContaining('Failed to apply file operations: Access denied'), - }), - ) - consoleErrorSpy.mockRestore() -}) - -test('removeDirent - continues normally when no error occurs', async () => { - RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - 'FileSystem.remove'() { - return - }, - 'IconTheme.getFileIcon'() { - return '' - }, - 'IconTheme.getFolderIcon'() { - return '' - }, - 'IconTheme.getIcons'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - confirmDelete: false, - focusedIndex: 0, - items: [{ depth: 0, name: 'file1.txt', path: '/file1.txt', selected: false, type: File }], - } - - const result = await removeDirent(state) - expect(result.items).toHaveLength(0) - expect(result.focusedIndex).toBe(-1) -}) diff --git a/packages/explorer-view/test/RenameDirent.test.ts b/packages/explorer-view/test/RenameDirent.test.ts deleted file mode 100644 index d873733..0000000 --- a/packages/explorer-view/test/RenameDirent.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' -import * as InputSource from '../src/parts/InputSource/InputSource.ts' -import { renameDirent } from '../src/parts/RenameDirent/RenameDirent.ts' - -test('renameDirent updates state with editing properties', async () => { - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - icons: [''], - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - - const result = await renameDirent(mockState) - expect(result).toEqual({ - ...mockState, - editingIcon: '', - editingIndex: 0, - editingSelectionEnd: 4, - editingSelectionStart: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'test.txt', - focus: FocusId.Input, - inputSource: InputSource.Script, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.EditingFile }], - }) -}) - -test('renameDirent updates state with editing properties for folder', async () => { - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - icons: [''], - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], - } - - const result = await renameDirent(mockState) - expect(result).toEqual({ - ...mockState, - editingIcon: '', - editingIndex: 0, - editingSelectionEnd: 4, - editingSelectionStart: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'test', - focus: FocusId.Input, - inputSource: InputSource.Script, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.EditingFolder }], - }) -}) - -test('renameDirent handles empty state', async () => { - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: -1, - items: [], - } - - const result = await renameDirent(mockState) - expect(result).toBe(mockState) -}) - -test('renameDirent preserves icon when entering edit mode', async () => { - const mockState: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - icons: ['file-icon'], - items: [{ depth: 0, icon: 'file-icon', name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - minLineY: 0, - } - - const result = await renameDirent(mockState) - expect(result).toEqual({ - ...mockState, - editingIcon: 'file-icon', - editingIndex: 0, - editingSelectionEnd: 4, - editingSelectionStart: 0, - editingType: ExplorerEditingType.Rename, - editingValue: 'test.txt', - focus: FocusId.Input, - inputSource: InputSource.Script, - items: [{ depth: 0, icon: 'file-icon', name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.EditingFile }], - }) -}) diff --git a/packages/explorer-view/test/Render2.test.ts b/packages/explorer-view/test/Render2.test.ts deleted file mode 100644 index b3455e0..0000000 --- a/packages/explorer-view/test/Render2.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DiffType from '../src/parts/DiffType/DiffType.ts' -import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' -import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' -import * as Render2 from '../src/parts/Render2/Render2.ts' - -test('render2 - basic', () => { - const uid = 1 - const diffResult = [DiffType.RenderItems, DiffType.RenderFocus] - const oldState = createDefaultState() - const newState = { ...oldState } - ExplorerStates.set(uid, oldState, newState) - const result = Render2.render2(uid, diffResult) - expect(result).toEqual([ - [ - 'Viewlet.setDom2', - 1, - [ - { - childCount: 1, - className: 'Viewlet Explorer', - role: 'none', - type: 4, - }, - { - ariaActiveDescendant: 'TreeItemActive', - ariaLabel: 'Files Explorer', - childCount: 0, - className: 'ListItems', - onBlur: DomEventListenerFunctions.HandleListBlur, - onClick: DomEventListenerFunctions.HandleClick, - onContextMenu: DomEventListenerFunctions.HandleContextMenu, - onDblClick: DomEventListenerFunctions.HandleDoubleClick, - onDragEnd: DomEventListenerFunctions.HandleDragEnd, - onDragLeave: DomEventListenerFunctions.HandleDragLeave, - onDragOver: DomEventListenerFunctions.HandleDragOver, - onDragStart: DomEventListenerFunctions.HandleDragStart, - onDrop: DomEventListenerFunctions.HandleDrop, - onFocus: DomEventListenerFunctions.HandleListFocus, - onPointerDown: DomEventListenerFunctions.HandlePointerDown, - onWheel: DomEventListenerFunctions.HandleWheel, - // onKeyDown: 'handleListKeyDown', - role: 'tree', - tabIndex: 0, - type: 4, - }, - ], - ], - ]) -}) diff --git a/packages/explorer-view/test/RenderActions2.test.ts b/packages/explorer-view/test/RenderActions2.test.ts deleted file mode 100644 index b5df30a..0000000 --- a/packages/explorer-view/test/RenderActions2.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' -import { renderActions } from '../src/parts/RenderActions2/RenderActions2.ts' - -test('should render actions for valid uid', () => { - const uid = 123 - const mockState = { ...createDefaultState(), root: '/test/path' } - - // Set up the state in ExplorerStates - ExplorerStates.set(uid, mockState, mockState) - - const result = renderActions(uid) - - // The function should return an array of VirtualDomNode - expect(Array.isArray(result)).toBe(true) - expect(result.length).toBeGreaterThan(0) - - // Check that the first element is the actions container - expect(result[0]).toHaveProperty('type') - expect(result[0]).toHaveProperty('className') -}) - -test('should handle state with empty root', () => { - const uid = 456 - const mockState = { ...createDefaultState(), root: '' } - - ExplorerStates.set(uid, mockState, mockState) - - const result = renderActions(uid) - - // When root is empty, getActions should return empty array - // but getActionsVirtualDom should still return the container - expect(Array.isArray(result)).toBe(true) - expect(result.length).toBeGreaterThan(0) -}) - -test('should handle different root paths', () => { - const uid = 789 - const mockState = { ...createDefaultState(), root: '/some/other/path' } - - ExplorerStates.set(uid, mockState, mockState) - - const result = renderActions(uid) - - expect(Array.isArray(result)).toBe(true) - expect(result.length).toBeGreaterThan(0) -}) diff --git a/packages/explorer-view/test/RenderCss.test.ts b/packages/explorer-view/test/RenderCss.test.ts deleted file mode 100644 index 872dac9..0000000 --- a/packages/explorer-view/test/RenderCss.test.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { renderCss } from '../src/parts/RenderCss/RenderCss.ts' - -test('renderCss - basic with empty visibleExplorerItems', () => { - const oldState = createDefaultState() - const newState: ExplorerState = { - ...createDefaultState(), - scrollBarHeight: 20, - uid: 123, - visibleExplorerItems: [], - } - const result = renderCss(oldState, newState) - expect(result).toEqual([ - 'Viewlet.setCss', - 123, - `.Explorer { - --ScrollBarThumbHeight: 0px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 20px; - --ErrorMessageLeft: 48px; - --ErrorMessageWidth: 52px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -}`, - ]) -}) - -test('renderCss - with single visibleExplorerItem', () => { - const oldState = createDefaultState() - const newState: ExplorerState = { - ...createDefaultState(), - scrollBarHeight: 15, - uid: 456, - visibleExplorerItems: [ - { - ariaExpanded: undefined, - chevron: 0, - className: 'file', - depth: 0, - hasEditingError: false, - icon: 'file', - id: '1', - indent: 10, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'test.txt', - path: '/test.txt', - posInSet: 1, - selected: false, - setSize: 1, - }, - ], - } - const result = renderCss(oldState, newState) - expect(result).toEqual([ - 'Viewlet.setCss', - 456, - `.Explorer { - --ScrollBarThumbHeight: 0px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 20px; - --ErrorMessageLeft: 48px; - --ErrorMessageWidth: 52px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-10 { - padding-left: 10px; -}`, - ]) -}) - -test('renderCss - with multiple visibleExplorerItems with different indents', () => { - const oldState = createDefaultState() - const newState: ExplorerState = { - ...createDefaultState(), - scrollBarHeight: 25, - uid: 789, - visibleExplorerItems: [ - { - ariaExpanded: 'true', - chevron: 1, - className: 'folder', - depth: 0, - hasEditingError: false, - icon: 'folder', - id: '1', - indent: 0, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'folder1', - path: '/folder1', - posInSet: 1, - selected: false, - setSize: 2, - }, - { - ariaExpanded: undefined, - chevron: 0, - className: 'file', - depth: 1, - hasEditingError: false, - icon: 'file', - id: '2', - indent: 20, - index: 1, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'file1.txt', - path: '/folder1/file1.txt', - posInSet: 1, - selected: false, - setSize: 1, - }, - { - ariaExpanded: undefined, - chevron: 0, - className: 'file', - depth: 1, - hasEditingError: false, - icon: 'file', - id: '3', - indent: 20, - index: 2, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'file2.txt', - path: '/folder1/file2.txt', - posInSet: 2, - selected: false, - setSize: 1, - }, - ], - } - const result = renderCss(oldState, newState) - expect(result).toEqual([ - 'Viewlet.setCss', - 789, - `.Explorer { - --ScrollBarThumbHeight: 0px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 20px; - --ErrorMessageLeft: 48px; - --ErrorMessageWidth: 52px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-0 { - padding-left: 0px; -} -.Indent-20 { - padding-left: 20px; -}`, - ]) -}) - -test('renderCss - with duplicate indents should only generate unique indent classes', () => { - const oldState = createDefaultState() - const newState: ExplorerState = { - ...createDefaultState(), - scrollBarHeight: 30, - uid: 999, - visibleExplorerItems: [ - { - ariaExpanded: undefined, - chevron: 0, - className: 'file', - depth: 0, - hasEditingError: false, - icon: 'file', - id: '1', - indent: 10, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'file1.txt', - path: '/file1.txt', - posInSet: 1, - selected: false, - setSize: 3, - }, - { - ariaExpanded: undefined, - chevron: 0, - className: 'file', - depth: 0, - hasEditingError: false, - icon: 'file', - id: '2', - indent: 10, - index: 1, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'file2.txt', - path: '/file2.txt', - posInSet: 2, - selected: false, - setSize: 3, - }, - { - ariaExpanded: undefined, - chevron: 0, - className: 'file', - depth: 0, - hasEditingError: false, - icon: 'file', - id: '3', - indent: 20, - index: 2, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'file3.txt', - path: '/file3.txt', - posInSet: 3, - selected: false, - setSize: 3, - }, - ], - } - const result = renderCss(oldState, newState) - expect(result).toEqual([ - 'Viewlet.setCss', - 999, - `.Explorer { - --ScrollBarThumbHeight: 0px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 20px; - --ErrorMessageLeft: 48px; - --ErrorMessageWidth: 52px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-10 { - padding-left: 10px; -} -.Indent-20 { - padding-left: 20px; -}`, - ]) -}) - -test('renderCss - with zero scrollBarHeight', () => { - const oldState = createDefaultState() - const newState: ExplorerState = { - ...createDefaultState(), - scrollBarHeight: 0, - uid: 111, - visibleExplorerItems: [ - { - ariaExpanded: undefined, - chevron: 0, - className: 'file', - depth: 0, - hasEditingError: false, - icon: 'file', - id: '1', - indent: 5, - index: 0, - isCut: false, - isEditing: false, - isIgnored: false, - name: 'test.txt', - path: '/test.txt', - posInSet: 1, - selected: false, - setSize: 1, - }, - ], - } - const result = renderCss(oldState, newState) - expect(result).toEqual([ - 'Viewlet.setCss', - 111, - `.Explorer { - --ScrollBarThumbHeight: 0px; - --ScrollBarThumbTop: 0px; - --ErrorMessageTop: 20px; - --ErrorMessageLeft: 48px; - --ErrorMessageWidth: 52px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -} -.Indent-5 { - padding-left: 5px; -}`, - ]) -}) diff --git a/packages/explorer-view/test/RenderDragData.test.ts b/packages/explorer-view/test/RenderDragData.test.ts deleted file mode 100644 index 369fe63..0000000 --- a/packages/explorer-view/test/RenderDragData.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.js' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' -import { renderDragData } from '../src/parts/RenderDragData/RenderDragData.js' - -test('renderDragData - no items', () => { - const oldState: ExplorerState = createDefaultState() - const newState: ExplorerState = { - ...oldState, - focusedIndex: 0, - items: [], - uid: 123, - } - const result = renderDragData(oldState, newState) - expect(result).toEqual(['Viewlet.setDragData', 123, expect.anything()]) -}) diff --git a/packages/explorer-view/test/RenderEditingSelection.test.ts b/packages/explorer-view/test/RenderEditingSelection.test.ts deleted file mode 100644 index bb8d91d..0000000 --- a/packages/explorer-view/test/RenderEditingSelection.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as InputName from '../src/parts/InputName/InputName.ts' -import { renderEditingSelection } from '../src/parts/RenderEditingSelection/RenderEditingSelection.ts' - -test('renderEditingSelection', () => { - const oldState: ExplorerState = createDefaultState() - const newState: ExplorerState = { - ...createDefaultState(), - editingSelectionEnd: 6, - editingSelectionStart: 1, - } - const result = renderEditingSelection(oldState, newState) - expect(result).toEqual(['Viewlet.setSelectionByName', newState.uid, InputName.ExplorerInput, 1, 6]) -}) diff --git a/packages/explorer-view/test/RenderEventListeners.test.ts b/packages/explorer-view/test/RenderEventListeners.test.ts deleted file mode 100644 index 41e6778..0000000 --- a/packages/explorer-view/test/RenderEventListeners.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { expect, test } from '@jest/globals' -import * as RenderEventListeners from '../src/parts/RenderEventListeners/RenderEventListeners.ts' - -test('renderEventListeners', () => { - const eventListeners = RenderEventListeners.renderEventListeners() - expect(eventListeners).toBeDefined() -}) diff --git a/packages/explorer-view/test/RenderFocus.test.ts b/packages/explorer-view/test/RenderFocus.test.ts deleted file mode 100644 index 71405ed..0000000 --- a/packages/explorer-view/test/RenderFocus.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' -import * as InputName from '../src/parts/InputName/InputName.ts' -import * as InputSource from '../src/parts/InputSource/InputSource.ts' -import { renderFocus } from '../src/parts/RenderFocus/RenderFocus.ts' - -test('empty array when input source is user', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - inputSource: InputSource.User, - } - const result = renderFocus(oldState, newState) - expect(result).toEqual([]) -}) - -test('focus input when focus is input', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - focus: FocusId.Input, - } - const result = renderFocus(oldState, newState) - expect(result).toEqual(['Viewlet.focusElementByName', InputName.ExplorerInput]) -}) - -test('focus list when focus is list', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - focus: FocusId.List, - } - const result = renderFocus(oldState, newState) - expect(result).toEqual(['Viewlet.focusSelector', '.ListItems']) -}) - -test('empty array when no focus state', () => { - const oldState = createDefaultState() - const newState = createDefaultState() - const result = renderFocus(oldState, newState) - expect(result).toEqual([]) -}) diff --git a/packages/explorer-view/test/RenderFocusContext.test.ts b/packages/explorer-view/test/RenderFocusContext.test.ts deleted file mode 100644 index 1c38345..0000000 --- a/packages/explorer-view/test/RenderFocusContext.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { expect, test } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' -import { renderFocusContext } from '../src/parts/RenderFocusContext/RenderFocusContext.ts' -import * as WhenExpression from '../src/parts/WhenExpression/WhenExpression.ts' - -test('should return FocusExplorerEditBox when focus is Input', () => { - const oldState = createDefaultState() - const newState = { ...oldState, focus: FocusId.Input } - - const result = renderFocusContext(oldState, newState) - - expect(result).toEqual(['Viewlet.setFocusContext', newState.uid, WhenExpression.FocusExplorerEditBox]) -}) - -test('should return FocusExplorer when focus is List', () => { - const oldState = createDefaultState() - const newState = { ...oldState, focus: FocusId.List } - - const result = renderFocusContext(oldState, newState) - - expect(result).toEqual(['Viewlet.setFocusContext', newState.uid, WhenExpression.FocusExplorer]) -}) - -test('should return empty array when focus is None', () => { - const oldState = createDefaultState() - const newState = { ...oldState, focus: FocusId.None } - - const result = renderFocusContext(oldState, newState) - - expect(result).toEqual([]) -}) - -test('should return empty array for unknown focus value', () => { - const oldState = createDefaultState() - const newState = { ...oldState, focus: 999 } - - const result = renderFocusContext(oldState, newState) - - expect(result).toEqual([]) -}) diff --git a/packages/explorer-view/test/RenderItems.test.ts b/packages/explorer-view/test/RenderItems.test.ts deleted file mode 100644 index 1e36dc1..0000000 --- a/packages/explorer-view/test/RenderItems.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DomEventListenerFunctions from '../src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts' -import { renderItems } from '../src/parts/RenderItems/RenderItems.ts' - -test('renderItems - basic', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - focused: true, - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: 1, - }, - ], - width: 500, - } - const result = renderItems(oldState, newState) - expect(result[0]).toBe('Viewlet.setDom2') - expect(result[1]).toBeDefined() -}) - -test('renderItems - narrow width', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - focused: true, - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: 1, - }, - ], - width: 400, - } - const result = renderItems(oldState, newState) - expect(result[0]).toBe('Viewlet.setDom2') - expect(result[1]).toBeDefined() -}) - -test('renderItems - load error message', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - errorCode: 'EACCES', - errorMessage: 'permission was denied', - focused: true, - hasError: true, - items: [ - { - depth: 0, - name: 'test', - path: '/test', - selected: false, - type: 1, - }, - ], - root: '/workspace', - } - const result = renderItems(oldState, newState) - const dom = result[2] - expect(dom).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ - className: 'ListItems', - }), - ]), - ) - expect(dom).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - text: 'Could not open folder due to permission was denied (error code: EACCES).', - }), - ]), - ) -}) - -test('renderItems - editing and load error messages are both passed and load error mode is used', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - editingErrorMessage: 'file already exists', - errorCode: 'EACCES', - errorMessage: 'permission was denied', - hasError: true, - root: '/workspace', - } - const result = renderItems(oldState, newState) - const dom = result[2] - expect(dom).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ - className: 'ListItems', - }), - ]), - ) - expect(dom).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - text: 'Could not open folder due to permission was denied (error code: EACCES).', - }), - ]), - ) -}) - -test('renderItems - missing folder load error shows friendly message and button', () => { - const oldState = createDefaultState() - const newState = { - ...createDefaultState(), - errorCode: 'ENOENT', - errorMessage: 'the folder does not exist', - hasError: true, - root: '/workspace/missing-folder', - width: 500, - } - const result = renderItems(oldState, newState) - const dom = result[2] - expect(dom).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - text: 'Could not open "/workspace/missing-folder" because the folder does not exist. It may have been moved or deleted.', - }), - expect.objectContaining({ - className: 'Button ButtonPrimary ButtonWide', - name: 'OpenFolder', - onClick: DomEventListenerFunctions.HandleClickOpenFolder, - }), - expect.objectContaining({ - text: 'Open another folder', - }), - ]), - ) -}) diff --git a/packages/explorer-view/test/RenderValue.test.ts b/packages/explorer-view/test/RenderValue.test.ts deleted file mode 100644 index f91b22d..0000000 --- a/packages/explorer-view/test/RenderValue.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as FocusId from '../src/parts/FocusId/FocusId.ts' -import * as InputName from '../src/parts/InputName/InputName.ts' -import * as InputSource from '../src/parts/InputSource/InputSource.ts' -import { renderValue } from '../src/parts/RenderValue/RenderValue.ts' - -test('should return empty array when inputSource is User', () => { - const oldState = createDefaultState() - const newState = { ...oldState, inputSource: InputSource.User } - - const result = renderValue(oldState, newState) - - expect(result).toEqual([]) -}) - -test('should return setValue command when focus is Input', () => { - const oldState = createDefaultState() - const newState = { ...oldState, editingValue: 'test-value', focus: FocusId.Input } - - const result = renderValue(oldState, newState) - - expect(result).toEqual(['Viewlet.setValueByName', InputName.ExplorerInput, 'test-value']) -}) - -test('should return empty array when focus is not Input', () => { - const oldState = createDefaultState() - const newState = { ...oldState, focus: FocusId.List } - - const result = renderValue(oldState, newState) - - expect(result).toEqual([]) -}) - -test('should return empty array when focus is None', () => { - const oldState = createDefaultState() - const newState = { ...oldState, focus: FocusId.None } - - const result = renderValue(oldState, newState) - - expect(result).toEqual([]) -}) - -test('should return empty array when inputSource is Script and focus is not Input', () => { - const oldState = createDefaultState() - const newState = { ...oldState, focus: FocusId.List, inputSource: InputSource.Script } - - const result = renderValue(oldState, newState) - - expect(result).toEqual([]) -}) diff --git a/packages/explorer-view/test/RequestFileIcons.test.ts b/packages/explorer-view/test/RequestFileIcons.test.ts deleted file mode 100644 index ca3bcc9..0000000 --- a/packages/explorer-view/test/RequestFileIcons.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { test, expect } from '@jest/globals' -import { IconThemeWorker } from '@lvce-editor/rpc-registry' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as RequestFileIcons from '../src/parts/RequestFileIcons/RequestFileIcons.ts' - -test('requestFileIcons - empty requests', async () => { - using mockRpc = IconThemeWorker.registerMockRpc({}) - - const result = await RequestFileIcons.requestFileIcons([]) - expect(result).toEqual([]) - expect(mockRpc.invocations).toEqual([]) -}) - -test('requestFileIcons - file icons', async () => { - const requests = [{ name: 'file.txt', path: '/test/file.txt', type: DirentType.File }] - - using mockRpc = IconThemeWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return ['file-icon'] - }, - }) - - const result = await RequestFileIcons.requestFileIcons(requests) - expect(result).toEqual(['file-icon']) - expect(mockRpc.invocations).toEqual([['IconTheme.getIcons', [{ name: 'file.txt', type: 1 }]]]) -}) - -test('requestFileIcons - folder icons', async () => { - const requests = [{ name: 'folder', path: '/test/folder', type: DirentType.Directory }] - - using mockRpc = IconThemeWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return ['folder-icon'] - }, - }) - - const result = await RequestFileIcons.requestFileIcons(requests) - expect(result).toEqual(['folder-icon']) - expect(mockRpc.invocations).toEqual([['IconTheme.getIcons', [{ name: 'folder', type: 2 }]]]) -}) - -test('requestFileIcons - mixed requests', async () => { - const requests = [ - { name: 'file.txt', path: '/test/file.txt', type: DirentType.File }, - { name: 'folder', path: '/test/folder', type: DirentType.Directory }, - ] - - using mockRpc = IconThemeWorker.registerMockRpc({ - 'IconTheme.getIcons'() { - return ['file-icon', 'folder-icon'] - }, - }) - - const result = await RequestFileIcons.requestFileIcons(requests) - expect(result).toEqual(['file-icon', 'folder-icon']) - expect(mockRpc.invocations).toEqual([ - [ - 'IconTheme.getIcons', - [ - { name: 'file.txt', type: 1 }, - { name: 'folder', type: 2 }, - ], - ], - ]) -}) diff --git a/packages/explorer-view/test/ResolveSymbolicLinks.test.ts b/packages/explorer-view/test/ResolveSymbolicLinks.test.ts deleted file mode 100644 index 32e46b4..0000000 --- a/packages/explorer-view/test/ResolveSymbolicLinks.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { expect, jest, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ErrorCodes from '../src/parts/ErrorCodes/ErrorCodes.ts' -import * as ResolveSymbolicLinks from '../src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts' - -test('should resolve symbolic links to files', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.stat'(path: string) { - if (path.includes('symlink-file')) { - return DirentType.File - } - if (path.includes('symlink-dir')) { - return DirentType.Directory - } - throw new Error(`unexpected path ${path}`) - }, - }) - - const uri = '/test/path' - const rawDirents = [ - { name: 'symlink-file', type: DirentType.Symlink }, - { name: 'regular-file', type: DirentType.File }, - { name: 'symlink-dir', type: DirentType.Symlink }, - ] - - const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - - expect(result).toEqual([ - { name: 'symlink-file', type: DirentType.SymLinkFile }, - { name: 'regular-file', type: DirentType.File }, - { name: 'symlink-dir', type: DirentType.SymLinkFolder }, - ]) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.stat', '/test/path/symlink-file'], - ['FileSystem.stat', '/test/path/symlink-dir'], - ]) -}) - -test('should handle ENOENT errors by returning SymLinkFile type', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.stat'() { - const enoentError = new Error('File not found') as Error & { code: string } - enoentError.code = ErrorCodes.ENOENT - throw enoentError - }, - }) - - const uri = '/test/path' - const rawDirents = [{ name: 'broken-symlink', type: DirentType.Symlink }] - - const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - - expect(result).toEqual([{ name: 'broken-symlink', type: DirentType.SymLinkFile }]) - expect(mockRpc.invocations).toEqual([['FileSystem.stat', '/test/path/broken-symlink']]) -}) - -test('should handle other errors by returning original dirent', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.stat'() { - const otherError = new Error('Permission denied') as Error & { code: string } - otherError.code = 'EACCES' - throw otherError - }, - }) - - // Mock console.error to prevent noise in test output - const originalConsoleError = console.error - console.error = jest.fn() - - const uri = '/test/path' - const rawDirents = [{ name: 'error-symlink', type: DirentType.Symlink }] - - const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - - expect(result).toEqual([{ name: 'error-symlink', type: DirentType.Symlink }]) - expect(mockRpc.invocations).toEqual([['FileSystem.stat', '/test/path/error-symlink']]) - - // Verify console.error was called with the expected message - expect(console.error).toHaveBeenCalledWith('Failed to resolve symbolic link for error-symlink: Error: Permission denied') - - // Restore console.error - console.error = originalConsoleError -}) - -test('should handle non-symbolic link dirents without processing', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - - const uri = '/test/path' - const rawDirents = [ - { name: 'file.txt', type: DirentType.File }, - { name: 'folder', type: DirentType.Directory }, - { name: 'device', type: DirentType.BlockDevice }, - ] - - const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - - expect(result).toEqual(rawDirents) - expect(mockRpc.invocations).toEqual([]) -}) - -test('should handle empty dirents array', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - - const uri = '/test/path' - const rawDirents: any[] = [] - - const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - - expect(result).toEqual([]) - expect(mockRpc.invocations).toEqual([]) -}) - -test('should handle mixed dirents with some symlinks and some regular files', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.stat'(path: string) { - if (path.includes('symlink1')) { - return DirentType.File - } - if (path.includes('symlink2')) { - return DirentType.Directory - } - throw new Error(`unexpected path ${path}`) - }, - }) - - const uri = '/test/path' - const rawDirents = [ - { name: 'file1.txt', type: DirentType.File }, - { name: 'symlink1', type: DirentType.Symlink }, - { name: 'folder', type: DirentType.Directory }, - { name: 'symlink2', type: DirentType.Symlink }, - { name: 'file2.txt', type: DirentType.File }, - ] - - const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - - expect(result).toEqual([ - { name: 'file1.txt', type: DirentType.File }, - { name: 'symlink1', type: DirentType.SymLinkFile }, - { name: 'folder', type: DirentType.Directory }, - { name: 'symlink2', type: DirentType.SymLinkFolder }, - { name: 'file2.txt', type: DirentType.File }, - ]) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.stat', '/test/path/symlink1'], - ['FileSystem.stat', '/test/path/symlink2'], - ]) -}) - -test('should handle symlinks that resolve to different types', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.stat'(path: string) { - if (path.includes('symlink-file')) { - return DirentType.File - } - if (path.includes('symlink-dir')) { - return DirentType.Directory - } - if (path.includes('symlink-socket')) { - return DirentType.Socket - } - throw new Error(`unexpected path ${path}`) - }, - }) - - const uri = '/test/path' - const rawDirents = [ - { name: 'symlink-file', type: DirentType.Symlink }, - { name: 'symlink-dir', type: DirentType.Symlink }, - { name: 'symlink-socket', type: DirentType.Symlink }, - ] - - const result = await ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - - expect(result).toEqual([ - { name: 'symlink-file', type: DirentType.SymLinkFile }, - { name: 'symlink-dir', type: DirentType.SymLinkFolder }, - { name: 'symlink-socket', type: DirentType.Symlink }, - ]) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.stat', '/test/path/symlink-file'], - ['FileSystem.stat', '/test/path/symlink-dir'], - ['FileSystem.stat', '/test/path/symlink-socket'], - ]) -}) diff --git a/packages/explorer-view/test/RestoreDirentType.test.ts b/packages/explorer-view/test/RestoreDirentType.test.ts deleted file mode 100644 index a5e9179..0000000 --- a/packages/explorer-view/test/RestoreDirentType.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { test, expect } from '@jest/globals' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as RestoreDirentType from '../src/parts/RestoreDirentType/RestoreDirentType.ts' - -test('restoreDirentType - directory in expanded paths', () => { - const result = RestoreDirentType.restoreDirentType(DirentType.Directory, '/test', ['/test']) - expect(result).toBe(DirentType.DirectoryExpanded) -}) - -test('restoreDirentType - directory not in expanded paths', () => { - const result = RestoreDirentType.restoreDirentType(DirentType.Directory, '/test', ['/other']) - expect(result).toBe(DirentType.Directory) -}) - -test('restoreDirentType - non-directory type', () => { - const result = RestoreDirentType.restoreDirentType(DirentType.File, '/test', ['/test']) - expect(result).toBe(DirentType.File) -}) diff --git a/packages/explorer-view/test/RestoreState.test.ts b/packages/explorer-view/test/RestoreState.test.ts deleted file mode 100644 index 18e6ae3..0000000 --- a/packages/explorer-view/test/RestoreState.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { test, expect } from '@jest/globals' -import { restoreState } from '../src/parts/RestoreState/RestoreState.ts' - -test('restoreState returns default state when savedState is null', () => { - const result = restoreState(null) - expect(result).toEqual({ - deltaY: 0, - minLineY: 0, - root: '', - }) -}) - -test('restoreState returns default state when savedState is undefined', () => { - const result = restoreState(undefined) - expect(result).toEqual({ - deltaY: 0, - minLineY: 0, - root: '', - }) -}) - -test('restoreState returns correct state with valid input', () => { - const savedState = { - deltaY: 50, - minLineY: 100, - workspacePath: '/test/path', - } - const result = restoreState(savedState) - expect(result).toEqual({ - deltaY: 50, - minLineY: 100, - root: '/test/path', - }) -}) - -test('restoreState handles partial state with missing properties', () => { - const savedState = { - workspacePath: '/test/path', - } - const result = restoreState(savedState) - expect(result).toEqual({ - deltaY: 0, - minLineY: 0, - root: '/test/path', - }) -}) - -test('restoreState handles invalid property types', () => { - const savedState = { - deltaY: true, - minLineY: '100', - workspacePath: 123, - } - const result = restoreState(savedState) - expect(result).toEqual({ - deltaY: 0, - minLineY: 0, - root: '', - }) -}) - -test('restoreState handles non-object input', () => { - const result = restoreState('invalid') - expect(result).toEqual({ - deltaY: 0, - minLineY: 0, - root: '', - }) -}) diff --git a/packages/explorer-view/test/RevealItem.test.ts b/packages/explorer-view/test/RevealItem.test.ts deleted file mode 100644 index d98ddf8..0000000 --- a/packages/explorer-view/test/RevealItem.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { revealItem } from '../src/parts/RevealItem/RevealItem.ts' - -test('revealItem - item not found', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const state = createDefaultState() - const newState = await revealItem(state, 'test') - expect(newState.items).toEqual([]) - expect(mockRpc.invocations).toEqual([]) -}) - -test('revealItem - uri outside root', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - root: '/root', - } - const newState = await revealItem(state, 'non-existent:///some-file.txt') - expect(newState).toEqual(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test('revealItem - item found', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { - depth: 0, - name: 'test', - path: 'test', - selected: false, - type: 1, - }, - ], - } - const newState = await revealItem(state, 'test') - expect(newState.items[0].path).toBe('test') - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/RevealItemHidden.test.ts b/packages/explorer-view/test/RevealItemHidden.test.ts deleted file mode 100644 index 551d701..0000000 --- a/packages/explorer-view/test/RevealItemHidden.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { revealItemHidden } from '../src/parts/RevealItemHidden/RevealItemHidden.ts' - -test('revealItemHidden - reveals hidden item', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'(path: string) { - if (path === '/root') { - return [{ isDirectory: true, name: 'folder1', path: '/root/folder1', type: DirentType.File }] - } - if (path === '/root/folder1') { - return [ - { isDirectory: false, name: 'file1.txt', path: '/root/folder1/file1.txt', type: DirentType.File }, - { isDirectory: false, name: 'file2.txt', path: '/root/folder1/file2.txt', type: DirentType.File }, - ] - } - return [] - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - root: '/root', - } - const newState = await revealItemHidden(state, '/root/folder1/file1.txt') - expect(newState.items.length).toBeGreaterThan(0) - expect(newState.focused).toBe(true) - expect(newState.focusedIndex).toBeGreaterThanOrEqual(0) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/root'], - ['FileSystem.readDirWithFileTypes', '/root/folder1'], - ]) -}) - -test('revealItemHidden - returns same state for empty path parts', async () => { - using mockRpc = RendererWorker.registerMockRpc({}) - const state = createDefaultState() - const newState = await revealItemHidden(state, '') - expect(newState).toEqual(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test('revealItemHidden - throws error for non-existent file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [] - }, - }) - const state = createDefaultState() - await expect(revealItemHidden(state, '/non/existent/file.txt')).rejects.toThrow('File not found in explorer') - expect(mockRpc.invocations).toEqual([ - ['FileSystem.readDirWithFileTypes', '/non'], - ['FileSystem.readDirWithFileTypes', '/non/existent'], - ]) -}) diff --git a/packages/explorer-view/test/RevealItemVisible.test.ts b/packages/explorer-view/test/RevealItemVisible.test.ts deleted file mode 100644 index 95bab7e..0000000 --- a/packages/explorer-view/test/RevealItemVisible.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect } from '@jest/globals' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { revealItemVisible } from '../src/parts/RevealItemVisible/RevealItemVisible.ts' - -test('revealItemVisible - updates state with new scroll position and focus', () => { - const state = createDefaultState() - const result = revealItemVisible(state, 2) - expect(result).toEqual({ - ...state, - focused: true, - focusedIndex: 2, - maxLineY: 2, - minLineY: 2, - }) -}) diff --git a/packages/explorer-view/test/SaveState.test.ts b/packages/explorer-view/test/SaveState.test.ts deleted file mode 100644 index fade7e2..0000000 --- a/packages/explorer-view/test/SaveState.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerStates from '../src/parts/ExplorerStates/ExplorerStates.ts' -import { saveState } from '../src/parts/SaveState/SaveState.ts' - -test('saveState - returns correct saved state', () => { - const uid = 1 - const oldState = createDefaultState() - const newState: ExplorerState = { - ...oldState, - deltaY: 0, - items: [ - { depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.DirectoryExpanded }, - { depth: 1, name: 'file.txt', path: '/test/file.txt', selected: false, type: DirentType.File }, - ], - maxLineY: 100, - minLineY: 0, - root: '/', - } - ExplorerStates.set(uid, oldState, newState) - - const result = saveState(newState) - - expect(result).toEqual({ - deltaY: 0, - expandedPaths: ['/test'], - maxLineY: 100, - minLineY: 0, - root: '/', - }) -}) - -test('saveState - handles empty items', () => { - const uid = 1 - const oldState = createDefaultState() - const newState: ExplorerState = { - ...oldState, - deltaY: 0, - items: [], - maxLineY: 0, - minLineY: 0, - root: '/', - } - ExplorerStates.set(uid, oldState, newState) - - const result = saveState(newState) - - expect(result).toEqual({ - deltaY: 0, - expandedPaths: [], - maxLineY: 0, - minLineY: 0, - root: '/', - }) -}) diff --git a/packages/explorer-view/test/ScrollInto.test.ts b/packages/explorer-view/test/ScrollInto.test.ts deleted file mode 100644 index 4234f5a..0000000 --- a/packages/explorer-view/test/ScrollInto.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { test, expect } from '@jest/globals' -import { scrollInto } from '../src/parts/ScrollInto/ScrollInto.ts' - -test('when index is below minLineY', () => { - const result = scrollInto(5, 10, 20) - expect(result).toEqual({ - newMaxLineY: 10, - newMinLineY: 0, - }) -}) - -test('when index is above maxLineY', () => { - const result = scrollInto(25, 10, 20) - expect(result).toEqual({ - newMaxLineY: 30, - newMinLineY: 20, - }) -}) - -test('when index is within range', () => { - const result = scrollInto(15, 10, 20) - expect(result).toEqual({ - newMaxLineY: 20, - newMinLineY: 10, - }) -}) - -test('when range is odd', () => { - const result = scrollInto(5, 10, 21) - expect(result).toEqual({ - newMaxLineY: 11, - newMinLineY: 0, - }) -}) diff --git a/packages/explorer-view/test/SelectAll.test.ts b/packages/explorer-view/test/SelectAll.test.ts deleted file mode 100644 index 145583c..0000000 --- a/packages/explorer-view/test/SelectAll.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { selectAll } from '../src/parts/SelectAll/SelectAll.ts' - -const createItem = (name: string, selected: boolean): ExplorerItem => ({ - depth: 0, - name, - path: `/${name}`, - selected, - type: 0, -}) - -test('selectAll', () => { - const state = createDefaultState() - const items = [createItem('file1', false), createItem('file2', false), createItem('file3', false)] - const newState = selectAll({ - ...state, - items, - }) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(true) -}) diff --git a/packages/explorer-view/test/SelectDown.test.ts b/packages/explorer-view/test/SelectDown.test.ts deleted file mode 100644 index 28e2d6f..0000000 --- a/packages/explorer-view/test/SelectDown.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { selectDown } from '../src/parts/SelectDown/SelectDown.ts' - -const createTestState = (): ExplorerState => ({ - ...createDefaultState(), - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], -}) - -const createStateWithSelections = (selectedIndices: number[]): ExplorerState => { - const state = createTestState() - return { - ...state, - items: state.items.map((item, index) => ({ - ...item, - selected: selectedIndices.includes(index), - })), - } -} - -test.skip('selectDown - no selection', () => { - const state = createTestState() - const newState = selectDown(state) - expect(newState.items[0].selected).toBe(true) -}) - -test('selectDown - single selection', () => { - const state = createStateWithSelections([0]) - const newState = selectDown(state) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(true) -}) - -test('selectDown - multiple selections', () => { - const state = createStateWithSelections([0, 1]) - const newState = selectDown(state) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(true) -}) - -test('selectDown - at end', () => { - const state = createTestState() - const lastIndex = state.items.length - 1 - const stateWithSelection = createStateWithSelections([lastIndex]) - const newState = selectDown(stateWithSelection) - expect(newState.items[lastIndex].selected).toBe(true) -}) - -test('selectDown - last item', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - ], - } - const newState = selectDown(state) - expect(newState).toBe(state) -}) - -test('selectDown - first item', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - ], - } - const newState = selectDown(state) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(true) -}) - -test.skip('selectDown - multiple items with selection', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const newState = selectDown(state) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(false) -}) - -test('selectDown - multiple items with selection at bottom', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: true, type: 0 }, - ], - } - const newState = selectDown(state) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[1].selected).toBe(false) - expect(newState.items[2].selected).toBe(true) -}) - -test.skip('selectDown - multiple items with multiple selections', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [ - { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const newState = selectDown(state) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(false) -}) diff --git a/packages/explorer-view/test/SelectForCompare.test.ts b/packages/explorer-view/test/SelectForCompare.test.ts deleted file mode 100644 index fa774c6..0000000 --- a/packages/explorer-view/test/SelectForCompare.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { selectForCompare } from '../src/parts/SelectForCompare/SelectForCompare.ts' - -test('selectForCompare - stores focused file uri', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'a.txt', path: '/a.txt', selected: false, type: DirentType.File }], - } - - const result = selectForCompare(state) - - expect(result).toEqual({ - ...state, - compareSourceUri: '/a.txt', - }) -}) - -test('selectForCompare - ignores non-file focus', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 0, - items: [{ depth: 0, name: 'folder', path: '/folder', selected: false, type: DirentType.Directory }], - } - - const result = selectForCompare(state) - - expect(result).toBe(state) -}) diff --git a/packages/explorer-view/test/SelectIndices.test.ts b/packages/explorer-view/test/SelectIndices.test.ts deleted file mode 100644 index e482258..0000000 --- a/packages/explorer-view/test/SelectIndices.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' -import { setSelectedIndices } from '../src/parts/SelectIndices/SelectIndices.js' - -test('setSelectedIndices sets selection for given indices', () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, - { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, - { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, - ], - } - - const newState = setSelectedIndices(state, [0, 2]) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(false) - expect(newState.items[2].selected).toBe(true) -}) diff --git a/packages/explorer-view/test/SelectUp.test.ts b/packages/explorer-view/test/SelectUp.test.ts deleted file mode 100644 index 9c6a814..0000000 --- a/packages/explorer-view/test/SelectUp.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { selectUp } from '../src/parts/SelectUp/SelectUp.ts' - -test('selectUp - first item', () => { - const state = createDefaultState() - const newState = selectUp(state) - expect(newState).toBe(state) -}) - -test('selectUp - second item', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - ], - } - const newState = selectUp(state) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(false) -}) - -test.skip('selectUp - multiple items with selection', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 2, - items: [ - { depth: 1, name: 'a', path: '/a', selected: false, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const newState = selectUp(state) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(false) -}) - -test('selectUp - multiple items with selection at top', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 1, - items: [ - { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: false, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const newState = selectUp(state) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(false) - expect(newState.items[2].selected).toBe(false) -}) - -test.skip('selectUp - multiple items with multiple selections', () => { - const state: ExplorerState = { - ...createDefaultState(), - focusedIndex: 2, - items: [ - { depth: 1, name: 'a', path: '/a', selected: true, type: 0 }, - { depth: 1, name: 'b', path: '/b', selected: true, type: 0 }, - { depth: 1, name: 'c', path: '/c', selected: false, type: 0 }, - ], - } - const newState = selectUp(state) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(false) -}) diff --git a/packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts b/packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts deleted file mode 100644 index e7e35ab..0000000 --- a/packages/explorer-view/test/SendMessagePortToFileSystemWorker.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { sendMessagePortToFileSystemWorker } from '../src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts' - -test('sendMessagePortToFileSystemWorker calls RendererWorker.sendMessagePortToFileSystemWorker with correct parameters', async () => { - const { port1 } = new MessageChannel() - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { - return undefined - }, - }) - - await sendMessagePortToFileSystemWorker(port1) - - expect(mockRpc.invocations).toEqual([ - ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port1, 'FileSystem.handleMessagePort', 0], - ]) -}) - -test('sendMessagePortToFileSystemWorker handles different port types', async () => { - const { port1: port1a } = new MessageChannel() - const { port1: port2a } = new MessageChannel() - - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { - return undefined - }, - }) - - await sendMessagePortToFileSystemWorker(port1a) - await sendMessagePortToFileSystemWorker(port2a) - - expect(mockRpc.invocations).toEqual([ - ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port1a, 'FileSystem.handleMessagePort', 0], - ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port2a, 'FileSystem.handleMessagePort', 0], - ]) -}) - -test('sendMessagePortToFileSystemWorker propagates errors from RendererWorker', async () => { - const { port1 } = new MessageChannel() - - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { - throw new Error('RPC call failed') - }, - }) - - await expect(sendMessagePortToFileSystemWorker(port1)).rejects.toThrow('RPC call failed') - expect(mockRpc.invocations).toEqual([ - ['SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port1, 'FileSystem.handleMessagePort', 0], - ]) -}) - -test('sendMessagePortToFileSystemWorker returns void when successful', async () => { - const { port1 } = new MessageChannel() - - RendererWorker.registerMockRpc({ - 'FileSystem.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker'() { - return undefined - }, - }) - - const result = await sendMessagePortToFileSystemWorker(port1) - expect(result).toBeUndefined() -}) diff --git a/packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts b/packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts deleted file mode 100644 index 5342b06..0000000 --- a/packages/explorer-view/test/SendMessagePortToIconThemeWorker.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { sendMessagePortToIconThemeWorker } from '../src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts' - -test('sendMessagePortToIconThemeWorker calls RendererWorker.sendMessagePortToIconThemeWorker with correct parameters', async () => { - const { port1 } = new MessageChannel() - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { - return undefined - }, - }) - - await sendMessagePortToIconThemeWorker(port1) - - expect(mockRpc.invocations).toEqual([ - ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port1, 'IconTheme.handleMessagePort', 0], - ]) -}) - -test('sendMessagePortToIconThemeWorker handles different port types', async () => { - const { port1: port1a } = new MessageChannel() - const { port1: port2a } = new MessageChannel() - - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { - return undefined - }, - }) - - await sendMessagePortToIconThemeWorker(port1a) - await sendMessagePortToIconThemeWorker(port2a) - - expect(mockRpc.invocations).toEqual([ - ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port1a, 'IconTheme.handleMessagePort', 0], - ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port2a, 'IconTheme.handleMessagePort', 0], - ]) -}) - -test('sendMessagePortToIconThemeWorker propagates errors from RendererWorker', async () => { - const { port1 } = new MessageChannel() - - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { - throw new Error('RPC call failed') - }, - }) - - await expect(sendMessagePortToIconThemeWorker(port1)).rejects.toThrow('RPC call failed') - expect(mockRpc.invocations).toEqual([ - ['SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker', port1, 'IconTheme.handleMessagePort', 0], - ]) -}) - -test('sendMessagePortToIconThemeWorker returns void when successful', async () => { - const { port1 } = new MessageChannel() - - RendererWorker.registerMockRpc({ - 'IconTheme.handleMessagePort'() { - return undefined - }, - 'SendMessagePortToExtensionHostWorker.sendMessagePortToIconThemeWorker'() { - return undefined - }, - }) - - const result = await sendMessagePortToIconThemeWorker(port1) - expect(result).toBeUndefined() -}) diff --git a/packages/explorer-view/test/SetDeltaY.test.ts b/packages/explorer-view/test/SetDeltaY.test.ts deleted file mode 100644 index 542f408..0000000 --- a/packages/explorer-view/test/SetDeltaY.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { setDeltaY } from '../src/parts/SetDeltaY/SetDeltaY.ts' - -test('should not change state when deltaY is the same', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return 'icon' - }, - 'IconTheme.getFolderIcon'() { - return 'icon' - }, - 'IconTheme.getIcons'() { - return ['icon'] - }, - }) - const state: ExplorerState = createDefaultState() - const result = await setDeltaY(state, 0) - expect(result).toBe(state) - expect(mockRpc.invocations).toEqual([]) -}) - -test('should clamp deltaY to 0 when negative', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return 'icon' - }, - 'IconTheme.getFolderIcon'() { - return 'icon' - }, - 'IconTheme.getIcons'() { - return ['icon'] - }, - }) - const state: ExplorerState = createDefaultState() - const result = await setDeltaY(state, -50) - expect(result.deltaY).toBe(0) - expect(result.minLineY).toBe(0) - expect(mockRpc.invocations).toEqual([]) -}) - -test('should clamp deltaY to max scroll value', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return 'icon' - }, - 'IconTheme.getFolderIcon'() { - return 'icon' - }, - 'IconTheme.getIcons'() { - return ['icon'] - }, - }) - const items: ExplorerItem[] = Array.from({ length: 20 }, (_, i) => ({ - depth: 0, - name: `file${i}`, - path: `/file${i}`, - selected: false, - type: 1, - })) - const state: ExplorerState = { - ...createDefaultState(), - items, - } - const result = await setDeltaY(state, 500) - expect(result.deltaY).toBe(300) - expect(result.minLineY).toBe(15) - expect(mockRpc.invocations).toEqual([]) -}) - -test('should update visible items and icons', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return 'icon' - }, - 'IconTheme.getFolderIcon'() { - return 'icon' - }, - 'IconTheme.getIcons'() { - return ['icon'] - }, - }) - const items: ExplorerItem[] = Array.from({ length: 20 }, (_, i) => ({ - depth: 0, - name: `file${i}`, - path: `/file${i}`, - selected: false, - type: 1, - })) - const state: ExplorerState = { - ...createDefaultState(), - items, - } - const result = await setDeltaY(state, 100) - expect(result.deltaY).toBe(100) - expect(result.minLineY).toBe(5) - expect(result.maxLineY).toBe(10) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/SortExplorerItems.test.ts b/packages/explorer-view/test/SortExplorerItems.test.ts deleted file mode 100644 index 4a29405..0000000 --- a/packages/explorer-view/test/SortExplorerItems.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { test, expect } from '@jest/globals' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { sortExplorerItems } from '../src/parts/SortExplorerItems/SortExplorerItems.ts' - -const createItem = (name: string, type: number): any => ({ - depth: 1, - name, - path: `/test/${name}`, - selected: false, - type, -}) - -test('sorts folders before files', () => { - const items = [ - createItem('file1', DirentType.File), - createItem('folder1', DirentType.Directory), - createItem('file2', DirentType.File), - createItem('folder2', DirentType.Directory), - ] - const sorted = sortExplorerItems(items) - expect(sorted[0].type).toBe(DirentType.Directory) - expect(sorted[1].type).toBe(DirentType.Directory) - expect(sorted[2].type).toBe(DirentType.File) - expect(sorted[3].type).toBe(DirentType.File) -}) - -test('sorts items alphabetically within same type', () => { - const items = [ - createItem('b', DirentType.Directory), - createItem('a', DirentType.Directory), - createItem('d', DirentType.File), - createItem('c', DirentType.File), - ] - const sorted = sortExplorerItems(items) - expect(sorted[0].name).toBe('a') - expect(sorted[1].name).toBe('b') - expect(sorted[2].name).toBe('c') - expect(sorted[3].name).toBe('d') -}) - -test('sorts numeric names correctly', () => { - const items = [createItem('10', DirentType.Directory), createItem('2', DirentType.Directory), createItem('1', DirentType.Directory)] - const sorted = sortExplorerItems(items) - expect(sorted[0].name).toBe('1') - expect(sorted[1].name).toBe('2') - expect(sorted[2].name).toBe('10') -}) - -test('handles mixed types and names', () => { - const items = [ - createItem('file2', DirentType.File), - createItem('folder1', DirentType.Directory), - createItem('file1', DirentType.File), - createItem('folder2', DirentType.Directory), - ] - const sorted = sortExplorerItems(items) - expect(sorted[0].name).toBe('folder1') - expect(sorted[1].name).toBe('folder2') - expect(sorted[2].name).toBe('file1') - expect(sorted[3].name).toBe('file2') -}) diff --git a/packages/explorer-view/test/Terminate.test.ts b/packages/explorer-view/test/Terminate.test.ts deleted file mode 100644 index dda5ba4..0000000 --- a/packages/explorer-view/test/Terminate.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { expect, jest, test } from '@jest/globals' -import { terminate } from '../src/parts/Terminate/Terminate.ts' - -test('terminate', () => { - const mockClose = jest.fn() - globalThis.close = mockClose - terminate() - expect(mockClose).toHaveBeenCalled() -}) diff --git a/packages/explorer-view/test/ToCollapsedDirent.test.ts b/packages/explorer-view/test/ToCollapsedDirent.test.ts deleted file mode 100644 index 05747cf..0000000 --- a/packages/explorer-view/test/ToCollapsedDirent.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { toCollapsedDirent } from '../src/parts/ToCollapsedDirent/ToCollapsedDirent.ts' - -test('should collapse expanded directory to regular directory', () => { - const expandedDir: ExplorerItem = { - depth: 1, - name: 'test-dir', - path: '/test/test-dir', - selected: false, - type: DirentType.DirectoryExpanded, - } - - const result = toCollapsedDirent(expandedDir) - - expect(result).toEqual({ - depth: 1, - name: 'test-dir', - path: '/test/test-dir', - selected: false, - type: DirentType.Directory, - }) -}) - -test('should return unchanged item for non-expanded directory', () => { - const regularDir: ExplorerItem = { - depth: 1, - name: 'test-dir', - path: '/test/test-dir', - selected: false, - type: DirentType.Directory, - } - - const result = toCollapsedDirent(regularDir) - - expect(result).toBe(regularDir) -}) - -test('should return unchanged item for file', () => { - const file: ExplorerItem = { - depth: 1, - name: 'test-file.txt', - path: '/test/test-file.txt', - selected: false, - type: DirentType.File, - } - - const result = toCollapsedDirent(file) - - expect(result).toBe(file) -}) - -test('should return unchanged item for symlink', () => { - const symlink: ExplorerItem = { - depth: 1, - name: 'test-symlink', - path: '/test/test-symlink', - selected: false, - type: DirentType.Symlink, - } - - const result = toCollapsedDirent(symlink) - - expect(result).toBe(symlink) -}) - -test('should preserve all properties when collapsing expanded directory', () => { - const expandedDir: ExplorerItem = { - depth: 2, - icon: 'folder-icon', - name: 'test-dir', - path: '/test/test-dir', - posInSet: 3, - selected: true, - setSize: 5, - type: DirentType.DirectoryExpanded, - } - - const result = toCollapsedDirent(expandedDir) - - expect(result).toEqual({ - depth: 2, - icon: 'folder-icon', - name: 'test-dir', - path: '/test/test-dir', - posInSet: 3, - selected: true, - setSize: 5, - type: DirentType.Directory, - }) -}) diff --git a/packages/explorer-view/test/ToggleIndividualSelection.test.ts b/packages/explorer-view/test/ToggleIndividualSelection.test.ts deleted file mode 100644 index 2d524a7..0000000 --- a/packages/explorer-view/test/ToggleIndividualSelection.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.js' -import { toggleIndividualSelection } from '../src/parts/ToggleIndividualSelection/ToggleIndividualSelection.js' - -test('toggleIndividualSelection - toggles selection of item at valid index', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, - { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, - { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, - ], - } - - const newState = await toggleIndividualSelection(state, 1) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[2].selected).toBe(false) -}) - -test('toggleIndividualSelection - toggles selection from true to false', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, - { depth: 0, name: 'file2', path: '/file2', selected: true, type: 0 }, - { depth: 0, name: 'file3', path: '/file3', selected: false, type: 0 }, - ], - } - - const newState = await toggleIndividualSelection(state, 1) - expect(newState.items[1].selected).toBe(false) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[2].selected).toBe(false) -}) - -test('toggleIndividualSelection - does nothing when index is negative', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, - { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, - ], - } - - const newState = await toggleIndividualSelection(state, -1) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[1].selected).toBe(false) -}) - -test('toggleIndividualSelection - does nothing when index is out of range', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'file1', path: '/file1', selected: false, type: 0 }, - { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, - ], - } - - const newState = await toggleIndividualSelection(state, 2) - expect(newState.items[0].selected).toBe(false) - expect(newState.items[1].selected).toBe(false) -}) - -test('toggleIndividualSelection - preserves other selections', async () => { - const state: ExplorerState = { - ...createDefaultState(), - items: [ - { depth: 0, name: 'file1', path: '/file1', selected: true, type: 0 }, - { depth: 0, name: 'file2', path: '/file2', selected: false, type: 0 }, - { depth: 0, name: 'file3', path: '/file3', selected: true, type: 0 }, - ], - } - - const newState = await toggleIndividualSelection(state, 1) - expect(newState.items[0].selected).toBe(true) - expect(newState.items[1].selected).toBe(true) - expect(newState.items[2].selected).toBe(true) -}) diff --git a/packages/explorer-view/test/TreeToArray.test.ts b/packages/explorer-view/test/TreeToArray.test.ts deleted file mode 100644 index 2ff29b6..0000000 --- a/packages/explorer-view/test/TreeToArray.test.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { expect, test } from '@jest/globals' -import type { Tree } from '../src/parts/Tree/Tree.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { treeToArray } from '../src/parts/TreeToArray/TreeToArray.ts' - -test('treeToArray - empty tree', () => { - const map: Tree = {} - const root = '/test' - expect(treeToArray(map, root)).toEqual([]) -}) - -test('treeToArray - single file', () => { - const map: Tree = { - '': [{ name: 'file.txt', type: DirentType.File }], - } - const root = '/test' - const result = treeToArray(map, root) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'file.txt', - path: '/test/file.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: 7, - }, - ]) -}) - -test('treeToArray - nested structure', () => { - const map: Tree = { - '': [ - { name: 'folder', type: DirentType.Directory }, - { name: 'file.txt', type: DirentType.File }, - ], - '/folder': [{ name: 'nested.txt', type: DirentType.File }], - } - const root = '/test' - const result = treeToArray(map, root) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'folder', - path: '/test/folder', - posInSet: 1, - selected: false, - setSize: 2, - type: 3, - }, - { - depth: 2, - icon: '', - name: 'nested.txt', - path: '/test/folder/nested.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'file.txt', - path: '/test/file.txt', - posInSet: 2, - selected: false, - setSize: 2, - type: 7, - }, - ]) -}) - -test('treeToArray - deep nested structure', () => { - const map: Tree = { - '': [{ name: 'folder1', type: DirentType.Directory }], - '/folder1': [{ name: 'folder2', type: DirentType.Directory }], - '/folder1/folder2': [{ name: 'deep.txt', type: DirentType.File }], - } - const root = '/test' - const result = treeToArray(map, root) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'folder1', - path: '/test/folder1', - posInSet: 1, - selected: false, - setSize: 1, - type: 3, - }, - { - depth: 2, - icon: '', - name: 'folder2', - path: '/test/folder1/folder2', - posInSet: 1, - selected: false, - setSize: 1, - type: 3, - }, - { - depth: 3, - icon: '', - name: 'deep.txt', - path: '/test/folder1/folder2/deep.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: 7, - }, - ]) -}) - -test('treeToArray - update tree and children', () => { - const map: Tree = { - '': [ - { name: 'folder1', type: DirentType.Directory }, - { name: 'folder2', type: DirentType.Directory }, - ], - '/folder1': [ - { name: 'subfolder', type: DirentType.Directory }, - { name: 'file1.txt', type: DirentType.File }, - ], - '/folder1/subfolder': [{ name: 'deep.txt', type: DirentType.File }], - '/folder2': [{ name: 'file2.txt', type: DirentType.File }], - } - const root = '/test' - const result = treeToArray(map, root) - expect(result).toEqual([ - { - depth: 1, - icon: '', - name: 'folder1', - path: '/test/folder1', - posInSet: 1, - selected: false, - setSize: 2, - type: 3, - }, - { - depth: 2, - icon: '', - name: 'subfolder', - path: '/test/folder1/subfolder', - posInSet: 1, - selected: false, - setSize: 2, - type: 3, - }, - { - depth: 3, - icon: '', - name: 'deep.txt', - path: '/test/folder1/subfolder/deep.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: 7, - }, - { - depth: 2, - icon: '', - name: 'file1.txt', - path: '/test/folder1/file1.txt', - posInSet: 2, - selected: false, - setSize: 2, - type: 7, - }, - { - depth: 1, - icon: '', - name: 'folder2', - path: '/test/folder2', - posInSet: 2, - selected: false, - setSize: 2, - type: 3, - }, - { - depth: 2, - icon: '', - name: 'file2.txt', - path: '/test/folder2/file2.txt', - posInSet: 1, - selected: false, - setSize: 1, - type: 7, - }, - ]) -}) diff --git a/packages/explorer-view/test/UpdateDirentsAtPath.test.ts b/packages/explorer-view/test/UpdateDirentsAtPath.test.ts deleted file mode 100644 index 8271460..0000000 --- a/packages/explorer-view/test/UpdateDirentsAtPath.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { updateDirentsAtPath } from '../src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts' - -test.skip('updateDirentsAtPath - empty items', () => { - const items: readonly ExplorerItem[] = [] - const path = '/test' - const root = '/test' - const newDirents = [{ name: 'file.txt', type: DirentType.File }] - const result = updateDirentsAtPath(items, path, root, newDirents) - expect(result).toHaveLength(1) - expect(result[0].name).toBe('file.txt') - expect(result[0].type).toBe(DirentType.File) - expect(result[0].path).toBe('/test/file.txt') - expect(result[0].depth).toBe(0) - expect(result[0].posInSet).toBe(1) - expect(result[0].setSize).toBe(1) -}) - -test.skip('updateDirentsAtPath - update existing items', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, icon: '', name: 'folder', path: '/test/folder', posInSet: 1, selected: false, setSize: 2, type: DirentType.Directory }, - { depth: 0, icon: '', name: 'file.txt', path: '/test/file.txt', posInSet: 2, selected: false, setSize: 2, type: DirentType.File }, - ] - const path = '/test' - const root = '/test' - const newDirents = [ - { name: 'new.txt', type: DirentType.File }, - { name: 'folder', type: DirentType.Directory }, - ] - const result = updateDirentsAtPath(items, path, root, newDirents) - expect(result).toHaveLength(2) - expect(result[0].name).toBe('folder') - expect(result[0].type).toBe(DirentType.Directory) - expect(result[0].path).toBe('/test/folder') - expect(result[0].depth).toBe(0) - expect(result[0].posInSet).toBe(1) - expect(result[0].setSize).toBe(2) - expect(result[1].name).toBe('new.txt') - expect(result[1].type).toBe(DirentType.File) - expect(result[1].path).toBe('/test/new.txt') - expect(result[1].depth).toBe(0) - expect(result[1].posInSet).toBe(2) - expect(result[1].setSize).toBe(2) -}) - -test.skip('updateDirentsAtPath - nested structure', () => { - const items: readonly ExplorerItem[] = [ - { depth: 0, icon: '', name: 'folder', path: '/test/folder', posInSet: 1, selected: false, setSize: 1, type: DirentType.Directory }, - { depth: 1, icon: '', name: 'nested.txt', path: '/test/folder/nested.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, - ] - const path = '/test/folder' - const root = '/test' - const newDirents = [{ name: 'new.txt', type: DirentType.File }] - const result = updateDirentsAtPath(items, path, root, newDirents) - expect(result).toHaveLength(2) - expect(result[0].name).toBe('folder') - expect(result[0].type).toBe(DirentType.Directory) - expect(result[0].path).toBe('/test/folder') - expect(result[0].depth).toBe(0) - expect(result[0].posInSet).toBe(1) - expect(result[0].setSize).toBe(1) - expect(result[1].name).toBe('new.txt') - expect(result[1].type).toBe(DirentType.File) - expect(result[1].path).toBe('/test/folder/new.txt') - expect(result[1].depth).toBe(1) - expect(result[1].posInSet).toBe(1) - expect(result[1].setSize).toBe(1) -}) diff --git a/packages/explorer-view/test/UpdateEditingValue.test.ts b/packages/explorer-view/test/UpdateEditingValue.test.ts deleted file mode 100644 index bfa0929..0000000 --- a/packages/explorer-view/test/UpdateEditingValue.test.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as ExplorerEditingType from '../src/parts/ExplorerEditingType/ExplorerEditingType.ts' -import * as InputSource from '../src/parts/InputSource/InputSource.ts' -import { updateEditingValue } from '../src/parts/UpdateEditingValue/UpdateEditingValue.ts' - -test('updateEditingValue - updates state with new value', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - const state: ExplorerState = createDefaultState() - const newValue = 'new value' - const result = await updateEditingValue(state, newValue) - expect(result.editingValue).toBe(newValue) - expect(result.editingIcon).toBe('') - expect(mockRpc.invocations).toEqual([]) -}) - -test('updateEditingValue - updates state with new value and input source', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - const state: ExplorerState = createDefaultState() - const newValue = 'new value' - const result = await updateEditingValue(state, newValue, InputSource.User) - expect(result.editingValue).toBe(newValue) - expect(result.editingIcon).toBe('') - expect(mockRpc.invocations).toEqual([]) -}) - -test('updateEditingValue - updates file icon', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingType: ExplorerEditingType.CreateFile, - } - const newValue = 'test.txt' - const result = await updateEditingValue(state, newValue) - expect(result.editingValue).toBe(newValue) - expect(result.editingIcon).toBe('file-test.txt') - expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'test.txt' }]]) -}) - -test('updateEditingValue - updates folder icon', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingType: ExplorerEditingType.CreateFolder, - } - const newValue = 'test' - const result = await updateEditingValue(state, newValue) - expect(result.editingValue).toBe(newValue) - expect(result.editingIcon).toBe('folder-test') - expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'test' }]]) -}) - -test('updateEditingValue - updates file icon when renaming file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - items: [{ depth: 0, name: 'test.txt', path: '/test.txt', selected: false, type: DirentType.File }], - } - const newValue = 'new.txt' - const result = await updateEditingValue(state, newValue) - expect(result.editingValue).toBe(newValue) - expect(result.editingIcon).toBe('file-new.txt') - expect(mockRpc.invocations).toEqual([['IconTheme.getFileIcon', { name: 'new.txt' }]]) -}) - -test('updateEditingValue - updates folder icon when renaming folder', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - const state: ExplorerState = { - ...createDefaultState(), - editingIndex: 0, - editingType: ExplorerEditingType.Rename, - items: [{ depth: 0, name: 'test', path: '/test', selected: false, type: DirentType.Directory }], - } - const newValue = 'new' - const result = await updateEditingValue(state, newValue) - expect(result.editingValue).toBe(newValue) - expect(result.editingIcon).toBe('folder-new') - expect(mockRpc.invocations).toEqual([['IconTheme.getFolderIcon', { name: 'new' }]]) -}) - -test('updateEditingValue - preserves other state properties', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - const state: ExplorerState = createDefaultState() - const result = await updateEditingValue(state, 'new value') - expect(result.uid).toBe(state.uid) - expect(result.root).toBe(state.root) - expect(result.items).toBe(state.items) - expect(mockRpc.invocations).toEqual([]) -}) - -test('updateEditingValue - real-time validation during file creation', async () => { - RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingType: ExplorerEditingType.CreateFile, - focusedIndex: 0, - items: [ - { - depth: 0, - icon: '', - name: 'existing-file.txt', - path: '/root/existing-file.txt', - posInSet: 0, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ], - } - - // Test typing a name that already exists - const result = await updateEditingValue(state, 'existing-file.txt') - expect(result.editingErrorMessage).toBe('A file or folder **existing-file.txt** already exists at this location. Please choose a different name.') - - // Test typing a name that doesn't exist - const result2 = await updateEditingValue(state, 'new-file.txt') - expect(result2.editingErrorMessage).toBe('') -}) - -test('updateEditingValue - real-time validation during folder creation', async () => { - RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingType: ExplorerEditingType.CreateFolder, - focusedIndex: 0, - items: [ - { - depth: 0, - icon: '', - name: 'existing-folder', - path: '/root/existing-folder', - posInSet: 0, - selected: false, - setSize: 1, - type: DirentType.Directory, - }, - ], - } - - // Test typing a name that already exists - const result = await updateEditingValue(state, 'existing-folder') - expect(result.editingErrorMessage).toBe('A file or folder **existing-folder** already exists at this location. Please choose a different name.') - - // Test typing a name that doesn't exist - const result2 = await updateEditingValue(state, 'new-folder') - expect(result2.editingErrorMessage).toBe('') -}) - -test('updateEditingValue - no validation during rename', async () => { - RendererWorker.registerMockRpc({ - 'IconTheme.getFileIcon'(params: any) { - return `file-${params.name}` - }, - 'IconTheme.getFolderIcon'(params: any) { - return `folder-${params.name}` - }, - }) - - const state: ExplorerState = { - ...createDefaultState(), - editingType: ExplorerEditingType.Rename, - focusedIndex: 0, - items: [ - { - depth: 0, - icon: '', - name: 'existing-file.txt', - path: '/root/existing-file.txt', - posInSet: 0, - selected: false, - setSize: 1, - type: DirentType.File, - }, - ], - } - - // During rename, file existence validation should not apply - const result = await updateEditingValue(state, 'existing-file.txt') - expect(result.editingErrorMessage).toBe('') -}) diff --git a/packages/explorer-view/test/UpdateIconCache.test.ts b/packages/explorer-view/test/UpdateIconCache.test.ts deleted file mode 100644 index 657cca6..0000000 --- a/packages/explorer-view/test/UpdateIconCache.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { FileIconCache } from '../src/parts/FileIconCache/FileIconCache.ts' -import type { IconRequest } from '../src/parts/IconRequest/IconRequest.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import * as UpdateIconCache from '../src/parts/UpdateIconCache/UpdateIconCache.ts' - -test('updateIconCache - empty requests', () => { - const cache: FileIconCache = {} - const requests: readonly IconRequest[] = [] - const newIcons: readonly string[] = [] - expect(UpdateIconCache.updateIconCache(cache, requests, newIcons)).toBe(cache) -}) - -test('updateIconCache - new icons', () => { - const cache: FileIconCache = { - '/test/file1.txt': 'icon1', - } - const requests: readonly IconRequest[] = [{ name: 'file2.txt', path: '/test/file2.txt', type: DirentType.File }] - const newIcons: readonly string[] = ['icon2'] - expect(UpdateIconCache.updateIconCache(cache, requests, newIcons)).toEqual({ - '/test/file1.txt': 'icon1', - '/test/file2.txt': 'icon2', - }) -}) - -test('updateIconCache - immutability', () => { - const cache: FileIconCache = { existing: 'icon' } - const requests: readonly IconRequest[] = [{ name: 'file.txt', path: '/test/file.txt', type: DirentType.File }] - const newIcons: readonly string[] = ['new-icon'] - const result = UpdateIconCache.updateIconCache(cache, requests, newIcons) - expect(result).not.toBe(cache) - expect(cache).toEqual({ existing: 'icon' }) -}) diff --git a/packages/explorer-view/test/UpdateIcons.test.ts b/packages/explorer-view/test/UpdateIcons.test.ts deleted file mode 100644 index af5baab..0000000 --- a/packages/explorer-view/test/UpdateIcons.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { expect, test } from '@jest/globals' -import { IconThemeWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../src/parts/ExplorerState/ExplorerState.ts' -import * as CreateDefaultState from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import * as UpdateIcons from '../src/parts/UpdateIcons/UpdateIcons.ts' - -test('updateIcons - should update icons for visible items', async () => { - using mockRpc = IconThemeWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getFolderIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getIcons'() { - return ['icon1', 'icon2'] - }, - }) - const defaultState: ExplorerState = CreateDefaultState.createDefaultState() - const state: ExplorerState = { - ...defaultState, - items: [ - { depth: 1, name: 'file1.ts', path: '/test/file1.ts', selected: false, type: 1 }, - { depth: 1, name: 'file2.ts', path: '/test/file2.ts', selected: false, type: 1 }, - { depth: 1, name: 'file3.ts', path: '/test/file3.ts', selected: false, type: 1 }, - ], - maxLineY: 2, - minLineY: 0, - } - - const result = await UpdateIcons.updateIcons(state) - - expect(result.icons).toHaveLength(2) - expect(result.fileIconCache).toBeDefined() - expect(result.items).toEqual(state.items) - expect(result.minLineY).toBe(state.minLineY) - expect(result.maxLineY).toBe(state.maxLineY) - expect(mockRpc.invocations).toEqual([ - [ - 'IconTheme.getIcons', - [ - { name: 'file1.ts', type: 1 }, - { name: 'file2.ts', type: 1 }, - ], - ], - ]) -}) - -test('updateIcons - should handle empty visible items', async () => { - using mockRpc = IconThemeWorker.registerMockRpc({ - 'IconTheme.getFileIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getFolderIcon'() { - return ['icon1', 'icon2'] - }, - 'IconTheme.getIcons'() { - return ['icon1', 'icon2'] - }, - }) - const defaultState: ExplorerState = CreateDefaultState.createDefaultState() - const state: ExplorerState = { - ...defaultState, - items: [], - maxLineY: 0, - minLineY: 0, - } - - const result = await UpdateIcons.updateIcons(state) - - expect(result.icons).toHaveLength(0) - expect(result.fileIconCache).toBeDefined() - expect(result.items).toEqual(state.items) - expect(mockRpc.invocations).toEqual([]) -}) diff --git a/packages/explorer-view/test/UpdateRoot.test.ts b/packages/explorer-view/test/UpdateRoot.test.ts deleted file mode 100644 index 4308fd7..0000000 --- a/packages/explorer-view/test/UpdateRoot.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { test, expect } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { createDefaultState } from '../src/parts/CreateDefaultState/CreateDefaultState.ts' -import { updateRoot } from '../src/parts/UpdateRoot/UpdateRoot.ts' - -test('updateRoot should return same disposed state', async () => { - const state = createDefaultState() - // @ disposed is used in source but not typed - // @ts-ignore - state.disposed = true - const result = await updateRoot(state) - expect(result).toBe(state) -}) - -test('updateRoot should merge dirents correctly', async () => { - const state = createDefaultState() - - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.readDirWithFileTypes'() { - return [ - { name: 'file1', type: 'file' }, - { name: 'dir1', type: 'directory' }, - ] - }, - }) - - const result = await updateRoot(state) - expect(result.items).toHaveLength(2) - expect(result.items[0].name).toBe('dir1') - expect(result.items[1].name).toBe('file1') - expect(mockRpc.invocations).toEqual([['FileSystem.readDirWithFileTypes', '/']]) -}) diff --git a/packages/explorer-view/test/UpdateTree.test.ts b/packages/explorer-view/test/UpdateTree.test.ts deleted file mode 100644 index 7977059..0000000 --- a/packages/explorer-view/test/UpdateTree.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { ExplorerItem } from '../src/parts/ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../src/parts/DirentType/DirentType.ts' -import { updateTree } from '../src/parts/UpdateTree/UpdateTree.ts' - -test('updateTree - empty tree', () => { - const tree = {} - const path = '/test' - const newDirents: readonly ExplorerItem[] = [ - { depth: 0, icon: '', name: 'file.txt', path: '/test/file.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, - ] - const result = updateTree(tree, path, newDirents) - expect(result).toEqual({ - '/test': newDirents, - }) -}) - -test('updateTree - existing tree', () => { - const tree = { - '/test': [{ depth: 0, icon: '', name: 'old.txt', path: '/test/old.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }], - } - const path = '/test' - const newDirents: readonly ExplorerItem[] = [ - { depth: 0, icon: '', name: 'new.txt', path: '/test/new.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, - ] - const result = updateTree(tree, path, newDirents) - expect(result).toEqual({ - '/test': newDirents, - }) -}) - -test('updateTree - nested path', () => { - const tree = { - '/test': [{ depth: 0, icon: '', name: 'folder', path: '/test/folder', posInSet: 1, selected: false, setSize: 1, type: DirentType.Directory }], - } - const path = '/test/folder' - const newDirents: readonly ExplorerItem[] = [ - { depth: 0, icon: '', name: 'nested.txt', path: '/test/folder/nested.txt', posInSet: 1, selected: false, setSize: 1, type: DirentType.File }, - ] - const result = updateTree(tree, path, newDirents) - expect(result).toEqual({ - '/test': tree['/test'], - '/test/folder': newDirents, - }) -}) diff --git a/packages/explorer-view/test/UploadFileSystemHandles.test.ts b/packages/explorer-view/test/UploadFileSystemHandles.test.ts deleted file mode 100644 index 91cb8c8..0000000 --- a/packages/explorer-view/test/UploadFileSystemHandles.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { expect, test } from '@jest/globals' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { DroppedFileItem } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' -import { uploadFileSystemHandles } from '../src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts' - -class MockFileHandle implements FileSystemHandle { - kind: 'file' | 'directory' - name: string - getFile?: () => Promise<{ text: () => Promise }> - values?: () => { [Symbol.asyncIterator]: () => AsyncGenerator } - - constructor(kind: 'file' | 'directory', name: string, content?: string, children?: MockFileHandle[]) { - this.kind = kind - this.name = name - - if (kind === 'file' && content) { - this.getFile = async (): Promise<{ text: () => Promise }> => ({ - text: async (): Promise => content, - }) - } - - if (kind === 'directory' && children) { - this.values = (): { [Symbol.asyncIterator]: () => AsyncGenerator } => ({ - [Symbol.asyncIterator]: async function* (): AsyncGenerator { - for (const child of children) { - yield child - } - }, - }) - } - } - - async isSameEntry(other: FileSystemHandle): Promise { - return this === other - } -} - -const asDroppedFileItem = (fileHandle: MockFileHandle): DroppedFileItem => { - return { - kind: 'file', - value: fileHandle as FileSystemFileHandle, - } -} - -test('upload single file', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return true - }, - 'FileSystem.writeFile'() { - return true - }, - }) - const fileHandle = new MockFileHandle('file', 'test.txt', 'content') - const result = await uploadFileSystemHandles('/', '/', [fileHandle]) - expect(result).toBe(true) - expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test.txt', 'content']]) -}) - -test('upload single dropped file item', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return true - }, - 'FileSystem.writeFile'() { - return true - }, - }) - const fileHandle = new MockFileHandle('file', 'test.txt', 'content') - const result = await uploadFileSystemHandles('/', '/', [asDroppedFileItem(fileHandle)]) - expect(result).toBe(true) - expect(mockRpc.invocations).toEqual([['FileSystem.writeFile', '/test.txt', 'content']]) -}) - -test('upload directory with files', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return true - }, - 'FileSystem.writeFile'() { - return true - }, - }) - const file1 = new MockFileHandle('file', 'file1.txt', 'content1') - const file2 = new MockFileHandle('file', 'file2.txt', 'content2') - const dir = new MockFileHandle('directory', 'dir', undefined, [file1, file2]) - const result = await uploadFileSystemHandles('/', '/', [dir]) - expect(result).toBe(true) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', '/dir'], - ['FileSystem.writeFile', '/dir/file1.txt', 'content1'], - ['FileSystem.writeFile', '/dir/file2.txt', 'content2'], - ]) -}) - -test('upload multiple files and directories', async () => { - using mockRpc = RendererWorker.registerMockRpc({ - 'FileSystem.mkdir'() { - return true - }, - 'FileSystem.writeFile'() { - return true - }, - }) - const file1 = new MockFileHandle('file', 'file1.txt', 'content1') - const file2 = new MockFileHandle('file', 'file2.txt', 'content2') - const dir1 = new MockFileHandle('directory', 'dir1', undefined, [file1]) - const dir2 = new MockFileHandle('directory', 'dir2', undefined, [file2]) - const result = await uploadFileSystemHandles('/', '/', [dir1, dir2]) - expect(result).toBe(true) - expect(mockRpc.invocations).toEqual([ - ['FileSystem.mkdir', '/dir1'], - ['FileSystem.writeFile', '/dir1/file1.txt', 'content1'], - ['FileSystem.mkdir', '/dir2'], - ['FileSystem.writeFile', '/dir2/file2.txt', 'content2'], - ]) -}) diff --git a/packages/explorer-view/test/getFileHandleText.test.ts b/packages/explorer-view/test/getFileHandleText.test.ts deleted file mode 100644 index f49b2b7..0000000 --- a/packages/explorer-view/test/getFileHandleText.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect, jest } from '@jest/globals' -import { getFileHandleText } from '../src/parts/GetFileHandleText/GetFileHandleText.ts' - -test('getFileHandleText returns file content as text', async () => { - const mockGetFile = jest.fn<() => Promise<{ text: () => Promise }>>().mockResolvedValue({ - text: jest.fn<() => Promise>().mockResolvedValue('test content'), - }) - const mockFileHandle = { - getFile: mockGetFile, - } as unknown as FileSystemFileHandle - - const result = await getFileHandleText(mockFileHandle) - expect(result).toBe('test content') - expect(mockGetFile).toHaveBeenCalled() -}) From 56a90f3235b03751bf2c8c04473ef9f6acebf06c Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:28:15 +0200 Subject: [PATCH 04/17] commands --- .../src/parts/CommandMap/CommandMap.ts | 170 ----------- .../test/ValidateFileName2.test.ts | 79 ------ .../test/ValidateFolderCopy.test.ts | 37 --- .../test/ValidateOperations.test.ts | 263 ------------------ 4 files changed, 549 deletions(-) delete mode 100644 packages/explorer-view/test/ValidateFileName2.test.ts delete mode 100644 packages/explorer-view/test/ValidateFolderCopy.test.ts delete mode 100644 packages/explorer-view/test/ValidateOperations.test.ts diff --git a/packages/explorer-view/src/parts/CommandMap/CommandMap.ts b/packages/explorer-view/src/parts/CommandMap/CommandMap.ts index 07184f2..a315aa7 100644 --- a/packages/explorer-view/src/parts/CommandMap/CommandMap.ts +++ b/packages/explorer-view/src/parts/CommandMap/CommandMap.ts @@ -1,176 +1,6 @@ -import { terminate } from '@lvce-editor/viewlet-registry' -import * as AcceptEdit from '../AcceptEdit/AcceptEdit.ts' -import * as CancelEdit from '../CancelEdit/CancelEdit.ts' -import * as CancelTypeAhead from '../CancelTypeAhead/CancelTypeAhead.ts' -import * as CollapseAll from '../CollapseAll/CollapseAll.ts' -import * as CompareWithSelected from '../CompareWithSelected/CompareWithSelected.ts' -import * as CopyPath from '../CopyPath/CopyPath.ts' -import * as CopyRelativePath from '../CopyRelativePath/CopyRelativePath.ts' -import * as Create2 from '../Create2/Create2.ts' -import * as Create from '../Create/Create.ts' -import * as Diff2 from '../Diff2/Diff2.ts' -import * as ExpandAll from '../ExpandAll/ExpandAll.ts' -import * as ExpandRecursively from '../ExpandRecursively/ExpandRecursively.ts' import * as WrapCommand from '../ExplorerStates/ExplorerStates.ts' -import * as Focus from '../Focus/Focus.ts' -import * as FocusFirst from '../FocusFirst/FocusFirst.ts' -import * as FocusIndex from '../FocusIndex/FocusIndex.ts' -import * as FocusLast from '../FocusLast/FocusLast.ts' -import * as FocusNext from '../FocusNext/FocusNext.ts' -import * as FocusNone from '../FocusNone/FocusNone.ts' -import * as FocusPrevious from '../FocusPrevious/FocusPrevious.ts' -import * as GetKeyBindings from '../GetKeyBindings/GetKeyBindings.ts' -import * as GetMenuEntries2 from '../GetMenuEntries2/GetMenuEntries2.ts' -import * as GetMenuEntries from '../GetMenuEntries/GetMenuEntries.ts' -import * as GetMouseActions from '../GetMouseActions/GetMouseActions.ts' -import * as HandleArrowLeft from '../HandleArrowLeft/HandleArrowLeft.ts' -import * as HandleArrowRight from '../HandleArrowRight/HandleArrowRight.ts' -import * as HandleBlur from '../HandleBlur/HandleBlur.ts' -import { handleButtonClick } from '../HandleButtonClick/HandleButtonClick.ts' -import * as HandleClick from '../HandleClick/HandleClick.ts' -import * as HandleClickAt from '../HandleClickAt/HandleClickAt.ts' -import * as HandleClickCurrent from '../HandleClickCurrent/HandleClickCurrent.ts' -import * as HandleClickCurrentButKeepFocus from '../HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts' -import * as HandleClickOpenFolder from '../HandleClickOpenFolder/HandleClickOpenFolder.ts' -import * as HandleContextMenu from '../HandleContextMenu/HandleContextMenu.ts' -import * as HandleContextMenuKeyboard from '../HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts' -import * as HandleContextMenuWelcome from '../HandleContextMenuWelcome/HandleContextMenuWelcome.ts' -import * as HandleCopy from '../HandleCopy/HandleCopy.ts' -import * as HandleCut from '../HandleCut/HandleCut.ts' -import { handleDoubleClick } from '../HandleDoubleClick/HandleDoubleClick.ts' -import { handleDragEnd } from '../HandleDragEnd/HandleDragEnd.ts' -import * as HandleDragLeave from '../HandleDragLeave/HandleDragLeave.ts' -import * as HandleDragOver from '../HandleDragOver/HandleDragOver.ts' -import * as HandleDragOverIndex from '../HandleDragOverIndex/HandleDragOverIndex.ts' -import * as HandleDragStart from '../HandleDragStart/HandleDragStart.ts' -import * as HandleDrop from '../HandleDrop/HandleDrop.ts' -import { handleDropIndex } from '../HandleDropIndex/HandleDropIndex.ts' -import { handleEscape } from '../HandleEscape/HandleEscape.ts' -import * as HandleFocus from '../HandleFocus/HandleFocus.ts' -import * as HandleIconThemeChange from '../HandleIconThemeChange/HandleIconThemeChange.ts' -import * as HandleInputBlur from '../HandleInputBlur/HandleInputBlur.ts' -import * as HandleInputClick from '../HandleInputClick/HandleInputClick.ts' -import * as HandleInputKeyDown from '../HandleInputKeyDown/HandleInputKeyDown.ts' -import * as HandleKeyDown from '../HandleKeyDown/HandleKeyDown.ts' -import * as HandlePaste from '../HandlePaste/HandlePaste.ts' -import * as HandlePointerDown from '../HandlePointerDown/HandlePointerDown.ts' -import * as HandleResize from '../HandleResize/HandleResize.ts' -import * as HandleUpload from '../HandleUpload/HandleUpload.ts' -import * as HandleWheel from '../HandleWheel/HandleWheel.ts' -import * as HandleWorkspaceChange from '../HandleWorkspaceChange/HandleWorkspaceChange.ts' -import { handleWorkspaceRefresh } from '../HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts' -import * as Initialize from '../Initialize/Initialize.ts' -import * as LoadContent from '../LoadContent/LoadContent.ts' -import * as NewFile from '../NewFile/NewFile.ts' -import * as NewFolder from '../NewFolder/NewFolder.ts' -import * as OpenContainingFolder from '../OpenContainingFolder/OpenContainingFolder.ts' -import * as Refresh from '../Refresh/Refresh.ts' -import * as RemoveDirent from '../RemoveDirent/RemoveDirent.ts' -import * as RenameDirent from '../RenameDirent/RenameDirent.ts' -import * as Render2 from '../Render2/Render2.ts' -import * as RenderActions2 from '../RenderActions2/RenderActions2.ts' -import * as RenderEventListeners from '../RenderEventListeners/RenderEventListeners.ts' -import * as RestoreState from '../RestoreState/RestoreState.ts' -import * as RevealItem from '../RevealItem/RevealItem.ts' -import * as SaveState from '../SaveState/SaveState.ts' -import * as SelectAll from '../SelectAll/SelectAll.ts' -import * as SelectDown from '../SelectDown/SelectDown.ts' -import * as SelectForCompare from '../SelectForCompare/SelectForCompare.ts' -import * as SelectIndices from '../SelectIndices/SelectIndices.ts' -import * as SelectUp from '../SelectUp/SelectUp.ts' -import * as SetDeltaY from '../SetDeltaY/SetDeltaY.ts' -import * as ToggleIndividualSelection from '../ToggleIndividualSelection/ToggleIndividualSelection.ts' -import * as UpdateEditingValue from '../UpdateEditingValue/UpdateEditingValue.ts' import * as UpdateIcons from '../UpdateIcons/UpdateIcons.ts' export const commandMap = { - 'Explorer.acceptEdit': WrapCommand.wrapListItemCommand(AcceptEdit.acceptEdit), - 'Explorer.cancelEdit': WrapCommand.wrapListItemCommand(CancelEdit.cancelEdit), - 'Explorer.cancelTypeAhead': WrapCommand.wrapListItemCommand(CancelTypeAhead.cancelTypeAhead), - 'Explorer.collapseAll': WrapCommand.wrapListItemCommand(CollapseAll.collapseAll), - 'Explorer.compareWithSelected': WrapCommand.wrapListItemCommand(CompareWithSelected.compareWithSelected), - 'Explorer.copyPath': WrapCommand.wrapListItemCommand(CopyPath.copyPath), - 'Explorer.copyRelativePath': WrapCommand.wrapListItemCommand(CopyRelativePath.copyRelativePath), - 'Explorer.create': Create.create, - // not wrapped - 'Explorer.create2': Create2.create2, - 'Explorer.diff2': Diff2.diff2, - 'Explorer.expandAll': WrapCommand.wrapListItemCommand(ExpandAll.expandAll), - 'Explorer.expandRecursively': WrapCommand.wrapListItemCommand(ExpandRecursively.expandRecursively), - 'Explorer.focus': WrapCommand.wrapListItemCommand(Focus.focus), - 'Explorer.focusFirst': WrapCommand.wrapListItemCommand(FocusFirst.focusFirst), - 'Explorer.focusIndex': WrapCommand.wrapListItemCommand(FocusIndex.focusIndex), - 'Explorer.focusLast': WrapCommand.wrapListItemCommand(FocusLast.focusLast), - 'Explorer.focusNext': WrapCommand.wrapListItemCommand(FocusNext.focusNext), - 'Explorer.focusNone': WrapCommand.wrapListItemCommand(FocusNone.focusNone), - 'Explorer.focusPrevious': WrapCommand.wrapListItemCommand(FocusPrevious.focusPrevious), - 'Explorer.getCommandIds': WrapCommand.getCommandIds, - 'Explorer.getKeyBindings': GetKeyBindings.getKeyBindings, - 'Explorer.getMenuEntries': GetMenuEntries.getMenuEntries, - 'Explorer.getMenuEntries2': WrapCommand.wrapGetter(GetMenuEntries2.getMenuEntries2), - 'Explorer.getMouseActions': GetMouseActions.getMouseActions, - 'Explorer.handleArrowLeft': WrapCommand.wrapListItemCommand(HandleArrowLeft.handleArrowLeft), - 'Explorer.handleArrowRight': WrapCommand.wrapListItemCommand(HandleArrowRight.handleArrowRight), - 'Explorer.handleBlur': WrapCommand.wrapListItemCommand(HandleBlur.handleBlur), - 'Explorer.handleButtonClick': WrapCommand.wrapListItemCommand(handleButtonClick), - 'Explorer.handleClick': WrapCommand.wrapListItemCommand(HandleClick.handleClick), - 'Explorer.handleClickAt': WrapCommand.wrapListItemCommand(HandleClickAt.handleClickAt), - 'Explorer.handleClickCurrent': WrapCommand.wrapListItemCommand(HandleClickCurrent.handleClickCurrent), - 'Explorer.handleClickCurrentButKeepFocus': WrapCommand.wrapListItemCommand(HandleClickCurrentButKeepFocus.handleClickCurrentButKeepFocus), - 'Explorer.handleClickOpenFolder': WrapCommand.wrapListItemCommand(HandleClickOpenFolder.handleClickOpenFolder), - 'Explorer.handleContextMenu': WrapCommand.wrapListItemCommand(HandleContextMenu.handleContextMenu), - 'Explorer.handleContextMenuKeyboard': WrapCommand.wrapListItemCommand(HandleContextMenuKeyboard.handleContextMenuKeyboard), - 'Explorer.handleContextMenuWelcome': WrapCommand.wrapListItemCommand(HandleContextMenuWelcome.handleContextMenuWelcome), - 'Explorer.handleCopy': WrapCommand.wrapListItemCommand(HandleCopy.handleCopy), - 'Explorer.handleCut': WrapCommand.wrapListItemCommand(HandleCut.handleCut), - 'Explorer.handleDoubleClick': WrapCommand.wrapListItemCommand(handleDoubleClick), - 'Explorer.handleDragEnd': WrapCommand.wrapListItemCommand(handleDragEnd), - 'Explorer.handleDragLeave': WrapCommand.wrapListItemCommand(HandleDragLeave.handleDragLeave), - 'Explorer.handleDragOver': WrapCommand.wrapListItemCommand(HandleDragOver.handleDragOver), - 'Explorer.handleDragOverIndex': WrapCommand.wrapListItemCommand(HandleDragOverIndex.handleDragOverIndex), - 'Explorer.handleDragStart': WrapCommand.wrapListItemCommand(HandleDragStart.handleDragStart), - 'Explorer.handleDrop': WrapCommand.wrapListItemCommand(HandleDrop.handleDrop), - 'Explorer.handleDropIndex': WrapCommand.wrapListItemCommand(handleDropIndex), - 'Explorer.handleEscape': WrapCommand.wrapListItemCommand(handleEscape), - 'Explorer.handleFocus': WrapCommand.wrapListItemCommand(HandleFocus.handleFocus), - 'Explorer.handleIconThemeChange': WrapCommand.wrapListItemCommand(HandleIconThemeChange.handleIconThemeChange), - 'Explorer.handleInputBlur': WrapCommand.wrapListItemCommand(HandleInputBlur.handleInputBlur), - 'Explorer.handleInputClick': WrapCommand.wrapListItemCommand(HandleInputClick.handleInputClick), - 'Explorer.handleInputKeyDown': WrapCommand.wrapListItemCommand(HandleInputKeyDown.handleInputKeyDown), - 'Explorer.handleKeyDown': WrapCommand.wrapListItemCommand(HandleKeyDown.handleKeyDown), - 'Explorer.handlePaste': WrapCommand.wrapListItemCommand(HandlePaste.handlePaste), - 'Explorer.handlePointerDown': WrapCommand.wrapListItemCommand(HandlePointerDown.handlePointerDown), - 'Explorer.handleResize': WrapCommand.wrapListItemCommand(HandleResize.handleResize), - 'Explorer.handleUpload': WrapCommand.wrapListItemCommand(HandleUpload.handleUpload), - 'Explorer.handleWheel': WrapCommand.wrapListItemCommand(HandleWheel.handleWheel), - 'Explorer.handleWorkspaceChange': WrapCommand.wrapListItemCommand(HandleWorkspaceChange.handleWorkspaceChange), - 'Explorer.handleWorkspaceRefresh': WrapCommand.wrapListItemCommand(handleWorkspaceRefresh), - 'Explorer.initialize': Initialize.initialize, - 'Explorer.loadContent': WrapCommand.wrapListItemCommand(LoadContent.loadContent), - 'Explorer.newFile': WrapCommand.wrapListItemCommand(NewFile.newFile), - 'Explorer.newFolder': WrapCommand.wrapListItemCommand(NewFolder.newFolder), - 'Explorer.openContainingFolder': WrapCommand.wrapListItemCommand(OpenContainingFolder.openContainingFolder), - 'Explorer.refresh': WrapCommand.wrapListItemCommand(Refresh.refresh), - 'Explorer.removeDirent': WrapCommand.wrapListItemCommand(RemoveDirent.removeDirent), - 'Explorer.renameDirent': WrapCommand.wrapListItemCommand(RenameDirent.renameDirent), - 'Explorer.render2': Render2.render2, - 'Explorer.renderActions2': RenderActions2.renderActions, - 'Explorer.renderEventListeners': RenderEventListeners.renderEventListeners, - 'Explorer.restoreState': RestoreState.restoreState, - 'Explorer.reveal': WrapCommand.wrapListItemCommand(RevealItem.revealItem), - 'Explorer.revealItem': WrapCommand.wrapListItemCommand(RevealItem.revealItem), - - 'Explorer.saveState': WrapCommand.wrapGetter(SaveState.saveState), - 'Explorer.selectAll': WrapCommand.wrapListItemCommand(SelectAll.selectAll), - 'Explorer.selectDown': WrapCommand.wrapListItemCommand(SelectDown.selectDown), - 'Explorer.selectForCompare': WrapCommand.wrapListItemCommand(SelectForCompare.selectForCompare), - 'Explorer.selectIndices': WrapCommand.wrapListItemCommand(SelectIndices.setSelectedIndices), - 'Explorer.selectUp': WrapCommand.wrapListItemCommand(SelectUp.selectUp), - 'Explorer.setDeltaY': WrapCommand.wrapListItemCommand(SetDeltaY.setDeltaY), - 'Explorer.setSelectedIndices': WrapCommand.wrapListItemCommand(SelectIndices.setSelectedIndices), - 'Explorer.terminate': terminate, - 'Explorer.toggleIndividualSelection': WrapCommand.wrapListItemCommand(ToggleIndividualSelection.toggleIndividualSelection), - 'Explorer.updateEditingValue': WrapCommand.wrapListItemCommand(UpdateEditingValue.updateEditingValue), - 'Explorer.updateIcons': WrapCommand.wrapListItemCommand(UpdateIcons.updateIcons), } diff --git a/packages/explorer-view/test/ValidateFileName2.test.ts b/packages/explorer-view/test/ValidateFileName2.test.ts deleted file mode 100644 index 3ad2053..0000000 --- a/packages/explorer-view/test/ValidateFileName2.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { test, expect } from '@jest/globals' -import * as ValidateFileName2 from '../src/parts/ValidateFileName2/ValidateFileName2.ts' - -test('validateFileName2 - empty name', () => { - const result = ValidateFileName2.validateFileName2('') - expect(result).toBe('A file or folder name must be provided.') -}) - -test('validateFileName2 - name starting with dot (allowed)', () => { - const result = ValidateFileName2.validateFileName2('.hidden') - expect(result).toBe('') -}) - -test('validateFileName2 - dotfile like .git (allowed)', () => { - const result = ValidateFileName2.validateFileName2('.git') - expect(result).toBe('') -}) - -test('validateFileName2 - dotfile like .editorconfig (allowed)', () => { - const result = ValidateFileName2.validateFileName2('.editorconfig') - expect(result).toBe('') -}) - -test('validateFileName2 - reserved name "." (not allowed)', () => { - const result = ValidateFileName2.validateFileName2('.') - expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -}) - -test('validateFileName2 - reserved name ".." (not allowed)', () => { - const result = ValidateFileName2.validateFileName2('..') - expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -}) - -test('validateFileName2 - reserved name "..." (not allowed)', () => { - const result = ValidateFileName2.validateFileName2('...') - expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -}) - -test('validateFileName2 - reserved name "../" (not allowed)', () => { - const result = ValidateFileName2.validateFileName2('../') - expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -}) - -test('validateFileName2 - name starting with "../" (not allowed)', () => { - const result = ValidateFileName2.validateFileName2('../file.txt') - expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -}) - -test('validateFileName2 - name starting with "../" folder (not allowed)', () => { - const result = ValidateFileName2.validateFileName2('../folder') - expect(result).toBe('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -}) - -test('validateFileName2 - name starting with slash', () => { - const result = ValidateFileName2.validateFileName2('/file') - expect(result).toBe('A file or folder name cannot start with a slash.') -}) - -test('validateFileName2 - name starting with backslash', () => { - const result = ValidateFileName2.validateFileName2('\\file') - expect(result).toBe('A file or folder name cannot start with a backslash.') -}) - -test('validateFileName2 - valid name', () => { - const result = ValidateFileName2.validateFileName2('valid-file.txt') - expect(result).toBe('') -}) - -test('validateFileName2 - file already exists', () => { - const siblingFileNames = ['existing-file.txt', 'another-file.js'] - const result = ValidateFileName2.validateFileName2('existing-file.txt', siblingFileNames) - expect(result).toBe('A file or folder **existing-file.txt** already exists at this location. Please choose a different name.') -}) - -test('validateFileName2 - file does not exist', () => { - const siblingFileNames = ['existing-file.txt', 'another-file.js'] - const result = ValidateFileName2.validateFileName2('new-file.txt', siblingFileNames) - expect(result).toBe('') -}) diff --git a/packages/explorer-view/test/ValidateFolderCopy.test.ts b/packages/explorer-view/test/ValidateFolderCopy.test.ts deleted file mode 100644 index 3221fea..0000000 --- a/packages/explorer-view/test/ValidateFolderCopy.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { test, expect } from '@jest/globals' -import * as ValidateFolderCopy from '../src/parts/ValidateFolderCopy/ValidateFolderCopy.ts' - -test('should return null when copying folder to different location', () => { - const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder2') - expect(result).toBeNull() -}) - -test('should return null when copying file to different location', () => { - const result = ValidateFolderCopy.validateFolderCopy('test:///file.txt', 'test:///folder') - expect(result).toBeNull() -}) - -test('should return error when copying folder into its own subfolder', () => { - const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1/subfolder') - expect(result).toBe('Cannot copy folder folder1 into a subfolder of itself') -}) - -test('should return error when copying folder into nested subfolder', () => { - const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1/subfolder/nested') - expect(result).toBe('Cannot copy folder folder1 into a subfolder of itself') -}) - -test('should return error with Windows path separators', () => { - const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1\\subfolder') - expect(result).toBe('Cannot copy folder folder1 into a subfolder of itself') -}) - -test('should return null when paths are exactly the same', () => { - const result = ValidateFolderCopy.validateFolderCopy('test:///folder1', 'test:///folder1') - expect(result).toBeNull() -}) - -test('should return null when target is parent of source', () => { - const result = ValidateFolderCopy.validateFolderCopy('test:///folder1/subfolder', 'test:///folder1') - expect(result).toBeNull() -}) diff --git a/packages/explorer-view/test/ValidateOperations.test.ts b/packages/explorer-view/test/ValidateOperations.test.ts deleted file mode 100644 index a1e623b..0000000 --- a/packages/explorer-view/test/ValidateOperations.test.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { test, expect } from '@jest/globals' -import type { FileOperation } from '../src/parts/FileOperation/FileOperation.ts' -import * as FileOperationType from '../src/parts/FileOperationType/FileOperationType.ts' -import * as ValidateOperations from '../src/parts/ValidateOperations/ValidateOperations.ts' - -test('should return empty array when no operations provided', () => { - const result = ValidateOperations.validateOperations([]) - expect(result).toEqual([]) -}) - -test('should return empty array when operations contain only non-copy operations', () => { - const operations: FileOperation[] = [ - { - path: '/home/user/file.txt', - text: 'content', - type: FileOperationType.CreateFile, - }, - { - path: '/home/user/folder', - type: FileOperationType.CreateFolder, - }, - { - from: '/home/user/old.txt', - path: '/home/user/new.txt', - type: FileOperationType.Rename, - }, - { - path: '/home/user/delete.txt', - type: FileOperationType.Remove, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual([]) -}) - -test('should return empty array when copy operations are valid', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder2', - type: FileOperationType.Copy, - }, - { - from: 'test:///file.txt', - path: 'test:///copied.txt', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual([]) -}) - -test('should return error when copying folder into its own subfolder', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder1/subfolder', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should return error when copying folder into nested subfolder', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder1/subfolder/nested', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should return error with Windows path separators', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder1\\subfolder', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should return empty array when copying file into folder', () => { - const operations: FileOperation[] = [ - { - from: 'test:///file.txt', - path: 'test:///folder/file.txt', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual([]) -}) - -test('should return empty array when copying folder to different location', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder2', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual([]) -}) - -test('should return empty array when copying folder to parent directory', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1/subfolder', - path: 'test:///folder1', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual([]) -}) - -test('should return empty array when paths are exactly the same', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder1', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual([]) -}) - -test('should return errors for all invalid operations when multiple operations', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder2', // valid - type: FileOperationType.Copy, - }, - { - from: 'test:///folder3', - path: 'test:///folder3/subfolder', // invalid - type: FileOperationType.Copy, - }, - { - from: 'test:///folder4', - path: 'test:///folder4/nested', // also invalid - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder3 into a subfolder of itself', 'Cannot copy folder folder4 into a subfolder of itself']) -}) - -test('should handle mixed operation types with invalid copy', () => { - const operations: FileOperation[] = [ - { - path: 'test:///file.txt', - text: 'content', - type: FileOperationType.CreateFile, - }, - { - from: 'test:///folder1', - path: 'test:///folder1/subfolder', // invalid - type: FileOperationType.Copy, - }, - { - from: 'test:///old.txt', - path: 'test:///new.txt', - type: FileOperationType.Rename, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should handle paths with trailing separators', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1/', - path: 'test:///folder1/subfolder/', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should handle mixed path separators', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder1\\subfolder', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should handle relative paths', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder1', - path: 'test:///folder1/subfolder', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should handle deep nested paths', () => { - const operations: FileOperation[] = [ - { - from: 'test:///a/b/c/d/e/folder1', - path: 'test:///a/b/c/d/e/folder1/subfolder', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder1 into a subfolder of itself']) -}) - -test('should handle single character folder names', () => { - const operations: FileOperation[] = [ - { - from: 'test:///a', - path: 'test:///a/b', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder a into a subfolder of itself']) -}) - -test('should handle folder names with special characters', () => { - const operations: FileOperation[] = [ - { - from: 'test:///folder-name_123', - path: 'test:///folder-name_123/subfolder', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder folder-name_123 into a subfolder of itself']) -}) - -test('should handle empty folder names', () => { - const operations: FileOperation[] = [ - { - from: 'test:///', - path: 'test:///subfolder', - type: FileOperationType.Copy, - }, - ] - const result = ValidateOperations.validateOperations(operations) - expect(result).toEqual(['Cannot copy folder test: into a subfolder of itself']) -}) From 3b7278d0c806668ee7dc2b1d4521a6509eaca1b3 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:28:30 +0200 Subject: [PATCH 05/17] init --- packages/explorer-view/src/parts/Listen/Listen.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/explorer-view/src/parts/Listen/Listen.ts b/packages/explorer-view/src/parts/Listen/Listen.ts index c0f1aa9..8b93f30 100644 --- a/packages/explorer-view/src/parts/Listen/Listen.ts +++ b/packages/explorer-view/src/parts/Listen/Listen.ts @@ -1,11 +1,8 @@ import * as CommandMap from '../CommandMap/CommandMap.ts' import { registerCommands } from '../ExplorerStates/ExplorerStates.ts' -import { initializeFileSystemWorker } from '../InitializeFileSystemWorker/InitializeFileSystemWorker.ts' -import { initializeIconThemeWorker } from '../InitializeIconThemeWorker/InitializeIconThemeWorker.ts' import { initializeRendererWorker } from '../InitializeRendererWorker/initializeRendereWorker.ts' -import { initializeSourceControlWorker } from '../InitializeSourceControlWorker/InitializeSourceControlWorker.ts' export const listen = async (): Promise => { registerCommands(CommandMap.commandMap) - await Promise.all([initializeRendererWorker(), initializeFileSystemWorker(), initializeIconThemeWorker(), initializeSourceControlWorker()]) + await Promise.all([initializeRendererWorker()]) } From a83af770176e5b932f5986d4629f9ca2a47d3bb5 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:33:33 +0200 Subject: [PATCH 06/17] unused --- .../src/parts/AcceptCreate/AcceptCreate.ts | 68 ------ .../AcceptCreateFile/AcceptCreateFile.ts | 7 - .../AcceptCreateFolder/AcceptCreateFolder.ts | 7 - .../src/parts/AcceptEdit/AcceptEdit.ts | 19 -- .../src/parts/AcceptRename/AcceptRename.ts | 55 ----- .../src/parts/ActionType/ActionType.ts | 1 - .../AdjustScrollAfterPaste.ts | 17 -- .../ApplyFileOperation/ApplyFileOperation.ts | 18 -- .../ApplyFileOperations.ts | 16 -- .../src/parts/ApplyRender/ApplyRender.ts | 14 -- .../src/parts/AriaRoles/AriaRoles.ts | 4 - .../explorer-view/src/parts/Arrays/Arrays.ts | 11 - .../explorer-view/src/parts/Assert/Assert.ts | 1 - .../CanBeDroppedInto/CanBeDroppedInto.ts | 16 -- .../src/parts/CancelEdit/CancelEdit.ts | 6 - .../CancelEditCreate/CancelEditCreate.ts | 22 -- .../CancelEditInternal/CancelEditInternal.ts | 12 - .../CancelEditRename/CancelEditRename.ts | 24 -- .../parts/CancelTypeAhead/CancelTypeAhead.ts | 8 - .../src/parts/Character/Character.ts | 4 - .../ChevronDownVirtualDom.ts | 10 - .../ChevronRightVirtualDom.ts | 10 - .../src/parts/ChevronType/ChevronType.ts | 3 - .../src/parts/ClassNames/ClassNames.ts | 40 ---- .../src/parts/ClickHandler/ClickHandler.ts | 6 - .../src/parts/ClipBoard/ClipBoard.ts | 14 -- .../src/parts/CollapseAll/CollapseAll.ts | 13 -- .../src/parts/CommandMap/CommandMap.ts | 6 - .../src/parts/Compare/Compare.ts | 8 - .../src/parts/CompareDirent/CompareDirent.ts | 24 -- .../CompareWithSelected.ts | 18 -- .../ComputeExplorerRenamedDirentUpdate.ts | 28 --- .../src/parts/ConfirmDelete/ConfirmDelete.ts | 8 - .../src/parts/ConfirmPaste/ConfirmPaste.ts | 7 - .../src/parts/ContextMenu/ContextMenu.ts | 12 - .../ContextMenuHandler/ContextMenuHandler.ts | 5 - .../ContextMenuProps/ContextMenuProps.ts | 11 - .../CopyFilesElectron/CopyFilesElectron.ts | 11 - .../src/parts/CopyPath/CopyPath.ts | 12 - .../CopyRelativePath/CopyRelativePath.ts | 28 --- .../src/parts/CountInRange/CountInRange.ts | 7 - .../explorer-view/src/parts/Create/Create.ts | 82 ------- .../src/parts/Create2/Create2.ts | 17 -- .../CreateDecorationMap.ts | 10 - .../CreateDefaultState/CreateDefaultState.ts | 62 ----- .../CreateFileSystemWorkerRpc.ts | 15 -- .../CreateIconThemeWorkerRpc.ts | 19 -- .../CreateNestedPath/CreateNestedPath.ts | 18 -- .../CreateSourceControlWorkerWorkerRpc.ts | 20 -- .../src/parts/CreateTree/CreateTree.ts | 33 --- .../CreateUploadTree/CreateUploadTree.ts | 22 -- .../src/parts/DeltaEditing/DeltaEditing.ts | 1 - packages/explorer-view/src/parts/Diff/Diff.ts | 13 -- .../explorer-view/src/parts/Diff2/Diff2.ts | 8 - .../src/parts/DiffCss/DiffCss.ts | 21 -- .../src/parts/DiffDragData/DiffDragData.ts | 5 - .../DiffEditingSelection.ts | 10 - .../src/parts/DiffFocus/DiffFocus.ts | 5 - .../src/parts/DiffItems/DiffItems.ts | 23 -- .../src/parts/DiffModules/DiffModules.ts | 27 --- .../src/parts/DiffSelection/DiffSelection.ts | 5 - .../src/parts/DiffType/DiffType.ts | 9 - .../src/parts/DiffValue/DiffValue.ts | 9 - .../src/parts/DirentType/DirentType.ts | 21 -- .../DomEventListener/DomEventListener.ts | 7 - .../DomEventListenerFunctions.ts | 18 -- .../src/parts/DragDataItem/DragDataItem.ts | 4 - .../src/parts/DropHandler/DropHandler.ts | 6 - .../parts/DropTargetFull/DropTargetFull.ts | 1 - .../src/parts/EnsureUris/EnsureUris.ts | 10 - .../src/parts/ErrorCodes/ErrorCodes.ts | 1 - .../src/parts/ExpandAll/ExpandAll.ts | 38 ---- .../ExpandRecursively/ExpandRecursively.ts | 38 ---- .../src/parts/ExpandedType/ExpandedType.ts | 3 - .../ExplorerEditingType.ts | 7 - .../src/parts/ExplorerError/ExplorerError.ts | 6 - .../src/parts/ExplorerItem/ExplorerItem.ts | 10 - .../src/parts/ExplorerState/ExplorerState.ts | 65 ------ .../parts/ExplorerStates/ExplorerStates.ts | 81 ------- .../parts/ExplorerStrings/ExplorerStrings.ts | 140 ------------ .../parts/FileDecoration/FileDecoration.ts | 4 - .../src/parts/FileIconCache/FileIconCache.ts | 3 - .../parts/FileIconsRequest/FileIconsResult.ts | 6 - .../src/parts/FileOperation/FileOperation.ts | 35 --- .../FileOperationType/FileOperationType.ts | 5 - .../src/parts/FileSystem/FileSystem.ts | 41 ---- .../FileSystemWorker/FileSystemWorker.ts | 8 - .../FilterByFocusWord/FilterByFocusWord.ts | 25 -- .../explorer-view/src/parts/Focus/Focus.ts | 12 - .../src/parts/FocusFirst/FocusFirst.ts | 10 - .../src/parts/FocusId/FocusId.ts | 3 - .../src/parts/FocusIndex/FocusIndex.ts | 45 ---- .../src/parts/FocusKey/FocusKey.ts | 3 - .../src/parts/FocusLast/FocusLast.ts | 12 - .../src/parts/FocusNext/FocusNext.ts | 11 - .../src/parts/FocusNone/FocusNone.ts | 10 - .../FocusParentFolder/FocusParentFolder.ts | 11 - .../src/parts/FocusPrevious/FocusPrevious.ts | 18 -- .../GenerateUniqueName/GenerateUniqueName.ts | 42 ---- .../GetActionButtonVirtualDom.ts | 19 -- .../GetActionVirtualDom.ts | 13 -- .../src/parts/GetActions/GetActions.ts | 41 ---- .../GetActionsVirtualDom.ts | 20 -- .../parts/GetChevronType/GetChevronType.ts | 17 -- .../GetChevronVirtualDom.ts | 13 -- .../parts/GetChildDirents/GetChildDirents.ts | 22 -- .../GetChildDirentsRaw/GetChildDirentsRaw.ts | 14 -- .../GetChildDirentsRecursively.ts | 24 -- .../parts/GetChildHandles/GetChildHandles.ts | 8 - .../src/parts/GetClickFn/GetClickFn.ts | 49 ---- .../GetContainingFolder.ts | 10 - .../GetContextMenuHandler.ts | 13 -- .../explorer-view/src/parts/GetCss/GetCss.ts | 27 --- .../src/parts/GetDragData/GetDragData.ts | 36 --- .../src/parts/GetDragLabel/GetDragLabel.ts | 8 - .../parts/GetDropHandler/GetDropHandler.ts | 12 - .../parts/GetEditingIcon/GetEditingIcon.ts | 21 -- .../parts/GetEditingType/GetEditingType.ts | 8 - .../src/parts/GetErrorCode/GetErrorCode.ts | 6 - .../parts/GetErrorMessage/GetErrorMessage.ts | 9 - .../GetErrorMessageDom/GetErrorMessageDom.ts | 19 -- .../GetErrorMessagePosition.ts | 25 -- .../src/parts/GetExcluded/GetExcluded.ts | 10 - .../GetExpandedDirents/GetExpandedDirents.ts | 6 - .../parts/GetExpandedType/GetExpandedType.ts | 14 -- .../GetExplorerItemVirtualDom.ts | 43 ---- .../GetExplorerVirtualDom.ts | 65 ------ .../GetExplorerWelcomeVirtualDom.ts | 52 ----- .../src/parts/GetFileArray/GetFileArray.ts | 5 - .../GetFileDecorations/GetFileDecorations.ts | 32 --- .../GetFileHandleText/GetFileHandleText.ts | 5 - .../parts/GetFileHandles/GetFileHandles.ts | 10 - .../GetFileIconVirtualDom.ts | 14 -- .../src/parts/GetFileIcons/GetFileIcons.ts | 20 -- .../GetFileIconsCached/GetFileIconsCached.ts | 5 - .../GetFileOperations/GetFileOperations.ts | 22 -- .../GetFileOperationsCopy.ts | 33 --- .../GetFileOperationsCreate.ts | 47 ---- .../GetFileOperationsCut.ts | 20 -- .../GetFileOperationsElectron.ts | 24 -- .../GetFileOperationsRename.ts | 16 -- .../GetFilePathElectron.ts | 5 - .../src/parts/GetFilePaths/GetFilePaths.ts | 15 -- .../parts/GetFittingIndex/GetFittingIndex.ts | 16 -- .../GetFocusedDirent/GetFocusedDirent.ts | 8 - .../parts/GetFocusedFile/GetFocusedFile.ts | 14 -- .../GetFocusedIndexCancel.ts | 6 - .../src/parts/GetFolderIcon/GetFolderIcon.ts | 5 - .../GetFriendlyErrorMessage.ts | 15 -- .../GetIconVirtualDom/GetIconVirtualDom.ts | 12 - .../src/parts/GetIndentRule/GetIndentRule.ts | 5 - .../src/parts/GetIndex/GetIndex.ts | 11 - .../GetIndexFromPosition.ts | 13 -- .../GetInputClassName/GetInputClassName.ts | 9 - .../src/parts/GetInputDom/GetInputDom.ts | 30 --- .../parts/GetKeyBindings/GetKeyBindings.ts | 123 ---------- .../src/parts/GetLabelDom/GetLabelDom.ts | 28 --- .../GetListItemsVirtualDom.ts | 58 ----- .../GetLoadErrorMessage.ts | 24 -- .../GetLoadErrorVirtualDom.ts | 57 ----- .../src/parts/GetMaxLineY/GetMaxLineY.ts | 6 - .../parts/GetMenuEntries/GetMenuEntries.ts | 214 ------------------ .../parts/GetMenuEntries2/GetMenuEntries2.ts | 7 - .../GetMissingIconRequests.ts | 27 --- .../parts/GetMouseAction/GetMouseAction.ts | 5 - .../parts/GetMouseActions/GetMouseActions.ts | 33 --- .../GetNewChildDirentsForNewDirent.ts | 43 ---- .../GetNewDirentType/GetNewDirentType.ts | 13 -- .../GetNewDirentsAccept.ts | 72 ------ .../GetNewDirentsForCancelRename.ts | 12 - .../GetNewDirentsForNewDirent.ts | 50 ---- .../GetNewDirentsForRename.ts | 15 -- .../GetNewDropTargets/GetNewDropTargets.ts | 24 -- .../GetNumberOfVisibleItems.ts | 9 - .../GetParentEndIndex/GetParentEndIndex.ts | 11 - .../parts/GetParentFolder/GetParentFolder.ts | 22 -- .../GetParentStartIndex.ts | 10 - .../parts/GetPasteHandler/GetPasteHandler.ts | 18 -- .../src/parts/GetPath/GetPath.ts | 5 - .../GetPathDirentsMap/GetPathDirentsMap.ts | 17 -- .../src/parts/GetPathParts/GetPathParts.ts | 18 -- .../GetPathPartsChildren.ts | 16 -- .../GetPathPartsFromFileOperations.ts | 20 -- .../GetPathPartsToReveal.ts | 15 -- .../GetPathSeparator/GetPathSeparator.ts | 5 - .../src/parts/GetPaths/GetPaths.ts | 6 - .../src/parts/GetProtoMap/GetProtoMap.ts | 11 - .../GetProtoMapInternal.ts | 34 --- .../GetRenameSelectionRange.ts | 15 -- .../src/parts/GetRenderer/GetRenderer.ts | 33 --- .../GetRestoredDeltaY/GetRestoredDeltaY.ts | 6 - .../GetSavedChildDirents.ts | 48 ---- .../src/parts/GetSavedRoot/GetSavedRoot.ts | 3 - .../src/parts/GetScheme/GetScheme.ts | 9 - .../GetScrollBarSize/GetScrollBarSize.ts | 6 - .../parts/GetScrollBarTop/GetScrollBarTop.ts | 10 - .../GetScrollBarVirtualDom.ts | 23 -- .../GetSelectedItems/GetSelectedItems.ts | 7 - .../src/parts/GetSettings/GetSettings.ts | 21 -- .../GetSiblingFileNames.ts | 20 -- .../GetSimpleIconRequestType.ts | 13 -- .../parts/GetSymlinkType/GetSymlinkType.ts | 12 - .../GetTopLevelDirents/GetTopLevelDirents.ts | 8 - .../GetTreeItemClassName.ts | 24 -- .../GetTreeItemIndent/GetTreeItemIndent.ts | 5 - .../GetTreeItemIndentWithChevron.ts | 13 -- .../src/parts/GetUnique/GetUnique.ts | 9 - .../GetUniqueIndents/GetUniqueIndents.ts | 10 - .../GetVisibleExplorerItems.ts | 84 ------- .../GetWorkspacePath/GetWorkspacePath.ts | 5 - .../parts/HandleArrowLeft/HandleArrowLeft.ts | 23 -- .../HandleArrowRight/HandleArrowRight.ts | 28 --- .../HandleArrowRightDirectoryExpanded.ts | 14 -- .../src/parts/HandleBlur/HandleBlur.ts | 18 -- .../HandleButtonClick/HandleButtonClick.ts | 21 -- .../src/parts/HandleClick/HandleClick.ts | 49 ---- .../src/parts/HandleClickAt/HandleClickAt.ts | 32 --- .../HandleClickAtRangeSelection.ts | 13 -- .../HandleClickCurrent/HandleClickCurrent.ts | 6 - .../HandleClickCurrentButKeepFocus.ts | 6 - .../HandleClickDirectory.ts | 37 --- .../HandleClickDirectoryExpanded.ts | 44 ---- .../HandleClickDirectoryExpanding.ts | 20 -- .../parts/HandleClickFile/HandleClickFile.ts | 12 - .../HandleClickOpenFolder.ts | 7 - .../HandleClickSymlink/HandleClickSymlink.ts | 16 -- .../HandleContextMenu/HandleContextMenu.ts | 8 - .../HandleContextMenuAtIndex.ts | 21 -- .../HandleContextMenuKeyboard.ts | 9 - .../HandleContextMenuMouseAt.ts | 11 - .../HandleContextMenuWelcome.ts | 5 - .../src/parts/HandleCopy/HandleCopy.ts | 21 -- .../src/parts/HandleCut/HandleCut.ts | 20 -- .../HandleDoubleClick/HandleDoubleClick.ts | 11 - .../src/parts/HandleDragEnd/HandleDragEnd.ts | 8 - .../parts/HandleDragLeave/HandleDragLeave.ts | 5 - .../parts/HandleDragOver/HandleDragOver.ts | 11 - .../HandleDragOverIndex.ts | 15 -- .../parts/HandleDragStart/HandleDragStart.ts | 5 - .../src/parts/HandleDrop/HandleDrop.ts | 28 --- .../parts/HandleDropIndex/HandleDropIndex.ts | 90 -------- .../parts/HandleDropRoot/HandleDropRoot.ts | 27 --- .../HandleDropRootDefault.ts | 79 ------- .../HandleDropRootElectron.ts | 67 ------ .../src/parts/HandleEscape/HandleEscape.ts | 8 - .../src/parts/HandleFocus/HandleFocus.ts | 12 - .../HandleIconThemeChange.ts | 6 - .../parts/HandleInputBlur/HandleInputBlur.ts | 14 -- .../HandleInputClick/HandleInputClick.ts | 5 - .../HandleInputKeyDown/HandleInputKeyDown.ts | 5 - .../src/parts/HandleKeyDown/HandleKeyDown.ts | 42 ---- .../src/parts/HandlePaste/HandlePaste.ts | 35 --- .../parts/HandlePasteCopy/HandlePasteCopy.ts | 53 ----- .../parts/HandlePasteCut/HandlePasteCut.ts | 63 ------ .../parts/HandlePasteNone/HandlePasteNone.ts | 7 - .../HandlePointerDown/HandlePointerDown.ts | 17 -- .../HandleRangeSelection.ts | 24 -- .../src/parts/HandleResize/HandleResize.ts | 43 ---- .../parts/HandleSelection/HandleSelection.ts | 13 -- .../src/parts/HandleUpload/HandleUpload.ts | 18 -- .../src/parts/HandleWheel/HandleWheel.ts | 6 - .../HandleWorkspaceChange.ts | 10 - .../HandleWorkspaceRefresh.ts | 6 - .../HasLeadingOrTrailingWhitespace.ts | 5 - .../src/parts/HasProperty/HasProperty.ts | 7 - .../parts/HasSymbolicLink/HasSymbolicLink.ts | 6 - .../explorer-view/src/parts/Height/Height.ts | 1 - .../src/parts/I18NString/I18NString.ts | 1 - .../src/parts/IconRequest/IconRequest.ts | 5 - .../src/parts/IconTheme/IconTheme.ts | 23 -- .../src/parts/Initialize/Initialize.ts | 3 - .../InitializeFileSystemWorker.ts | 7 - .../InitializeIconThemeWorker.ts | 7 - .../initializeRendereWorker.ts | 10 - .../InitializeSourceControlWorker.ts | 12 - .../src/parts/InputName/InputName.ts | 6 - .../src/parts/InputSource/InputSource.ts | 2 - .../src/parts/IsAscii/IsAscii.ts | 5 - .../IsDirectoryHandle/IsDirectoryHandle.ts | 3 - .../src/parts/IsEqual/IsEqual.ts | 12 - .../src/parts/IsExpanded/IsExpanded.ts | 6 - .../IsExpandedDirectory.ts | 6 - .../src/parts/IsFileHandle/IsFileHandle.ts | 3 - .../src/parts/IsNormalItem/IsNormalItem.ts | 6 - .../parts/IsSymbolicLink/IsSymbolicLink.ts | 6 - .../src/parts/IsTopLevel/IsTopLevel.ts | 5 - .../parts/IsUriWithinRoot/IsUriWithinRoot.ts | 7 - .../parts/IsValidBaseName/IsValidBaseName.ts | 47 ---- .../src/parts/KeyBinding/KeyBinding.ts | 5 - .../src/parts/KeyCode/KeyCode.ts | 18 -- .../src/parts/KeyModifier/KeyModifier.ts | 4 - .../src/parts/LoadContent/LoadContent.ts | 71 ------ .../src/parts/MakeExpanded/MakeExpanded.ts | 12 - .../src/parts/MaskIcon/MaskIcon.ts | 4 - .../src/parts/MenuEntry/MenuEntry.ts | 6 - .../src/parts/MenuEntryId/MenuEntryId.ts | 1 - .../MenuEntrySeparator/MenuEntrySeparator.ts | 8 - .../src/parts/MenuItemFlags/MenuItemFlags.ts | 5 - .../parts/MergeClassNames/MergeClassNames.ts | 1 - .../src/parts/MergeDirents/MergeDirents.ts | 17 -- .../src/parts/MergeTrees/MergeTrees.ts | 8 - .../MergeVisibleWithHiddenItems.ts | 15 -- .../src/parts/MouseAction/MouseAction.ts | 12 - .../parts/MouseEventType/MouseEventType.ts | 3 - .../parts/NativeFileTypes/NativeFileTypes.ts | 3 - .../NativeFilesResult/NativeFilesResult.ts | 5 - .../src/parts/NewDirent/NewDirent.ts | 27 --- .../NewDirentsAcceptResult.ts | 6 - .../src/parts/NewFile/NewFile.ts | 8 - .../src/parts/NewFolder/NewFolder.ts | 7 - .../NormalizeDecorations.ts | 12 - .../NormalizeDirentType.ts | 8 - .../OpenContainingFolder.ts | 10 - .../src/parts/OpenDiff/OpenDiff.ts | 5 - .../src/parts/OpenFolder/OpenFolder.ts | 5 - .../OpenNativeFolder/OpenNativeFolder.ts | 5 - .../src/parts/OpenUri/OpenUri.ts | 5 - .../src/parts/OrderDirents/OrderDirents.ts | 28 --- .../src/parts/PasteHandler/PasteHandler.ts | 6 - packages/explorer-view/src/parts/Path/Path.ts | 26 --- .../src/parts/PathPart/PathPart.ts | 7 - .../PathSeparatorType/PathSeparatorType.ts | 1 - .../src/parts/PlatformType/PlatformType.ts | 7 - .../src/parts/PromiseStatus/PromiseStatus.ts | 3 - packages/explorer-view/src/parts/Px/Px.ts | 1 - .../src/parts/RawDirent/RawDirent.ts | 4 - .../src/parts/Refresh/Refresh.ts | 25 -- .../RefreshChildDirents.ts | 46 ---- .../RefreshWorkspace/RefreshWorkspace.ts | 10 - .../src/parts/RemoveDirent/RemoveDirent.ts | 44 ---- .../src/parts/RenameDirent/RenameDirent.ts | 28 --- .../src/parts/Render2/Render2.ts | 9 - .../parts/RenderActions2/RenderActions2.ts | 11 - .../src/parts/RenderCss/RenderCss.ts | 33 --- .../parts/RenderDragData/RenderDragData.ts | 10 - .../RenderEditingSelection.ts | 8 - .../RenderEventListeners.ts | 98 -------- .../src/parts/RenderFocus/RenderFocus.ts | 21 -- .../RenderFocusContext/RenderFocusContext.ts | 14 -- .../RenderIncremental/RenderIncremental.ts | 11 - .../src/parts/RenderItems/RenderItems.ts | 30 --- .../src/parts/RenderValue/RenderValue.ts | 14 -- .../src/parts/Renderer/Renderer.ts | 5 - .../RequestFileIcons/RequestFileIcons.ts | 12 - .../src/parts/ResetEditing/ResetEditing.ts | 13 -- .../ResolveSymbolicLinks.ts | 44 ---- .../RestoreDirentType/RestoreDirentType.ts | 8 - .../RestoreExpandedState.ts | 53 ----- .../src/parts/RestoreState/RestoreState.ts | 41 ---- .../src/parts/RestoredState/RestoredState.ts | 5 - .../src/parts/RevealItem/RevealItem.ts | 20 -- .../RevealItemHidden/RevealItemHidden.ts | 35 --- 352 files changed, 6660 deletions(-) delete mode 100644 packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts delete mode 100644 packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts delete mode 100644 packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts delete mode 100644 packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts delete mode 100644 packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts delete mode 100644 packages/explorer-view/src/parts/ActionType/ActionType.ts delete mode 100644 packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts delete mode 100644 packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts delete mode 100644 packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts delete mode 100644 packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts delete mode 100644 packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts delete mode 100644 packages/explorer-view/src/parts/Arrays/Arrays.ts delete mode 100644 packages/explorer-view/src/parts/Assert/Assert.ts delete mode 100644 packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts delete mode 100644 packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts delete mode 100644 packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts delete mode 100644 packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts delete mode 100644 packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts delete mode 100644 packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts delete mode 100644 packages/explorer-view/src/parts/Character/Character.ts delete mode 100644 packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/ChevronType/ChevronType.ts delete mode 100644 packages/explorer-view/src/parts/ClassNames/ClassNames.ts delete mode 100644 packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts delete mode 100644 packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts delete mode 100644 packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts delete mode 100644 packages/explorer-view/src/parts/CommandMap/CommandMap.ts delete mode 100644 packages/explorer-view/src/parts/Compare/Compare.ts delete mode 100644 packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts delete mode 100644 packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts delete mode 100644 packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts delete mode 100644 packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts delete mode 100644 packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts delete mode 100644 packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts delete mode 100644 packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts delete mode 100644 packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts delete mode 100644 packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts delete mode 100644 packages/explorer-view/src/parts/CopyPath/CopyPath.ts delete mode 100644 packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts delete mode 100644 packages/explorer-view/src/parts/CountInRange/CountInRange.ts delete mode 100644 packages/explorer-view/src/parts/Create/Create.ts delete mode 100644 packages/explorer-view/src/parts/Create2/Create2.ts delete mode 100644 packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts delete mode 100644 packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts delete mode 100644 packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts delete mode 100644 packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts delete mode 100644 packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts delete mode 100644 packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts delete mode 100644 packages/explorer-view/src/parts/CreateTree/CreateTree.ts delete mode 100644 packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts delete mode 100644 packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts delete mode 100644 packages/explorer-view/src/parts/Diff/Diff.ts delete mode 100644 packages/explorer-view/src/parts/Diff2/Diff2.ts delete mode 100644 packages/explorer-view/src/parts/DiffCss/DiffCss.ts delete mode 100644 packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts delete mode 100644 packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts delete mode 100644 packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts delete mode 100644 packages/explorer-view/src/parts/DiffItems/DiffItems.ts delete mode 100644 packages/explorer-view/src/parts/DiffModules/DiffModules.ts delete mode 100644 packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts delete mode 100644 packages/explorer-view/src/parts/DiffType/DiffType.ts delete mode 100644 packages/explorer-view/src/parts/DiffValue/DiffValue.ts delete mode 100644 packages/explorer-view/src/parts/DirentType/DirentType.ts delete mode 100644 packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts delete mode 100644 packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts delete mode 100644 packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts delete mode 100644 packages/explorer-view/src/parts/DropHandler/DropHandler.ts delete mode 100644 packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts delete mode 100644 packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts delete mode 100644 packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts delete mode 100644 packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts delete mode 100644 packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts delete mode 100644 packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts delete mode 100644 packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts delete mode 100644 packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts delete mode 100644 packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts delete mode 100644 packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts delete mode 100644 packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts delete mode 100644 packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts delete mode 100644 packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts delete mode 100644 packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts delete mode 100644 packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts delete mode 100644 packages/explorer-view/src/parts/FileOperation/FileOperation.ts delete mode 100644 packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts delete mode 100644 packages/explorer-view/src/parts/FileSystem/FileSystem.ts delete mode 100644 packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts delete mode 100644 packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts delete mode 100644 packages/explorer-view/src/parts/Focus/Focus.ts delete mode 100644 packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts delete mode 100644 packages/explorer-view/src/parts/FocusId/FocusId.ts delete mode 100644 packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts delete mode 100644 packages/explorer-view/src/parts/FocusKey/FocusKey.ts delete mode 100644 packages/explorer-view/src/parts/FocusLast/FocusLast.ts delete mode 100644 packages/explorer-view/src/parts/FocusNext/FocusNext.ts delete mode 100644 packages/explorer-view/src/parts/FocusNone/FocusNone.ts delete mode 100644 packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts delete mode 100644 packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts delete mode 100644 packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts delete mode 100644 packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetActions/GetActions.ts delete mode 100644 packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts delete mode 100644 packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts delete mode 100644 packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts delete mode 100644 packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts delete mode 100644 packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts delete mode 100644 packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts delete mode 100644 packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts delete mode 100644 packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts delete mode 100644 packages/explorer-view/src/parts/GetCss/GetCss.ts delete mode 100644 packages/explorer-view/src/parts/GetDragData/GetDragData.ts delete mode 100644 packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts delete mode 100644 packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts delete mode 100644 packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts delete mode 100644 packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts delete mode 100644 packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts delete mode 100644 packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts delete mode 100644 packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts delete mode 100644 packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts delete mode 100644 packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts delete mode 100644 packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts delete mode 100644 packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts delete mode 100644 packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts delete mode 100644 packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts delete mode 100644 packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts delete mode 100644 packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts delete mode 100644 packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts delete mode 100644 packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts delete mode 100644 packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts delete mode 100644 packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts delete mode 100644 packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts delete mode 100644 packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts delete mode 100644 packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts delete mode 100644 packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts delete mode 100644 packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts delete mode 100644 packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts delete mode 100644 packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts delete mode 100644 packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts delete mode 100644 packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts delete mode 100644 packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts delete mode 100644 packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts delete mode 100644 packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts delete mode 100644 packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts delete mode 100644 packages/explorer-view/src/parts/GetIndex/GetIndex.ts delete mode 100644 packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts delete mode 100644 packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts delete mode 100644 packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts delete mode 100644 packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts delete mode 100644 packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts delete mode 100644 packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts delete mode 100644 packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts delete mode 100644 packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts delete mode 100644 packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts delete mode 100644 packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts delete mode 100644 packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts delete mode 100644 packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts delete mode 100644 packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts delete mode 100644 packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts delete mode 100644 packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts delete mode 100644 packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts delete mode 100644 packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts delete mode 100644 packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts delete mode 100644 packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts delete mode 100644 packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts delete mode 100644 packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts delete mode 100644 packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts delete mode 100644 packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts delete mode 100644 packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts delete mode 100644 packages/explorer-view/src/parts/GetPath/GetPath.ts delete mode 100644 packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts delete mode 100644 packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts delete mode 100644 packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts delete mode 100644 packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts delete mode 100644 packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts delete mode 100644 packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts delete mode 100644 packages/explorer-view/src/parts/GetPaths/GetPaths.ts delete mode 100644 packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts delete mode 100644 packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts delete mode 100644 packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts delete mode 100644 packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts delete mode 100644 packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts delete mode 100644 packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts delete mode 100644 packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts delete mode 100644 packages/explorer-view/src/parts/GetScheme/GetScheme.ts delete mode 100644 packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts delete mode 100644 packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts delete mode 100644 packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts delete mode 100644 packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts delete mode 100644 packages/explorer-view/src/parts/GetSettings/GetSettings.ts delete mode 100644 packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts delete mode 100644 packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts delete mode 100644 packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts delete mode 100644 packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts delete mode 100644 packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts delete mode 100644 packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts delete mode 100644 packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts delete mode 100644 packages/explorer-view/src/parts/GetUnique/GetUnique.ts delete mode 100644 packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts delete mode 100644 packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts delete mode 100644 packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts delete mode 100644 packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts delete mode 100644 packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts delete mode 100644 packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts delete mode 100644 packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts delete mode 100644 packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts delete mode 100644 packages/explorer-view/src/parts/HandleClick/HandleClick.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts delete mode 100644 packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts delete mode 100644 packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts delete mode 100644 packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts delete mode 100644 packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts delete mode 100644 packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts delete mode 100644 packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts delete mode 100644 packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts delete mode 100644 packages/explorer-view/src/parts/HandleCut/HandleCut.ts delete mode 100644 packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts delete mode 100644 packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts delete mode 100644 packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts delete mode 100644 packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts delete mode 100644 packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts delete mode 100644 packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts delete mode 100644 packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts delete mode 100644 packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts delete mode 100644 packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts delete mode 100644 packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts delete mode 100644 packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts delete mode 100644 packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts delete mode 100644 packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts delete mode 100644 packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts delete mode 100644 packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts delete mode 100644 packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts delete mode 100644 packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts delete mode 100644 packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts delete mode 100644 packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts delete mode 100644 packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts delete mode 100644 packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts delete mode 100644 packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts delete mode 100644 packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts delete mode 100644 packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts delete mode 100644 packages/explorer-view/src/parts/HandleResize/HandleResize.ts delete mode 100644 packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts delete mode 100644 packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts delete mode 100644 packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts delete mode 100644 packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts delete mode 100644 packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts delete mode 100644 packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts delete mode 100644 packages/explorer-view/src/parts/HasProperty/HasProperty.ts delete mode 100644 packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts delete mode 100644 packages/explorer-view/src/parts/Height/Height.ts delete mode 100644 packages/explorer-view/src/parts/I18NString/I18NString.ts delete mode 100644 packages/explorer-view/src/parts/IconRequest/IconRequest.ts delete mode 100644 packages/explorer-view/src/parts/IconTheme/IconTheme.ts delete mode 100644 packages/explorer-view/src/parts/Initialize/Initialize.ts delete mode 100644 packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts delete mode 100644 packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts delete mode 100644 packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts delete mode 100644 packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts delete mode 100644 packages/explorer-view/src/parts/InputName/InputName.ts delete mode 100644 packages/explorer-view/src/parts/InputSource/InputSource.ts delete mode 100644 packages/explorer-view/src/parts/IsAscii/IsAscii.ts delete mode 100644 packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts delete mode 100644 packages/explorer-view/src/parts/IsEqual/IsEqual.ts delete mode 100644 packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts delete mode 100644 packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts delete mode 100644 packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts delete mode 100644 packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts delete mode 100644 packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts delete mode 100644 packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts delete mode 100644 packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts delete mode 100644 packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts delete mode 100644 packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts delete mode 100644 packages/explorer-view/src/parts/KeyCode/KeyCode.ts delete mode 100644 packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts delete mode 100644 packages/explorer-view/src/parts/LoadContent/LoadContent.ts delete mode 100644 packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts delete mode 100644 packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts delete mode 100644 packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts delete mode 100644 packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts delete mode 100644 packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts delete mode 100644 packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts delete mode 100644 packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts delete mode 100644 packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts delete mode 100644 packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts delete mode 100644 packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts delete mode 100644 packages/explorer-view/src/parts/MouseAction/MouseAction.ts delete mode 100644 packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts delete mode 100644 packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts delete mode 100644 packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts delete mode 100644 packages/explorer-view/src/parts/NewDirent/NewDirent.ts delete mode 100644 packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts delete mode 100644 packages/explorer-view/src/parts/NewFile/NewFile.ts delete mode 100644 packages/explorer-view/src/parts/NewFolder/NewFolder.ts delete mode 100644 packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts delete mode 100644 packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts delete mode 100644 packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts delete mode 100644 packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts delete mode 100644 packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts delete mode 100644 packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts delete mode 100644 packages/explorer-view/src/parts/OpenUri/OpenUri.ts delete mode 100644 packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts delete mode 100644 packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts delete mode 100644 packages/explorer-view/src/parts/Path/Path.ts delete mode 100644 packages/explorer-view/src/parts/PathPart/PathPart.ts delete mode 100644 packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts delete mode 100644 packages/explorer-view/src/parts/PlatformType/PlatformType.ts delete mode 100644 packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts delete mode 100644 packages/explorer-view/src/parts/Px/Px.ts delete mode 100644 packages/explorer-view/src/parts/RawDirent/RawDirent.ts delete mode 100644 packages/explorer-view/src/parts/Refresh/Refresh.ts delete mode 100644 packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts delete mode 100644 packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts delete mode 100644 packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts delete mode 100644 packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts delete mode 100644 packages/explorer-view/src/parts/Render2/Render2.ts delete mode 100644 packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts delete mode 100644 packages/explorer-view/src/parts/RenderCss/RenderCss.ts delete mode 100644 packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts delete mode 100644 packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts delete mode 100644 packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts delete mode 100644 packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts delete mode 100644 packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts delete mode 100644 packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts delete mode 100644 packages/explorer-view/src/parts/RenderItems/RenderItems.ts delete mode 100644 packages/explorer-view/src/parts/RenderValue/RenderValue.ts delete mode 100644 packages/explorer-view/src/parts/Renderer/Renderer.ts delete mode 100644 packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts delete mode 100644 packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts delete mode 100644 packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts delete mode 100644 packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts delete mode 100644 packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts delete mode 100644 packages/explorer-view/src/parts/RestoreState/RestoreState.ts delete mode 100644 packages/explorer-view/src/parts/RestoredState/RestoredState.ts delete mode 100644 packages/explorer-view/src/parts/RevealItem/RevealItem.ts delete mode 100644 packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts diff --git a/packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts b/packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts deleted file mode 100644 index 117b074..0000000 --- a/packages/explorer-view/src/parts/AcceptCreate/AcceptCreate.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' -import { createTree } from '../CreateTree/CreateTree.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import * as GetFileOperationsCreate from '../GetFileOperationsCreate/GetFileOperationsCreate.ts' -import * as GetIndex from '../GetIndex/GetIndex.ts' -import { getParentFolder } from '../GetParentFolder/GetParentFolder.ts' -import { getPathParts } from '../GetPathParts/GetPathParts.ts' -import { getPathPartsChildren } from '../GetPathPartsChildren/GetPathPartsChildren.ts' -import { getSiblingFileNames } from '../GetSiblingFileNames/GetSiblingFileNames.ts' -import { mergeTrees } from '../MergeTrees/MergeTrees.ts' -import { openUri } from '../OpenUri/OpenUri.ts' -import { join2 } from '../Path/Path.ts' -import { refreshWorkspace } from '../RefreshWorkspace/RefreshWorkspace.ts' -import { treeToArray } from '../TreeToArray/TreeToArray.ts' -import * as ValidateFileName2 from '../ValidateFileName2/ValidateFileName2.ts' - -export const acceptCreate = async (state: ExplorerState, newDirentType: number): Promise => { - const { editingValue, focusedIndex, items, pathSeparator, root } = state - const newFileName = editingValue - const siblingFileNames = getSiblingFileNames(items, focusedIndex, root, pathSeparator) - const editingErrorMessage = ValidateFileName2.validateFileName2(newFileName, siblingFileNames) - if (editingErrorMessage) { - return { - ...state, - editingErrorMessage, - } - } - const parentFolder = getParentFolder(items, focusedIndex, root, pathSeparator) - const absolutePath = join2(parentFolder, newFileName) - const operations = GetFileOperationsCreate.getFileOperationsCreate(editingValue, newDirentType, pathSeparator, absolutePath, root) - const createErrorMessage = await ApplyFileOperations.applyFileOperations(operations) - if (createErrorMessage) { - return { - ...state, - editingErrorMessage: createErrorMessage, - } - } - - const pathPaths = getPathParts(root, absolutePath, pathSeparator) - const children = await getPathPartsChildren(pathPaths) - - const tree = createTree(items, root) - const childTree = createTree(children, root) - const merged = mergeTrees(tree, childTree) - - const newItems = treeToArray(merged, root) - - const dirents = newItems - const newFocusedIndex = GetIndex.getIndex(newItems, absolutePath) - - await refreshWorkspace() - - if (newDirentType === DirentType.File) { - await openUri(absolutePath, true) - } - - return { - ...state, - editingIndex: -1, - editingType: ExplorerEditingType.None, - focus: FocusId.List, - focusedIndex: newFocusedIndex, - items: dirents, - } -} diff --git a/packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts b/packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts deleted file mode 100644 index eefc3e2..0000000 --- a/packages/explorer-view/src/parts/AcceptCreateFile/AcceptCreateFile.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { acceptCreate } from '../AcceptCreate/AcceptCreate.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const acceptCreateFile = async (state: ExplorerState): Promise => { - return acceptCreate(state, DirentType.File) -} diff --git a/packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts b/packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts deleted file mode 100644 index a579b1d..0000000 --- a/packages/explorer-view/src/parts/AcceptCreateFolder/AcceptCreateFolder.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { acceptCreate } from '../AcceptCreate/AcceptCreate.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const acceptCreateFolder = async (state: ExplorerState): Promise => { - return acceptCreate(state, DirentType.Directory) -} diff --git a/packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts b/packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts deleted file mode 100644 index 93aa374..0000000 --- a/packages/explorer-view/src/parts/AcceptEdit/AcceptEdit.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { acceptCreateFile } from '../AcceptCreateFile/AcceptCreateFile.ts' -import { acceptCreateFolder } from '../AcceptCreateFolder/AcceptCreateFolder.ts' -import { acceptRename } from '../AcceptRename/AcceptRename.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' - -export const acceptEdit = async (state: ExplorerState): Promise => { - const { editingType } = state - switch (editingType) { - case ExplorerEditingType.CreateFile: - return acceptCreateFile(state) - case ExplorerEditingType.CreateFolder: - return acceptCreateFolder(state) - case ExplorerEditingType.Rename: - return acceptRename(state) - default: - return state - } -} diff --git a/packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts b/packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts deleted file mode 100644 index 70b531d..0000000 --- a/packages/explorer-view/src/parts/AcceptRename/AcceptRename.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' -import { computeExplorerRenamedDirentUpdate } from '../ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts' -import { createTree } from '../CreateTree/CreateTree.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' -import * as GetFileOperationsRename from '../GetFileOperationsRename/GetFileOperationsRename.ts' -import { getIndex } from '../GetIndex/GetIndex.ts' -import { dirname2, join2 } from '../Path/Path.ts' -import { treeToArray } from '../TreeToArray/TreeToArray.ts' -import { updateTree2 } from '../UpdateTree2/UpdateTree2.ts' -import * as ValidateFileName2 from '../ValidateFileName2/ValidateFileName2.ts' - -export const acceptRename = async (state: ExplorerState): Promise => { - const { editingIndex, editingValue, items, root } = state - const editingErrorMessage = ValidateFileName2.validateFileName2(editingValue) - if (editingErrorMessage) { - return { - ...state, - editingErrorMessage, - } - } - const renamedDirent = items[editingIndex] - const operations = GetFileOperationsRename.getFileOperationsRename(renamedDirent.path, editingValue) - const renameErrorMessage = await ApplyFileOperations.applyFileOperations(operations) - if (renameErrorMessage) { - return { - ...state, - editingErrorMessage: renameErrorMessage, - } - } - const oldUri = renamedDirent.path - const dirname = dirname2(oldUri) - const newUri = join2(dirname, editingValue) - const children = await getChildDirents('/', dirname, renamedDirent.depth - 1, []) - const tree = createTree(items, root) - const update = computeExplorerRenamedDirentUpdate(root, dirname, oldUri, children, tree, newUri) - const newTree = updateTree2(tree, update) - const newDirents = treeToArray(newTree, root) - const newFocusedIndex = getIndex(newDirents, newUri) - return { - ...state, - editingIcon: '', - editingIndex: -1, - editingSelectionEnd: 0, - editingSelectionStart: 0, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: true, - focusedIndex: newFocusedIndex, - items: newDirents, - } -} diff --git a/packages/explorer-view/src/parts/ActionType/ActionType.ts b/packages/explorer-view/src/parts/ActionType/ActionType.ts deleted file mode 100644 index fb7182d..0000000 --- a/packages/explorer-view/src/parts/ActionType/ActionType.ts +++ /dev/null @@ -1 +0,0 @@ -export const Button = 1 diff --git a/packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts b/packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts deleted file mode 100644 index dd0338a..0000000 --- a/packages/explorer-view/src/parts/AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ScrollInto from '../ScrollInto/ScrollInto.ts' - -export const adjustScrollAfterPaste = (state: ExplorerState, focusedIndex: number): ExplorerState => { - const { itemHeight, maxLineY, minLineY } = state - const { newMaxLineY, newMinLineY } = ScrollInto.scrollInto(focusedIndex, minLineY, maxLineY) - const newDeltaY = newMinLineY * itemHeight - - return { - ...state, - deltaY: newDeltaY, - focused: true, - focusedIndex, - maxLineY: newMaxLineY, - minLineY: newMinLineY, - } -} diff --git a/packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts b/packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts deleted file mode 100644 index b00b1e2..0000000 --- a/packages/explorer-view/src/parts/ApplyFileOperation/ApplyFileOperation.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' - -export const applyOperation = (operation: FileOperation): Promise => { - switch (operation.type) { - case FileOperationType.Copy: - return FileSystem.copy(operation.from || '', operation.path) - case FileOperationType.CreateFolder: - return FileSystem.mkdir(operation.path) - case FileOperationType.Remove: - return FileSystem.remove(operation.path) - case FileOperationType.Rename: - return FileSystem.rename(operation.from || '', operation.path) - default: - return FileSystem.writeFile(operation.path, operation.text) - } -} diff --git a/packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts b/packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts deleted file mode 100644 index 7a5e6b4..0000000 --- a/packages/explorer-view/src/parts/ApplyFileOperations/ApplyFileOperations.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { VError } from '@lvce-editor/verror' -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import { applyOperation as applyFileOperation } from '../ApplyFileOperation/ApplyFileOperation.ts' - -export const applyFileOperations = async (operations: readonly FileOperation[]): Promise => { - try { - // TODO run operations in parallel if possible - for (const operation of operations) { - await applyFileOperation(operation) - } - return '' - } catch (error) { - console.error(new VError(error, `Failed to apply file operations`)) - return `${error}` - } -} diff --git a/packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts b/packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts deleted file mode 100644 index 57531b8..0000000 --- a/packages/explorer-view/src/parts/ApplyRender/ApplyRender.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetRenderer from '../GetRenderer/GetRenderer.ts' - -export const applyRender = (oldState: ExplorerState, newState: ExplorerState, diffResult: readonly number[]): readonly any[] => { - const commands = [] - for (const item of diffResult) { - const fn = GetRenderer.getRenderer(item) - const result = fn(oldState, newState) - if (result.length > 0) { - commands.push(result) - } - } - return commands -} diff --git a/packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts b/packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts deleted file mode 100644 index 3b08ee9..0000000 --- a/packages/explorer-view/src/parts/AriaRoles/AriaRoles.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const None = 'none' -export const ToolBar = 'toolbar' -export const Tree = 'tree' -export const TreeItem = 'treeitem' diff --git a/packages/explorer-view/src/parts/Arrays/Arrays.ts b/packages/explorer-view/src/parts/Arrays/Arrays.ts deleted file mode 100644 index f9a711a..0000000 --- a/packages/explorer-view/src/parts/Arrays/Arrays.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const lastIndex = (array: readonly any[]): number => { - return array.length - 1 -} - -export const fromAsync = async (asyncIterable: any): Promise => { - const children = [] - for await (const value of asyncIterable) { - children.push(value) - } - return children -} diff --git a/packages/explorer-view/src/parts/Assert/Assert.ts b/packages/explorer-view/src/parts/Assert/Assert.ts deleted file mode 100644 index 57950a9..0000000 --- a/packages/explorer-view/src/parts/Assert/Assert.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@lvce-editor/assert' diff --git a/packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts b/packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts deleted file mode 100644 index c907b95..0000000 --- a/packages/explorer-view/src/parts/CanBeDroppedInto/CanBeDroppedInto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const canBeDroppedInto = (dirent: ExplorerItem): boolean => { - if (!dirent) { - return false - } - switch (dirent.type) { - case DirentType.Directory: - case DirentType.DirectoryExpanded: - case DirentType.DirectoryExpanding: - return true - default: - return false - } -} diff --git a/packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts b/packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts deleted file mode 100644 index e49a584..0000000 --- a/packages/explorer-view/src/parts/CancelEdit/CancelEdit.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { cancelEditInternal } from '../CancelEditInternal/CancelEditInternal.ts' - -export const cancelEdit = async (state: ExplorerState): Promise => { - return cancelEditInternal(state, true) -} diff --git a/packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts b/packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts deleted file mode 100644 index deb3fa2..0000000 --- a/packages/explorer-view/src/parts/CancelEditCreate/CancelEditCreate.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import { getFocusedIndexCancel } from '../GetFocusedIndexCancel/GetFocusedIndexCancel.ts' -import { isNormalItem } from '../IsNormalItem/IsNormalItem.ts' - -export const cancelEditCreate = async (state: ExplorerState, keepFocus: boolean): Promise => { - const { editingIndex, items } = state - const filteredItems = items.filter(isNormalItem) - const newFocusedIndex = getFocusedIndexCancel(filteredItems, editingIndex) - return { - ...state, - editingErrorMessage: '', - editingIndex: -1, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: keepFocus, - focusedIndex: newFocusedIndex, - items: filteredItems, - } -} diff --git a/packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts b/packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts deleted file mode 100644 index 013d262..0000000 --- a/packages/explorer-view/src/parts/CancelEditInternal/CancelEditInternal.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { cancelEditCreate } from '../CancelEditCreate/CancelEditCreate.ts' -import { cancelEditRename } from '../CancelEditRename/CancelEditRename.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' - -export const cancelEditInternal = async (state: ExplorerState, keepFocus: boolean): Promise => { - const { editingType } = state - if (editingType === ExplorerEditingType.Rename) { - return cancelEditRename(state, keepFocus) - } - return cancelEditCreate(state, keepFocus) -} diff --git a/packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts b/packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts deleted file mode 100644 index 21cd212..0000000 --- a/packages/explorer-view/src/parts/CancelEditRename/CancelEditRename.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import { getFocusedIndexCancel } from '../GetFocusedIndexCancel/GetFocusedIndexCancel.ts' -import { getNewDirentsForCancelRename } from '../GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts' - -export const cancelEditRename = (state: ExplorerState, keepFocus: boolean): ExplorerState => { - const { editingIndex, items } = state - const newItems = getNewDirentsForCancelRename(items, editingIndex) - const newFocusedIndex = getFocusedIndexCancel(items, editingIndex) - return { - ...state, - editingErrorMessage: '', - editingIndex: -1, - editingSelectionEnd: 0, - editingSelectionStart: 0, - editingType: ExplorerEditingType.None, - editingValue: '', - focus: FocusId.List, - focused: keepFocus, - focusedIndex: newFocusedIndex, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts b/packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts deleted file mode 100644 index de9dc33..0000000 --- a/packages/explorer-view/src/parts/CancelTypeAhead/CancelTypeAhead.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const cancelTypeAhead = (state: ExplorerState): ExplorerState => { - return { - ...state, - focusWord: '', - } -} diff --git a/packages/explorer-view/src/parts/Character/Character.ts b/packages/explorer-view/src/parts/Character/Character.ts deleted file mode 100644 index fd657d0..0000000 --- a/packages/explorer-view/src/parts/Character/Character.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const EmptyString = '' -export const Slash = '/' -export const Dot = '.' -export const BackSlash = '\\' diff --git a/packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts b/packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts deleted file mode 100644 index 3fa3a25..0000000 --- a/packages/explorer-view/src/parts/ChevronDownVirtualDom/ChevronDownVirtualDom.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const chevronDownVirtualDom: VirtualDomNode = { - childCount: 0, - className: MergeClassNames.mergeClassNames(ClassNames.Chevron, ClassNames.MaskIconChevronDown), - type: VirtualDomElements.Div, -} diff --git a/packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts b/packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts deleted file mode 100644 index 25c3ac0..0000000 --- a/packages/explorer-view/src/parts/ChevronRightVirtualDom/ChevronRightVirtualDom.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const chevronRightVirtualDom: VirtualDomNode = { - childCount: 0, - className: MergeClassNames.mergeClassNames(ClassNames.Chevron, ClassNames.MaskIconChevronRight), - type: VirtualDomElements.Div, -} diff --git a/packages/explorer-view/src/parts/ChevronType/ChevronType.ts b/packages/explorer-view/src/parts/ChevronType/ChevronType.ts deleted file mode 100644 index 2525169..0000000 --- a/packages/explorer-view/src/parts/ChevronType/ChevronType.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const None = 0 -export const Right = 1 -export const Down = 2 diff --git a/packages/explorer-view/src/parts/ClassNames/ClassNames.ts b/packages/explorer-view/src/parts/ClassNames/ClassNames.ts deleted file mode 100644 index 412a034..0000000 --- a/packages/explorer-view/src/parts/ClassNames/ClassNames.ts +++ /dev/null @@ -1,40 +0,0 @@ -// 0 = 'Button' -// 1 = 'IconButton' -// 2 = 'Button IconButton' -// it could make dom diffing faster, since for classname, -// once at start, send all classnames to renderer process -// only numbers are compared. it could also make rendering faster, -// representing the concatenated strings for example -// since less data is transferred to renderer process -// then, components uses numeric classname -// TODO add option to make classnames numeric -// when a component uses multiple classnames, it is a new number -export const Actions = 'Actions' -export const Button = 'Button' -export const ButtonNarrow = 'ButtonNarrow' -export const ButtonPrimary = 'ButtonPrimary' -export const ButtonWide = 'ButtonWide' -export const Chevron = 'Chevron' -export const Empty = '' -export const Explorer = 'Explorer' -export const ExplorerDropTarget = 'DropTarget' -export const ExplorerErrorMessage = 'ExplorerErrorMessage' -export const ExplorerInputBox = 'ExplorerInputBox' -export const FileIcon = 'FileIcon' -export const FocusOutline = 'FocusOutline' -export const IconButton = 'IconButton' -export const InputBox = 'InputBox' -export const InputValidationError = 'InputValidationError' -export const Label = 'Label' -export const LabelCut = 'LabelCut' -export const ListItems = 'ListItems' -export const MaskIconChevronDown = 'MaskIconChevronDown' -export const MaskIconChevronRight = 'MaskIconChevronRight' -export const ScrollBar = 'ScrollBar' -export const ScrollBarSmall = 'ScrollBarSmall' -export const ScrollBarThumb = 'ScrollBarThumb' -export const TreeItem = 'TreeItem' -export const TreeItemActive = 'TreeItemActive' -export const Viewlet = 'Viewlet' -export const Welcome = 'Welcome' -export const WelcomeMessage = 'WelcomeMessage' diff --git a/packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts b/packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts deleted file mode 100644 index a39bc7e..0000000 --- a/packages/explorer-view/src/parts/ClickHandler/ClickHandler.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export interface ClickHandler { - (state: ExplorerState, dirent: ExplorerItem, index: number, keepFocus: boolean): Promise -} diff --git a/packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts b/packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts deleted file mode 100644 index 92664bc..0000000 --- a/packages/explorer-view/src/parts/ClipBoard/ClipBoard.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' - -export const writeText = async (text: string): Promise => { - await RendererWorker.writeClipBoardText(text) -} - -export const readNativeFiles = async (): Promise => { - return RendererWorker.invoke('ClipBoard.readNativeFiles') -} - -export const writeNativeFiles = async (type: string, files: readonly string[]): Promise => { - return RendererWorker.invoke('ClipBoard.writeNativeFiles', type, files) -} diff --git a/packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts b/packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts deleted file mode 100644 index cd711b2..0000000 --- a/packages/explorer-view/src/parts/CollapseAll/CollapseAll.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as IsTopLevel from '../IsTopLevel/IsTopLevel.ts' -import * as ToCollapsedDirent from '../ToCollapsedDirent/ToCollapsedDirent.ts' - -export const collapseAll = async (state: ExplorerState): Promise => { - const { items } = state - const newDirents = items.filter(IsTopLevel.isTopLevel).map(ToCollapsedDirent.toCollapsedDirent) - return { - ...state, - focusedIndex: 0, - items: newDirents, - } -} diff --git a/packages/explorer-view/src/parts/CommandMap/CommandMap.ts b/packages/explorer-view/src/parts/CommandMap/CommandMap.ts deleted file mode 100644 index a315aa7..0000000 --- a/packages/explorer-view/src/parts/CommandMap/CommandMap.ts +++ /dev/null @@ -1,6 +0,0 @@ -import * as WrapCommand from '../ExplorerStates/ExplorerStates.ts' -import * as UpdateIcons from '../UpdateIcons/UpdateIcons.ts' - -export const commandMap = { - 'Explorer.updateIcons': WrapCommand.wrapListItemCommand(UpdateIcons.updateIcons), -} diff --git a/packages/explorer-view/src/parts/Compare/Compare.ts b/packages/explorer-view/src/parts/Compare/Compare.ts deleted file mode 100644 index 4ca33ca..0000000 --- a/packages/explorer-view/src/parts/Compare/Compare.ts +++ /dev/null @@ -1,8 +0,0 @@ -const RE_CHARACTERS = /^[a-zA-Z.-]+$/ - -export const compareStringNumeric = (a: string, b: string): number => { - if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) { - return a < b ? -1 : 1 - } - return a.localeCompare(b, 'en', { numeric: true }) -} diff --git a/packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts b/packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts deleted file mode 100644 index 83c3ee3..0000000 --- a/packages/explorer-view/src/parts/CompareDirent/CompareDirent.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as Compare from '../Compare/Compare.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -const priorityMapFoldersFirst: Record = { - [DirentType.Directory]: 1, - [DirentType.File]: 0, - [DirentType.Socket]: 0, - [DirentType.SymLinkFile]: 0, - [DirentType.SymLinkFolder]: 1, - [DirentType.Unknown]: 0, -} - -const compareDirentType = (direntA: RawDirent, direntB: RawDirent): number => { - return priorityMapFoldersFirst[direntB.type] - priorityMapFoldersFirst[direntA.type] -} - -const compareDirentName = (direntA: RawDirent, direntB: RawDirent): number => { - return Compare.compareStringNumeric(direntA.name, direntB.name) -} - -export const compareDirent = (direntA: RawDirent, direntB: RawDirent): number => { - return compareDirentType(direntA, direntB) || compareDirentName(direntA, direntB) -} diff --git a/packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts b/packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts deleted file mode 100644 index c0f5b5e..0000000 --- a/packages/explorer-view/src/parts/CompareWithSelected/CompareWithSelected.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetFocusedFile from '../GetFocusedFile/GetFocusedFile.ts' -import * as OpenDiff from '../OpenDiff/OpenDiff.ts' - -export const compareWithSelected = async (state: ExplorerState): Promise => { - const focusedFile = GetFocusedFile.getFocusedFile(state) - if (!focusedFile) { - return state - } - if (!state.compareSourceUri || state.compareSourceUri === focusedFile.path) { - return state - } - await OpenDiff.openDiff(state.compareSourceUri, focusedFile.path, true) - return { - ...state, - compareSourceUri: '', - } -} diff --git a/packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts b/packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts deleted file mode 100644 index 2d25dd1..0000000 --- a/packages/explorer-view/src/parts/ComputeExplorerRenamedDirentUpdate/ComputeExplorerRenamedDirentUpdate.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { Tree } from '../Tree/Tree.ts' -import type { TreeUpdate } from '../TreeUpdate/TreeUpdate.ts' - -export const computeExplorerRenamedDirentUpdate = ( - root: string, - parentPath: string, - oldUri: string, - children: readonly ExplorerItem[], - tree: Tree, - newUri: string, -): TreeUpdate => { - const rootLength = root.length - const relativeDirname = parentPath.slice(rootLength) - const relativeOldPath = oldUri.slice(rootLength) - const relativeNewUri = newUri.slice(rootLength) - const update: TreeUpdate = Object.create(null) - update[relativeDirname] = children - const oldItems = tree[relativeOldPath] || [] - update[relativeNewUri] = oldItems - for (const [key, value] of Object.entries(tree)) { - if (key.startsWith(`${relativeOldPath}/`)) { - const newKey = `${relativeNewUri}` + key.slice(relativeOldPath.length) - update[newKey] = value - } - } - return update -} diff --git a/packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts b/packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts deleted file mode 100644 index ac4e728..0000000 --- a/packages/explorer-view/src/parts/ConfirmDelete/ConfirmDelete.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const confirmDelete = async (paths: readonly string[]): Promise => { - // TODO use i18n string - const message = paths.length === 1 ? `Are you sure you want to delete "${paths[0]}"?` : `Are you sure you want to delete ${paths.length} items?` - const result = await RendererWorker.confirm(message) - return result === true -} diff --git a/packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts b/packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts deleted file mode 100644 index 52ca7c7..0000000 --- a/packages/explorer-view/src/parts/ConfirmPaste/ConfirmPaste.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' - -export const confirmPaste = async (): Promise => { - const result = await RendererWorker.confirm(ExplorerStrings.pasteConfirmation()) - return result === true -} diff --git a/packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts b/packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts deleted file mode 100644 index 40c7ab7..0000000 --- a/packages/explorer-view/src/parts/ContextMenu/ContextMenu.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ContextMenuProps } from '../ContextMenuProps/ContextMenuProps.ts' - -export const show2 = async ( - uid: number, - menuId: ContextMenuProps['menuId'], - x: number, - y: number, - args: ContextMenuProps, -): Promise => { - await RendererWorker.showContextMenu2(uid, menuId, x, y, args) -} diff --git a/packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts b/packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts deleted file mode 100644 index 2ab40c0..0000000 --- a/packages/explorer-view/src/parts/ContextMenuHandler/ContextMenuHandler.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export interface ContextMenuHandler { - (state: ExplorerState, x: number, y: number): Promise -} diff --git a/packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts b/packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts deleted file mode 100644 index 08f5e6f..0000000 --- a/packages/explorer-view/src/parts/ContextMenuProps/ContextMenuProps.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { MenuEntryId } from '@lvce-editor/constants' - -export interface ContextMenuPropsBase { - readonly menuId: number -} - -export interface ContextMenuPropsExplorer extends ContextMenuPropsBase { - readonly menuId: typeof MenuEntryId.Explorer -} - -export type ContextMenuProps = ContextMenuPropsExplorer diff --git a/packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts b/packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts deleted file mode 100644 index f59019d..0000000 --- a/packages/explorer-view/src/parts/CopyFilesElectron/CopyFilesElectron.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' -import { applyFileOperations } from '../ApplyFileOperations/ApplyFileOperations.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' -import { getFileOperationsElectron } from '../GetFileOperationsElectron/GetFileOperationsElectron.ts' - -// TODO copy files in parallel -export const copyFilesElectron = async (root: string, fileHandles: DroppedArgs, files: readonly File[], paths: readonly string[]): Promise => { - const pathSeparator = await FileSystem.getPathSeparator(root) - const operations = await getFileOperationsElectron(root, paths, fileHandles, pathSeparator) - await applyFileOperations(operations) -} diff --git a/packages/explorer-view/src/parts/CopyPath/CopyPath.ts b/packages/explorer-view/src/parts/CopyPath/CopyPath.ts deleted file mode 100644 index e7272fe..0000000 --- a/packages/explorer-view/src/parts/CopyPath/CopyPath.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetFocusedDirent from '../GetFocusedDirent/GetFocusedDirent.ts' - -export const copyPath = async (state: ExplorerState): Promise => { - const dirent = GetFocusedDirent.getFocusedDirent(state) - // TODO windows paths - // TODO handle error - const path = dirent ? dirent.path : state.root - await RendererWorker.writeClipBoardText(path) - return state -} diff --git a/packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts b/packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts deleted file mode 100644 index f8cec66..0000000 --- a/packages/explorer-view/src/parts/CopyRelativePath/CopyRelativePath.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ClipBoard from '../ClipBoard/ClipBoard.ts' -import * as GetFocusedDirent from '../GetFocusedDirent/GetFocusedDirent.ts' - -const getRelativePath = (root: string, pathSeparator: string, path: string): string => { - if (root && path.startsWith(root)) { - const relativePath = path.slice(root.length) - if (relativePath.startsWith(pathSeparator)) { - return relativePath.slice(pathSeparator.length) - } - return relativePath - } - if (path.startsWith(pathSeparator)) { - return path.slice(pathSeparator.length) - } - return path -} - -export const copyRelativePath = async (state: ExplorerState): Promise => { - const dirent = GetFocusedDirent.getFocusedDirent(state) - if (!dirent) { - return state - } - const relativePath = getRelativePath(state.root, state.pathSeparator, dirent.path) - // TODO handle error - await ClipBoard.writeText(relativePath) - return state -} diff --git a/packages/explorer-view/src/parts/CountInRange/CountInRange.ts b/packages/explorer-view/src/parts/CountInRange/CountInRange.ts deleted file mode 100644 index f8c48df..0000000 --- a/packages/explorer-view/src/parts/CountInRange/CountInRange.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const countInRange = (start: number, end: number): readonly number[] => { - const items: number[] = [] - for (let i = start; i <= end; i++) { - items.push(i) - } - return items -} diff --git a/packages/explorer-view/src/parts/Create/Create.ts b/packages/explorer-view/src/parts/Create/Create.ts deleted file mode 100644 index 7d3dc29..0000000 --- a/packages/explorer-view/src/parts/Create/Create.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' -import * as Height from '../Height/Height.ts' -import * as PathSeparatorType from '../PathSeparatorType/PathSeparatorType.ts' - -// TODO parentUid might ot be needed -export const create = ( - id: number, - uri: string, - x: number, - y: number, - width: number, - height: number, - args: any, - parentUid: any, - platform: number = 0, - assetDir: string = '', -): any => { - const state: ExplorerState = { - assetDir, - compareSourceUri: '', - confirmDelete: false, - confirmPaste: false, - cutItems: [], - decorations: [], - deltaY: 0, - dropTargets: [], - editingErrorMessage: '', - editingIcon: '', - editingIndex: -1, - editingSelectionEnd: 0, - editingSelectionStart: 0, - editingType: ExplorerEditingType.None, - editingValue: '', - errorCode: '', - errorMessage: '', - errorMessageLeft: 0, - errorMessageTop: 0, - errorMessageWidth: 0, - excluded: [], - fileIconCache: Object.create(null), - finalDeltaY: 0, - focus: 0, - focused: false, - focusedIndex: -1, - focusWord: '', - focusWordTimeout: 800, - handleOffset: 0, - hasError: false, - height, - hoverIndex: -1, - icons: [], - initial: true, - inputSource: 0, - isPointerDown: false, - itemHeight: Height.ListItem, - items: [], - maxIndent: 0, - maxLineY: 0, - minLineY: 0, - parentUid, - pasteShouldMove: false, - pathSeparator: PathSeparatorType.Slash, - platform, - pointerDownIndex: -1, - root: '', - scrollBarActive: false, - scrollBarHeight: 0, - sourceControlDecorations: false, - sourceControlIgnoredUris: [], - uid: id, - useChevrons: false, - version: 0, - visibleExplorerItems: [], - width, - x, - y, - } - ExplorerStates.set(state.uid, state, state) - return state -} diff --git a/packages/explorer-view/src/parts/Create2/Create2.ts b/packages/explorer-view/src/parts/Create2/Create2.ts deleted file mode 100644 index 97dc62b..0000000 --- a/packages/explorer-view/src/parts/Create2/Create2.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { create } from '../Create/Create.ts' - -// TODO parentUid might ot be needed -export const create2 = ( - uid: number, - uri: string, - x: number, - y: number, - width: number, - height: number, - args: any, - parentUid: any, - platform: number = 0, - assetDir: string = '', -): void => { - return create(uid, uri, x, y, width, height, args, parentUid, platform, assetDir) -} diff --git a/packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts b/packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts deleted file mode 100644 index 0228b59..0000000 --- a/packages/explorer-view/src/parts/CreateDecorationMap/CreateDecorationMap.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ensureUri } from '../EnsureUris/EnsureUris.ts' - -export const createDecorationMap = (decorations: readonly any[]): Record => { - const map: Record = Object.create(null) - for (const decoration of decorations) { - const uri = ensureUri(decoration.uri) - map[uri] = decoration.decoration - } - return map -} diff --git a/packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts b/packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts deleted file mode 100644 index ec6deb7..0000000 --- a/packages/explorer-view/src/parts/CreateDefaultState/CreateDefaultState.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const createDefaultState = (): ExplorerState => ({ - assetDir: '', - compareSourceUri: '', - confirmDelete: false, - confirmPaste: false, - cutItems: [], - decorations: [], - deltaY: 0, - dropTargets: [], - editingErrorMessage: '', - editingIcon: '', - editingIndex: -1, - editingSelectionEnd: 0, - editingSelectionStart: 0, - editingType: 0, - editingValue: '', - errorCode: '', - errorMessage: '', - errorMessageLeft: 0, - errorMessageTop: 0, - errorMessageWidth: 0, - excluded: [], - fileIconCache: {}, - finalDeltaY: 0, - focus: 0, - focused: true, - focusedIndex: 0, - focusWord: '', - focusWordTimeout: 1000, - handleOffset: 0, - hasError: false, - height: 100, - hoverIndex: 0, - icons: [], - initial: false, - inputSource: 0, - isPointerDown: false, - itemHeight: 20, - items: [], - maxIndent: 0, - maxLineY: 0, - minLineY: 0, - parentUid: 0, - pasteShouldMove: false, - pathSeparator: '/', - platform: 0, - pointerDownIndex: -1, - root: '/', - scrollBarActive: false, - scrollBarHeight: 0, - sourceControlDecorations: false, - sourceControlIgnoredUris: [], - uid: 1, - useChevrons: false, - version: 1, - visibleExplorerItems: [], - width: 100, - x: 0, - y: 0, -}) diff --git a/packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts b/packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts deleted file mode 100644 index 829144d..0000000 --- a/packages/explorer-view/src/parts/CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { type Rpc, LazyTransferMessagePortRpcParent } from '@lvce-editor/rpc' -import { VError } from '@lvce-editor/verror' -import * as SendMessagePortToFileSystemWorker from '../SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts' - -export const createFileSystemWorkerRpc = async (): Promise => { - try { - const rpc = await LazyTransferMessagePortRpcParent.create({ - commandMap: {}, - send: SendMessagePortToFileSystemWorker.sendMessagePortToFileSystemWorker, - }) - return rpc - } catch (error) { - throw new VError(error, `Failed to create file system worker rpc`) - } -} diff --git a/packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts b/packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts deleted file mode 100644 index b62b62e..0000000 --- a/packages/explorer-view/src/parts/CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { type Rpc, LazyTransferMessagePortRpcParent } from '@lvce-editor/rpc' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { VError } from '@lvce-editor/verror' - -const send = (port: MessagePort): Promise => { - return RendererWorker.sendMessagePortToIconThemeWorker(port, 0) -} - -export const createIconThemeWorkerRpc = async (): Promise => { - try { - const rpc = await LazyTransferMessagePortRpcParent.create({ - commandMap: {}, - send, - }) - return rpc - } catch (error) { - throw new VError(error, `Failed to create icon theme worker rpc`) - } -} diff --git a/packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts b/packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts deleted file mode 100644 index d7de3bf..0000000 --- a/packages/explorer-view/src/parts/CreateNestedPath/CreateNestedPath.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as FileSystem from '../FileSystem/FileSystem.ts' - -export const createNestedPath = async (root: string, path: string, pathSeparator: string): Promise => { - const parts = path.slice(root.length).split(pathSeparator) - let currentPath = '' - for (const part of parts) { - if (!part) continue - currentPath = currentPath ? `${currentPath}${pathSeparator}${part}` : part - try { - await FileSystem.mkdir(`${root}${currentPath}`) - } catch (error) { - // Ignore error if directory already exists - if (!(error instanceof Error && error.message.includes('already exists'))) { - throw error - } - } - } -} diff --git a/packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts b/packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts deleted file mode 100644 index 513b5fd..0000000 --- a/packages/explorer-view/src/parts/CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { type Rpc, LazyTransferMessagePortRpcParent } from '@lvce-editor/rpc' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import { VError } from '@lvce-editor/verror' - -const send = (port: MessagePort): Promise => { - // @ts-ignore - return RendererWorker.sendMessagePortToSourceControlWorker(port, 0) -} - -export const createSourceControlWorkerRpc = async (): Promise => { - try { - const rpc = await LazyTransferMessagePortRpcParent.create({ - commandMap: {}, - send, - }) - return rpc - } catch (error) { - throw new VError(error, `Failed to create source control worker rpc`) - } -} diff --git a/packages/explorer-view/src/parts/CreateTree/CreateTree.ts b/packages/explorer-view/src/parts/CreateTree/CreateTree.ts deleted file mode 100644 index 7529c35..0000000 --- a/packages/explorer-view/src/parts/CreateTree/CreateTree.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { Tree } from '../Tree/Tree.ts' -import type { TreeItem } from '../TreeItem/TreeItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as Path from '../Path/Path.ts' - -const getActualType = (type: number, expanded: boolean): number => { - const actualType = type === DirentType.Directory && expanded ? DirentType.DirectoryExpanded : type - return actualType -} - -export const createTree = (items: readonly ExplorerItem[], root: string): Tree => { - const tree: Record = Object.create(null) - const rootLength = root.length - const paths = items.map((item) => { - const relativePath = item.path.slice(rootLength) - const dirname = Path.dirname2(relativePath) - return dirname - }) - for (const item of items) { - const { name, path, type } = item - const relativePath = path.slice(rootLength) - const dirname = Path.dirname2(relativePath) - const isExpanded = paths.includes(relativePath) - const actualType = getActualType(type, isExpanded) - tree[dirname] ||= [] - tree[dirname].push({ - name, - type: actualType, - }) - } - return tree -} diff --git a/packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts b/packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts deleted file mode 100644 index 7cadf87..0000000 --- a/packages/explorer-view/src/parts/CreateUploadTree/CreateUploadTree.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { getChildHandles } from '../GetChildHandles/GetChildHandles.ts' -import { getFileHandleText } from '../GetFileHandleText/GetFileHandleText.ts' -import { isDirectoryHandle } from '../IsDirectoryHandle/IsDirectoryHandle.ts' -import { isFileHandle } from '../IsFileHandle/IsFileHandle.ts' - -export const createUploadTree = async (root: string, fileHandles: readonly FileSystemHandle[]): Promise => { - const uploadTree = Object.create(null) - const normalized = fileHandles.filter(Boolean) - for (const fileHandle of normalized) { - const { name } = fileHandle - if (isDirectoryHandle(fileHandle)) { - const children = await getChildHandles(fileHandle) - const childTree = await createUploadTree(name, children) - uploadTree[name] = childTree - } else if (isFileHandle(fileHandle)) { - // TODO maybe save blob and use filesystem.writeblob - const text = await getFileHandleText(fileHandle) - uploadTree[name] = text - } - } - return uploadTree -} diff --git a/packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts b/packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts deleted file mode 100644 index fcbcc6d..0000000 --- a/packages/explorer-view/src/parts/DeltaEditing/DeltaEditing.ts +++ /dev/null @@ -1 +0,0 @@ -export const DELTA_EDITING = 100 diff --git a/packages/explorer-view/src/parts/Diff/Diff.ts b/packages/explorer-view/src/parts/Diff/Diff.ts deleted file mode 100644 index d85bc2f..0000000 --- a/packages/explorer-view/src/parts/Diff/Diff.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DiffModules from '../DiffModules/DiffModules.ts' - -export const diff = (oldState: ExplorerState, newState: ExplorerState): readonly number[] => { - const diffResult: number[] = [] - for (let i = 0; i < DiffModules.modules.length; i++) { - const fn = DiffModules.modules[i] - if (!fn(oldState, newState)) { - diffResult.push(DiffModules.numbers[i]) - } - } - return diffResult -} diff --git a/packages/explorer-view/src/parts/Diff2/Diff2.ts b/packages/explorer-view/src/parts/Diff2/Diff2.ts deleted file mode 100644 index 988bc96..0000000 --- a/packages/explorer-view/src/parts/Diff2/Diff2.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as Diff from '../Diff/Diff.ts' -import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' - -export const diff2 = (uid: number): readonly number[] => { - const { newState, oldState } = ExplorerStates.get(uid) - const result = Diff.diff(oldState, newState) - return result -} diff --git a/packages/explorer-view/src/parts/DiffCss/DiffCss.ts b/packages/explorer-view/src/parts/DiffCss/DiffCss.ts deleted file mode 100644 index 490681d..0000000 --- a/packages/explorer-view/src/parts/DiffCss/DiffCss.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { - // TODO compute css more optimized - // maybe only when items change, and even then not - // always, but only when it affects the css - return ( - oldState.deltaY === newState.deltaY && - oldState.editingErrorMessage === newState.editingErrorMessage && - oldState.hasError === newState.hasError && - oldState.errorMessage === newState.errorMessage && - oldState.errorCode === newState.errorCode && - oldState.errorMessageLeft === newState.errorMessageLeft && - oldState.errorMessageTop === newState.errorMessageTop && - oldState.maxIndent === newState.maxIndent && - oldState.scrollBarActive === newState.scrollBarActive && - oldState.scrollBarHeight === newState.scrollBarHeight && - oldState.visibleExplorerItems === newState.visibleExplorerItems && - oldState.width === newState.width - ) -} diff --git a/packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts b/packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts deleted file mode 100644 index 85ec20e..0000000 --- a/packages/explorer-view/src/parts/DiffDragData/DiffDragData.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { - return oldState.isPointerDown || !newState.isPointerDown -} diff --git a/packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts b/packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts deleted file mode 100644 index 19083a6..0000000 --- a/packages/explorer-view/src/parts/DiffEditingSelection/DiffEditingSelection.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { Selection } from '../Selection/Selection.ts' - -export const diffEditingSelection = (state: ExplorerState, start: number, end: number): Selection | undefined => { - const { editingSelectionEnd, editingSelectionStart } = state - if (editingSelectionStart === start && editingSelectionEnd === end) { - return undefined - } - return { end, start } -} diff --git a/packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts b/packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts deleted file mode 100644 index dd68b49..0000000 --- a/packages/explorer-view/src/parts/DiffFocus/DiffFocus.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { - return oldState.focused === newState.focused && oldState.focus === newState.focus -} diff --git a/packages/explorer-view/src/parts/DiffItems/DiffItems.ts b/packages/explorer-view/src/parts/DiffItems/DiffItems.ts deleted file mode 100644 index 37e3e58..0000000 --- a/packages/explorer-view/src/parts/DiffItems/DiffItems.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { - return ( - oldState.items === newState.items && - oldState.minLineY === newState.minLineY && - oldState.maxLineY === newState.maxLineY && - oldState.focusedIndex === newState.focusedIndex && - oldState.editingIndex === newState.editingIndex && - oldState.editingType === newState.editingType && - oldState.editingValue === newState.editingValue && - oldState.editingErrorMessage === newState.editingErrorMessage && - oldState.hasError === newState.hasError && - oldState.errorMessage === newState.errorMessage && - oldState.errorCode === newState.errorCode && - oldState.width === newState.width && - oldState.focused === newState.focused && - oldState.dropTargets === newState.dropTargets && - oldState.icons === newState.icons && - oldState.cutItems === newState.cutItems && - oldState.visibleExplorerItems === newState.visibleExplorerItems - ) -} diff --git a/packages/explorer-view/src/parts/DiffModules/DiffModules.ts b/packages/explorer-view/src/parts/DiffModules/DiffModules.ts deleted file mode 100644 index 499e2c3..0000000 --- a/packages/explorer-view/src/parts/DiffModules/DiffModules.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as DiffCss from '../DiffCss/DiffCss.ts' -import * as DiffDragData from '../DiffDragData/DiffDragData.ts' -import * as DiffFocus from '../DiffFocus/DiffFocus.ts' -import * as DiffItems from '../DiffItems/DiffItems.ts' -import * as DiffSelection from '../DiffSelection/DiffSelection.ts' -import * as DiffType from '../DiffType/DiffType.ts' -import * as DiffValue from '../DiffValue/DiffValue.ts' - -export const modules = [ - DiffItems.isEqual, - DiffFocus.isEqual, - DiffFocus.isEqual, - DiffValue.isEqual, - DiffSelection.isEqual, - DiffDragData.isEqual, - DiffCss.isEqual, -] - -export const numbers = [ - DiffType.RenderIncremental, - DiffType.RenderFocus, - DiffType.RenderFocusContext, - DiffType.RenderValue, - DiffType.RenderSelection, - DiffType.RenderDragData, - DiffType.RenderCss, -] diff --git a/packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts b/packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts deleted file mode 100644 index ac1c39a..0000000 --- a/packages/explorer-view/src/parts/DiffSelection/DiffSelection.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { - return oldState.editingSelectionStart === newState.editingSelectionStart && oldState.editingSelectionEnd === newState.editingSelectionEnd -} diff --git a/packages/explorer-view/src/parts/DiffType/DiffType.ts b/packages/explorer-view/src/parts/DiffType/DiffType.ts deleted file mode 100644 index 898bd08..0000000 --- a/packages/explorer-view/src/parts/DiffType/DiffType.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const RenderItems = 4 -export const RenderEditingIndex = 5 -export const RenderFocus = 6 -export const RenderFocusContext = 7 -export const RenderValue = 8 -export const RenderSelection = 9 -export const RenderDragData = 10 -export const RenderCss = 11 -export const RenderIncremental = 12 diff --git a/packages/explorer-view/src/parts/DiffValue/DiffValue.ts b/packages/explorer-view/src/parts/DiffValue/DiffValue.ts deleted file mode 100644 index 86cc483..0000000 --- a/packages/explorer-view/src/parts/DiffValue/DiffValue.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusId from '../FocusId/FocusId.ts' - -export const isEqual = (oldState: ExplorerState, newState: ExplorerState): boolean => { - if (newState.focus !== FocusId.Input) { - return true - } - return oldState.focus === FocusId.Input && newState.focus === FocusId.Input && oldState.editingValue === newState.editingValue -} diff --git a/packages/explorer-view/src/parts/DirentType/DirentType.ts b/packages/explorer-view/src/parts/DirentType/DirentType.ts deleted file mode 100644 index 98b34c3..0000000 --- a/packages/explorer-view/src/parts/DirentType/DirentType.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { DELTA_EDITING } from '../DeltaEditing/DeltaEditing.ts' - -export const BlockDevice = 1 -export const CharacterDevice = 2 -export const Directory = 3 -export const DirectoryExpanded = 4 -export const DirectoryExpanding = 5 -export const File = 7 -export const Socket = 8 -export const Symlink = 9 -export const SymLinkFile = 10 -export const SymLinkFolder = 11 -export const Unknown = 12 - -export const EditingFile = File + DELTA_EDITING -export const EditingFolder = Directory + DELTA_EDITING -export const EditingDirectoryExpanded = DirectoryExpanded + DELTA_EDITING -export const EditingUnknown = Unknown + DELTA_EDITING -export const EditingSymLinkFile = SymLinkFile + DELTA_EDITING -export const EditingSymLinkFolder = SymLinkFolder + DELTA_EDITING -export const EditingSymLinkUnknown = Symlink + DELTA_EDITING diff --git a/packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts b/packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts deleted file mode 100644 index 7c7ca5a..0000000 --- a/packages/explorer-view/src/parts/DomEventListener/DomEventListener.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface DomEventListener { - readonly name: string | number - readonly params: readonly string[] - readonly passive?: boolean - readonly preventDefault?: boolean - readonly stopPropagation?: boolean -} diff --git a/packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts b/packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts deleted file mode 100644 index 5301d5d..0000000 --- a/packages/explorer-view/src/parts/DomEventListenerFunctions/DomEventListenerFunctions.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const HandleButtonClick = 18 -export const HandleClick = 1 -export const HandleClickOpenFolder = 2 -export const HandleContextMenu = 3 -export const HandleContextMenuWelcome = 20 -export const HandleDragEnd = 19 -export const HandleDragLeave = 4 -export const HandleDragOver = 5 -export const HandleDragStart = 17 -export const HandleDrop = 6 -export const HandleEditingInput = 7 -export const HandleInputBlur = 8 -export const HandleInputClick = 9 -export const HandleListBlur = 11 -export const HandleListFocus = 12 -export const HandlePointerDown = 14 -export const HandleWheel = 15 -export const HandleDoubleClick = 16 diff --git a/packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts b/packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts deleted file mode 100644 index 0dd2ddc..0000000 --- a/packages/explorer-view/src/parts/DragDataItem/DragDataItem.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface DragDataItem { - readonly data: string - readonly type: string -} diff --git a/packages/explorer-view/src/parts/DropHandler/DropHandler.ts b/packages/explorer-view/src/parts/DropHandler/DropHandler.ts deleted file mode 100644 index c055948..0000000 --- a/packages/explorer-view/src/parts/DropHandler/DropHandler.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' - -export interface DropHandler { - (state: ExplorerState, fileHandles: DroppedArgs, files: readonly File[], paths: readonly string[], index: number): Promise -} diff --git a/packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts b/packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts deleted file mode 100644 index 9d94738..0000000 --- a/packages/explorer-view/src/parts/DropTargetFull/DropTargetFull.ts +++ /dev/null @@ -1 +0,0 @@ -export const dropTargetFull = [-1] diff --git a/packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts b/packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts deleted file mode 100644 index 657b3a6..0000000 --- a/packages/explorer-view/src/parts/EnsureUris/EnsureUris.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const ensureUri = (item: string): string => { - if (item.startsWith('/')) { - return `file://` + item - } - return item -} - -export const ensureUris = (maybeUris: readonly string[]): readonly string[] => { - return maybeUris.map(ensureUri) -} diff --git a/packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts b/packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts deleted file mode 100644 index 0e4fc54..0000000 --- a/packages/explorer-view/src/parts/ErrorCodes/ErrorCodes.ts +++ /dev/null @@ -1 +0,0 @@ -export const ENOENT = 'ENOENT' diff --git a/packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts b/packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts deleted file mode 100644 index 86d9987..0000000 --- a/packages/explorer-view/src/parts/ExpandAll/ExpandAll.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' - -export const expandAll = async (state: ExplorerState): Promise => { - const { focusedIndex, items, pathSeparator } = state - if (focusedIndex === -1) { - return state - } - const dirent = items[focusedIndex] - const { depth } = dirent - const newDirents = [...items] - // TODO fetch child dirents in parallel - for (const dirent of newDirents) { - if (dirent.depth === depth && dirent.type === DirentType.Directory) { - // TODO expand - // TODO avoid mutating state here - // @ts-ignore - dirent.type = DirentType.DirectoryExpanding - // TODO handle error - // TODO race condition - const childDirents = await GetChildDirents.getChildDirents(pathSeparator, dirent.path, dirent.depth) - const newIndex = newDirents.indexOf(dirent) - if (newIndex === -1) { - continue - } - newDirents.splice(newIndex + 1, 0, ...childDirents) - // TODO avoid mutating state here - // @ts-ignore - dirent.type = DirentType.DirectoryExpanded - // await expand(state, dirent.index) - } - } - return { - ...state, - items: newDirents, - } -} diff --git a/packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts b/packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts deleted file mode 100644 index bf80a58..0000000 --- a/packages/explorer-view/src/parts/ExpandRecursively/ExpandRecursively.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as GetChildDirentsRecursively from '../GetChildDirentsRecursively/GetChildDirentsRecursively.ts' -import * as GetParentEndIndex from '../GetParentEndIndex/GetParentEndIndex.ts' - -export const expandRecursively = async (state: ExplorerState): Promise => { - const { focusedIndex, items, pathSeparator, root } = state - const dirent = - focusedIndex < 0 - ? { - depth: 0, - path: root, - type: DirentType.Directory, - } - : items[focusedIndex] - if (dirent.type !== DirentType.Directory && dirent.type !== DirentType.DirectoryExpanding && dirent.type !== DirentType.DirectoryExpanded) { - return state - } - // TODO race condition: what if folder is being collapse while it is recursively expanding? - // TODO race condition: what if folder is being deleted while it is recursively expanding? - // TODO race condition: what if a new file/folder is created while the folder is recursively expanding? - // @ts-ignore - const childDirents = await GetChildDirentsRecursively.getChildDirentsRecursively(dirent, pathSeparator) - const startIndex = focusedIndex - if (focusedIndex >= 0) { - const endIndex = GetParentEndIndex.getParentEndIndex(items, focusedIndex) - const newDirents = [...items.slice(0, startIndex), ...childDirents, ...items.slice(endIndex)] - return { - ...state, - items: newDirents, - } - } - const newDirents = childDirents.slice(1) - return { - ...state, - items: newDirents, - } -} diff --git a/packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts b/packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts deleted file mode 100644 index dcf2e7e..0000000 --- a/packages/explorer-view/src/parts/ExpandedType/ExpandedType.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const None = 0 -export const Expanded = 1 -export const Collapsed = 2 diff --git a/packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts b/packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts deleted file mode 100644 index 29966d2..0000000 --- a/packages/explorer-view/src/parts/ExplorerEditingType/ExplorerEditingType.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const None = 0 - -export const CreateFile = 1 - -export const CreateFolder = 2 - -export const Rename = 3 diff --git a/packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts b/packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts deleted file mode 100644 index a888eba..0000000 --- a/packages/explorer-view/src/parts/ExplorerError/ExplorerError.ts +++ /dev/null @@ -1,6 +0,0 @@ -export class ExplorerError extends Error { - constructor(message: string) { - super(message) - this.name = 'ExplorerError' - } -} diff --git a/packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts b/packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts deleted file mode 100644 index f239a38..0000000 --- a/packages/explorer-view/src/parts/ExplorerItem/ExplorerItem.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface ExplorerItem { - readonly depth: number - readonly icon?: string - readonly name: string - readonly path: string - readonly posInSet?: number - readonly selected: boolean - readonly setSize?: number - readonly type: number -} diff --git a/packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts b/packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts deleted file mode 100644 index 060af6e..0000000 --- a/packages/explorer-view/src/parts/ExplorerState/ExplorerState.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' -import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' -import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' - -export interface ExplorerState { - readonly assetDir: string - readonly compareSourceUri: string - readonly confirmDelete: boolean - readonly confirmPaste: boolean - readonly cutItems: readonly string[] - readonly decorations: readonly FileDecoration[] - readonly deltaY: number - readonly dropTargets: readonly number[] - readonly editingErrorMessage: string - readonly editingIcon: string - readonly editingIndex: number - readonly editingSelectionEnd: number - readonly editingSelectionStart: number - readonly editingType: number - readonly editingValue: string - readonly errorCode: string - readonly errorMessage: string - readonly errorMessageLeft: number - readonly errorMessageTop: number - readonly errorMessageWidth: number - readonly excluded: readonly any[] - readonly fileIconCache: FileIconCache - readonly finalDeltaY: number - readonly focus: number - readonly focused: boolean - readonly focusedIndex: number - readonly focusWord: string - readonly focusWordTimeout: number - readonly handleOffset: number - readonly hasError: boolean - readonly height: number - readonly hoverIndex: number - readonly icons: readonly string[] - readonly initial: boolean - readonly inputSource: number - readonly isPointerDown: boolean - readonly itemHeight: number - readonly items: readonly ExplorerItem[] - readonly maxIndent: number - readonly maxLineY: number - readonly minLineY: number - readonly parentUid: number - readonly pasteShouldMove: boolean - readonly pathSeparator: string - readonly platform: number - readonly pointerDownIndex: number - readonly root: string - readonly scrollBarActive: boolean - readonly scrollBarHeight: number - readonly sourceControlDecorations: boolean - readonly sourceControlIgnoredUris: readonly string[] - readonly uid: number - readonly useChevrons: boolean - readonly version: number - readonly visibleExplorerItems: readonly VisibleExplorerItem[] - readonly width: number - readonly x: number - readonly y: number -} diff --git a/packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts b/packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts deleted file mode 100644 index 38cbb41..0000000 --- a/packages/explorer-view/src/parts/ExplorerStates/ExplorerStates.ts +++ /dev/null @@ -1,81 +0,0 @@ -import * as ViewletRegistry from '@lvce-editor//viewlet-registry' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetFileIcons from '../GetFileIcons/GetFileIcons.ts' -import * as GetExplorerMaxLineY from '../GetMaxLineY/GetMaxLineY.ts' -import * as GetVisibleExplorerItems from '../GetVisibleExplorerItems/GetVisibleExplorerItems.ts' - -export const { get, getCommandIds, registerCommands, set, wrapGetter } = ViewletRegistry.create() - -interface Fn { - (state: ExplorerState, ...args: T): ExplorerState | Promise -} - -export const wrapListItemCommand = (fn: Fn): ((id: number, ...args: T) => Promise) => { - const wrappedCommand = async (id: number, ...args: T): Promise => { - const { newState } = get(id) - const updatedState = await fn(newState, ...args) - if (newState === updatedState) { - return - } - const { - cutItems, - decorations, - dropTargets, - editingErrorMessage, - editingIcon, - editingIndex, - fileIconCache, - focusedIndex, - height, - itemHeight, - items, - minLineY, - sourceControlIgnoredUris, - useChevrons, - } = updatedState - const intermediate = get(id) - set(id, intermediate.oldState, updatedState) - const maxLineY = GetExplorerMaxLineY.getExplorerMaxLineY(minLineY, height, itemHeight, items.length) - if ( - items === intermediate.newState.items && - minLineY === intermediate.newState.minLineY && - height === intermediate.newState.height && - itemHeight === intermediate.newState.itemHeight && - editingIcon === intermediate.newState.editingIcon && - cutItems === intermediate.newState.cutItems && - editingErrorMessage === intermediate.newState.editingErrorMessage && - dropTargets === intermediate.newState.dropTargets && - fileIconCache === intermediate.newState.fileIconCache && - decorations === intermediate.newState.decorations - ) { - return - } - const visible = items.slice(minLineY, maxLineY) - const { icons, newFileIconCache } = await GetFileIcons.getFileIcons(visible, fileIconCache) - const visibleExplorerItems = GetVisibleExplorerItems.getVisibleExplorerItems( - items, - minLineY, - maxLineY, - focusedIndex, - editingIndex, - editingErrorMessage, - icons, - useChevrons, - dropTargets, - editingIcon, - cutItems, - sourceControlIgnoredUris, - decorations, - ) - const finalState: ExplorerState = { - ...updatedState, - fileIconCache: newFileIconCache, - icons, - maxLineY, - visibleExplorerItems, - } - const intermediate2 = get(id) - set(id, intermediate2.oldState, finalState) - } - return wrappedCommand -} diff --git a/packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts b/packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts deleted file mode 100644 index 17a6e94..0000000 --- a/packages/explorer-view/src/parts/ExplorerStrings/ExplorerStrings.ts +++ /dev/null @@ -1,140 +0,0 @@ -import * as I18nString from '../I18NString/I18NString.ts' -import * as UiStrings from '../UiStrings/UiStrings.ts' - -export const newFile = (): string => { - return I18nString.i18nString(UiStrings.NewFile) -} - -export const newFolder = (): string => { - return I18nString.i18nString(UiStrings.NewFolder) -} - -export const openContainingFolder = (): string => { - return I18nString.i18nString(UiStrings.OpenContainingFolder) -} - -export const openInIntegratedTerminal = (): string => { - return I18nString.i18nString(UiStrings.OpenInIntegratedTerminal) -} - -export const cut = (): string => { - return I18nString.i18nString(UiStrings.Cut) -} - -export const copy = (): string => { - return I18nString.i18nString(UiStrings.Copy) -} - -export const paste = (): string => { - return I18nString.i18nString(UiStrings.Paste) -} - -export const pasteConfirmation = (): string => { - return I18nString.i18nString(UiStrings.PasteConfirmation) -} - -export const copyPath = (): string => { - return I18nString.i18nString(UiStrings.CopyPath) -} - -export const copyRelativePath = (): string => { - return I18nString.i18nString(UiStrings.CopyRelativePath) -} - -export const compareWithSelected = (): string => { - return I18nString.i18nString(UiStrings.CompareWithSelected) -} - -export const selectForCompare = (): string => { - return I18nString.i18nString(UiStrings.SelectForCompare) -} - -export const rename = (): string => { - return I18nString.i18nString(UiStrings.Rename) -} - -export const deleteItem = (): string => { - return I18nString.i18nString(UiStrings.Delete) -} - -export const deleteConfirmationSingle = (path: string): string => { - return I18nString.i18nString(UiStrings.DeleteConfirmationSingle, [path]) -} - -export const deleteConfirmationMultiple = (count: number): string => { - return I18nString.i18nString(UiStrings.DeleteConfirmationMultiple, [count.toString()]) -} - -export const refresh = (): string => { - return I18nString.i18nString(UiStrings.RefreshExplorer) -} - -export const removeFolderFromWorkspace = (): string => { - return I18nString.i18nString(UiStrings.RemoveFolderFromWorkspace) -} - -export const collapseAll = (): string => { - return I18nString.i18nString(UiStrings.CollapseAllFoldersInExplorer) -} - -export const explorer = (): string => { - return I18nString.i18nString(UiStrings.Explorer) -} - -export const filesExplorer = (): string => { - return I18nString.i18nString(UiStrings.FilesExplorer) -} - -export const youHaveNotYetOpenedAFolder = (): string => { - return I18nString.i18nString(UiStrings.YouHaveNotYetOpenedAFolder) -} - -export const openFolder = (): string => { - return I18nString.i18nString(UiStrings.OpenFolder) -} - -export const openAnotherFolder = (): string => { - return I18nString.i18nString(UiStrings.OpenAnotherFolder) -} - -export const noFolderOpen = (): string => { - return I18nString.i18nString(UiStrings.NoFolderOpen) -} - -export const fileOrFolderNameMustBeProvided = (): string => { - return I18nString.i18nString(UiStrings.FileOrFolderNameMustBeProvider) -} - -export const fileCannotStartWithSlash = (): string => { - return I18nString.i18nString(UiStrings.FileNameCannotStartWithSlash) -} - -export const fileCannotStartWithDot = (): string => { - return I18nString.i18nString(UiStrings.FileCannotStartWithDot) -} - -export const fileCannotStartWithBackSlash = (): string => { - return I18nString.i18nString(UiStrings.FileCannotStartWithBackSlash) -} - -export const typeAFileName = (): string => { - return I18nString.i18nString(UiStrings.TypeAFileName) -} - -export const fileNameCannotStartWithSlash = (): string => { - return I18nString.i18nString(UiStrings.FileNameCannotStartWithSlash) -} - -export const fileOrFolderAlreadyExists = (name: string): string => { - return I18nString.i18nString(UiStrings.FileOrFolderAlreadyExists, { - PH1: name, - }) -} - -export const theNameIsNotValid = (): string => { - return I18nString.i18nString(UiStrings.TheNameIsNotValid) -} - -export const leadingOrTrailingWhitespaceDetected = (): string => { - return I18nString.i18nString(UiStrings.LeadingOrTrailingWhitespaceDetected) -} diff --git a/packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts b/packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts deleted file mode 100644 index 8b96bf3..0000000 --- a/packages/explorer-view/src/parts/FileDecoration/FileDecoration.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface FileDecoration { - readonly decoration: string - readonly uri: string -} diff --git a/packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts b/packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts deleted file mode 100644 index 0af9114..0000000 --- a/packages/explorer-view/src/parts/FileIconCache/FileIconCache.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface FileIconCache { - readonly [key: string]: string -} diff --git a/packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts b/packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts deleted file mode 100644 index c90f913..0000000 --- a/packages/explorer-view/src/parts/FileIconsRequest/FileIconsResult.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' - -export interface FileIconsResult { - readonly icons: readonly string[] - readonly newFileIconCache: FileIconCache -} diff --git a/packages/explorer-view/src/parts/FileOperation/FileOperation.ts b/packages/explorer-view/src/parts/FileOperation/FileOperation.ts deleted file mode 100644 index 8af40f1..0000000 --- a/packages/explorer-view/src/parts/FileOperation/FileOperation.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Copy, CreateFile, CreateFolder, Remove, Rename } from '../FileOperationType/FileOperationType.ts' - -export interface FileOperationBase { - readonly type: number -} - -export interface FileOperationCreateFile extends FileOperationBase { - readonly path: string - readonly text: string - readonly type: typeof CreateFile -} - -export interface FileOperationCreateFolder extends FileOperationBase { - readonly path: string - readonly type: typeof CreateFolder -} - -export interface FileOperationCopy extends FileOperationBase { - readonly from: string - readonly path: string - readonly type: typeof Copy -} - -export interface FileOperationRename extends FileOperationBase { - readonly from: string - readonly path: string - readonly type: typeof Rename -} - -export interface FileOperationRemove extends FileOperationBase { - readonly path: string - readonly type: typeof Remove -} - -export type FileOperation = FileOperationCopy | FileOperationCreateFile | FileOperationCreateFolder | FileOperationRename | FileOperationRemove diff --git a/packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts b/packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts deleted file mode 100644 index 5554459..0000000 --- a/packages/explorer-view/src/parts/FileOperationType/FileOperationType.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const CreateFolder = 1 -export const CreateFile = 2 -export const Copy = 3 -export const Rename = 4 -export const Remove = 5 diff --git a/packages/explorer-view/src/parts/FileSystem/FileSystem.ts b/packages/explorer-view/src/parts/FileSystem/FileSystem.ts deleted file mode 100644 index f968218..0000000 --- a/packages/explorer-view/src/parts/FileSystem/FileSystem.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as FileSystemWorker from '../FileSystemWorker/FileSystemWorker.ts' - -export const remove = async (dirent: string): Promise => { - return FileSystemWorker.invoke('FileSystem.remove', dirent) -} - -export const readDirWithFileTypes = async (uri: string): Promise => { - return FileSystemWorker.invoke('FileSystem.readDirWithFileTypes', uri) -} - -export const getPathSeparator = async (root: string): Promise => { - return FileSystemWorker.invoke('FileSystem.getPathSeparator', root) -} - -export const getRealPath = async (path: string): Promise => { - return FileSystemWorker.invoke('FileSystem.getRealPath', path) -} - -export const stat = async (dirent: string): Promise => { - return FileSystemWorker.invoke('FileSystem.stat', dirent) -} - -export const createFile = async (uri: string): Promise => { - return FileSystemWorker.invoke('FileSystem.writeFile', uri, '') -} - -export const writeFile = async (uri: string, content: string): Promise => { - return FileSystemWorker.invoke('FileSystem.writeFile', uri, content) -} - -export const mkdir = async (uri: string): Promise => { - return FileSystemWorker.invoke('FileSystem.mkdir', uri) -} - -export const rename = async (oldUri: string, newUri: string): Promise => { - return FileSystemWorker.invoke('FileSystem.rename', oldUri, newUri) -} - -export const copy = async (oldUri: string, newUri: string): Promise => { - return FileSystemWorker.invoke('FileSystem.copy', oldUri, newUri) -} diff --git a/packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts b/packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts deleted file mode 100644 index 81608cc..0000000 --- a/packages/explorer-view/src/parts/FileSystemWorker/FileSystemWorker.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { FileSystemWorker, RendererWorker } from '@lvce-editor/rpc-registry' - -// TODO use direct connection -export const invoke = async (method: string, ...params: readonly unknown[]): Promise => { - return RendererWorker.invoke(method, ...params) -} - -export const { set } = FileSystemWorker diff --git a/packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts b/packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts deleted file mode 100644 index 8886653..0000000 --- a/packages/explorer-view/src/parts/FilterByFocusWord/FilterByFocusWord.ts +++ /dev/null @@ -1,25 +0,0 @@ -export const filterByFocusWord = (items: readonly string[], focusedIndex: number, focusWord: string): number => { - if (items.length === 0) { - return -1 - } - - const matches: number[] = [] - for (let i = 0; i < items.length; i++) { - if (items[i].toLowerCase().includes(focusWord)) { - matches.push(i) - } - } - - if (matches.length === 0) { - return -1 - } - - // Find the next match after the current focus - let nextIndex = matches.findIndex((index) => index > focusedIndex) - if (nextIndex === -1) { - // If no match found after current focus, wrap around to the first match - nextIndex = 0 - } - - return matches[nextIndex] -} diff --git a/packages/explorer-view/src/parts/Focus/Focus.ts b/packages/explorer-view/src/parts/Focus/Focus.ts deleted file mode 100644 index 65e6d14..0000000 --- a/packages/explorer-view/src/parts/Focus/Focus.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusId from '../FocusId/FocusId.ts' - -export const focus = (state: ExplorerState): ExplorerState => { - if (state.focus) { - return state - } - return { - ...state, - focus: FocusId.List, - } -} diff --git a/packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts b/packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts deleted file mode 100644 index 3159108..0000000 --- a/packages/explorer-view/src/parts/FocusFirst/FocusFirst.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { focusIndex } from '../FocusIndex/FocusIndex.ts' - -export const focusFirst = (state: ExplorerState): ExplorerState => { - const { focusedIndex, items } = state - if (items.length === 0 || focusedIndex === 0) { - return state - } - return focusIndex(state, 0) -} diff --git a/packages/explorer-view/src/parts/FocusId/FocusId.ts b/packages/explorer-view/src/parts/FocusId/FocusId.ts deleted file mode 100644 index a291d8e..0000000 --- a/packages/explorer-view/src/parts/FocusId/FocusId.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const None = 0 -export const List = 1 -export const Input = 2 diff --git a/packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts b/packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts deleted file mode 100644 index f276402..0000000 --- a/packages/explorer-view/src/parts/FocusIndex/FocusIndex.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const focusIndex = (state: ExplorerState, index: number): ExplorerState => { - const { items, maxLineY, minLineY } = state - const newItems = items.map((item, i) => ({ - ...item, - selected: i === index ? false : false, - })) - if (index < minLineY) { - if (index < 0) { - return { - ...state, - focused: true, - focusedIndex: index, - items: newItems, - } - } - const diff = maxLineY - minLineY - return { - ...state, - focused: true, - focusedIndex: index, - items: newItems, - maxLineY: index + diff, - minLineY: index, - } - } - if (index >= maxLineY) { - const diff = maxLineY - minLineY - return { - ...state, - focused: true, - focusedIndex: index, - items: newItems, - maxLineY: index + 1, - minLineY: index + 1 - diff, - } - } - return { - ...state, - focused: true, - focusedIndex: index, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/FocusKey/FocusKey.ts b/packages/explorer-view/src/parts/FocusKey/FocusKey.ts deleted file mode 100644 index a8b4139..0000000 --- a/packages/explorer-view/src/parts/FocusKey/FocusKey.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { WhenExpression } from '@lvce-editor/constants' - -export const ExplorerEditBox = WhenExpression.FocusExplorerEditBox diff --git a/packages/explorer-view/src/parts/FocusLast/FocusLast.ts b/packages/explorer-view/src/parts/FocusLast/FocusLast.ts deleted file mode 100644 index b5ce9ae..0000000 --- a/packages/explorer-view/src/parts/FocusLast/FocusLast.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as Arrays from '../Arrays/Arrays.ts' -import { focusIndex } from '../FocusIndex/FocusIndex.ts' - -export const focusLast = (state: ExplorerState): ExplorerState => { - const { focusedIndex, items } = state - const lastIndex = Arrays.lastIndex(items) - if (items.length === 0 || focusedIndex === lastIndex) { - return state - } - return focusIndex(state, lastIndex) -} diff --git a/packages/explorer-view/src/parts/FocusNext/FocusNext.ts b/packages/explorer-view/src/parts/FocusNext/FocusNext.ts deleted file mode 100644 index 3116321..0000000 --- a/packages/explorer-view/src/parts/FocusNext/FocusNext.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as Arrays from '../Arrays/Arrays.ts' -import { focusIndex } from '../FocusIndex/FocusIndex.ts' - -export const focusNext = (state: ExplorerState): ExplorerState => { - const { focusedIndex, items } = state - if (focusedIndex === Arrays.lastIndex(items)) { - return state - } - return focusIndex(state, focusedIndex + 1) -} diff --git a/packages/explorer-view/src/parts/FocusNone/FocusNone.ts b/packages/explorer-view/src/parts/FocusNone/FocusNone.ts deleted file mode 100644 index 9dbdd6e..0000000 --- a/packages/explorer-view/src/parts/FocusNone/FocusNone.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { focusIndex } from '../FocusIndex/FocusIndex.ts' - -export const focusNone = (state: ExplorerState): ExplorerState => { - const { focusedIndex } = state - if (focusedIndex === -1) { - return state - } - return focusIndex(state, -1) -} diff --git a/packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts b/packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts deleted file mode 100644 index af9e01a..0000000 --- a/packages/explorer-view/src/parts/FocusParentFolder/FocusParentFolder.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusIndex from '../FocusIndex/FocusIndex.ts' -import * as GetParentStartIndex from '../GetParentStartIndex/GetParentStartIndex.ts' - -export const focusParentFolder = (state: ExplorerState): ExplorerState => { - const parentStartIndex = GetParentStartIndex.getParentStartIndex(state.items, state.focusedIndex) - if (parentStartIndex === -1) { - return state - } - return FocusIndex.focusIndex(state, parentStartIndex) -} diff --git a/packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts b/packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts deleted file mode 100644 index cdf070a..0000000 --- a/packages/explorer-view/src/parts/FocusPrevious/FocusPrevious.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as Arrays from '../Arrays/Arrays.ts' -import { focusIndex } from '../FocusIndex/FocusIndex.ts' - -export const focusPrevious = (state: ExplorerState): ExplorerState => { - const { focusedIndex, items } = state - switch (focusedIndex) { - case -1: - if (items.length === 0) { - return state - } - return focusIndex(state, Arrays.lastIndex(items)) - case 0: - return state - default: - return focusIndex(state, focusedIndex - 1) - } -} diff --git a/packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts b/packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts deleted file mode 100644 index ab26d33..0000000 --- a/packages/explorer-view/src/parts/GenerateUniqueName/GenerateUniqueName.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as Path from '../Path/Path.ts' - -export const generateUniqueName = (baseName: string, existingPaths: readonly string[], root: string): string => { - // Handle files with extensions - const lastDotIndex = baseName.lastIndexOf('.') - const hasExtension = lastDotIndex !== -1 && lastDotIndex !== 0 && lastDotIndex !== baseName.length - 1 - - let nameWithoutExtension: string - let extension: string - - if (hasExtension) { - nameWithoutExtension = baseName.slice(0, lastDotIndex) - extension = baseName.slice(lastDotIndex) - } else { - nameWithoutExtension = baseName - extension = '' - } - - // Check if original name exists - const originalPath = Path.join2(root, baseName) - if (!existingPaths.includes(originalPath)) { - return baseName - } - - // Try "original copy" - const copyName = `${nameWithoutExtension} copy${extension}` - const copyPath = Path.join2(root, copyName) - if (!existingPaths.includes(copyPath)) { - return copyName - } - - // Try "original copy 1", "original copy 2", etc. - let counter = 1 - while (true) { - const numberedCopyName = `${nameWithoutExtension} copy ${counter}${extension}` - const numberedCopyPath = Path.join2(root, numberedCopyName) - if (!existingPaths.includes(numberedCopyPath)) { - return numberedCopyName - } - counter++ - } -} diff --git a/packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts b/packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts deleted file mode 100644 index 32bd161..0000000 --- a/packages/explorer-view/src/parts/GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as GetIconVirtualDom from '../GetIconVirtualDom/GetIconVirtualDom.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const getActionButtonVirtualDom = (action: ViewletAction): readonly VirtualDomNode[] => { - const { icon, id, name } = action - return [ - { - childCount: 1, - className: ClassNames.IconButton, - name, - title: id, - type: VirtualDomElements.Button, - }, - GetIconVirtualDom.getIconVirtualDom(icon || ''), - ] -} diff --git a/packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts b/packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts deleted file mode 100644 index 51464aa..0000000 --- a/packages/explorer-view/src/parts/GetActionVirtualDom/GetActionVirtualDom.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ActionType from '../ActionType/ActionType.ts' -import * as GetActionButtonVirtualDom from '../GetActionButtonVirtualDom/GetActionButtonVirtualDom.ts' - -export const getActionVirtualDom = (action: ViewletAction): readonly VirtualDomNode[] => { - switch (action.type) { - case ActionType.Button: - return GetActionButtonVirtualDom.getActionButtonVirtualDom(action) - default: - return [] - } -} diff --git a/packages/explorer-view/src/parts/GetActions/GetActions.ts b/packages/explorer-view/src/parts/GetActions/GetActions.ts deleted file mode 100644 index c05294b..0000000 --- a/packages/explorer-view/src/parts/GetActions/GetActions.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' -import * as ActionType from '../ActionType/ActionType.ts' -import * as ViewletExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' -import * as InputName from '../InputName/InputName.ts' -import * as MaskIcon from '../MaskIcon/MaskIcon.ts' - -export const getActions = (root: string): readonly ViewletAction[] => { - if (!root) { - return [] - } - return [ - { - command: 'newFile', - icon: MaskIcon.NewFile, - id: ViewletExplorerStrings.newFile(), - name: InputName.NewFile, - type: ActionType.Button, - }, - { - command: 'newFolder', - icon: MaskIcon.NewFolder, - id: ViewletExplorerStrings.newFolder(), - name: InputName.NewFolder, - type: ActionType.Button, - }, - { - command: 'refresh', - icon: MaskIcon.Refresh, - id: ViewletExplorerStrings.refresh(), - name: InputName.Refresh, - type: ActionType.Button, - }, - { - command: 'collapseAll', - icon: MaskIcon.CollapseAll, - id: ViewletExplorerStrings.collapseAll(), - name: InputName.CollapseAll, - type: ActionType.Button, - }, - ] -} diff --git a/packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts b/packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts deleted file mode 100644 index 098bbd4..0000000 --- a/packages/explorer-view/src/parts/GetActionsVirtualDom/GetActionsVirtualDom.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ViewletAction } from '../ViewletAction/ViewletAction.ts' -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as AriaRoles from '../AriaRoles/AriaRoles.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' -import * as GetActionVirtualDom from '../GetActionVirtualDom/GetActionVirtualDom.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const getActionsVirtualDom = (actions: readonly ViewletAction[]): readonly VirtualDomNode[] => { - return [ - { - childCount: actions.length, - className: ClassNames.Actions, - onClick: DomEventListenerFunctions.HandleButtonClick, - role: AriaRoles.ToolBar, - type: VirtualDomElements.Div, - }, - ...actions.flatMap(GetActionVirtualDom.getActionVirtualDom), - ] -} diff --git a/packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts b/packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts deleted file mode 100644 index c671a8b..0000000 --- a/packages/explorer-view/src/parts/GetChevronType/GetChevronType.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as ChevronType from '../ChevronType/ChevronType.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const getChevronType = (type: number, useChevrons: boolean): number => { - if (!useChevrons) { - return ChevronType.None - } - switch (type) { - case DirentType.Directory: - return ChevronType.Right - case DirentType.DirectoryExpanded: - case DirentType.DirectoryExpanding: - return ChevronType.Down - default: - return ChevronType.None - } -} diff --git a/packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts b/packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts deleted file mode 100644 index 6cd51e7..0000000 --- a/packages/explorer-view/src/parts/GetChevronVirtualDom/GetChevronVirtualDom.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ChevronDownVirtualDom from '../ChevronDownVirtualDom/ChevronDownVirtualDom.ts' -import * as ChevronRightVirtualDom from '../ChevronRightVirtualDom/ChevronRightVirtualDom.ts' - -const chevronDomNodes: readonly (readonly VirtualDomNode[])[] = [ - [], - [ChevronRightVirtualDom.chevronRightVirtualDom], - [ChevronDownVirtualDom.chevronDownVirtualDom], -] - -export const getChevronVirtualDom = (chevronType: number): readonly VirtualDomNode[] => { - return chevronDomNodes[chevronType] -} diff --git a/packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts b/packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts deleted file mode 100644 index 62a0239..0000000 --- a/packages/explorer-view/src/parts/GetChildDirents/GetChildDirents.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as Assert from '../Assert/Assert.ts' -import { getChildDirentsRaw } from '../GetChildDirentsRaw/GetChildDirentsRaw.ts' -import * as ToDisplayDirents from '../ToDisplayDirents/ToDisplayDirents.ts' - -export const getChildDirents = async ( - pathSeparator: string, - parentDirentPath: string, - parentDirentDepth: number, - excluded: readonly string[] = [], -): Promise => { - Assert.string(pathSeparator) - // TODO use event/actor based code instead, this is impossible to cancel right now - // also cancel updating when opening new folder - // const dispose = state => state.pendingRequests.forEach(cancelRequest) - // TODO should use FileSystem directly in this case because it is globally available anyway - // and more typesafe than Command.execute - // and more performant - const rawDirents = await getChildDirentsRaw(parentDirentPath) - const displayDirents = ToDisplayDirents.toDisplayDirents(pathSeparator, rawDirents, parentDirentPath, parentDirentDepth, excluded) - return displayDirents -} diff --git a/packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts b/packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts deleted file mode 100644 index 2248376..0000000 --- a/packages/explorer-view/src/parts/GetChildDirentsRaw/GetChildDirentsRaw.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as Assert from '../Assert/Assert.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' -import { hasSymbolicLinks } from '../HasSymbolicLink/HasSymbolicLink.ts' -import * as ResolveSymbolicLinks from '../ResolveSymbolicLinks/ResolveSymbolicLinks.ts' - -export const getChildDirentsRaw = async (uri: string): Promise => { - const rawDirents = await FileSystem.readDirWithFileTypes(uri) - Assert.array(rawDirents) - if (hasSymbolicLinks(rawDirents)) { - return ResolveSymbolicLinks.resolveSymbolicLinks(uri, rawDirents) - } - return rawDirents -} diff --git a/packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts b/packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts deleted file mode 100644 index 8df1ee1..0000000 --- a/packages/explorer-view/src/parts/GetChildDirentsRecursively/GetChildDirentsRecursively.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' -import * as MakeExpanded from '../MakeExpanded/MakeExpanded.ts' - -// TODO this is very inefficient -export const getChildDirentsRecursively = async (dirent: ExplorerItem, pathSeparator: string): Promise => { - switch (dirent.type) { - case DirentType.Directory: - case DirentType.DirectoryExpanded: - case DirentType.DirectoryExpanding: - const childDirents = await GetChildDirents.getChildDirents(pathSeparator, dirent.path, dirent.depth) - const all = [MakeExpanded.makeExpanded(dirent)] - for (const childDirent of childDirents) { - const childAll = await getChildDirentsRecursively(childDirent, pathSeparator) - all.push(...childAll) - } - return all - case DirentType.File: - return [dirent] - default: - return [] - } -} diff --git a/packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts b/packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts deleted file mode 100644 index d89f4f0..0000000 --- a/packages/explorer-view/src/parts/GetChildHandles/GetChildHandles.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as Arrays from '../Arrays/Arrays.ts' - -export const getChildHandles = async (fileHandle: FileSystemDirectoryHandle): Promise => { - // @ts-ignore - const values = fileHandle.values() - const children = await Arrays.fromAsync(values) - return children -} diff --git a/packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts b/packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts deleted file mode 100644 index 7393a61..0000000 --- a/packages/explorer-view/src/parts/GetClickFn/GetClickFn.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { ClickHandler } from '../ClickHandler/ClickHandler.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import { ExplorerError } from '../ExplorerError/ExplorerError.ts' -import * as HandleClickDirectory from '../HandleClickDirectory/HandleClickDirectory.ts' -import * as HandleClickDirectoryExpanded from '../HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' -import * as HandleClickDirectoryExpanding from '../HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts' -import * as HandleClickFile from '../HandleClickFile/HandleClickFile.ts' -import * as HandleClickSymlink from '../HandleClickSymlink/HandleClickSymlink.ts' -// TODO viewlet should only have create and refresh functions -// every thing else can be in a separate module .lazy.js -// and .ipc.js - -// viewlet: creating | refreshing | done | disposed -// TODO recycle viewlets (maybe) - -// TODO instead of root string, there should be a root dirent - -// TODO rename dirents to items, then can use virtual list component directly - -// TODO support multiselection and removing multiple dirents - -// TODO use posInSet and setSize properties to compute more effectively - -// TODO much shared logic with newFolder - -export const getClickFn = (direntType: number): ClickHandler => { - switch (direntType) { - case DirentType.Directory: - case DirentType.SymLinkFolder: - return HandleClickDirectory.handleClickDirectory - case DirentType.DirectoryExpanded: - return HandleClickDirectoryExpanded.handleClickDirectoryExpanded - case DirentType.DirectoryExpanding: - return HandleClickDirectoryExpanding.handleClickDirectoryExpanding - case DirentType.File: - case DirentType.SymLinkFile: - return HandleClickFile.handleClickFile - case DirentType.Symlink: - return HandleClickSymlink.handleClickSymLink - case DirentType.CharacterDevice: - throw new ExplorerError('Cannot open character device files') - case DirentType.BlockDevice: - throw new ExplorerError('Cannot open block device files') - case DirentType.Socket: - throw new ExplorerError('Cannot open socket files') - default: - throw new ExplorerError(`unsupported dirent type ${direntType}`) - } -} diff --git a/packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts b/packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts deleted file mode 100644 index b21a5cf..0000000 --- a/packages/explorer-view/src/parts/GetContainingFolder/GetContainingFolder.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const getContainingFolder = (root: string, dirents: readonly any[], focusedIndex: number, pathSeparator: string): string => { - if (focusedIndex < 0) { - return root - } - const dirent = dirents[focusedIndex] - const direntPath = dirent.path - const direntParentPath = direntPath.slice(0, -(dirent.name.length + 1)) - const path = `${direntParentPath}` - return path -} diff --git a/packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts b/packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts deleted file mode 100644 index 29bd9ed..0000000 --- a/packages/explorer-view/src/parts/GetContextMenuHandler/GetContextMenuHandler.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ContextMenuHandler } from '../ContextMenuHandler/ContextMenuHandler.ts' -import * as ViewletExplorerHandleContextMenuKeyBoard from '../HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts' -import * as ViewletExplorerHandleContextMenuMouseAt from '../HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts' -import * as MouseEventType from '../MouseEventType/MouseEventType.ts' - -export const getContextMenuHandler = (button: number): ContextMenuHandler => { - switch (button) { - case MouseEventType.Keyboard: - return ViewletExplorerHandleContextMenuKeyBoard.handleContextMenuKeyboard - default: - return ViewletExplorerHandleContextMenuMouseAt.handleContextMenuMouseAt - } -} diff --git a/packages/explorer-view/src/parts/GetCss/GetCss.ts b/packages/explorer-view/src/parts/GetCss/GetCss.ts deleted file mode 100644 index 2caddb5..0000000 --- a/packages/explorer-view/src/parts/GetCss/GetCss.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { getIndentRule } from '../GetIndentRule/GetIndentRule.ts' - -export const getCss = ( - scrollBarHeight: number, - scrollBarTop: number, - uniqueIndents: readonly number[], - errorMessageLeft: number, - errorMessageTop: number, - errorMessageWidth: number, -): string => { - const rules = [ - `.Explorer { - --ScrollBarThumbHeight: ${scrollBarHeight}px; - --ScrollBarThumbTop: ${scrollBarTop}px; - --ErrorMessageTop: ${errorMessageTop}px; - --ErrorMessageLeft: ${errorMessageLeft}px; - --ErrorMessageWidth: ${errorMessageWidth}px; -} -.Explorer .ScrollBarThumb { - height: var(--ScrollBarThumbHeight); - translate: 0px var(--ScrollBarThumbTop); -}`, - ...uniqueIndents.map(getIndentRule), - ] - const css = rules.join('\n') - return css -} diff --git a/packages/explorer-view/src/parts/GetDragData/GetDragData.ts b/packages/explorer-view/src/parts/GetDragData/GetDragData.ts deleted file mode 100644 index cbfcef7..0000000 --- a/packages/explorer-view/src/parts/GetDragData/GetDragData.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { getDragLabel } from '../GetDragLabel/GetDragLabel.ts' - -const toUri = (path: string): string => { - if (path.startsWith('file://')) { - return path - } - return 'file://' + path -} - -export interface DragInfoItem { - readonly data: string - readonly type: string -} - -export interface IDragInfoNew { - readonly items: readonly DragInfoItem[] - readonly label?: string -} - -export const getDragData = (urls: readonly string[]): IDragInfoNew => { - const data = urls.map(toUri).join('\n') - const dragData: readonly DragInfoItem[] = [ - { - data, - type: 'text/uri-list', - }, - { - data, - type: 'text/plain', - }, - ] - return { - items: dragData, - label: getDragLabel(urls), - } -} diff --git a/packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts b/packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts deleted file mode 100644 index abd961b..0000000 --- a/packages/explorer-view/src/parts/GetDragLabel/GetDragLabel.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { getBaseName } from '../Path/Path.ts' - -export const getDragLabel = (urls: readonly string[]): string => { - if (urls.length === 1) { - return getBaseName('/', urls[0]) - } - return `${urls.length}` -} diff --git a/packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts b/packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts deleted file mode 100644 index 7d93aec..0000000 --- a/packages/explorer-view/src/parts/GetDropHandler/GetDropHandler.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { DropHandler } from '../DropHandler/DropHandler.ts' -import * as HandleDropIndex from '../HandleDropIndex/HandleDropIndex.ts' -import * as HandleDropRoot from '../HandleDropRoot/HandleDropRoot.ts' - -export const getDropHandler = (index: number): DropHandler => { - switch (index) { - case -1: - return HandleDropRoot.handleDropRoot - default: - return HandleDropIndex.handleDropIndex - } -} diff --git a/packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts b/packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts deleted file mode 100644 index 4902674..0000000 --- a/packages/explorer-view/src/parts/GetEditingIcon/GetEditingIcon.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { RendererWorker as Rpc } from '@lvce-editor/rpc-registry' -import * as DirentType from '../DirentType/DirentType.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' - -export const getEditingIcon = async (editingType: number, value: string, direntType?: number): Promise => { - if (editingType === ExplorerEditingType.CreateFile) { - return Rpc.invoke('IconTheme.getFileIcon', { name: value }) - } - if (editingType === ExplorerEditingType.Rename) { - if (direntType === DirentType.File || direntType === DirentType.EditingFile) { - return Rpc.invoke('IconTheme.getFileIcon', { name: value }) - } - if (direntType === DirentType.Directory || direntType === DirentType.EditingFolder || direntType === DirentType.EditingDirectoryExpanded) { - return Rpc.invoke('IconTheme.getFolderIcon', { name: value }) - } - } - if (editingType === ExplorerEditingType.CreateFolder) { - return Rpc.invoke('IconTheme.getFolderIcon', { name: value }) - } - return '' -} diff --git a/packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts b/packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts deleted file mode 100644 index f5bd518..0000000 --- a/packages/explorer-view/src/parts/GetEditingType/GetEditingType.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { DELTA_EDITING } from '../DeltaEditing/DeltaEditing.ts' - -export const getEditingType = (direntType: number): number => { - if (direntType < DELTA_EDITING) { - return direntType + DELTA_EDITING - } - return direntType -} diff --git a/packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts b/packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts deleted file mode 100644 index 220d232..0000000 --- a/packages/explorer-view/src/parts/GetErrorCode/GetErrorCode.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const getErrorCode = (error: unknown): string => { - if (error && typeof error === 'object' && 'code' in error && typeof error.code === 'string') { - return error.code - } - return '' -} diff --git a/packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts b/packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts deleted file mode 100644 index 5dbaf15..0000000 --- a/packages/explorer-view/src/parts/GetErrorMessage/GetErrorMessage.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const getErrorMessage = (error: unknown): string => { - if (error instanceof Error) { - return error.message - } - if (typeof error === 'string') { - return error - } - return 'Unknown error' -} diff --git a/packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts b/packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts deleted file mode 100644 index 88382ff..0000000 --- a/packages/explorer-view/src/parts/GetErrorMessageDom/GetErrorMessageDom.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { type VirtualDomNode, text } from '@lvce-editor/virtual-dom-worker' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const getErrorMessageDom = (errorMessage: string): readonly VirtualDomNode[] => { - if (!errorMessage) { - return [] - } - - return [ - { - childCount: 1, - className: MergeClassNames.mergeClassNames(ClassNames.ExplorerErrorMessage), - type: VirtualDomElements.Div, - }, - text(errorMessage), - ] -} diff --git a/packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts b/packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts deleted file mode 100644 index 4c6caa5..0000000 --- a/packages/explorer-view/src/parts/GetErrorMessagePosition/GetErrorMessagePosition.ts +++ /dev/null @@ -1,25 +0,0 @@ -export interface Position { - readonly errorMessageWidth: number - readonly left: number - readonly top: number -} - -export const getErrorMessagePosition = ( - itemHeight: number, - focusedIndex: number, - minLineY: number, - depth: number, - indent: number, - fileIconWidth: number, - padding: number, - width: number, -): Position => { - const top = itemHeight * (focusedIndex - minLineY + 1) - const left = depth * indent + fileIconWidth + padding - const errorMessageWidth = width - left - return { - errorMessageWidth, - left, - top, - } -} diff --git a/packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts b/packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts deleted file mode 100644 index 5da0cca..0000000 --- a/packages/explorer-view/src/parts/GetExcluded/GetExcluded.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const getExcluded = (): string[] => { - const excludedObject = {} - const excluded = [] - for (const [key, value] of Object.entries(excludedObject)) { - if (value) { - excluded.push(key) - } - } - return excluded -} diff --git a/packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts b/packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts deleted file mode 100644 index c6b7e90..0000000 --- a/packages/explorer-view/src/parts/GetExpandedDirents/GetExpandedDirents.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import { isExpanded } from '../IsExpanded/IsExpanded.ts' - -export const getExpandedDirents = (items: readonly ExplorerItem[]): readonly ExplorerItem[] => { - return items.filter(isExpanded) -} diff --git a/packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts b/packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts deleted file mode 100644 index f29acd1..0000000 --- a/packages/explorer-view/src/parts/GetExpandedType/GetExpandedType.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as DirentType from '../DirentType/DirentType.ts' -import * as ExpandedType from '../ExpandedType/ExpandedType.ts' - -export const getExpandedType = (type: number): number => { - switch (type) { - case DirentType.Directory: - return ExpandedType.Collapsed - case DirentType.DirectoryExpanded: - case DirentType.DirectoryExpanding: - return ExpandedType.Expanded - default: - return ExpandedType.None - } -} diff --git a/packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts b/packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts deleted file mode 100644 index ca4f967..0000000 --- a/packages/explorer-view/src/parts/GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' -import * as AriaRoles from '../AriaRoles/AriaRoles.ts' -import * as GetChevronVirtualDom from '../GetChevronVirtualDom/GetChevronVirtualDom.ts' -import * as GetFileIconVirtualDom from '../GetFileIconVirtualDom/GetFileIconVirtualDom.ts' -import * as GetInputDom from '../GetInputDom/GetInputDom.ts' -import * as GetLabelDom from '../GetLabelDom/GetLabelDom.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -const getTitle = (path: string): string => { - if (path.startsWith('file://')) { - return path.slice('file://'.length) - } - return path -} - -export const getExplorerItemVirtualDom = (item: VisibleExplorerItem): readonly VirtualDomNode[] => { - const { ariaExpanded, chevron, className, depth, hasEditingError, icon, id, index, isCut, isEditing, isIgnored, name, path, posInSet, setSize } = - item - const chevronDom = GetChevronVirtualDom.getChevronVirtualDom(chevron) - return [ - { - ariaDescription: '', - ariaExpanded, - ariaLabel: name, - ariaLevel: depth, - ariaPosInSet: posInSet, - ariaSetSize: setSize, - childCount: 2 + chevronDom.length, - className, - 'data-index': index, - draggable: true, - id, - role: AriaRoles.TreeItem, - title: getTitle(path), - type: VirtualDomElements.Div, - }, - ...chevronDom, - GetFileIconVirtualDom.getFileIconVirtualDom(icon), - ...GetInputDom.getInputDom(isEditing, hasEditingError), - ...GetLabelDom.getLabelDom(isEditing, name, isCut || isIgnored), - ] -} diff --git a/packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts b/packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts deleted file mode 100644 index 0e368fd..0000000 --- a/packages/explorer-view/src/parts/GetExplorerVirtualDom/GetExplorerVirtualDom.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' -import * as AriaRoles from '../AriaRoles/AriaRoles.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as GetErrorMessageDom from '../GetErrorMessageDom/GetErrorMessageDom.ts' -import * as GetExplorerWelcomeVirtualDom from '../GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts' -import * as GetListItemsVirtualDom from '../GetListItemsVirtualDom/GetListItemsVirtualDom.ts' -import * as GetLoadErrorVirtualDom from '../GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts' -import * as GetScrollBarSize from '../GetScrollBarSize/GetScrollBarSize.ts' -import * as GetScrollBarVirtualDom from '../GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -const getParentNode = (childCount: number): VirtualDomNode => { - return { - childCount, - className: MergeClassNames.mergeClassNames(ClassNames.Viewlet, ClassNames.Explorer), - role: AriaRoles.None, - type: VirtualDomElements.Div, - } -} - -const getChildCount = (scrollBarDomLength: number, errorDomLength: number): number => { - let childCount = 1 - if (scrollBarDomLength > 0) { - childCount++ - } - if (errorDomLength > 0) { - childCount++ - } - return childCount -} - -export const getExplorerVirtualDom = ( - visibleItems: readonly VisibleExplorerItem[], - focusedIndex: number, - root: string, - isWide: boolean, - focused: boolean, - dropTargets: readonly number[], - height: number, - contentHeight: number, - editingErrorMessage: string, - loadErrorMessage: string, - showOpenAnotherFolderButton: boolean, -): readonly VirtualDomNode[] => { - if (!root) { - return GetExplorerWelcomeVirtualDom.getExplorerWelcomeVirtualDom(isWide, dropTargets) - } - if (loadErrorMessage) { - return GetLoadErrorVirtualDom.getLoadErrorVirtualDom(loadErrorMessage, isWide, showOpenAnotherFolderButton) - } - const scrollBarHeight = GetScrollBarSize.getScrollBarSize(height, contentHeight, 20) - const scrollBarDom = GetScrollBarVirtualDom.getScrollBarVirtualDom(scrollBarHeight) - const errorDom = GetErrorMessageDom.getErrorMessageDom(editingErrorMessage) - const childCount = getChildCount(scrollBarDom.length, errorDom.length) - const parentNode = getParentNode(childCount) - const dom: readonly VirtualDomNode[] = [ - parentNode, - ...GetListItemsVirtualDom.getListItemsVirtualDom(visibleItems, focusedIndex, focused, dropTargets), - ...scrollBarDom, - ...errorDom, - ] - return dom -} diff --git a/packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts b/packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts deleted file mode 100644 index a00b454..0000000 --- a/packages/explorer-view/src/parts/GetExplorerWelcomeVirtualDom/GetExplorerWelcomeVirtualDom.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' -import { dropTargetFull } from '../DropTargetFull/DropTargetFull.ts' -import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' -import * as InputName from '../InputName/InputName.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' -import { text } from '../VirtualDomHelpers/VirtualDomHelpers.ts' - -const getClassName = (dropTargets: readonly number[]): string => { - const extraClassName = dropTargets === dropTargetFull ? ClassNames.ExplorerDropTarget : ClassNames.Empty - return MergeClassNames.mergeClassNames(ClassNames.Viewlet, ClassNames.Explorer, extraClassName) -} - -export const getExplorerWelcomeVirtualDom = (isWide: boolean, dropTargets: readonly number[]): readonly VirtualDomNode[] => { - return [ - { - childCount: 1, - className: getClassName(dropTargets), - onContextMenu: DomEventListenerFunctions.HandleContextMenuWelcome, - onDragLeave: DomEventListenerFunctions.HandleDragLeave, - onDragOver: DomEventListenerFunctions.HandleDragOver, - onDrop: DomEventListenerFunctions.HandleDrop, - tabIndex: 0, - type: VirtualDomElements.Div, - }, - { - childCount: 2, - className: ClassNames.Welcome, - type: VirtualDomElements.Div, - }, - { - childCount: 1, - className: ClassNames.WelcomeMessage, - type: VirtualDomElements.P, - }, - text(ExplorerStrings.youHaveNotYetOpenedAFolder()), - { - childCount: 1, - className: MergeClassNames.mergeClassNames( - ClassNames.Button, - ClassNames.ButtonPrimary, - isWide ? ClassNames.ButtonWide : ClassNames.ButtonNarrow, - ), - name: InputName.OpenFolder, - onClick: DomEventListenerFunctions.HandleClickOpenFolder, - type: VirtualDomElements.Button, - }, - text(ExplorerStrings.openFolder()), - ] -} diff --git a/packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts b/packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts deleted file mode 100644 index 585c602..0000000 --- a/packages/explorer-view/src/parts/GetFileArray/GetFileArray.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const getFileArray = (fileList: FileList): readonly File[] => { - // @ts-ignore - const files = [...fileList] - return files -} diff --git a/packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts b/packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts deleted file mode 100644 index e8865be..0000000 --- a/packages/explorer-view/src/parts/GetFileDecorations/GetFileDecorations.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { SourceControlWorker } from '@lvce-editor/rpc-registry' -import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' -import { ensureUris } from '../EnsureUris/EnsureUris.ts' -import { normalizeDecorations } from '../NormalizeDecorations/NormalizeDecorations.ts' - -export const getFileDecorations = async ( - scheme: string, - root: string, - maybeUris: readonly string[], - decorationsEnabled: boolean, - assetDir: string, - platform: number, -): Promise => { - try { - if (!decorationsEnabled) { - return [] - } - const providerIds = await SourceControlWorker.invoke('SourceControl.getEnabledProviderIds', scheme, root, assetDir, platform) - if (providerIds.length === 0) { - return [] - } - // TODO how to handle multiple providers? - const providerId = providerIds.at(-1) - const uris = ensureUris(maybeUris) - const decorations = await SourceControlWorker.invoke('SourceControl.getFileDecorations', providerId, uris, assetDir, platform) - const normalized = normalizeDecorations(decorations) - return normalized - } catch (error) { - console.error(error) - return [] - } -} diff --git a/packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts b/packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts deleted file mode 100644 index 8091ace..0000000 --- a/packages/explorer-view/src/parts/GetFileHandleText/GetFileHandleText.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const getFileHandleText = async (fileHandle: FileSystemFileHandle): Promise => { - const file = await fileHandle.getFile() - const text = await file.text() - return text -} diff --git a/packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts b/packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts deleted file mode 100644 index 845820c..0000000 --- a/packages/explorer-view/src/parts/GetFileHandles/GetFileHandles.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' - -export const getFileHandles = async (fileIds: readonly number[]): Promise => { - if (fileIds.length === 0) { - return [] - } - const files = await RendererWorker.getFileHandles(fileIds) - return files -} diff --git a/packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts b/packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts deleted file mode 100644 index 22c27dc..0000000 --- a/packages/explorer-view/src/parts/GetFileIconVirtualDom/GetFileIconVirtualDom.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as AriaRoles from '../AriaRoles/AriaRoles.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const getFileIconVirtualDom = (icon: string): VirtualDomNode => { - return { - childCount: 0, - className: ClassNames.FileIcon, - role: AriaRoles.None, - src: icon, - type: VirtualDomElements.Img, - } -} diff --git a/packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts b/packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts deleted file mode 100644 index 817176b..0000000 --- a/packages/explorer-view/src/parts/GetFileIcons/GetFileIcons.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' -import type { FileIconsResult } from '../FileIconsRequest/FileIconsResult.ts' -import * as GetFileIconsCached from '../GetFileIconsCached/GetFileIconsCached.ts' -import * as GetMissingIconRequests from '../GetMissingIconRequests/GetMissingIconRequests.ts' -import { getPaths } from '../GetPaths/GetPaths.ts' -import * as RequestFileIcons from '../RequestFileIcons/RequestFileIcons.ts' -import * as UpdateIconCache from '../UpdateIconCache/UpdateIconCache.ts' - -export const getFileIcons = async (dirents: readonly ExplorerItem[], fileIconCache: FileIconCache): Promise => { - const missingRequests = GetMissingIconRequests.getMissingIconRequests(dirents, fileIconCache) - const newIcons = await RequestFileIcons.requestFileIcons(missingRequests) - const newFileIconCache = UpdateIconCache.updateIconCache(fileIconCache, missingRequests, newIcons) - const paths = getPaths(dirents) - const icons = GetFileIconsCached.getIconsCached(paths, newFileIconCache) - return { - icons, - newFileIconCache, - } -} diff --git a/packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts b/packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts deleted file mode 100644 index ae83b79..0000000 --- a/packages/explorer-view/src/parts/GetFileIconsCached/GetFileIconsCached.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' - -export const getIconsCached = (dirents: readonly string[], fileIconCache: FileIconCache): string[] => { - return dirents.map((dirent) => fileIconCache[dirent]) -} diff --git a/packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts b/packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts deleted file mode 100644 index e77b96a..0000000 --- a/packages/explorer-view/src/parts/GetFileOperations/GetFileOperations.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import { join2 } from '../Path/Path.ts' - -export const getFileOperations = (root: string, uploadTree: any): readonly FileOperation[] => { - const operations: FileOperation[] = [] - - const processTree = (tree: any, currentPath: string): void => { - for (const [path, value] of Object.entries(tree)) { - const fullPath = currentPath ? join2(currentPath, path) : path - if (typeof value === 'object') { - operations.push({ path: join2(root, fullPath), type: FileOperationType.CreateFolder }) - processTree(value, fullPath) - } else if (typeof value === 'string') { - operations.push({ path: join2(root, fullPath), text: value, type: FileOperationType.CreateFile }) - } - } - } - - processTree(uploadTree, '') - return operations -} diff --git a/packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts b/packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts deleted file mode 100644 index 5861737..0000000 --- a/packages/explorer-view/src/parts/GetFileOperationsCopy/GetFileOperationsCopy.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import { generateUniqueName } from '../GenerateUniqueName/GenerateUniqueName.ts' -import * as Path from '../Path/Path.ts' - -export const getFileOperationsCopy = ( - root: string, - existingUris: readonly string[], - files: readonly string[], - focusedUri: string, -): readonly FileOperation[] => { - const operations: FileOperation[] = [] - - for (const file of files) { - const baseName = Path.getBaseName('/', file) - if (existingUris.includes(file)) { - operations.push({ - from: file, - path: Path.join2(focusedUri, baseName), - type: FileOperationType.Rename, - }) - } else { - const uniqueName = generateUniqueName(baseName, existingUris, root) - const newUri = Path.join2(root, uniqueName) - operations.push({ - from: file, // TODO ensure file is uri - path: newUri, - type: FileOperationType.Copy, - }) - } - } - return operations -} diff --git a/packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts b/packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts deleted file mode 100644 index bfe5187..0000000 --- a/packages/explorer-view/src/parts/GetFileOperationsCreate/GetFileOperationsCreate.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import * as Path from '../Path/Path.ts' - -const getFileOperationsNestedPath = (path: string, root: string, pathSeparator: string): readonly FileOperation[] => { - const parts = path.slice(root.length).split(pathSeparator) - const operations: FileOperation[] = [] - let currentPath = '' - for (const part of parts) { - if (!part) continue - currentPath = Path.join2(currentPath, part) - operations.push({ - path: Path.join2(root, currentPath), - type: FileOperationType.CreateFolder, - }) - } - return operations -} - -export const getFileOperationsCreate = ( - newFileName: string, - newDirentType: number, - pathSeparator: string, - absolutePath: string, - root: string, -): readonly FileOperation[] => { - const operations: FileOperation[] = [] - const parentPath = Path.dirname(pathSeparator, absolutePath) - - operations.push(...getFileOperationsNestedPath(parentPath, root, pathSeparator)) - - if (newDirentType === DirentType.File) { - operations.push({ - path: absolutePath, - text: '', - type: FileOperationType.CreateFile, - }) - } else if (newDirentType === DirentType.Directory) { - operations.push({ - path: absolutePath, - type: FileOperationType.CreateFolder, - }) - } - - return operations -} diff --git a/packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts b/packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts deleted file mode 100644 index aaa881c..0000000 --- a/packages/explorer-view/src/parts/GetFileOperationsCut/GetFileOperationsCut.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import { generateUniqueName } from '../GenerateUniqueName/GenerateUniqueName.ts' -import * as Path from '../Path/Path.ts' - -export const getFileOperationsCut = (root: string, existingUris: readonly string[], files: readonly string[]): readonly FileOperation[] => { - const operations: FileOperation[] = [] - - for (const file of files) { - const baseName = Path.getBaseName('/', file) - const uniqueName = generateUniqueName(baseName, existingUris, root) - const newUri = Path.join2(root, uniqueName) - operations.push({ - from: file, // TODO ensure file is uri - path: newUri, - type: FileOperationType.Copy, - }) - } - return operations -} diff --git a/packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts b/packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts deleted file mode 100644 index aeee343..0000000 --- a/packages/explorer-view/src/parts/GetFileOperationsElectron/GetFileOperationsElectron.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import { join } from '../Path/Path.ts' -import { getDroppedName, type DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' - -export const getFileOperationsElectron = async ( - root: string, - paths: readonly string[], - fileHandles: DroppedArgs, - pathSeparator: string, -): Promise => { - const operations: FileOperation[] = [] - for (let i = 0; i < paths.length; i++) { - const fileHandle = fileHandles[i] - const name = getDroppedName(fileHandle) - const path = paths[i] - operations.push({ - from: path, - path: join(pathSeparator, root, name), - type: FileOperationType.Copy, - }) - } - return operations -} diff --git a/packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts b/packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts deleted file mode 100644 index 9a299d3..0000000 --- a/packages/explorer-view/src/parts/GetFileOperationsRename/GetFileOperationsRename.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import * as Path from '../Path/Path.ts' - -export const getFileOperationsRename = (oldAbsolutePath: string, newFileName: string): readonly FileOperation[] => { - const operations: FileOperation[] = [] - const oldParentPath = Path.dirname2(oldAbsolutePath) - const newAbsolutePath = Path.join2(oldParentPath, newFileName) - operations.push({ - from: oldAbsolutePath, - path: newAbsolutePath, - type: FileOperationType.Rename, - }) - - return operations -} diff --git a/packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts b/packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts deleted file mode 100644 index 7b512ff..0000000 --- a/packages/explorer-view/src/parts/GetFilePathElectron/GetFilePathElectron.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const getFilePathElectron = async (file: File): Promise => { - return RendererWorker.invoke('FileSystemHandle.getFilePathElectron', file) -} diff --git a/packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts b/packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts deleted file mode 100644 index 2cb19d0..0000000 --- a/packages/explorer-view/src/parts/GetFilePaths/GetFilePaths.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as GetFilePathElectron from '../GetFilePathElectron/GetFilePathElectron.ts' -import * as PlatformType from '../PlatformType/PlatformType.ts' - -const getFilepath = async (file: File): Promise => { - return GetFilePathElectron.getFilePathElectron(file) -} - -export const getFilePaths = async (files: readonly File[], platform: number): Promise => { - if (platform !== PlatformType.Electron) { - return files.map((file) => '') - } - const promises = files.map(getFilepath) - const paths = await Promise.all(promises) - return paths -} diff --git a/packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts b/packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts deleted file mode 100644 index fd21ba7..0000000 --- a/packages/explorer-view/src/parts/GetFittingIndex/GetFittingIndex.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -const isFolder = (direntType: number): boolean => { - return direntType === DirentType.Directory || direntType === DirentType.DirectoryExpanded || direntType === DirentType.SymLinkFolder -} - -export const getFittingIndex = (dirents: readonly ExplorerItem[], startIndex: number): number => { - for (let i = startIndex; i >= 0; i--) { - const dirent = dirents[i] - if (dirent && isFolder(dirent.type)) { - return i - } - } - return -1 -} diff --git a/packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts b/packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts deleted file mode 100644 index e25cf8e..0000000 --- a/packages/explorer-view/src/parts/GetFocusedDirent/GetFocusedDirent.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const getFocusedDirent = (state: ExplorerState): ExplorerItem | undefined => { - const { focusedIndex, items, minLineY } = state - const dirent = items[focusedIndex + minLineY] - return dirent -} diff --git a/packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts b/packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts deleted file mode 100644 index da505d6..0000000 --- a/packages/explorer-view/src/parts/GetFocusedFile/GetFocusedFile.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const getFocusedFile = (state: ExplorerState): ExplorerItem | undefined => { - if (state.focusedIndex < 0 || state.focusedIndex >= state.items.length) { - return undefined - } - const item = state.items[state.focusedIndex] - if (item.type !== DirentType.File) { - return undefined - } - return item -} diff --git a/packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts b/packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts deleted file mode 100644 index 9b534e9..0000000 --- a/packages/explorer-view/src/parts/GetFocusedIndexCancel/GetFocusedIndexCancel.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const getFocusedIndexCancel = (items: readonly ExplorerItem[], editingIndex: number): number => { - const newFocusedIndex = editingIndex >= items.length ? items.length - 1 : editingIndex - return newFocusedIndex -} diff --git a/packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts b/packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts deleted file mode 100644 index 379f0c1..0000000 --- a/packages/explorer-view/src/parts/GetFolderIcon/GetFolderIcon.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker as Rpc } from '@lvce-editor/rpc-registry' - -export const getFolderIcon = async (name: string): Promise => { - return Rpc.invoke('IconTheme.getFolderIcon', { name }) -} diff --git a/packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts b/packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts deleted file mode 100644 index ec47294..0000000 --- a/packages/explorer-view/src/parts/GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const getFriendlyErrorMessage = (errorMessage: string, errorCode: string): string => { - switch (errorCode) { - case 'EACCES': - case 'EPERM': - return 'permission was denied' - case 'EBUSY': - return 'the folder is currently in use' - case 'ENOENT': - return 'the folder does not exist' - case 'ENOTDIR': - return 'the path is not a folder' - default: - return errorMessage || 'an unexpected error occurred' - } -} diff --git a/packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts b/packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts deleted file mode 100644 index 9036f5c..0000000 --- a/packages/explorer-view/src/parts/GetIconVirtualDom/GetIconVirtualDom.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as AriaRoles from '../AriaRoles/AriaRoles.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const getIconVirtualDom = (icon: string, type = VirtualDomElements.Div): VirtualDomNode => { - return { - childCount: 0, - className: `MaskIcon MaskIcon${icon}`, - role: AriaRoles.None, - type, - } -} diff --git a/packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts b/packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts deleted file mode 100644 index ab8ac4e..0000000 --- a/packages/explorer-view/src/parts/GetIndentRule/GetIndentRule.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const getIndentRule = (indent: number): string => { - return `.Indent-${indent} { - padding-left: ${indent}px; -}` -} diff --git a/packages/explorer-view/src/parts/GetIndex/GetIndex.ts b/packages/explorer-view/src/parts/GetIndex/GetIndex.ts deleted file mode 100644 index 6898e27..0000000 --- a/packages/explorer-view/src/parts/GetIndex/GetIndex.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const getIndex = (dirents: readonly ExplorerItem[], uri: string): number => { - for (let i = 0; i < dirents.length; i++) { - const dirent = dirents[i] - if (dirent.path === uri) { - return i - } - } - return -1 -} diff --git a/packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts b/packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts deleted file mode 100644 index 9078506..0000000 --- a/packages/explorer-view/src/parts/GetIndexFromPosition/GetIndexFromPosition.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const getIndexFromPosition = (state: ExplorerState, eventX: number, eventY: number): number => { - const { itemHeight, items, minLineY, y } = state - const index = Math.floor((eventY - y) / itemHeight) - if (index < 0) { - return 0 - } - if (index >= items.length) { - return -1 - } - return index + minLineY -} diff --git a/packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts b/packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts deleted file mode 100644 index 3ec7175..0000000 --- a/packages/explorer-view/src/parts/GetInputClassName/GetInputClassName.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' - -export const getInputClassName = (hasEditingError: boolean): string => { - if (hasEditingError) { - return MergeClassNames.mergeClassNames(ClassNames.ExplorerInputBox, ClassNames.InputValidationError) - } - return ClassNames.ExplorerInputBox -} diff --git a/packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts b/packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts deleted file mode 100644 index 2af52ec..0000000 --- a/packages/explorer-view/src/parts/GetInputDom/GetInputDom.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' -import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' -import { getInputClassName } from '../GetInputClassName/GetInputClassName.ts' -import * as InputName from '../InputName/InputName.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const getInputDom = (isEditing: boolean, hasEditingError: boolean): readonly VirtualDomNode[] => { - if (!isEditing) { - return [] - } - const ariaLabel = ExplorerStrings.typeAFileName() - return [ - { - ariaLabel: ariaLabel, - autocapitalize: 'off', - autocomplete: 'off', - autocorrect: 'off', - childCount: 0, - className: getInputClassName(hasEditingError), - id: 'ExplorerInput', - name: InputName.ExplorerInput, - onBlur: DomEventListenerFunctions.HandleInputBlur, - onClick: DomEventListenerFunctions.HandleInputClick, - onInput: DomEventListenerFunctions.HandleEditingInput, - spellcheck: 'false', - type: VirtualDomElements.Input, - }, - ] -} diff --git a/packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts b/packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts deleted file mode 100644 index ad77cbd..0000000 --- a/packages/explorer-view/src/parts/GetKeyBindings/GetKeyBindings.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { WhenExpression } from '@lvce-editor/constants' -import { KeyCode, KeyModifier } from '@lvce-editor/virtual-dom-worker' -import type { KeyBinding } from '../KeyBinding/KeyBinding.ts' - -export const getKeyBindings = (): readonly KeyBinding[] => { - return [ - { - command: 'Explorer.selectUp', - key: KeyModifier.Shift | KeyCode.UpArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.selectDown', - key: KeyModifier.Shift | KeyCode.DownArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handleArrowRight', - key: KeyCode.RightArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handleArrowLeft', - key: KeyCode.LeftArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.focusFirst', - key: KeyCode.Home, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.focusLast', - key: KeyCode.End, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.focusPrevious', - key: KeyCode.UpArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.focusNext', - key: KeyCode.DownArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.expandAll', - key: KeyModifier.CtrlCmd | KeyCode.Star, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.expandRecursively', - key: KeyModifier.Alt | KeyCode.RightArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.collapseAll', - key: KeyModifier.CtrlCmd | KeyCode.LeftArrow, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handlePaste', - key: KeyModifier.CtrlCmd | KeyCode.KeyV, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handleCopy', - key: KeyModifier.CtrlCmd | KeyCode.KeyC, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handleCut', - key: KeyModifier.CtrlCmd | KeyCode.KeyX, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.renameDirent', - key: KeyCode.F2, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.cancelEdit', - key: KeyCode.Escape, - when: WhenExpression.FocusExplorerEditBox, - }, - { - command: 'Explorer.acceptEdit', - key: KeyCode.Enter, - when: WhenExpression.FocusExplorerEditBox, - }, - { - command: 'Explorer.removeDirent', - key: KeyCode.Delete, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.focusNone', - key: KeyCode.Escape, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handleClickCurrentButKeepFocus', - key: KeyCode.Space, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handleClickCurrent', - key: KeyCode.Enter, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.handleEscape', - key: KeyCode.Escape, - when: WhenExpression.FocusExplorer, - }, - { - command: 'Explorer.selectAll', - key: KeyModifier.CtrlCmd | KeyCode.KeyA, - when: WhenExpression.FocusExplorer, - }, - ] -} diff --git a/packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts b/packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts deleted file mode 100644 index aa1b0bd..0000000 --- a/packages/explorer-view/src/parts/GetLabelDom/GetLabelDom.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' -import { text } from '../VirtualDomHelpers/VirtualDomHelpers.ts' - -const label: VirtualDomNode = { - childCount: 1, - className: ClassNames.Label, - type: VirtualDomElements.Div, -} - -export const getLabelDom = (isEditing: boolean, name: string, isDimmed: boolean): readonly VirtualDomNode[] => { - if (isEditing) { - return [] - } - if (isDimmed) { - return [ - { - childCount: 1, - className: MergeClassNames.mergeClassNames(ClassNames.Label, ClassNames.LabelCut), - type: VirtualDomElements.Div, - }, - text(name), - ] - } - return [label, text(name)] -} diff --git a/packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts b/packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts deleted file mode 100644 index bf5cb77..0000000 --- a/packages/explorer-view/src/parts/GetListItemsVirtualDom/GetListItemsVirtualDom.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' -import * as AriaRoles from '../AriaRoles/AriaRoles.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' -import { dropTargetFull } from '../DropTargetFull/DropTargetFull.ts' -import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' -import * as GetExplorerItemVirtualDom from '../GetExplorerItemVirtualDom/GetExplorerItemVirtualDom.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -const getActiveDescendant = (focusedIndex: number): string | undefined => { - if (focusedIndex >= 0) { - return 'TreeItemActive' - } - return undefined -} - -const getClassName = (focused: boolean, focusedIndex: number, dropTarget: readonly number[]): string => { - const extraClass1 = focused && focusedIndex === -1 ? ClassNames.FocusOutline : ClassNames.Empty - const extraClass2 = dropTarget === dropTargetFull ? ClassNames.ExplorerDropTarget : ClassNames.Empty - const className = MergeClassNames.mergeClassNames(ClassNames.ListItems, extraClass1, extraClass2) - return className -} - -export const getListItemsVirtualDom = ( - visibleItems: readonly VisibleExplorerItem[], - focusedIndex: number, - focused: boolean, - dropTargets: readonly number[], -): readonly VirtualDomNode[] => { - const dom: readonly VirtualDomNode[] = [ - { - ariaActiveDescendant: getActiveDescendant(focusedIndex), - ariaLabel: ExplorerStrings.filesExplorer(), - childCount: visibleItems.length, - className: getClassName(focused, focusedIndex, dropTargets), - onBlur: DomEventListenerFunctions.HandleListBlur, - onClick: DomEventListenerFunctions.HandleClick, - onContextMenu: DomEventListenerFunctions.HandleContextMenu, - onDblClick: DomEventListenerFunctions.HandleDoubleClick, - onDragEnd: DomEventListenerFunctions.HandleDragEnd, - onDragLeave: DomEventListenerFunctions.HandleDragLeave, - onDragOver: DomEventListenerFunctions.HandleDragOver, - onDragStart: DomEventListenerFunctions.HandleDragStart, - onDrop: DomEventListenerFunctions.HandleDrop, - onFocus: DomEventListenerFunctions.HandleListFocus, - onPointerDown: DomEventListenerFunctions.HandlePointerDown, - onWheel: DomEventListenerFunctions.HandleWheel, - role: AriaRoles.Tree, - tabIndex: 0, - type: VirtualDomElements.Div, - // onKeyDown: DomEventListenerFunctions.HandleListKeyDown, - }, - ...visibleItems.flatMap(GetExplorerItemVirtualDom.getExplorerItemVirtualDom), - ] - return dom -} diff --git a/packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts b/packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts deleted file mode 100644 index 95dc156..0000000 --- a/packages/explorer-view/src/parts/GetLoadErrorMessage/GetLoadErrorMessage.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -const getMissingFolderMessage = (root: string): string => { - if (root) { - return `Could not open "${root}" because the folder does not exist. It may have been moved or deleted.` - } - return 'Could not open folder because the folder does not exist. It may have been moved or deleted.' -} - -export const getLoadErrorMessage = (state: ExplorerState): string => { - if (state.hasError) { - if (state.errorCode === 'ENOENT') { - return getMissingFolderMessage(state.root) - } - const code = state.errorCode ? ` (error code: ${state.errorCode})` : '' - const reason = state.errorMessage || 'an unexpected error occurred' - return `Could not open folder due to ${reason}${code}.` - } - return '' -} - -export const shouldShowOpenAnotherFolderButton = (state: ExplorerState): boolean => { - return state.hasError && state.errorCode === 'ENOENT' -} diff --git a/packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts b/packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts deleted file mode 100644 index 45e9963..0000000 --- a/packages/explorer-view/src/parts/GetLoadErrorVirtualDom/GetLoadErrorVirtualDom.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { text } from '@lvce-editor/virtual-dom-worker' -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as AriaRoles from '../AriaRoles/AriaRoles.ts' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as DomEventListenerFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' -import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' -import * as InputName from '../InputName/InputName.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -const getParentNode = (childCount: number): VirtualDomNode => { - return { - childCount, - className: MergeClassNames.mergeClassNames(ClassNames.Viewlet, ClassNames.Explorer), - role: AriaRoles.None, - type: VirtualDomElements.Div, - } -} - -export const getLoadErrorVirtualDom = ( - loadErrorMessage: string, - isWide: boolean, - showOpenAnotherFolderButton: boolean, -): readonly VirtualDomNode[] => { - const childCount = showOpenAnotherFolderButton ? 2 : 1 - const errorDom: readonly VirtualDomNode[] = [ - { - childCount, - className: ClassNames.Welcome, - type: VirtualDomElements.Div, - }, - { - childCount: 1, - className: ClassNames.WelcomeMessage, - type: VirtualDomElements.P, - }, - text(loadErrorMessage), - ] - const buttonDom = showOpenAnotherFolderButton - ? [ - { - childCount: 1, - className: MergeClassNames.mergeClassNames( - ClassNames.Button, - ClassNames.ButtonPrimary, - isWide ? ClassNames.ButtonWide : ClassNames.ButtonNarrow, - ), - name: InputName.OpenFolder, - onClick: DomEventListenerFunctions.HandleClickOpenFolder, - type: VirtualDomElements.Button, - }, - text(ExplorerStrings.openAnotherFolder()), - ] - : [] - const parentNode = getParentNode(1) - return [parentNode, ...errorDom, ...buttonDom] -} diff --git a/packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts b/packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts deleted file mode 100644 index 9bb1d3b..0000000 --- a/packages/explorer-view/src/parts/GetMaxLineY/GetMaxLineY.ts +++ /dev/null @@ -1,6 +0,0 @@ -import * as GetNumberOfVisibleItems from '../GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts' - -export const getExplorerMaxLineY = (minLineY: number, height: number, itemHeight: number, direntsLength: number): number => { - const maxLineY = minLineY + Math.min(GetNumberOfVisibleItems.getNumberOfVisibleItems(height, itemHeight), direntsLength) - return maxLineY -} diff --git a/packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts b/packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts deleted file mode 100644 index 34eabc7..0000000 --- a/packages/explorer-view/src/parts/GetMenuEntries/GetMenuEntries.ts +++ /dev/null @@ -1,214 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { MenuEntry } from '../MenuEntry/MenuEntry.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as ViewletExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' -import * as MenuEntrySeparator from '../MenuEntrySeparator/MenuEntrySeparator.ts' -import * as MenuItemFlags from '../MenuItemFlags/MenuItemFlags.ts' - -const menuEntryNewFile: MenuEntry = { - command: 'Explorer.newFile', - flags: MenuItemFlags.None, - id: 'newFile', - label: ViewletExplorerStrings.newFile(), -} - -const menuEntryNewFolder: MenuEntry = { - command: 'Explorer.newFolder', - flags: MenuItemFlags.None, - id: 'newFolder', - label: ViewletExplorerStrings.newFolder(), -} - -const menuEntryOpenContainingFolder: MenuEntry = { - command: 'Explorer.openContainingFolder', - flags: MenuItemFlags.RestoreFocus, - id: 'openContainingFolder', - label: ViewletExplorerStrings.openContainingFolder(), -} - -const menuEntryOpenInIntegratedTerminal: MenuEntry = { - command: /* TODO */ '-1', - flags: MenuItemFlags.None, - id: 'openInIntegratedTerminal', - label: ViewletExplorerStrings.openInIntegratedTerminal(), -} - -const menuEntryCut: MenuEntry = { - command: 'Explorer.handleCut', - flags: MenuItemFlags.RestoreFocus, - id: 'cut', - label: ViewletExplorerStrings.cut(), -} - -const menuEntryCopy: MenuEntry = { - command: 'Explorer.handleCopy', - flags: MenuItemFlags.RestoreFocus, - id: 'copy', - label: ViewletExplorerStrings.copy(), -} - -const menuEntryPaste: MenuEntry = { - command: 'Explorer.handlePaste', - flags: MenuItemFlags.None, - id: 'paste', - label: ViewletExplorerStrings.paste(), -} - -const menuEntryCopyPath: MenuEntry = { - command: 'Explorer.copyPath', - flags: MenuItemFlags.RestoreFocus, - id: 'copyPath', - label: ViewletExplorerStrings.copyPath(), -} - -const menuEntryCopyRelativePath: MenuEntry = { - command: 'Explorer.copyRelativePath', - flags: MenuItemFlags.RestoreFocus, - id: 'copyRelativePath', - label: ViewletExplorerStrings.copyRelativePath(), -} - -const menuEntrySelectForCompare: MenuEntry = { - command: 'Explorer.selectForCompare', - flags: MenuItemFlags.RestoreFocus, - id: 'selectForCompare', - label: ViewletExplorerStrings.selectForCompare(), -} - -const menuEntryCompareWithSelected: MenuEntry = { - command: 'Explorer.compareWithSelected', - flags: MenuItemFlags.RestoreFocus, - id: 'compareWithSelected', - label: ViewletExplorerStrings.compareWithSelected(), -} - -const menuEntryRename: MenuEntry = { - command: 'Explorer.renameDirent', - flags: MenuItemFlags.None, - id: 'rename', - label: ViewletExplorerStrings.rename(), -} - -const menuEntryDelete: MenuEntry = { - command: 'Explorer.removeDirent', - flags: MenuItemFlags.None, - id: 'delete', - label: ViewletExplorerStrings.deleteItem(), -} - -const menuEntryRemoveFolderFromWorkspace: MenuEntry = { - command: 'Workspace.close', - flags: MenuItemFlags.None, - id: 'removeFolderFromWorkspace', - label: ViewletExplorerStrings.removeFolderFromWorkspace(), -} - -const ALL_ENTRIES: readonly MenuEntry[] = [ - menuEntryNewFile, - menuEntryNewFolder, - menuEntryOpenContainingFolder, - menuEntryOpenInIntegratedTerminal, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCut, - menuEntryCopy, - menuEntryPaste, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCopyPath, - menuEntryCopyRelativePath, - MenuEntrySeparator.menuEntrySeparator, - menuEntryRename, - menuEntryDelete, -] - -// TODO there are two possible ways of getting the focused dirent of explorer -// 1. directly access state of explorer (bad because it directly accesses state of another component) -// 2. expose getFocusedDirent method in explorer (bad because explorer code should not know about for menuEntriesExplorer, which needs that method) -const getFocusedDirent = (explorerState: ExplorerState): ExplorerItem | undefined => { - if (!explorerState || explorerState.focusedIndex < 0) { - return undefined - } - return explorerState.items[explorerState.focusedIndex] -} - -const getMenuEntriesDirectory = (): readonly MenuEntry[] => { - return ALL_ENTRIES -} - -const getMenuEntriesFile = (): readonly MenuEntry[] => { - return [ - menuEntryOpenContainingFolder, - menuEntryOpenInIntegratedTerminal, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCut, - menuEntryCopy, - menuEntryPaste, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCopyPath, - menuEntryCopyRelativePath, - MenuEntrySeparator.menuEntrySeparator, - menuEntrySelectForCompare, - MenuEntrySeparator.menuEntrySeparator, - menuEntryRename, - menuEntryDelete, - ] -} - -const getMenuEntriesFileCompareWithSelected = (): readonly MenuEntry[] => { - return [ - menuEntryOpenContainingFolder, - menuEntryOpenInIntegratedTerminal, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCut, - menuEntryCopy, - menuEntryPaste, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCopyPath, - menuEntryCopyRelativePath, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCompareWithSelected, - MenuEntrySeparator.menuEntrySeparator, - menuEntryRename, - menuEntryDelete, - ] -} - -const getMenuEntriesDefault = (): readonly MenuEntry[] => { - return ALL_ENTRIES -} - -const getMenuEntriesRoot = (root: string): readonly MenuEntry[] => { - const entries: MenuEntry[] = [ - menuEntryNewFile, - menuEntryNewFolder, - menuEntryOpenContainingFolder, - menuEntryOpenInIntegratedTerminal, - MenuEntrySeparator.menuEntrySeparator, - menuEntryPaste, - MenuEntrySeparator.menuEntrySeparator, - menuEntryCopyPath, - menuEntryCopyRelativePath, - ] - if (root) { - entries.push(MenuEntrySeparator.menuEntrySeparator, menuEntryRemoveFolderFromWorkspace) - } - return entries -} - -export const getMenuEntries = (state: ExplorerState): readonly MenuEntry[] => { - const focusedDirent = getFocusedDirent(state) - if (!focusedDirent) { - return getMenuEntriesRoot(state.root) - } - switch (focusedDirent.type) { - case DirentType.Directory: - return getMenuEntriesDirectory() - case DirentType.File: - if (state.compareSourceUri && state.compareSourceUri !== focusedDirent.path) { - return getMenuEntriesFileCompareWithSelected() - } - return getMenuEntriesFile() - default: - return getMenuEntriesDefault() - } -} diff --git a/packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts b/packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts deleted file mode 100644 index 69dd8c6..0000000 --- a/packages/explorer-view/src/parts/GetMenuEntries2/GetMenuEntries2.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { MenuEntry } from '../MenuEntry/MenuEntry.ts' -import { getMenuEntries } from '../GetMenuEntries/GetMenuEntries.ts' - -export const getMenuEntries2 = (state: ExplorerState): readonly MenuEntry[] => { - return getMenuEntries(state) -} diff --git a/packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts b/packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts deleted file mode 100644 index fe65b4e..0000000 --- a/packages/explorer-view/src/parts/GetMissingIconRequests/GetMissingIconRequests.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' -import type { IconRequest } from '../IconRequest/IconRequest.ts' - -const getMissingDirents = (dirents: readonly ExplorerItem[], fileIconCache: FileIconCache): readonly ExplorerItem[] => { - const missingDirents: ExplorerItem[] = [] - for (const dirent of dirents) { - if (!(dirent.path in fileIconCache)) { - missingDirents.push(dirent) - } - } - return missingDirents -} - -const toIconRequest = (dirent: ExplorerItem): IconRequest => { - return { - name: dirent.name, - path: dirent.path, - type: dirent.type, - } -} - -export const getMissingIconRequests = (dirents: readonly ExplorerItem[], fileIconCache: FileIconCache): readonly IconRequest[] => { - const missingRequests = getMissingDirents(dirents, fileIconCache) - const iconRequests = missingRequests.map(toIconRequest) - return iconRequests -} diff --git a/packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts b/packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts deleted file mode 100644 index 8514c54..0000000 --- a/packages/explorer-view/src/parts/GetMouseAction/GetMouseAction.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const getMouseAction = (uid: number, button: number, modifiers: any): Promise => { - return RendererWorker.invoke('MouseActions.get', uid, button, modifiers) -} diff --git a/packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts b/packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts deleted file mode 100644 index c451c72..0000000 --- a/packages/explorer-view/src/parts/GetMouseActions/GetMouseActions.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { WhenExpression } from '@lvce-editor/constants' -import type { MouseAction } from '../MouseAction/MouseAction.ts' -import * as MouseEventType from '../MouseEventType/MouseEventType.ts' - -export const getMouseActions = (): readonly MouseAction[] => { - return [ - { - button: MouseEventType.LeftClick, - command: 'Explorer.openFile', - description: 'Open file on click', - modifiers: {}, - when: WhenExpression.FocusExplorer, - }, - { - button: MouseEventType.LeftClick, - command: 'Explorer.toggleSelection', - description: 'Toggle selection with Ctrl+Click', - modifiers: { - ctrl: true, - }, - when: WhenExpression.FocusExplorer, - }, - { - button: MouseEventType.LeftClick, - command: 'Explorer.rangeSelection', - description: 'Select range with Shift+Click', - modifiers: { - shift: true, - }, - when: WhenExpression.FocusExplorer, - }, - ] -} diff --git a/packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts b/packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts deleted file mode 100644 index 384f689..0000000 --- a/packages/explorer-view/src/parts/GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' -import { join2 } from '../Path/Path.ts' - -export const getNewChildDirentsForNewDirent = async ( - items: readonly ExplorerItem[], - depth: number, - parentPath: string, - direntType: number, -): Promise => { - // Get existing children or query them if they don't exist - let existingChildren = items.filter((item) => item.depth === depth && item.path.startsWith(parentPath)) - if (existingChildren.length === 0) { - const childDirents = await FileSystem.readDirWithFileTypes(parentPath) - existingChildren = childDirents.map((dirent: { name: string; type: number }, index: number) => ({ - depth, - icon: '', - name: dirent.name, - path: join2(parentPath, dirent.name), - posInSet: index + 1, - selected: false, - setSize: childDirents.length, - type: dirent.type, - })) - } - const updatedChildren = existingChildren.map((child, index) => ({ - ...child, - posInSet: index + 1, - setSize: existingChildren.length + 2, - })) - const newDirent: ExplorerItem = { - depth, - icon: '', - name: '', - path: parentPath, - posInSet: updatedChildren.length + 1, - selected: false, - setSize: existingChildren.length + 2, - type: direntType, - } - const allChildDirents = [...updatedChildren, newDirent] - return allChildDirents -} diff --git a/packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts b/packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts deleted file mode 100644 index b18bfe4..0000000 --- a/packages/explorer-view/src/parts/GetNewDirentType/GetNewDirentType.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as DirentType from '../DirentType/DirentType.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' - -export const getNewDirentType = (editingType: number): number => { - switch (editingType) { - case ExplorerEditingType.CreateFile: - return DirentType.EditingFile - case ExplorerEditingType.CreateFolder: - return DirentType.EditingFolder - default: - return DirentType.File - } -} diff --git a/packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts b/packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts deleted file mode 100644 index 0f43185..0000000 --- a/packages/explorer-view/src/parts/GetNewDirentsAccept/GetNewDirentsAccept.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { NewDirentsAcceptResult } from '../NewDirentsAcceptResult/NewDirentsAcceptResult.ts' -import * as CompareDirent from '../CompareDirent/CompareDirent.ts' -import { getParentFolder } from '../GetParentFolder/GetParentFolder.ts' - -export const getNewDirentsAccept = ( - items: readonly ExplorerItem[], - focusedIndex: number, - editingValue: string, - root: string, - pathSeparator: string, - newDirentType: number, -): NewDirentsAcceptResult => { - const newFileName = editingValue - const parentFolder = getParentFolder(items, focusedIndex, root, pathSeparator) - const absolutePath = [parentFolder, newFileName].join(pathSeparator) - - const parentDirent = - focusedIndex >= 0 - ? items[focusedIndex] - : { - depth: 0, - path: root, - } - const depth = parentDirent.depth + 1 - const newDirent: ExplorerItem = { - depth, - icon: '', - name: newFileName, - path: absolutePath, - posInSet: -1, - selected: false, - setSize: 1, - type: newDirentType, - } - // @ts-ignore - newDirent.icon = '' - let insertIndex = focusedIndex - let posInSet = 1 - let setSize = 1 - let i = Math.max(focusedIndex, -1) + 1 - // TODO update posinset and setsize of all affected dirents - for (; i < items.length; i++) { - const dirent = items[i] - if (dirent.depth !== depth) { - break - } - const compareResult = CompareDirent.compareDirent(dirent, newDirent) - if (compareResult === 1) { - insertIndex = i - 1 - break - } else { - // @ts-ignore - posInSet = dirent.posInSet + 1 - // @ts-ignore - setSize = dirent.setSize + 1 - insertIndex = i - } - // @ts-ignore - dirent.setSize++ - } - // @ts-ignore - newDirent.setSize = setSize - // @ts-ignore - newDirent.posInSet = posInSet - const newItems = [...items] - newItems.splice(insertIndex + 1, 0, newDirent) - return { - dirents: newItems, - newFocusedIndex: insertIndex + 1, - } -} diff --git a/packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts b/packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts deleted file mode 100644 index 1361691..0000000 --- a/packages/explorer-view/src/parts/GetNewDirentsForCancelRename/GetNewDirentsForCancelRename.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import { normalizeDirentType } from '../NormalizeDirentType/NormalizeDirentType.ts' - -export const getNewDirentsForCancelRename = (items: readonly ExplorerItem[], editingIndex: number): readonly ExplorerItem[] => { - const item = items[editingIndex] - const newItems = [...items] - newItems[editingIndex] = { - ...item, - type: normalizeDirentType(item.type), - } - return newItems -} diff --git a/packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts b/packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts deleted file mode 100644 index b475ee6..0000000 --- a/packages/explorer-view/src/parts/GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import { getNewChildDirentsForNewDirent } from '../GetNewChildDirentsForNewDirent/GetNewChildDirentsForNewDirent.ts' - -export const getNewDirentsForNewDirent = async ( - items: readonly ExplorerItem[], - focusedIndex: number, - type: number, - root: string, -): Promise => { - if (items.length === 0 || focusedIndex === -1) { - const newDirent: ExplorerItem = { - depth: 0, - icon: '', - name: '', - path: root, - posInSet: 1, - selected: false, - setSize: 1, - type, - } - return [...items, newDirent] - } - - const focusedItem = items[focusedIndex] - if (!focusedItem) { - return items - } - const parentPath = focusedItem.path - const depth = focusedItem.depth + 1 - - const updatedChildren = await getNewChildDirentsForNewDirent(items, depth, parentPath, type) - - // Create new array with updated items - const parentIndex = focusedIndex - const itemsBeforeParent = items.slice(0, parentIndex) - const itemsAfterChildren = items.slice(parentIndex + updatedChildren.length) - - let updatedParent = { - ...items[parentIndex], - setSize: (items[parentIndex]?.setSize || 0) + 1, - } - - // If the parent is a closed Directory, expand it - if (updatedParent.type === DirentType.Directory) { - updatedParent = { ...updatedParent, type: DirentType.DirectoryExpanded } - } - - return [...itemsBeforeParent, updatedParent, ...updatedChildren, ...itemsAfterChildren] -} diff --git a/packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts b/packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts deleted file mode 100644 index 6d28838..0000000 --- a/packages/explorer-view/src/parts/GetNewDirentsForRename/GetNewDirentsForRename.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as GetEditingType from '../GetEditingType/GetEditingType.ts' - -export const getNewDirentsForRename = (items: readonly ExplorerItem[], focusedIndex: number): readonly ExplorerItem[] => { - const item = items[focusedIndex] - const editingType = GetEditingType.getEditingType(item.type) - return [ - ...items.slice(0, focusedIndex), - { - ...item, - type: editingType, - }, - ...items.slice(focusedIndex + 1), - ] -} diff --git a/packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts b/packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts deleted file mode 100644 index 286b39e..0000000 --- a/packages/explorer-view/src/parts/GetNewDropTargets/GetNewDropTargets.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as CanBeDroppedInto from '../CanBeDroppedInto/CanBeDroppedInto.ts' -import { countInRange } from '../CountInRange/CountInRange.ts' -import { dropTargetFull } from '../DropTargetFull/DropTargetFull.ts' -import { getParentEndIndex } from '../GetParentEndIndex/GetParentEndIndex.ts' -import { getParentStartIndex } from '../GetParentStartIndex/GetParentStartIndex.ts' - -export const getNewDropTargets = (state: ExplorerState, index: number): readonly number[] => { - const { items } = state - if (index === -1) { - return dropTargetFull - } - const item = items[index] - if (!item) { - return dropTargetFull - } - if (!CanBeDroppedInto.canBeDroppedInto(item)) { - const startIndex = getParentStartIndex(items, index) - const endIndex = getParentEndIndex(items, index) - return countInRange(startIndex, endIndex) - } - const newDropTargets = [index] - return newDropTargets -} diff --git a/packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts b/packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts deleted file mode 100644 index e51d3f2..0000000 --- a/packages/explorer-view/src/parts/GetNumberOfVisibleItems/GetNumberOfVisibleItems.ts +++ /dev/null @@ -1,9 +0,0 @@ -// TODO optimize this function to return the minimum number -// of visible items needed, e.g. when not scrolled 5 items with -// 20px fill 100px but when scrolled 6 items are needed -export const getNumberOfVisibleItems = (listHeight: number, itemHeight: number): number => { - if (listHeight <= 0 || itemHeight <= 0) { - return 0 - } - return Math.ceil(listHeight / itemHeight) + 1 -} diff --git a/packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts b/packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts deleted file mode 100644 index 53b44f2..0000000 --- a/packages/explorer-view/src/parts/GetParentEndIndex/GetParentEndIndex.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const getParentEndIndex = (dirents: readonly ExplorerItem[], index: number): number => { - const dirent = dirents[index] - const { depth } = dirent - let endIndex = index + 1 - while (endIndex < dirents.length && dirents[endIndex].depth > depth) { - endIndex++ - } - return endIndex -} diff --git a/packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts b/packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts deleted file mode 100644 index 0b1bbaa..0000000 --- a/packages/explorer-view/src/parts/GetParentFolder/GetParentFolder.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import { dirname } from '../Path/Path.ts' - -const isFileLike = (type: number): boolean => { - return type === DirentType.File || type === DirentType.SymLinkFile -} - -export const getParentFolder = (dirents: readonly ExplorerItem[], index: number, root: string, pathSeparator: string): string => { - if (index < 0) { - return root - } - const item = dirents[index] - if (!item) { - return root - } - if (isFileLike(item.type)) { - const parentFolder = dirname(pathSeparator, item.path) - return parentFolder || root - } - return item.path -} diff --git a/packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts b/packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts deleted file mode 100644 index 9af0262..0000000 --- a/packages/explorer-view/src/parts/GetParentStartIndex/GetParentStartIndex.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const getParentStartIndex = (dirents: readonly ExplorerItem[], index: number): number => { - const dirent = dirents[index] - let startIndex = index - 1 - while (startIndex >= 0 && dirents[startIndex].depth >= dirent.depth) { - startIndex-- - } - return startIndex -} diff --git a/packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts b/packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts deleted file mode 100644 index 99857da..0000000 --- a/packages/explorer-view/src/parts/GetPasteHandler/GetPasteHandler.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { PasteHandler } from '../PasteHandler/PasteHandler.ts' -import * as HandlePasteCopy from '../HandlePasteCopy/HandlePasteCopy.ts' -import * as HandlePasteCut from '../HandlePasteCut/HandlePasteCut.ts' -import * as HandlePasteNone from '../HandlePasteNone/HandlePasteNone.ts' -import * as NativeFileTypes from '../NativeFileTypes/NativeFileTypes.ts' - -export const getPasteHandler = (type: string): PasteHandler => { - switch (type) { - case NativeFileTypes.Copy: - return HandlePasteCopy.handlePasteCopy - case NativeFileTypes.Cut: - return HandlePasteCut.handlePasteCut - case NativeFileTypes.None: - return HandlePasteNone.handlePasteNone - default: - throw new Error(`unexpected native paste type: ${type}`) - } -} diff --git a/packages/explorer-view/src/parts/GetPath/GetPath.ts b/packages/explorer-view/src/parts/GetPath/GetPath.ts deleted file mode 100644 index 769968b..0000000 --- a/packages/explorer-view/src/parts/GetPath/GetPath.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const getPath = (item: ExplorerItem): string => { - return item.path -} diff --git a/packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts b/packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts deleted file mode 100644 index 1d1544c..0000000 --- a/packages/explorer-view/src/parts/GetPathDirentsMap/GetPathDirentsMap.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' - -export const getPathDirentsMap = async (allPaths: readonly string[]): Promise> => { - const pathToDirents: Record = Object.create(null) - await Promise.all( - allPaths.map(async (path) => { - try { - const dirents = await FileSystem.readDirWithFileTypes(path) - pathToDirents[path] = dirents - } catch { - // ignore - } - }), - ) - return pathToDirents -} diff --git a/packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts b/packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts deleted file mode 100644 index 25bdc2c..0000000 --- a/packages/explorer-view/src/parts/GetPathParts/GetPathParts.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { PathPart } from '../PathPart/PathPart.ts' - -export const getPathParts = (root: string, uri: string, pathSeparator: string): readonly PathPart[] => { - const parts: PathPart[] = [] - let index = root.length - 1 - let depth = 0 - while ((index = uri.indexOf(pathSeparator, index + 1)) !== -1) { - const partUri = uri.slice(0, index) - parts.push({ - depth: depth++, - expanded: true, - path: partUri, - pathSeparator, - root, - }) - } - return parts -} diff --git a/packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts b/packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts deleted file mode 100644 index 129aef2..0000000 --- a/packages/explorer-view/src/parts/GetPathPartsChildren/GetPathPartsChildren.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { PathPart } from '../PathPart/PathPart.ts' -import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' -import { orderDirents } from '../OrderDirents/OrderDirents.ts' - -const getPathPartChildren = async (pathPart: PathPart): Promise => { - const children = await getChildDirents(pathPart.pathSeparator, pathPart.path, pathPart.depth) - return children -} - -export const getPathPartsChildren = async (pathparts: readonly PathPart[]): Promise => { - const pathPartsChildren = await Promise.all(pathparts.map(getPathPartChildren)) - const pathPartsChildrenFlat = pathPartsChildren.flat() - const orderedPathParts = orderDirents(pathPartsChildrenFlat) - return orderedPathParts -} diff --git a/packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts b/packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts deleted file mode 100644 index 947fa03..0000000 --- a/packages/explorer-view/src/parts/GetPathPartsFromFileOperations/GetPathPartsFromFileOperations.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import * as Path from '../Path/Path.ts' - -const getPathPartUpdate = (operation: FileOperation): string => { - switch (operation.type) { - case FileOperationType.CreateFile: - return Path.dirname2(operation.path) - case FileOperationType.CreateFolder: - return Path.dirname2(operation.path) - case FileOperationType.Rename: - return Path.dirname2(operation.path) - default: - return '' - } -} - -export const getPathPartsFromFileOperations = (operations: readonly FileOperation[]): readonly string[] => { - return operations.map(getPathPartUpdate).filter(Boolean) -} diff --git a/packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts b/packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts deleted file mode 100644 index 36c8354..0000000 --- a/packages/explorer-view/src/parts/GetPathPartsToReveal/GetPathPartsToReveal.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { PathPart } from '../PathPart/PathPart.ts' -import { getIndex } from '../GetIndex/GetIndex.ts' - -export const getPathPartsToReveal = (root: string, pathParts: readonly PathPart[], dirents: readonly ExplorerItem[]): readonly PathPart[] => { - for (let i = 0; i < pathParts.length; i++) { - const pathPart = pathParts[i] - const index = getIndex(dirents, pathPart.path) - if (index === -1) { - continue - } - return pathParts.slice(i) - } - return pathParts -} diff --git a/packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts b/packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts deleted file mode 100644 index e63932d..0000000 --- a/packages/explorer-view/src/parts/GetPathSeparator/GetPathSeparator.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as FileSystem from '../FileSystem/FileSystem.ts' - -export const getPathSeparator = async (root: string): Promise => { - return FileSystem.getPathSeparator(root) -} diff --git a/packages/explorer-view/src/parts/GetPaths/GetPaths.ts b/packages/explorer-view/src/parts/GetPaths/GetPaths.ts deleted file mode 100644 index b3d8288..0000000 --- a/packages/explorer-view/src/parts/GetPaths/GetPaths.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import { getPath } from '../GetPath/GetPath.ts' - -export const getPaths = (items: readonly ExplorerItem[]): readonly string[] => { - return items.map(getPath) -} diff --git a/packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts b/packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts deleted file mode 100644 index 5ad91ea..0000000 --- a/packages/explorer-view/src/parts/GetProtoMap/GetProtoMap.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import { getProtoMapInternal } from '../GetProtoMapInternal/GetProtoMapInternal.ts' - -export const getProtoMap = ( - root: string, - pathToDirents: Record, - expandedPaths: readonly string[], -): readonly ExplorerItem[] => { - return getProtoMapInternal(root, pathToDirents, expandedPaths, 1) -} diff --git a/packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts b/packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts deleted file mode 100644 index e6aca27..0000000 --- a/packages/explorer-view/src/parts/GetProtoMapInternal/GetProtoMapInternal.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import { join2 } from '../Path/Path.ts' -import { restoreDirentType } from '../RestoreDirentType/RestoreDirentType.ts' - -export const getProtoMapInternal = ( - root: string, - pathToDirents: Record, - expandedPaths: readonly string[], - depth: number, -): readonly ExplorerItem[] => { - if (!(root in pathToDirents)) { - return [] - } - const items = pathToDirents[root] || [] - const protoMap: ExplorerItem[] = [] - for (let i = 0; i < items.length; i++) { - const item = items[i] - const path = join2(root, item.name) - const displayDirent: ExplorerItem = { - depth, - icon: '', - name: item.name, - path, - posInSet: i + 1, - selected: false, - setSize: items.length, - type: restoreDirentType(item.type, path, expandedPaths), - } - const children = getProtoMapInternal(path, pathToDirents, expandedPaths, depth + 1) - protoMap.push(displayDirent, ...children) - } - return protoMap -} diff --git a/packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts b/packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts deleted file mode 100644 index 9de6d33..0000000 --- a/packages/explorer-view/src/parts/GetRenameSelectionRange/GetRenameSelectionRange.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Selection } from '../Selection/Selection.ts' - -export const getRenameSelectionRange = (name: string): Selection => { - const dotIndex = name.lastIndexOf('.') - if (dotIndex === -1) { - return { - end: name.length, - start: 0, - } - } - return { - end: dotIndex, - start: 0, - } -} diff --git a/packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts b/packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts deleted file mode 100644 index 35d6a3d..0000000 --- a/packages/explorer-view/src/parts/GetRenderer/GetRenderer.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Renderer } from '../Renderer/Renderer.ts' -import * as DiffType from '../DiffType/DiffType.ts' -import { renderCss } from '../RenderCss/RenderCss.ts' -import * as RenderDragData from '../RenderDragData/RenderDragData.ts' -import * as RenderEditingSelection from '../RenderEditingSelection/RenderEditingSelection.ts' -import * as RenderFocus from '../RenderFocus/RenderFocus.ts' -import * as RenderFocusContext from '../RenderFocusContext/RenderFocusContext.ts' -import { renderIncremental } from '../RenderIncremental/RenderIncremental.ts' -import * as RenderItems from '../RenderItems/RenderItems.ts' -import * as RenderValue from '../RenderValue/RenderValue.ts' - -export const getRenderer = (diffType: number): Renderer => { - switch (diffType) { - case DiffType.RenderCss: - return renderCss - case DiffType.RenderDragData: - return RenderDragData.renderDragData - case DiffType.RenderFocus: - return RenderFocus.renderFocus - case DiffType.RenderFocusContext: - return RenderFocusContext.renderFocusContext - case DiffType.RenderIncremental: - return renderIncremental - case DiffType.RenderItems: - return RenderItems.renderItems - case DiffType.RenderSelection: - return RenderEditingSelection.renderEditingSelection - case DiffType.RenderValue: - return RenderValue.renderValue - default: - throw new Error('unknown renderer') - } -} diff --git a/packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts b/packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts deleted file mode 100644 index 61280e7..0000000 --- a/packages/explorer-view/src/parts/GetRestoredDeltaY/GetRestoredDeltaY.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const getRestoredDeltaY = (savedState: any): number => { - if (savedState && typeof savedState.deltaY === 'number') { - return savedState.deltaY - } - return 0 -} diff --git a/packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts b/packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts deleted file mode 100644 index 4ab91bd..0000000 --- a/packages/explorer-view/src/parts/GetSavedChildDirents/GetSavedChildDirents.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as DirentType from '../DirentType/DirentType.ts' -import * as SortExplorerItems from '../SortExplorerItems/SortExplorerItems.ts' - -export const getSavedChildDirents = (map: any, path: any, depth: any, excluded: any, pathSeparator: any): readonly any[] => { - let children = map[path] - if (!children) { - return [] - } - const dirents = [] - children = SortExplorerItems.sortExplorerItems(children) - const visible = [] - const displayRoot = path.endsWith(pathSeparator) ? path : path + pathSeparator - for (const child of children) { - if (excluded.includes(child.name)) { - continue - } - visible.push(child) - } - const visibleLength = visible.length - for (let i = 0; i < visibleLength; i++) { - const child = visible[i] - const { name, type } = child - const childPath = displayRoot + name - if ((child.type === DirentType.Directory || child.type === DirentType.SymLinkFolder) && childPath in map) { - dirents.push({ - depth, - icon: '', - name, - path: childPath, - posInSet: i + 1, - setSize: visibleLength, - type: DirentType.DirectoryExpanded, - }) - dirents.push(...getSavedChildDirents(map, childPath, depth + 1, excluded, pathSeparator)) - } else { - dirents.push({ - depth, - icon: '', - name, - path: childPath, - posInSet: i + 1, - setSize: visibleLength, - type, - }) - } - } - return dirents -} diff --git a/packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts b/packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts deleted file mode 100644 index a85dde0..0000000 --- a/packages/explorer-view/src/parts/GetSavedRoot/GetSavedRoot.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const getSavedRoot = (savedState: any, workspacePath: string): string => { - return workspacePath -} diff --git a/packages/explorer-view/src/parts/GetScheme/GetScheme.ts b/packages/explorer-view/src/parts/GetScheme/GetScheme.ts deleted file mode 100644 index 199fefa..0000000 --- a/packages/explorer-view/src/parts/GetScheme/GetScheme.ts +++ /dev/null @@ -1,9 +0,0 @@ -const RE_PROTOCOL = /^[a-z+]:\/\// - -export const getScheme = (uri: string): string => { - const match = uri.match(RE_PROTOCOL) - if (!match) { - return '' - } - return match[0] -} diff --git a/packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts b/packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts deleted file mode 100644 index de2c610..0000000 --- a/packages/explorer-view/src/parts/GetScrollBarSize/GetScrollBarSize.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const getScrollBarSize = (size: number, contentSize: number, minimumSliderSize: number): number => { - if (size >= contentSize) { - return 0 - } - return Math.max(Math.round(size ** 2 / contentSize), minimumSliderSize) -} diff --git a/packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts b/packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts deleted file mode 100644 index 16fa46b..0000000 --- a/packages/explorer-view/src/parts/GetScrollBarTop/GetScrollBarTop.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const getScrollBarTop = (height: number, contentHeight: number, scrollTop: number): number => { - if (contentHeight <= 0 || !Number.isFinite(contentHeight)) { - return 0 - } - const scrollBarTop = Math.round((scrollTop / contentHeight) * height) - if (!Number.isFinite(scrollBarTop)) { - return 0 - } - return scrollBarTop -} diff --git a/packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts b/packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts deleted file mode 100644 index 9c77e66..0000000 --- a/packages/explorer-view/src/parts/GetScrollBarVirtualDom/GetScrollBarVirtualDom.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker' -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' -import * as VirtualDomElements from '../VirtualDomElements/VirtualDomElements.ts' - -export const getScrollBarVirtualDom = (scrollBarHeight: number): readonly VirtualDomNode[] => { - const shouldShowScrollbar = scrollBarHeight > 0 - if (!shouldShowScrollbar) { - return [] - } - return [ - { - childCount: 1, - className: MergeClassNames.mergeClassNames(ClassNames.ScrollBar, ClassNames.ScrollBarSmall), - type: VirtualDomElements.Div, - }, - { - childCount: 0, - className: ClassNames.ScrollBarThumb, - type: VirtualDomElements.Div, - }, - ] -} diff --git a/packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts b/packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts deleted file mode 100644 index fe3b270..0000000 --- a/packages/explorer-view/src/parts/GetSelectedItems/GetSelectedItems.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const getSelectedItems = (items: readonly ExplorerItem[], focusedIndex: number): readonly ExplorerItem[] => { - const dirent = items[focusedIndex] - const selectedItems = items.filter((item) => item.selected || item === dirent) - return selectedItems -} diff --git a/packages/explorer-view/src/parts/GetSettings/GetSettings.ts b/packages/explorer-view/src/parts/GetSettings/GetSettings.ts deleted file mode 100644 index 9c93461..0000000 --- a/packages/explorer-view/src/parts/GetSettings/GetSettings.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { Settings } from '../Settings/Settings.ts' - -export const getSettings = async (): Promise => { - // TODO don't return false always - // TODO get all settings at once - const useChevronsRaw = await RendererWorker.invoke('Preferences.get', 'explorer.useChevrons') - const useChevrons = useChevronsRaw === false ? false : true - const confirmDeleteRaw = await RendererWorker.invoke('Preferences.get', 'explorer.confirmdelete') - const confirmDelete = confirmDeleteRaw === false ? false : false - const confirmPasteRaw = await RendererWorker.invoke('Preferences.get', 'explorer.confirmpaste') - const confirmPaste = confirmPasteRaw === false ? false : false - const sourceControlDecorationsRaw = await RendererWorker.invoke('Preferences.get', 'explorer.sourceControlDecorations') - const sourceControlDecorations = sourceControlDecorationsRaw === false ? false : true - return { - confirmDelete, - confirmPaste, - sourceControlDecorations, - useChevrons, - } -} diff --git a/packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts b/packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts deleted file mode 100644 index b2b0e1f..0000000 --- a/packages/explorer-view/src/parts/GetSiblingFileNames/GetSiblingFileNames.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const getSiblingFileNames = (items: readonly ExplorerItem[], focusedIndex: number, root: string, pathSeparator: string): readonly string[] => { - if (focusedIndex < 0 || focusedIndex >= items.length) { - // If no focused item or invalid index, get root level items - return items.filter((item) => item.depth === 0).map((item) => item.name) - } - - const focusedItem = items[focusedIndex] - const nameLength = focusedItem.name ? focusedItem.name.length + 1 : 0 - const focusedItemParentPath = focusedItem.path.slice(0, -nameLength) - - // Find all items that are direct children of the same parent as the focused item - const siblingItems = items.filter((item) => { - const itemParentPath = item.path.slice(0, -nameLength) - return itemParentPath === focusedItemParentPath - }) - - return siblingItems.map((item) => item.name) -} diff --git a/packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts b/packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts deleted file mode 100644 index 2335cab..0000000 --- a/packages/explorer-view/src/parts/GetSimpleIconRequestType/GetSimpleIconRequestType.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as DirentType from '../DirentType/DirentType.ts' - -export const getSimpleIconRequestType = (direntType: number): 1 | 2 => { - if ( - direntType === DirentType.Directory || - direntType === DirentType.DirectoryExpanded || - direntType === DirentType.EditingDirectoryExpanded || - direntType === DirentType.EditingFolder - ) { - return 2 - } - return 1 -} diff --git a/packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts b/packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts deleted file mode 100644 index 1444024..0000000 --- a/packages/explorer-view/src/parts/GetSymlinkType/GetSymlinkType.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as DirentType from '../DirentType/DirentType.ts' - -export const getSymlinkType = (type: number): number => { - switch (type) { - case DirentType.Directory: - return DirentType.SymLinkFolder - case DirentType.File: - return DirentType.SymLinkFile - default: - return DirentType.Symlink - } -} diff --git a/packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts b/packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts deleted file mode 100644 index e61d775..0000000 --- a/packages/explorer-view/src/parts/GetTopLevelDirents/GetTopLevelDirents.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' - -export const getTopLevelDirents = (root: string, pathSeparator: string, excluded: any[]): any => { - if (!root) { - return [] - } - return getChildDirents(pathSeparator, root, 0, excluded) -} diff --git a/packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts b/packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts deleted file mode 100644 index b6db63a..0000000 --- a/packages/explorer-view/src/parts/GetTreeItemClassName/GetTreeItemClassName.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as ClassNames from '../ClassNames/ClassNames.ts' -import * as MergeClassNames from '../MergeClassNames/MergeClassNames.ts' - -export const getTreeItemClassName = ( - isSelected: boolean, - isFocused: boolean, - isDropping: boolean, - useChevrons: boolean, - indent: number, - decoration: string, -): string => { - let className = ClassNames.TreeItem - className = MergeClassNames.mergeClassNames(className, `Indent-${indent}`) - if (isSelected || isFocused) { - className = MergeClassNames.mergeClassNames(className, ClassNames.TreeItemActive) - } - if (isDropping) { - className = MergeClassNames.mergeClassNames(className, 'DropTarget') - } - if (decoration) { - className = MergeClassNames.mergeClassNames(className, `decoration-${decoration}`) - } - return className -} diff --git a/packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts b/packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts deleted file mode 100644 index 27b8c79..0000000 --- a/packages/explorer-view/src/parts/GetTreeItemIndent/GetTreeItemIndent.ts +++ /dev/null @@ -1,5 +0,0 @@ -const defaultIndent = 12 - -export const getTreeItemIndent = (depth: number): number => { - return depth * defaultIndent -} diff --git a/packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts b/packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts deleted file mode 100644 index 012821a..0000000 --- a/packages/explorer-view/src/parts/GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts +++ /dev/null @@ -1,13 +0,0 @@ -// TODO make all of these variable configurable -const defaultPaddingLeft = 4 - -const defaultIndent = 8 - -// TODO make chevron size configurable -const chevronSize = 22 - -export const getTreeItemIndentWithChevron = (depth: number, chevron: number): number => { - // TODO use numeric value here, convert to string value in renderer process - const extraSpace = chevron ? 0 : chevronSize - return depth * defaultIndent + extraSpace + defaultPaddingLeft -} diff --git a/packages/explorer-view/src/parts/GetUnique/GetUnique.ts b/packages/explorer-view/src/parts/GetUnique/GetUnique.ts deleted file mode 100644 index 4074d44..0000000 --- a/packages/explorer-view/src/parts/GetUnique/GetUnique.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const getUnique = (items: readonly number[]): readonly number[] => { - const seens: number[] = [] - for (const item of items) { - if (!seens.includes(item)) { - seens.push(item) - } - } - return seens -} diff --git a/packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts b/packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts deleted file mode 100644 index fbf57f4..0000000 --- a/packages/explorer-view/src/parts/GetUniqueIndents/GetUniqueIndents.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' -import { getUnique } from '../GetUnique/GetUnique.ts' - -const getIndent = (item: VisibleExplorerItem): number => item.indent - -export const getUniqueIndents = (items: readonly VisibleExplorerItem[]): readonly number[] => { - const indents = items.map(getIndent) - const uniqueIndents = getUnique(indents) - return uniqueIndents -} diff --git a/packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts b/packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts deleted file mode 100644 index 589cb85..0000000 --- a/packages/explorer-view/src/parts/GetVisibleExplorerItems/GetVisibleExplorerItems.ts +++ /dev/null @@ -1,84 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' -import type { VisibleExplorerItem } from '../VisibleExplorerItem/VisibleExplorerItem.ts' -import * as ChevronType from '../ChevronType/ChevronType.ts' -import { createDecorationMap } from '../CreateDecorationMap/CreateDecorationMap.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as GetChevronType from '../GetChevronType/GetChevronType.ts' -import * as GetExpandedType from '../GetExpandedType/GetExpandedType.ts' -import { getTreeItemClassName } from '../GetTreeItemClassName/GetTreeItemClassName.ts' -import * as GetTreeItemIndent from '../GetTreeItemIndent/GetTreeItemIndent.ts' -import * as GetTreeItemIndentWithChevron from '../GetTreeItemIndentWithChevron/GetTreeItemIndentWithChevron.ts' - -const ariaExpandedValues: (string | undefined)[] = [undefined, 'true', 'false'] - -const getEditingChevron = (direntType: number): number => { - switch (direntType) { - case DirentType.EditingDirectoryExpanded: - return ChevronType.Down - case DirentType.EditingFolder: - return ChevronType.Right - default: - return ChevronType.None - } -} - -export const getVisibleExplorerItems = ( - items: readonly ExplorerItem[], - minLineY: number, - maxLineY: number, - focusedIndex: number, - editingIndex: number, - editingErrorMessage: string, - icons: readonly string[], - useChevrons: boolean, - dropTargets: readonly number[], - editingIcon: string, - cutItems: readonly string[], - sourceControlIgnoredUris: readonly string[] = [], - decorations: readonly FileDecoration[], -): readonly VisibleExplorerItem[] => { - const decorationMap = createDecorationMap(decorations) - const visible: VisibleExplorerItem[] = [] - const indentFn = useChevrons ? GetTreeItemIndentWithChevron.getTreeItemIndentWithChevron : GetTreeItemIndent.getTreeItemIndent - let iconIndex = 0 - for (let i = minLineY; i < Math.min(maxLineY, items.length); i++) { - const item = items[i] - let chevron = GetChevronType.getChevronType(item.type, useChevrons) - const isEditing = i === editingIndex - let icon = icons[iconIndex++] - if (isEditing) { - icon = editingIcon - chevron = getEditingChevron(item.type) - } - const isFocused = i === focusedIndex - const id = isFocused ? 'TreeItemActive' : undefined - const isSelected = item.selected - const isCut = cutItems.includes(item.path) - const isDropping = dropTargets.includes(i) - const isIgnored = sourceControlIgnoredUris.includes(item.path) - const indent = indentFn(item.depth, chevron) - const decoration = decorationMap[item.path] || '' - const className = getTreeItemClassName(isSelected, isFocused, isDropping, useChevrons, indent, decoration) - const expanded = GetExpandedType.getExpandedType(item.type) - const ariaExpanded = ariaExpandedValues[expanded] - visible.push({ - ...item, - ariaExpanded, - chevron, - className, - decoration, - hasEditingError: isEditing && Boolean(editingErrorMessage), - icon, - id, - indent, - index: i, - isCut, - isEditing: isEditing, - isIgnored, - posInSet: item.posInSet ?? i + 1, - setSize: item.setSize ?? items.length, - }) - } - return visible -} diff --git a/packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts b/packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts deleted file mode 100644 index 8acd6e7..0000000 --- a/packages/explorer-view/src/parts/GetWorkspacePath/GetWorkspacePath.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker as Rpc } from '@lvce-editor/rpc-registry' - -export const getWorkspacePath = (): Promise => { - return Rpc.invoke('Workspace.getPath') -} diff --git a/packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts b/packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts deleted file mode 100644 index bb923f8..0000000 --- a/packages/explorer-view/src/parts/HandleArrowLeft/HandleArrowLeft.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as FocusParentFolder from '../FocusParentFolder/FocusParentFolder.ts' -import * as HandleClickDirectoryExpanded from '../HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts' - -export const handleArrowLeft = (state: ExplorerState): ExplorerState | Promise => { - const { focusedIndex, items } = state - if (focusedIndex === -1) { - return state - } - const dirent = items[focusedIndex] - switch (dirent.type) { - case DirentType.Directory: - case DirentType.File: - case DirentType.SymLinkFile: - return FocusParentFolder.focusParentFolder(state) - case DirentType.DirectoryExpanded: - return HandleClickDirectoryExpanded.handleClickDirectoryExpanded(state, dirent, focusedIndex, true) - default: - // TODO handle expanding directory and cancel file system call to read child dirents - return state - } -} diff --git a/packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts b/packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts deleted file mode 100644 index 28e9fa9..0000000 --- a/packages/explorer-view/src/parts/HandleArrowRight/HandleArrowRight.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as HandleArrowRightDirectoryExpanded from '../HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts' -import * as HandleClickDirectory from '../HandleClickDirectory/HandleClickDirectory.ts' -import * as HandleClickSymlink from '../HandleClickSymlink/HandleClickSymlink.ts' - -export const handleArrowRight = async (state: ExplorerState): Promise => { - const { focusedIndex, items } = state - if (focusedIndex === -1) { - return state - } - const dirent = items[focusedIndex] - switch (dirent.type) { - case DirentType.Directory: - case DirentType.SymLinkFolder: - // @ts-ignore - return HandleClickDirectory.handleClickDirectory(state, dirent, focusedIndex) - case DirentType.DirectoryExpanded: - return HandleArrowRightDirectoryExpanded.handleArrowRightDirectoryExpanded(state, dirent) - case DirentType.File: - case DirentType.SymLinkFile: - return state - case DirentType.Symlink: - return HandleClickSymlink.handleClickSymLink(state, dirent, focusedIndex) - default: - throw new Error(`unsupported file type ${dirent.type}`) - } -} diff --git a/packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts b/packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts deleted file mode 100644 index 115545a..0000000 --- a/packages/explorer-view/src/parts/HandleArrowRightDirectoryExpanded/HandleArrowRightDirectoryExpanded.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusIndex from '../FocusIndex/FocusIndex.ts' - -export const handleArrowRightDirectoryExpanded = (state: ExplorerState, dirent: any): ExplorerState => { - const { focusedIndex, items } = state - if (focusedIndex === items.length - 1) { - return state - } - const nextDirent = items[focusedIndex + 1] - if (nextDirent.depth === dirent.depth + 1) { - return FocusIndex.focusIndex(state, focusedIndex + 1) - } - return state -} diff --git a/packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts b/packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts deleted file mode 100644 index db76f3a..0000000 --- a/packages/explorer-view/src/parts/HandleBlur/HandleBlur.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleBlur = async (state: ExplorerState): Promise => { - // TODO when blur event occurs because of context menu, focused index should stay the same - // but focus outline should be removed - const { items } = state - const newItems = items.map((item) => { - return { - ...item, - selected: false, - } - }) - return { - ...state, - focused: false, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts b/packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts deleted file mode 100644 index bf4acdf..0000000 --- a/packages/explorer-view/src/parts/HandleButtonClick/HandleButtonClick.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { collapseAll } from '../CollapseAll/CollapseAll.ts' -import * as InputName from '../InputName/InputName.ts' -import { newFile } from '../NewFile/NewFile.ts' -import { newFolder } from '../NewFolder/NewFolder.ts' -import { refresh } from '../Refresh/Refresh.ts' - -export const handleButtonClick = async (state: ExplorerState, name: string): Promise => { - switch (name) { - case InputName.CollapseAll: - return collapseAll(state) - case InputName.NewFile: - return newFile(state) - case InputName.NewFolder: - return newFolder(state) - case InputName.Refresh: - return refresh(state) - default: - return state - } -} diff --git a/packages/explorer-view/src/parts/HandleClick/HandleClick.ts b/packages/explorer-view/src/parts/HandleClick/HandleClick.ts deleted file mode 100644 index 83df8e7..0000000 --- a/packages/explorer-view/src/parts/HandleClick/HandleClick.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusIndex from '../FocusIndex/FocusIndex.ts' -import * as GetClickFn from '../GetClickFn/GetClickFn.ts' -import { normalizeDirentType } from '../NormalizeDirentType/NormalizeDirentType.ts' -import { resetEditing } from '../ResetEditing/ResetEditing.ts' -// TODO viewlet should only have create and refresh functions -// every thing else can be in a separate module .lazy.js -// and .ipc.js - -// viewlet: creating | refreshing | done | disposed -// TODO recycle viewlets (maybe) - -// TODO instead of root string, there should be a root dirent - -// TODO rename dirents to items, then can use virtual list component directly - -// TODO use posInSet and setSize properties to compute more effectively - -// TODO much shared logic with newFolder - -export const handleClick = async (state: ExplorerState, index: number, keepFocus = false): Promise => { - const { items } = state - if (index === -1) { - return FocusIndex.focusIndex(state, -1) - } - const actualIndex = index - const dirent = items[actualIndex] - if (!dirent) { - console.warn(`[explorer] dirent at index ${actualIndex} not found`, state) - return state - } - const normalizedType = normalizeDirentType(dirent.type) - const clickFn = GetClickFn.getClickFn(normalizedType) - const newState = await clickFn(state, dirent, actualIndex, keepFocus) - if (newState.editingIndex === -1) { - return newState - } - return { - ...newState, - ...resetEditing, - } -} - -// export const handleBlur=()=>{} - -// TODO what happens when mouse leave and anther mouse enter event occur? -// should update preview instead of closing and reopening - -// TODO maybe just insert items into explorer and refresh whole explorer diff --git a/packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts b/packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts deleted file mode 100644 index ef63190..0000000 --- a/packages/explorer-view/src/parts/HandleClickAt/HandleClickAt.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusIndex from '../FocusIndex/FocusIndex.ts' -import * as GetIndexFromPosition from '../GetIndexFromPosition/GetIndexFromPosition.ts' -import * as HandleClick from '../HandleClick/HandleClick.ts' -import * as HandleClickAtRangeSelection from '../HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts' -import * as MouseEventType from '../MouseEventType/MouseEventType.ts' -import { toggleIndividualSelection } from '../ToggleIndividualSelection/ToggleIndividualSelection.ts' - -export const handleClickAt = async ( - state: ExplorerState, - defaultPrevented: boolean, - button: number, - ctrlKey: boolean, - shiftKey: boolean, - eventX: number, - eventY: number, -): Promise => { - if (defaultPrevented || button !== MouseEventType.LeftClick) { - return state - } - const index = GetIndexFromPosition.getIndexFromPosition(state, eventX, eventY) - if (index === -1 || index >= state.items.length) { - return FocusIndex.focusIndex(state, -1) - } - if (shiftKey) { - return HandleClickAtRangeSelection.handleClickAtRangeSelection(state, index) - } - if (ctrlKey) { - return toggleIndividualSelection(state, index) - } - return HandleClick.handleClick(state, index) -} diff --git a/packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts b/packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts deleted file mode 100644 index 9cceeda..0000000 --- a/packages/explorer-view/src/parts/HandleClickAtRangeSelection/HandleClickAtRangeSelection.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as HandleRangeSelection from '../HandleRangeSelection/HandleRangeSelection.ts' - -export const handleClickAtRangeSelection = async (state: ExplorerState, index: number): Promise => { - const { items } = state - const firstSelectedIndex = items.findIndex((item) => item.selected) - if (firstSelectedIndex === -1) { - return HandleRangeSelection.handleRangeSelection(state, index, index) - } - const min = Math.min(firstSelectedIndex, index) - const max = Math.min(firstSelectedIndex, index) - return HandleRangeSelection.handleRangeSelection(state, min, max) -} diff --git a/packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts b/packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts deleted file mode 100644 index 1d22e5b..0000000 --- a/packages/explorer-view/src/parts/HandleClickCurrent/HandleClickCurrent.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as HandleClick from '../HandleClick/HandleClick.ts' - -export const handleClickCurrent = (state: ExplorerState): Promise => { - return HandleClick.handleClick(state, state.focusedIndex - state.minLineY, /* keepFocus */ false) -} diff --git a/packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts b/packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts deleted file mode 100644 index 07afc99..0000000 --- a/packages/explorer-view/src/parts/HandleClickCurrentButKeepFocus/HandleClickCurrentButKeepFocus.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as HandleClick from '../HandleClick/HandleClick.ts' - -export const handleClickCurrentButKeepFocus = (state: ExplorerState): Promise => { - return HandleClick.handleClick(state, state.focusedIndex - state.minLineY, /* keepFocus */ true) -} diff --git a/packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts b/packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts deleted file mode 100644 index a0fd062..0000000 --- a/packages/explorer-view/src/parts/HandleClickDirectory/HandleClickDirectory.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' - -export const handleClickDirectory = async (state: ExplorerState, dirent: ExplorerItem, index: number, keepFocus: boolean): Promise => { - // @ts-ignore - dirent.type = DirentType.DirectoryExpanding - // TODO handle error - const dirents = await GetChildDirents.getChildDirents(state.pathSeparator, dirent.path, dirent.depth) - const state2 = state - if (!state2) { - return state - } - // TODO use Viewlet.getState here and check if it exists - const newIndex = state2.items.indexOf(dirent) - // TODO if viewlet is disposed or root has changed, return - if (newIndex === -1) { - return state - } - const newDirents = [...state2.items] - newDirents.splice(newIndex + 1, 0, ...dirents) - // @ts-ignore - dirent.type = DirentType.DirectoryExpanded - // @ts-ignore - dirent.icon = '' - // TODO when focused index has changed while expanding, don't update it - - return { - ...state, - focus: FocusId.List, - focused: keepFocus, - focusedIndex: newIndex, - items: newDirents, - } -} diff --git a/packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts b/packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts deleted file mode 100644 index 80e5ee1..0000000 --- a/packages/explorer-view/src/parts/HandleClickDirectoryExpanded/HandleClickDirectoryExpanded.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as GetParentEndIndex from '../GetParentEndIndex/GetParentEndIndex.ts' - -export const handleClickDirectoryExpanded = async ( - state: ExplorerState, - dirent: ExplorerItem, - index: number, - keepFocus: boolean, -): Promise => { - const { itemHeight, items, maxLineY, minLineY } = state - // @ts-ignore - dirent.type = DirentType.Directory - // @ts-ignore - dirent.icon = '' - const endIndex = GetParentEndIndex.getParentEndIndex(items, index) - const removeCount = endIndex - index - 1 - // TODO race conditions and side effects are everywhere - const newDirents = [...items] - newDirents.splice(index + 1, removeCount) - const newTotal = newDirents.length - if (newTotal < maxLineY) { - const visibleItems = Math.min(maxLineY - minLineY, newTotal) - const newMaxLineY = Math.min(maxLineY, newTotal) - const newMinLineY = newMaxLineY - visibleItems - const deltaY = newMinLineY * itemHeight - return { - ...state, - deltaY, - focused: keepFocus, - focusedIndex: index, - items: newDirents, - maxLineY: newMaxLineY, - minLineY: newMinLineY, - } - } - return { - ...state, - focused: keepFocus, - focusedIndex: index, - items: newDirents, - } -} diff --git a/packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts b/packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts deleted file mode 100644 index 96af48e..0000000 --- a/packages/explorer-view/src/parts/HandleClickDirectoryExpanding/HandleClickDirectoryExpanding.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const handleClickDirectoryExpanding = async ( - state: ExplorerState, - dirent: ExplorerItem, - index: number, - keepFocus: boolean, -): Promise => { - // @ts-ignore - dirent.type = DirentType.Directory - // @ts-ignore - dirent.icon = '' - return { - ...state, - focused: keepFocus, - focusedIndex: index, - } -} diff --git a/packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts b/packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts deleted file mode 100644 index 1d57818..0000000 --- a/packages/explorer-view/src/parts/HandleClickFile/HandleClickFile.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as OpenUri from '../OpenUri/OpenUri.ts' - -export const handleClickFile = async (state: ExplorerState, dirent: ExplorerItem, index: number, keepFocus = false): Promise => { - await OpenUri.openUri(dirent.path, !keepFocus) - return { - ...state, - focused: keepFocus, - focusedIndex: index, - } -} diff --git a/packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts b/packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts deleted file mode 100644 index 39af422..0000000 --- a/packages/explorer-view/src/parts/HandleClickOpenFolder/HandleClickOpenFolder.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as OpenFolder from '../OpenFolder/OpenFolder.ts' - -export const handleClickOpenFolder = async (state: ExplorerState): Promise => { - await OpenFolder.openFolder() - return state -} diff --git a/packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts b/packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts deleted file mode 100644 index a89e4b4..0000000 --- a/packages/explorer-view/src/parts/HandleClickSymlink/HandleClickSymlink.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' -import * as HandleClickFile from '../HandleClickFile/HandleClickFile.ts' - -export const handleClickSymLink = async (state: ExplorerState, dirent: ExplorerItem, index: number): Promise => { - const realPath = await FileSystem.getRealPath(dirent.path) - const type = await FileSystem.stat(realPath) - switch (type) { - case DirentType.File: - return HandleClickFile.handleClickFile(state, dirent, index) - default: - throw new Error(`unsupported file type ${type}`) - } -} diff --git a/packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts b/packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts deleted file mode 100644 index e97155d..0000000 --- a/packages/explorer-view/src/parts/HandleContextMenu/HandleContextMenu.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetContextMenuHandler from '../GetContextMenuHandler/GetContextMenuHandler.ts' - -export const handleContextMenu = async (state: ExplorerState, button: number, x: number, y: number): Promise => { - const fn = GetContextMenuHandler.getContextMenuHandler(button) - const newState = await fn(state, x, y) - return newState -} diff --git a/packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts b/packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts deleted file mode 100644 index f9a20e0..0000000 --- a/packages/explorer-view/src/parts/HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as Assert from '../Assert/Assert.ts' -import * as ContextMenu from '../ContextMenu/ContextMenu.ts' -import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' -import * as MenuEntryId from '../MenuEntryId/MenuEntryId.ts' - -export const handleContextMenuAtIndex = async (state: ExplorerState, index: number, x: number, y: number): Promise => { - Assert.number(x) - Assert.number(y) - const { uid } = state - const newState: ExplorerState = { - ...state, - focused: false, - focusedIndex: index, - } - ExplorerStates.set(uid, state, newState) - await ContextMenu.show2(uid, MenuEntryId.Explorer, x, y, { - menuId: MenuEntryId.Explorer, - }) - return newState -} diff --git a/packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts b/packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts deleted file mode 100644 index 5a4ba29..0000000 --- a/packages/explorer-view/src/parts/HandleContextMenuKeyboard/HandleContextMenuKeyboard.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { handleContextMenuAtIndex } from '../HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts' - -export const handleContextMenuKeyboard = async (state: ExplorerState, index: number = state.focusedIndex): Promise => { - const { itemHeight, minLineY, x, y } = state - const menuX = x - const menuY = y + (index - minLineY + 1) * itemHeight - return handleContextMenuAtIndex(state, index, menuX, menuY) -} diff --git a/packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts b/packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts deleted file mode 100644 index f56b534..0000000 --- a/packages/explorer-view/src/parts/HandleContextMenuMouseAt/HandleContextMenuMouseAt.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as Assert from '../Assert/Assert.ts' -import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' -import { handleContextMenuAtIndex } from '../HandleContextMenuAtIndex/HandleContextMenuAtIndex.ts' - -export const handleContextMenuMouseAt = async (state: ExplorerState, x: number, y: number): Promise => { - Assert.number(x) - Assert.number(y) - const focusedIndex = getIndexFromPosition(state, x, y) - return handleContextMenuAtIndex(state, focusedIndex, x, y) -} diff --git a/packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts b/packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts deleted file mode 100644 index 5ba6917..0000000 --- a/packages/explorer-view/src/parts/HandleContextMenuWelcome/HandleContextMenuWelcome.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleContextMenuWelcome = (state: ExplorerState): ExplorerState => { - return state -} diff --git a/packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts b/packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts deleted file mode 100644 index 0e06e63..0000000 --- a/packages/explorer-view/src/parts/HandleCopy/HandleCopy.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ClipBoard from '../ClipBoard/ClipBoard.ts' -import * as GetFocusedDirent from '../GetFocusedDirent/GetFocusedDirent.ts' - -export const handleCopy = async (state: ExplorerState): Promise => { - // TODO handle multiple files - // TODO if not file is selected, what happens? - const dirent = GetFocusedDirent.getFocusedDirent(state) - if (!dirent) { - console.error('[ViewletExplorer/handleCopy] no dirent selected') - return state - } - const absolutePath = dirent.path - // TODO handle copy error gracefully - const files = [absolutePath] - await ClipBoard.writeNativeFiles('copy', files) - return { - ...state, - pasteShouldMove: false, - } -} diff --git a/packages/explorer-view/src/parts/HandleCut/HandleCut.ts b/packages/explorer-view/src/parts/HandleCut/HandleCut.ts deleted file mode 100644 index 68e60f9..0000000 --- a/packages/explorer-view/src/parts/HandleCut/HandleCut.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ClipBoard from '../ClipBoard/ClipBoard.ts' -import { getSelectedItems } from '../GetSelectedItems/GetSelectedItems.ts' - -export const handleCut = async (state: ExplorerState): Promise => { - // TODO handle multiple files - // TODO if not file is selected, what happens? - const { focusedIndex, items } = state - const dirents = getSelectedItems(items, focusedIndex) - if (dirents.length === 0) { - return state - } - const files = dirents.map((dirent) => dirent.path) - await ClipBoard.writeNativeFiles('cut', files) - return { - ...state, - cutItems: files, - pasteShouldMove: true, - } -} diff --git a/packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts b/packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts deleted file mode 100644 index 2f86f3f..0000000 --- a/packages/explorer-view/src/parts/HandleDoubleClick/HandleDoubleClick.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' -import { newFile } from '../NewFile/NewFile.ts' - -export const handleDoubleClick = async (state: ExplorerState, eventX: number, eventY: number): Promise => { - const index = getIndexFromPosition(state, eventX, eventY) - if (index !== -1) { - return state - } - return newFile(state) -} diff --git a/packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts b/packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts deleted file mode 100644 index 02c99fa..0000000 --- a/packages/explorer-view/src/parts/HandleDragEnd/HandleDragEnd.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleDragEnd = (state: ExplorerState): ExplorerState => { - return { - ...state, - dropTargets: [], - } -} diff --git a/packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts b/packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts deleted file mode 100644 index ce4a8f6..0000000 --- a/packages/explorer-view/src/parts/HandleDragLeave/HandleDragLeave.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleDragLeave = (state: ExplorerState): ExplorerState => { - return state -} diff --git a/packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts b/packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts deleted file mode 100644 index d30d628..0000000 --- a/packages/explorer-view/src/parts/HandleDragOver/HandleDragOver.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as Assert from '../Assert/Assert.ts' -import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' -import { handleDragOverIndex } from '../HandleDragOverIndex/HandleDragOverIndex.ts' - -export const handleDragOver = (state: ExplorerState, x: number, y: number): ExplorerState => { - Assert.number(x) - Assert.number(y) - const index = getIndexFromPosition(state, x, y) - return handleDragOverIndex(state, index) -} diff --git a/packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts b/packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts deleted file mode 100644 index 20a4f29..0000000 --- a/packages/explorer-view/src/parts/HandleDragOverIndex/HandleDragOverIndex.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetNewDropTargets from '../GetNewDropTargets/GetNewDropTargets.ts' -import * as IsEqual from '../IsEqual/IsEqual.ts' - -export const handleDragOverIndex = (state: ExplorerState, index: number): ExplorerState => { - const { dropTargets } = state - const newDropTargets = GetNewDropTargets.getNewDropTargets(state, index) - if (IsEqual.isEqual(dropTargets, newDropTargets)) { - return state - } - return { - ...state, - dropTargets: newDropTargets, - } -} diff --git a/packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts b/packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts deleted file mode 100644 index f551e03..0000000 --- a/packages/explorer-view/src/parts/HandleDragStart/HandleDragStart.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleDragStart = (state: ExplorerState): ExplorerState => { - return state -} diff --git a/packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts b/packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts deleted file mode 100644 index 54f9d29..0000000 --- a/packages/explorer-view/src/parts/HandleDrop/HandleDrop.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getDropHandler } from '../GetDropHandler/GetDropHandler.ts' -import * as GetFileArray from '../GetFileArray/GetFileArray.ts' -import { getFileHandles } from '../GetFileHandles/GetFileHandles.ts' -import { getFilePaths } from '../GetFilePaths/GetFilePaths.ts' -import * as GetIndexFromPosition from '../GetIndexFromPosition/GetIndexFromPosition.ts' -import { VError } from '../VError/VError.ts' - -export const handleDrop = async ( - state: ExplorerState, - x: number, - y: number, - fileIds: readonly number[], - fileList: FileList, -): Promise => { - try { - const { platform } = state - const files = GetFileArray.getFileArray(fileList) - const fileHandles = await getFileHandles(fileIds) - const paths = await getFilePaths(files, platform) - const index = GetIndexFromPosition.getIndexFromPosition(state, x, y) - const fn = getDropHandler(index) - const result = await fn(state, fileHandles, files, paths, index) - return result - } catch (error) { - throw new VError(error, 'Failed to drop files') - } -} diff --git a/packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts b/packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts deleted file mode 100644 index 88d0391..0000000 --- a/packages/explorer-view/src/parts/HandleDropIndex/HandleDropIndex.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' -import * as GetParentStartIndex from '../GetParentStartIndex/GetParentStartIndex.ts' -import * as HandleDropRoot from '../HandleDropRoot/HandleDropRoot.ts' -import { uploadFileSystemHandles } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' - -const getEndIndex = (items: readonly ExplorerItem[], index: number, dirent: ExplorerItem): number => { - for (let i = index + 1; i < items.length; i++) { - if (items[i].depth === dirent.depth) { - return i - } - } - return items.length -} - -const getMergedDirents = ( - items: readonly ExplorerItem[], - index: number, - dirent: ExplorerItem, - childDirents: readonly ExplorerItem[], -): readonly ExplorerItem[] => { - const startIndex = index - const endIndex = getEndIndex(items, index, dirent) - const mergedDirents = [...items.slice(0, startIndex), { ...dirent, type: DirentType.DirectoryExpanded }, ...childDirents, ...items.slice(endIndex)] - return mergedDirents -} - -const handleDropIntoFolder = async ( - state: ExplorerState, - dirent: ExplorerItem, - index: number, - fileHandles: DroppedArgs, - files: readonly File[], - paths: readonly string[], -): Promise => { - const { items, pathSeparator } = state - - await uploadFileSystemHandles(dirent.path, '/', fileHandles) - - const childDirents = await GetChildDirents.getChildDirents(pathSeparator, dirent.path, dirent.depth) - const mergedDirents = getMergedDirents(items, index, dirent, childDirents) - // TODO update maxlineY - return { - ...state, - dropTargets: [], - items: mergedDirents, - } -} - -const handleDropIntoFile = ( - state: ExplorerState, - dirent: ExplorerItem, - index: number, - fileHandles: DroppedArgs, - files: readonly File[], - paths: readonly string[], -): Promise => { - const { items } = state - const parentIndex = GetParentStartIndex.getParentStartIndex(items, index) - if (parentIndex === -1) { - return HandleDropRoot.handleDropRoot(state, fileHandles, files, paths) - } - return handleDropIndex(state, fileHandles, files, paths, parentIndex) -} - -export const handleDropIndex = async ( - state: ExplorerState, - fileHandles: DroppedArgs, - files: readonly File[], - paths: readonly string[], - index: number, -): Promise => { - const { items } = state - const dirent = items[index] - // TODO if it is a file, drop into the folder of the file - // TODO if it is a folder, drop into the folder - // TODO if it is a symlink, read symlink and determine if file can be dropped - switch (dirent.type) { - case DirentType.Directory: - case DirentType.DirectoryExpanded: - return handleDropIntoFolder(state, dirent, index, fileHandles, files, paths) - case DirentType.File: - return handleDropIntoFile(state, dirent, index, fileHandles, files, paths) - default: - return state - } -} diff --git a/packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts b/packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts deleted file mode 100644 index df85c0b..0000000 --- a/packages/explorer-view/src/parts/HandleDropRoot/HandleDropRoot.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' -import * as HandleDropRootDefault from '../HandleDropRootDefault/HandleDropRootDefault.ts' -import * as HandleDropRootElectron from '../HandleDropRootElectron/HandleDropRootElectron.ts' -import * as PlatformType from '../PlatformType/PlatformType.ts' - -interface DropHandler { - (state: ExplorerState, fileHandles: DroppedArgs, files: readonly File[], paths: readonly string[]): Promise -} - -const getModule = (isElectron: boolean): DropHandler => { - if (isElectron) { - return HandleDropRootElectron.handleDrop - } - return HandleDropRootDefault.handleDrop -} - -export const handleDropRoot = async ( - state: ExplorerState, - fileHandles: DroppedArgs, - files: readonly File[], - paths: readonly string[], -): Promise => { - const isElectron = state.platform === PlatformType.Electron - const fn = getModule(isElectron) - return fn(state, fileHandles, files, paths) -} diff --git a/packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts b/packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts deleted file mode 100644 index a677aff..0000000 --- a/packages/explorer-view/src/parts/HandleDropRootDefault/HandleDropRootDefault.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' -import { getChildDirents } from '../GetChildDirents/GetChildDirents.ts' -import { isDirectoryHandle } from '../IsDirectoryHandle/IsDirectoryHandle.ts' -import * as LoadContent from '../LoadContent/LoadContent.ts' -import * as Refresh from '../Refresh/Refresh.ts' -import * as UploadFileSystemHandles from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' - -const mergeDirents = (oldDirents: readonly any[], newDirents: readonly any[]): readonly any[] => { - return newDirents -} - -const getMergedDirents = async (root: string, pathSeparator: string, dirents: readonly any[]): Promise => { - const childDirents = await getChildDirents(pathSeparator, root, 0) - const mergedDirents = mergeDirents(dirents, childDirents) - return mergedDirents -} - -const getDroppedDirectoryWorkspacePath = (fileHandle: FileSystemDirectoryHandle): string => { - return `html://${fileHandle.name}` -} - -const openDroppedDirectoryAsWorkspace = async (state: ExplorerState, fileHandle: FileSystemDirectoryHandle): Promise => { - const path = getDroppedDirectoryWorkspacePath(fileHandle) - await RendererWorker.invoke('PersistentFileHandle.addHandle', fileHandle.name, fileHandle) - await RendererWorker.invoke('Workspace.setPath', path) - const updated = await LoadContent.loadContent(state, undefined) - return { - ...updated, - dropTargets: [], - } -} - -const getFirstDroppedDirectory = (state: ExplorerState, fileHandles: DroppedArgs): FileSystemDirectoryHandle | undefined => { - if (state.root !== '') { - return undefined - } - for (const item of fileHandles) { - const fileHandle = UploadFileSystemHandles.getFileSystemHandle(item) - if (isDirectoryHandle(fileHandle)) { - return fileHandle - } - } - return undefined -} - -export const handleDrop = async ( - state: ExplorerState, - fileHandles: DroppedArgs, - files: readonly File[], - paths: readonly string[], -): Promise => { - const { items, pathSeparator, root } = state - const droppedDirectory = getFirstDroppedDirectory(state, fileHandles) - if (droppedDirectory) { - return openDroppedDirectoryAsWorkspace(state, droppedDirectory) - } - if (root === '') { - return { - ...state, - dropTargets: [], - } - } - const handled = await UploadFileSystemHandles.uploadFileSystemHandles(root, pathSeparator, fileHandles) - if (handled) { - const updated = await Refresh.refresh(state) - return { - ...updated, - dropTargets: [], - } - } - const mergedDirents = await getMergedDirents(root, pathSeparator, items) - return { - ...state, - dropTargets: [], - items: mergedDirents, - } -} diff --git a/packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts b/packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts deleted file mode 100644 index f140f97..0000000 --- a/packages/explorer-view/src/parts/HandleDropRootElectron/HandleDropRootElectron.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { DroppedArgs } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' -import { copyFilesElectron } from '../CopyFilesElectron/CopyFilesElectron.ts' -import * as GetChildDirents from '../GetChildDirents/GetChildDirents.ts' -import { isDirectoryHandle } from '../IsDirectoryHandle/IsDirectoryHandle.ts' -import * as LoadContent from '../LoadContent/LoadContent.ts' -import { getFileSystemHandle } from '../UploadFileSystemHandles/UploadFileSystemHandles.ts' - -const mergeDirents = (oldDirents: readonly ExplorerItem[], newDirents: readonly ExplorerItem[]): any => { - return newDirents -} - -const getMergedDirents = async (root: any, pathSeparator: any, dirents: any): Promise => { - const childDirents = await GetChildDirents.getChildDirents(pathSeparator, root, 0) - const mergedDirents = mergeDirents(dirents, childDirents) - return mergedDirents -} - -const openDroppedDirectoryAsWorkspace = async (state: ExplorerState, path: string): Promise => { - await RendererWorker.invoke('Workspace.setPath', path) - const updated = await LoadContent.loadContent(state, undefined) - return { - ...updated, - dropTargets: [], - } -} - -const getFirstDroppedDirectoryPath = (state: ExplorerState, fileHandles: DroppedArgs, paths: readonly string[]): string | undefined => { - if (state.root !== '') { - return undefined - } - for (let i = 0; i < fileHandles.length; i++) { - const fileHandle = getFileSystemHandle(fileHandles[i]) - if (isDirectoryHandle(fileHandle)) { - return paths[i] - } - } - return undefined -} - -export const handleDrop = async ( - state: ExplorerState, - fileHandles: DroppedArgs, - files: readonly File[], - paths: readonly string[], -): Promise => { - const { items, pathSeparator, root } = state - const droppedDirectoryPath = getFirstDroppedDirectoryPath(state, fileHandles, paths) - if (droppedDirectoryPath) { - return openDroppedDirectoryAsWorkspace(state, droppedDirectoryPath) - } - if (root === '') { - return { - ...state, - dropTargets: [], - } - } - await copyFilesElectron(root, fileHandles, files, paths) - const mergedDirents = await getMergedDirents(root, pathSeparator, items) - return { - ...state, - dropTargets: [], - items: mergedDirents, - } -} diff --git a/packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts b/packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts deleted file mode 100644 index 5738b03..0000000 --- a/packages/explorer-view/src/parts/HandleEscape/HandleEscape.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleEscape = async (state: ExplorerState): Promise => { - return { - ...state, - cutItems: [], - } -} diff --git a/packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts b/packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts deleted file mode 100644 index 3ece137..0000000 --- a/packages/explorer-view/src/parts/HandleFocus/HandleFocus.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusId from '../FocusId/FocusId.ts' - -export const handleFocus = async (state: ExplorerState): Promise => { - if (state.editingIndex !== -1) { - return state - } - return { - ...state, - focus: FocusId.List, - } -} diff --git a/packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts b/packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts deleted file mode 100644 index 5535947..0000000 --- a/packages/explorer-view/src/parts/HandleIconThemeChange/HandleIconThemeChange.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as UpdateIcons from '../UpdateIcons/UpdateIcons.ts' - -export const handleIconThemeChange = (state: ExplorerState): Promise => { - return UpdateIcons.updateIcons(state) -} diff --git a/packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts b/packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts deleted file mode 100644 index b941dfa..0000000 --- a/packages/explorer-view/src/parts/HandleInputBlur/HandleInputBlur.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { acceptEdit } from '../AcceptEdit/AcceptEdit.ts' -import { cancelEditInternal } from '../CancelEditInternal/CancelEditInternal.ts' - -export const handleInputBlur = async (state: ExplorerState): Promise => { - const { editingErrorMessage, editingIndex, editingValue } = state - if (editingIndex === -1) { - return state - } - if (editingErrorMessage || !editingValue) { - return cancelEditInternal(state, false) - } - return acceptEdit(state) -} diff --git a/packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts b/packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts deleted file mode 100644 index 695af6f..0000000 --- a/packages/explorer-view/src/parts/HandleInputClick/HandleInputClick.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleInputClick = (state: ExplorerState): ExplorerState => { - return state -} diff --git a/packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts b/packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts deleted file mode 100644 index 5d4a687..0000000 --- a/packages/explorer-view/src/parts/HandleInputKeyDown/HandleInputKeyDown.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleInputKeyDown = (state: ExplorerState, key: string): ExplorerState => { - return state -} diff --git a/packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts b/packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts deleted file mode 100644 index d9dc44d..0000000 --- a/packages/explorer-view/src/parts/HandleKeyDown/HandleKeyDown.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { cancelTypeAhead } from '../CancelTypeAhead/CancelTypeAhead.ts' -import { filterByFocusWord } from '../FilterByFocusWord/FilterByFocusWord.ts' -import { isAscii } from '../IsAscii/IsAscii.ts' - -let timeout: number | undefined - -export const handleKeyDown = (state: ExplorerState, key: string): ExplorerState => { - const { focusedIndex, focusWord, focusWordTimeout, items } = state - if (focusWord && key === '') { - return cancelTypeAhead(state) - } - if (!isAscii(key)) { - return state - } - - const newFocusWord = focusWord + key.toLowerCase() - const itemNames = items.map((item) => item.name) - const matchingIndex = filterByFocusWord(itemNames, focusedIndex, newFocusWord) - - if (timeout) { - clearTimeout(timeout) - } - - timeout = setTimeout(async () => { - await RendererWorker.invoke('Explorer.cancelTypeAhead') - }, focusWordTimeout) - - if (matchingIndex === -1) { - return { - ...state, - focusWord: newFocusWord, - } - } - - return { - ...state, - focusedIndex: matchingIndex, - focusWord: newFocusWord, - } -} diff --git a/packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts b/packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts deleted file mode 100644 index 09781ad..0000000 --- a/packages/explorer-view/src/parts/HandlePaste/HandlePaste.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ClipBoard from '../ClipBoard/ClipBoard.ts' -import * as HandlePasteCopy from '../HandlePasteCopy/HandlePasteCopy.ts' -import * as HandlePasteCut from '../HandlePasteCut/HandlePasteCut.ts' -import * as NativeFileTypes from '../NativeFileTypes/NativeFileTypes.ts' - -export const handlePaste = async (state: ExplorerState): Promise => { - const nativeFiles = await ClipBoard.readNativeFiles() - if (!nativeFiles) { - return state - } - // TODO detect cut/paste event, not sure if that is possible - // TODO check that pasted folder is not a parent folder of opened folder - // TODO support pasting multiple paths - // TODO what happens when pasting multiple paths, but some of them error? - // how many error messages should be shown? Should the operation be undone? - // TODO what if it is a large folder and takes a long time to copy? Should show progress - // TODO what if there is a permission error? Probably should show a modal to ask for permission - // TODO if error is EEXISTS, just rename the copy (e.g. file-copy-1.txt, file-copy-2.txt) - // TODO actual target should be selected folder - // TODO but what if a file is currently selected? Then maybe the parent folder - // TODO but will it work if the folder is a symlink? - // TODO handle error gracefully when copy fails - - // If no files to paste, return original state unchanged - if (nativeFiles.type === NativeFileTypes.None) { - return state - } - - // Use the pasteShouldMove flag to determine whether to cut or copy - if (state.pasteShouldMove) { - return HandlePasteCut.handlePasteCut(state, nativeFiles) - } - return HandlePasteCopy.handlePasteCopy(state, nativeFiles) -} diff --git a/packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts b/packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts deleted file mode 100644 index 8e5dfc5..0000000 --- a/packages/explorer-view/src/parts/HandlePasteCopy/HandlePasteCopy.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' -import * as AdjustScrollAfterPaste from '../AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts' -import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' -import { getFileOperationsCopy } from '../GetFileOperationsCopy/GetFileOperationsCopy.ts' -import { getIndex } from '../GetIndex/GetIndex.ts' -import { refresh } from '../Refresh/Refresh.ts' - -export const handlePasteCopy = async (state: ExplorerState, nativeFiles: NativeFilesResult): Promise => { - // TODO handle pasting files into nested folder - // TODO handle pasting files into symlink - // TODO handle pasting files into broken symlink - // TODO handle pasting files into hardlink - // TODO what if folder is big and it takes a long time - - // TODO use file operations and bulk edit - const { focusedIndex, items, root } = state - const focusedUri = items[focusedIndex]?.path || root - const existingUris = items.map((item) => item.path) - const operations = getFileOperationsCopy(root, existingUris, nativeFiles.files, focusedUri) - // TODO handle error? - await ApplyFileOperations.applyFileOperations(operations) - - // TODO use refreshExplorer with the paths that have been affected by file operations - // TODO only update folder at which level it changed - const latestState = await refresh(state) - - // Focus on the first newly created file and adjust scroll position - const newFilePaths = operations.map((operation) => operation.path) - if (newFilePaths.length > 0) { - const firstNewFilePath = newFilePaths[0] - const newFileIndex = getIndex(latestState.items, firstNewFilePath) - if (newFileIndex !== -1) { - const adjustedState = AdjustScrollAfterPaste.adjustScrollAfterPaste(latestState, newFileIndex) - return { - ...adjustedState, - pasteShouldMove: false, - } - } - } - // If there are no items, ensure focusedIndex is 0 - if (latestState.items.length === 0) { - return { - ...latestState, - focusedIndex: 0, - pasteShouldMove: false, - } - } - return { - ...latestState, - pasteShouldMove: false, - } -} diff --git a/packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts b/packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts deleted file mode 100644 index 6fa7261..0000000 --- a/packages/explorer-view/src/parts/HandlePasteCut/HandlePasteCut.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' -import * as AdjustScrollAfterPaste from '../AdjustScrollAfterPaste/AdjustScrollAfterPaste.ts' -import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import { getIndex } from '../GetIndex/GetIndex.ts' -import { getBaseName, join2 } from '../Path/Path.ts' -import { refresh } from '../Refresh/Refresh.ts' - -const getOperations = (toUri: string, files: readonly string[]): readonly FileOperation[] => { - const operations: FileOperation[] = [] - for (const file of files) { - const baseName = getBaseName('/', file) - const newUri = join2(toUri, baseName) - operations.push({ - from: file, - path: newUri, - type: FileOperationType.Rename, - }) - } - return operations -} - -const getTargetUri = (root: string, items: readonly ExplorerItem[], index: number): string => { - if (index === -1) { - return root - } - return items[index].path -} - -export const handlePasteCut = async (state: ExplorerState, nativeFiles: NativeFilesResult): Promise => { - const { focusedIndex, items, pathSeparator, root } = state - // TODO root is not necessrily target uri - const targetUri = getTargetUri(root, items, focusedIndex) - const operations = getOperations(targetUri, nativeFiles.files) - await ApplyFileOperations.applyFileOperations(operations) - - // Refresh the state after cut operations - const latestState = await refresh(state) - - // Focus on the first pasted file and adjust scroll position - if (nativeFiles.files.length > 0) { - const firstPastedFile = nativeFiles.files[0] - const targetPath = `${root}${pathSeparator}${getBaseName(pathSeparator, firstPastedFile)}` - const pastedFileIndex = getIndex(latestState.items, targetPath) - if (pastedFileIndex !== -1) { - const adjustedState = AdjustScrollAfterPaste.adjustScrollAfterPaste(latestState, pastedFileIndex) - return { - ...adjustedState, - cutItems: [], - pasteShouldMove: false, - } - } - } - - return { - ...latestState, - cutItems: [], - pasteShouldMove: false, - } -} diff --git a/packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts b/packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts deleted file mode 100644 index 96f5496..0000000 --- a/packages/explorer-view/src/parts/HandlePasteNone/HandlePasteNone.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' - -export const handlePasteNone = async (state: ExplorerState, nativeFiles: NativeFilesResult): Promise => { - console.error('[ViewletExplorer/handlePaste] no paths detected') - return state -} diff --git a/packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts b/packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts deleted file mode 100644 index 2013dcd..0000000 --- a/packages/explorer-view/src/parts/HandlePointerDown/HandlePointerDown.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import { getIndexFromPosition } from '../GetIndexFromPosition/GetIndexFromPosition.ts' -import * as MouseEventType from '../MouseEventType/MouseEventType.ts' - -export const handlePointerDown = (state: ExplorerState, button: number, x: number, y: number): ExplorerState => { - const index = getIndexFromPosition(state, x, y) - if (button === MouseEventType.LeftClick && index === -1) { - return { - ...state, - focus: FocusId.List, - focused: true, - focusedIndex: -1, - } - } - return state -} diff --git a/packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts b/packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts deleted file mode 100644 index 297399f..0000000 --- a/packages/explorer-view/src/parts/HandleRangeSelection/HandleRangeSelection.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -/** - * Handles range selection in the explorer. - * @param state The current explorer state - * @param startIndex The starting index of the range (must be ≤ endIndex) - * @param endIndex The ending index of the range (must be ≥ startIndex) - * @throws Error if startIndex > endIndex - */ -export const handleRangeSelection = (state: ExplorerState, startIndex: number, endIndex: number): ExplorerState => { - if (startIndex > endIndex) { - throw new Error('startIndex must be less than or equal to endIndex') - } - - const { items } = state - const newItems = items.map((item, i) => ({ - ...item, - selected: i >= startIndex && i <= endIndex ? true : item.selected, - })) - return { - ...state, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/HandleResize/HandleResize.ts b/packages/explorer-view/src/parts/HandleResize/HandleResize.ts deleted file mode 100644 index f4f9d9e..0000000 --- a/packages/explorer-view/src/parts/HandleResize/HandleResize.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetExplorerMaxLineY from '../GetMaxLineY/GetMaxLineY.ts' -import * as GetScrollBarSize from '../GetScrollBarSize/GetScrollBarSize.ts' - -export interface Dimensions { - readonly height: number - readonly width: number -} - -export const handleResize = (state: ExplorerState, dimensions: Dimensions): ExplorerState => { - const { height: rawHeight, width: rawWidth } = dimensions - if (!Number.isFinite(rawHeight) || !Number.isFinite(rawWidth)) { - return state - } - const height = Math.max(0, rawHeight) - const width = Math.max(0, rawWidth) - const { deltaY, itemHeight, items } = state - const contentHeight = items.length * itemHeight - const maxDeltaY = Math.max(contentHeight - height, 0) - const newDeltaY = Math.min(Math.max(deltaY, 0), maxDeltaY) - const minLineY = Math.round(newDeltaY / itemHeight) - const maxLineY = GetExplorerMaxLineY.getExplorerMaxLineY(minLineY, height, itemHeight, items.length) - const scrollBarHeight = GetScrollBarSize.getScrollBarSize(height, contentHeight, 20) - if ( - state.height === height && - state.width === width && - state.deltaY === newDeltaY && - state.minLineY === minLineY && - state.maxLineY === maxLineY && - state.scrollBarHeight === scrollBarHeight - ) { - return state - } - return { - ...state, - deltaY: newDeltaY, - height, - maxLineY, - minLineY, - scrollBarHeight, - width, - } -} diff --git a/packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts b/packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts deleted file mode 100644 index 7c78e23..0000000 --- a/packages/explorer-view/src/parts/HandleSelection/HandleSelection.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const handleSelection = (state: ExplorerState, index: number): ExplorerState => { - const { items } = state - const newItems = items.map((item, i) => ({ - ...item, - selected: i === index ? !item.selected : item.selected, - })) - return { - ...state, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts b/packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts deleted file mode 100644 index aa49edd..0000000 --- a/packages/explorer-view/src/parts/HandleUpload/HandleUpload.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' - -export const handleUpload = async (state: ExplorerState, dirents: readonly any[]): Promise => { - const { pathSeparator, root } = state - for (const dirent of dirents) { - // TODO switch - // TODO symlink might not be possible to be copied - // TODO create folder if type is 2 - if (dirent.type === /* File */ 1) { - // TODO reading text might be inefficient for binary files - // but not sure how else to send them via jsonrpc - const content = await dirent.file.text() - const absolutePath = [root, dirent.file.name].join(pathSeparator) - await FileSystem.writeFile(absolutePath, content) - } - } -} diff --git a/packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts b/packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts deleted file mode 100644 index f8cb052..0000000 --- a/packages/explorer-view/src/parts/HandleWheel/HandleWheel.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as SetDeltaY from '../SetDeltaY/SetDeltaY.ts' - -export const handleWheel = (state: ExplorerState, deltaMode: number, deltaY: number): Promise => { - return SetDeltaY.setDeltaY(state, state.deltaY + deltaY) -} diff --git a/packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts b/packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts deleted file mode 100644 index f80e13e..0000000 --- a/packages/explorer-view/src/parts/HandleWorkspaceChange/HandleWorkspaceChange.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetWorkspacePath from '../GetWorkspacePath/GetWorkspacePath.ts' -import * as LoadContent from '../LoadContent/LoadContent.ts' - -export const handleWorkspaceChange = async (state: ExplorerState): Promise => { - const newRoot = await GetWorkspacePath.getWorkspacePath() - const state1 = { ...state, root: newRoot } - const newState = await LoadContent.loadContent(state1, undefined) - return newState -} diff --git a/packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts b/packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts deleted file mode 100644 index 22fcf4a..0000000 --- a/packages/explorer-view/src/parts/HandleWorkspaceRefresh/HandleWorkspaceRefresh.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { refresh } from '../Refresh/Refresh.ts' - -export const handleWorkspaceRefresh = async (state: ExplorerState): Promise => { - return refresh(state) -} diff --git a/packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts b/packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts deleted file mode 100644 index 4696965..0000000 --- a/packages/explorer-view/src/parts/HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts +++ /dev/null @@ -1,5 +0,0 @@ -const RE_WHITESPACE = /^\s|\s$/ - -export const hasLeadingOrTrailingWhitespace = (text: string): boolean => { - return RE_WHITESPACE.test(text) -} diff --git a/packages/explorer-view/src/parts/HasProperty/HasProperty.ts b/packages/explorer-view/src/parts/HasProperty/HasProperty.ts deleted file mode 100644 index ed57d2d..0000000 --- a/packages/explorer-view/src/parts/HasProperty/HasProperty.ts +++ /dev/null @@ -1,7 +0,0 @@ -type ObjectWithProperty = { - [key in Options]: unknown -} - -export const hasProperty = (object: unknown, key: K): object is ObjectWithProperty => { - return !!object && typeof object === 'object' && key in object -} diff --git a/packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts b/packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts deleted file mode 100644 index e92784c..0000000 --- a/packages/explorer-view/src/parts/HasSymbolicLink/HasSymbolicLink.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as IsSymbolicLink from '../IsSymbolicLink/IsSymbolicLink.ts' - -export const hasSymbolicLinks = (rawDirents: readonly RawDirent[]): boolean => { - return rawDirents.some(IsSymbolicLink.isSymbolicLink) -} diff --git a/packages/explorer-view/src/parts/Height/Height.ts b/packages/explorer-view/src/parts/Height/Height.ts deleted file mode 100644 index 0cdee25..0000000 --- a/packages/explorer-view/src/parts/Height/Height.ts +++ /dev/null @@ -1 +0,0 @@ -export const ListItem = 22 diff --git a/packages/explorer-view/src/parts/I18NString/I18NString.ts b/packages/explorer-view/src/parts/I18NString/I18NString.ts deleted file mode 100644 index 288e81d..0000000 --- a/packages/explorer-view/src/parts/I18NString/I18NString.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@lvce-editor/i18n' diff --git a/packages/explorer-view/src/parts/IconRequest/IconRequest.ts b/packages/explorer-view/src/parts/IconRequest/IconRequest.ts deleted file mode 100644 index 85f7d37..0000000 --- a/packages/explorer-view/src/parts/IconRequest/IconRequest.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface IconRequest { - readonly name: string - readonly path: string - readonly type: number -} diff --git a/packages/explorer-view/src/parts/IconTheme/IconTheme.ts b/packages/explorer-view/src/parts/IconTheme/IconTheme.ts deleted file mode 100644 index 56a3bcd..0000000 --- a/packages/explorer-view/src/parts/IconTheme/IconTheme.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @deprecated - */ -export const getFileIcon = ({ name }: { readonly name: string }): string => { - console.warn('do not use') - return '' -} - -/** - * @deprecated - */ -export const getIcon = (dirent: any): string => { - console.warn('do not use') - return '' -} - -/** - * @deprecated - */ -export const getFolderIcon = (dirent: any): string => { - console.warn('do not use') - return '' -} diff --git a/packages/explorer-view/src/parts/Initialize/Initialize.ts b/packages/explorer-view/src/parts/Initialize/Initialize.ts deleted file mode 100644 index adc9f35..0000000 --- a/packages/explorer-view/src/parts/Initialize/Initialize.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const initialize = async (): Promise => { - // this function is not needed anymore -} diff --git a/packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts b/packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts deleted file mode 100644 index 1337d84..0000000 --- a/packages/explorer-view/src/parts/InitializeFileSystemWorker/InitializeFileSystemWorker.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createFileSystemWorkerRpc } from '../CreateFileSystemWorkerRpc/CreateFileSystemWorkerRpc.ts' -import * as FileSystemWorker from '../FileSystemWorker/FileSystemWorker.ts' - -export const initializeFileSystemWorker = async (): Promise => { - const rpc = await createFileSystemWorkerRpc() - FileSystemWorker.set(rpc) -} diff --git a/packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts b/packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts deleted file mode 100644 index f9aa597..0000000 --- a/packages/explorer-view/src/parts/InitializeIconThemeWorker/InitializeIconThemeWorker.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IconThemeWorker } from '@lvce-editor/rpc-registry' -import { createIconThemeWorkerRpc } from '../CreateIconThemeWorkerRpc/CreateIconThemeWorkerRpc.ts' - -export const initializeIconThemeWorker = async (): Promise => { - const rpc = await createIconThemeWorkerRpc() - IconThemeWorker.set(rpc) -} diff --git a/packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts b/packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts deleted file mode 100644 index 9541469..0000000 --- a/packages/explorer-view/src/parts/InitializeRendererWorker/initializeRendereWorker.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { WebWorkerRpcClient } from '@lvce-editor/rpc' -import { RendererWorker } from '@lvce-editor/rpc-registry' -import * as CommandMap from '../CommandMap/CommandMap.ts' - -export const initializeRendererWorker = async (): Promise => { - const rpc = await WebWorkerRpcClient.create({ - commandMap: CommandMap.commandMap, - }) - RendererWorker.set(rpc) -} diff --git a/packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts b/packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts deleted file mode 100644 index 9f03e42..0000000 --- a/packages/explorer-view/src/parts/InitializeSourceControlWorker/InitializeSourceControlWorker.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SourceControlWorker } from '@lvce-editor/rpc-registry' -import { createSourceControlWorkerRpc } from '../CreateSourceControlWorkerRpc/CreateSourceControlWorkerWorkerRpc.ts' - -export const initializeSourceControlWorker = async (): Promise => { - try { - const rpc = await createSourceControlWorkerRpc() - // TODO - SourceControlWorker.set(rpc) - } catch { - // ignore - } -} diff --git a/packages/explorer-view/src/parts/InputName/InputName.ts b/packages/explorer-view/src/parts/InputName/InputName.ts deleted file mode 100644 index 87652a0..0000000 --- a/packages/explorer-view/src/parts/InputName/InputName.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const CollapseAll = 'CollapseAll' -export const ExplorerInput = 'ExplorerInput' -export const NewFile = 'NewFile' -export const NewFolder = 'NewFolder' -export const OpenFolder = 'OpenFolder' -export const Refresh = 'Refresh' diff --git a/packages/explorer-view/src/parts/InputSource/InputSource.ts b/packages/explorer-view/src/parts/InputSource/InputSource.ts deleted file mode 100644 index 603f27e..0000000 --- a/packages/explorer-view/src/parts/InputSource/InputSource.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const User = 1 -export const Script = 2 diff --git a/packages/explorer-view/src/parts/IsAscii/IsAscii.ts b/packages/explorer-view/src/parts/IsAscii/IsAscii.ts deleted file mode 100644 index a31eec2..0000000 --- a/packages/explorer-view/src/parts/IsAscii/IsAscii.ts +++ /dev/null @@ -1,5 +0,0 @@ -const RE_ASCII = /^[a-z]$/ - -export const isAscii = (key: string): boolean => { - return RE_ASCII.test(key) -} diff --git a/packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts b/packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts deleted file mode 100644 index e7d1003..0000000 --- a/packages/explorer-view/src/parts/IsDirectoryHandle/IsDirectoryHandle.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const isDirectoryHandle = (fileHandle: FileSystemHandle): fileHandle is FileSystemDirectoryHandle => { - return fileHandle.kind === 'directory' -} diff --git a/packages/explorer-view/src/parts/IsEqual/IsEqual.ts b/packages/explorer-view/src/parts/IsEqual/IsEqual.ts deleted file mode 100644 index e0578d1..0000000 --- a/packages/explorer-view/src/parts/IsEqual/IsEqual.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const isEqual = (a: readonly any[], b: readonly any[]): boolean => { - if (a.length !== b.length) { - return false - } - const { length } = a - for (let i = 0; i < length; i++) { - if (a[i] !== b[i]) { - return false - } - } - return true -} diff --git a/packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts b/packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts deleted file mode 100644 index 9a12a9b..0000000 --- a/packages/explorer-view/src/parts/IsExpanded/IsExpanded.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const isExpanded = (item: ExplorerItem): boolean => { - return item.type === DirentType.DirectoryExpanded || item.type === DirentType.DirectoryExpanding -} diff --git a/packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts b/packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts deleted file mode 100644 index 6fc56de..0000000 --- a/packages/explorer-view/src/parts/IsExpandedDirectory/IsExpandedDirectory.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const isExpandedDirectory = (dirent: ExplorerItem): boolean => { - return dirent.type === DirentType.DirectoryExpanded -} diff --git a/packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts b/packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts deleted file mode 100644 index 98becbf..0000000 --- a/packages/explorer-view/src/parts/IsFileHandle/IsFileHandle.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const isFileHandle = (fileHandle: FileSystemHandle): fileHandle is FileSystemFileHandle => { - return fileHandle.kind === 'file' -} diff --git a/packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts b/packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts deleted file mode 100644 index 5fc95f5..0000000 --- a/packages/explorer-view/src/parts/IsNormalItem/IsNormalItem.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const isNormalItem = (item: ExplorerItem): boolean => { - return item.type !== DirentType.EditingFile && item.type !== DirentType.EditingFolder -} diff --git a/packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts b/packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts deleted file mode 100644 index f58b26a..0000000 --- a/packages/explorer-view/src/parts/IsSymbolicLink/IsSymbolicLink.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const isSymbolicLink = (dirent: RawDirent): boolean => { - return dirent.type === DirentType.Symlink -} diff --git a/packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts b/packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts deleted file mode 100644 index 8765086..0000000 --- a/packages/explorer-view/src/parts/IsTopLevel/IsTopLevel.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const isTopLevel = (dirent: ExplorerItem): boolean => { - return dirent.depth === 1 -} diff --git a/packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts b/packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts deleted file mode 100644 index 89d2862..0000000 --- a/packages/explorer-view/src/parts/IsUriWithinRoot/IsUriWithinRoot.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const isUriWithinRoot = (root: string, uri: string, pathSeparator: string): boolean => { - if (uri === root) { - return true - } - const rootWithSeparator = root.endsWith(pathSeparator) ? root : `${root}${pathSeparator}` - return uri.startsWith(rootWithSeparator) -} diff --git a/packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts b/packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts deleted file mode 100644 index 9045dcd..0000000 --- a/packages/explorer-view/src/parts/IsValidBaseName/IsValidBaseName.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-disable no-useless-escape */ - -// copied from https://github.com/microsoft/vscode/blob/6b924c51528e663dda5091a1493229a361676aca/src/vs/base/common/extpath.ts by Microsoft (License MIT) - -// Reference: https://en.wikipedia.org/wiki/Filename -const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g -const UNIX_INVALID_FILE_CHARS = /\//g -const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt\d|com\d)(\.(.*?))?$/i - -export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean): boolean { - const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS - - if (!name || name.length === 0 || /^\s+$/.test(name)) { - return false // require a name that is not just whitespace - } - - invalidFileChars.lastIndex = 0 // the holy grail of software development - if (invalidFileChars.test(name)) { - return false // check for certain invalid file characters - } - - if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) { - return false // check for certain invalid file names - } - - if (name === '.' || name === '..' || name === '...') { - return false // check for reserved values - } - - if (name.startsWith('../')) { - return false // check for names starting with ../ - } - - if (isWindowsOS && name.at(-1) === '.') { - return false // Windows: file cannot end with a "." - } - - if (isWindowsOS && name.length !== name.trim().length) { - return false // Windows: file cannot end with a whitespace - } - - if (name.length > 255) { - return false // most file systems do not allow files > 255 length - } - - return true -} diff --git a/packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts b/packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts deleted file mode 100644 index b01afe0..0000000 --- a/packages/explorer-view/src/parts/KeyBinding/KeyBinding.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface KeyBinding { - readonly command: string - readonly key: number - readonly when: number -} diff --git a/packages/explorer-view/src/parts/KeyCode/KeyCode.ts b/packages/explorer-view/src/parts/KeyCode/KeyCode.ts deleted file mode 100644 index bb3bf08..0000000 --- a/packages/explorer-view/src/parts/KeyCode/KeyCode.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const Enter = 3 -export const Escape = 8 -export const Space = 9 -export const End = 255 -export const Home = 12 -export const LeftArrow = 13 -export const UpArrow = 14 -export const RightArrow = 15 -export const DownArrow = 16 -export const Delete = 18 - -export const KeyA = 29 -export const KeyC = 31 -export const KeyV = 50 - -export const F2 = 58 - -export const Star = 131 diff --git a/packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts b/packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts deleted file mode 100644 index ebce747..0000000 --- a/packages/explorer-view/src/parts/KeyModifier/KeyModifier.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const CtrlCmd = (1 << 11) >>> 0 -export const Shift = (1 << 10) >>> 0 -export const Alt = (1 << 9) >>> 0 -export const WinCtrl = (1 << 8) >>> 0 diff --git a/packages/explorer-view/src/parts/LoadContent/LoadContent.ts b/packages/explorer-view/src/parts/LoadContent/LoadContent.ts deleted file mode 100644 index db49b66..0000000 --- a/packages/explorer-view/src/parts/LoadContent/LoadContent.ts +++ /dev/null @@ -1,71 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetErrorCode from '../GetErrorCode/GetErrorCode.ts' -import * as GetErrorMessage from '../GetErrorMessage/GetErrorMessage.ts' -import * as GetExcluded from '../GetExcluded/GetExcluded.ts' -import * as GetFileDecorations from '../GetFileDecorations/GetFileDecorations.ts' -import * as GetFriendlyErrorMessage from '../GetFriendlyErrorMessage/GetFriendlyErrorMessage.ts' -import * as GetPathSeparator from '../GetPathSeparator/GetPathSeparator.ts' -import * as GetRestoredDeltaY from '../GetRestoredDeltaY/GetRestoredDeltaY.ts' -import * as GetSavedRoot from '../GetSavedRoot/GetSavedRoot.ts' -import { getScheme } from '../GetScheme/GetScheme.ts' -import * as GetSettings from '../GetSettings/GetSettings.ts' -import * as GetWorkspacePath from '../GetWorkspacePath/GetWorkspacePath.ts' -import * as RestoreExpandedState from '../RestoreExpandedState/RestoreExpandedState.ts' - -export const loadContent = async (state: ExplorerState, savedState: any): Promise => { - const { assetDir, height, itemHeight, platform } = state - const { confirmDelete, sourceControlDecorations, useChevrons } = await GetSettings.getSettings() - const workspacePath = await GetWorkspacePath.getWorkspacePath() - const root = GetSavedRoot.getSavedRoot(savedState, workspacePath) - try { - // TODO path separator could be restored from saved state - const pathSeparator = await GetPathSeparator.getPathSeparator(root) // TODO only load path separator once - const excluded = GetExcluded.getExcluded() - const restoredDirents = await RestoreExpandedState.restoreExpandedState(savedState, root, pathSeparator, excluded) - const rawDeltaY = GetRestoredDeltaY.getRestoredDeltaY(savedState) - const maxDeltaY = Math.max(restoredDirents.length * itemHeight - height, 0) - const deltaY = Math.min(Math.max(rawDeltaY, 0), maxDeltaY) - const minLineY = Math.round(deltaY / itemHeight) - - const scheme = getScheme(root) - const decorations = await GetFileDecorations.getFileDecorations( - scheme, - root, - restoredDirents.filter((item: any) => item.depth === 1).map((item: any) => item.path), - sourceControlDecorations, - assetDir, - platform, - ) - return { - ...state, - confirmDelete, - decorations, - deltaY, - errorCode: '', - errorMessage: '', - excluded, - hasError: false, - initial: false, - items: restoredDirents, - maxIndent: 10, - minLineY, - pathSeparator, - root, - useChevrons, - } - } catch (error) { - const errorCode = GetErrorCode.getErrorCode(error) - const errorMessage = GetFriendlyErrorMessage.getFriendlyErrorMessage(GetErrorMessage.getErrorMessage(error), errorCode) - return { - ...state, - confirmDelete, - errorCode, - errorMessage, - hasError: true, - initial: false, - items: [], - root, - useChevrons, - } - } -} diff --git a/packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts b/packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts deleted file mode 100644 index 4c338e0..0000000 --- a/packages/explorer-view/src/parts/MakeExpanded/MakeExpanded.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const makeExpanded = (dirent: ExplorerItem): ExplorerItem => { - if (dirent.type === DirentType.Directory) { - return { - ...dirent, - type: DirentType.DirectoryExpanded, - } - } - return dirent -} diff --git a/packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts b/packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts deleted file mode 100644 index f702e27..0000000 --- a/packages/explorer-view/src/parts/MaskIcon/MaskIcon.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const CollapseAll = 'CollapseAll' -export const NewFile = 'NewFile' -export const NewFolder = 'NewFolder' -export const Refresh = 'Refresh' diff --git a/packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts b/packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts deleted file mode 100644 index b7bf9de..0000000 --- a/packages/explorer-view/src/parts/MenuEntry/MenuEntry.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface MenuEntry { - readonly command: string - readonly flags: number - readonly id: string - readonly label: string -} diff --git a/packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts b/packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts deleted file mode 100644 index 26765f4..0000000 --- a/packages/explorer-view/src/parts/MenuEntryId/MenuEntryId.ts +++ /dev/null @@ -1 +0,0 @@ -export const Explorer = 4 diff --git a/packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts b/packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts deleted file mode 100644 index 620506d..0000000 --- a/packages/explorer-view/src/parts/MenuEntrySeparator/MenuEntrySeparator.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as MenuItemFlags from '../MenuItemFlags/MenuItemFlags.ts' - -export const menuEntrySeparator = { - command: '', - flags: MenuItemFlags.Separator, - id: 'separator', - label: '', -} diff --git a/packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts b/packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts deleted file mode 100644 index 3ce7396..0000000 --- a/packages/explorer-view/src/parts/MenuItemFlags/MenuItemFlags.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const Separator = 1 - -export const None = 0 - -export const RestoreFocus = 6 diff --git a/packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts b/packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts deleted file mode 100644 index 653e3b1..0000000 --- a/packages/explorer-view/src/parts/MergeClassNames/MergeClassNames.ts +++ /dev/null @@ -1 +0,0 @@ -export { mergeClassNames } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts b/packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts deleted file mode 100644 index c3eefc7..0000000 --- a/packages/explorer-view/src/parts/MergeDirents/MergeDirents.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const mergeDirents = (oldDirents: readonly ExplorerItem[], newDirents: readonly ExplorerItem[]): readonly ExplorerItem[] => { - const merged: ExplorerItem[] = [] - let oldIndex = 0 - for (const newDirent of newDirents) { - merged.push(newDirent) - for (let i = oldIndex; i < oldDirents.length; i++) { - if (oldDirents[i].path === newDirent.path) { - // TOOD copy children of old dirent - oldIndex = i - break - } - } - } - return merged -} diff --git a/packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts b/packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts deleted file mode 100644 index d9b507b..0000000 --- a/packages/explorer-view/src/parts/MergeTrees/MergeTrees.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Tree } from '../Tree/Tree.ts' - -export const mergeTrees = (a: Tree, b: Tree): Tree => { - return { - ...a, - ...b, - } -} diff --git a/packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts b/packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts deleted file mode 100644 index a60e478..0000000 --- a/packages/explorer-view/src/parts/MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const mergeVisibleWithHiddenItems = (visibleItems: readonly ExplorerItem[], hiddenItems: readonly ExplorerItem[]): readonly ExplorerItem[] => { - const merged = [...visibleItems, ...hiddenItems] - const seen = Object.create(null) - const unique = [] - for (const item of merged) { - if (seen[item.path]) { - continue - } - seen[item.path] = true - unique.push(item) - } - return unique -} diff --git a/packages/explorer-view/src/parts/MouseAction/MouseAction.ts b/packages/explorer-view/src/parts/MouseAction/MouseAction.ts deleted file mode 100644 index 67bad55..0000000 --- a/packages/explorer-view/src/parts/MouseAction/MouseAction.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface MouseAction { - readonly button: number - readonly command: string - readonly description: string - readonly modifiers: { - readonly ctrl?: boolean - readonly shift?: boolean - readonly alt?: boolean - readonly meta?: boolean - } - readonly when?: number -} diff --git a/packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts b/packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts deleted file mode 100644 index ee59861..0000000 --- a/packages/explorer-view/src/parts/MouseEventType/MouseEventType.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const Keyboard = -1 - -export const LeftClick = 0 diff --git a/packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts b/packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts deleted file mode 100644 index 7d92318..0000000 --- a/packages/explorer-view/src/parts/NativeFileTypes/NativeFileTypes.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const None = 'none' -export const Copy = 'copy' -export const Cut = 'cut' diff --git a/packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts b/packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts deleted file mode 100644 index ebd73eb..0000000 --- a/packages/explorer-view/src/parts/NativeFilesResult/NativeFilesResult.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface NativeFilesResult { - readonly files: readonly string[] - readonly source: 'gnomeCopiedFiles' - readonly type: 'none' | 'copy' | 'cut' -} diff --git a/packages/explorer-view/src/parts/NewDirent/NewDirent.ts b/packages/explorer-view/src/parts/NewDirent/NewDirent.ts deleted file mode 100644 index 58aa3d3..0000000 --- a/packages/explorer-view/src/parts/NewDirent/NewDirent.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import * as GetFittingIndex from '../GetFittingIndex/GetFittingIndex.ts' -import * as GetNewDirentsForNewDirent from '../GetNewDirentsForNewDirent/GetNewDirentsForNewDirent.ts' -import * as GetNewDirentType from '../GetNewDirentType/GetNewDirentType.ts' - -export const newDirent = async (state: ExplorerState, editingType: number): Promise => { - // TODO do it like vscode, select position between folders and files - const { editingIndex, focusedIndex, items, root } = state - if (editingIndex !== -1) { - return state - } - const index = GetFittingIndex.getFittingIndex(items, focusedIndex) - const direntType = GetNewDirentType.getNewDirentType(editingType) - const newDirents = await GetNewDirentsForNewDirent.getNewDirentsForNewDirent(items, index, direntType, root) - const newEditingIndex = newDirents.findIndex((item) => item.type === DirentType.EditingFile || item.type === DirentType.EditingFolder) - return { - ...state, - editingIndex: newEditingIndex, - editingType, - editingValue: '', - focus: FocusId.Input, - focusedIndex: newEditingIndex, - items: newDirents, - } -} diff --git a/packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts b/packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts deleted file mode 100644 index 179b167..0000000 --- a/packages/explorer-view/src/parts/NewDirentsAcceptResult/NewDirentsAcceptResult.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export interface NewDirentsAcceptResult { - readonly dirents: readonly ExplorerItem[] - readonly newFocusedIndex: number -} diff --git a/packages/explorer-view/src/parts/NewFile/NewFile.ts b/packages/explorer-view/src/parts/NewFile/NewFile.ts deleted file mode 100644 index 2c155a3..0000000 --- a/packages/explorer-view/src/parts/NewFile/NewFile.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as NewDirent from '../NewDirent/NewDirent.ts' - -// TODO much shared logic with newFolder -export const newFile = (state: ExplorerState): Promise => { - return NewDirent.newDirent(state, ExplorerEditingType.CreateFile) -} diff --git a/packages/explorer-view/src/parts/NewFolder/NewFolder.ts b/packages/explorer-view/src/parts/NewFolder/NewFolder.ts deleted file mode 100644 index 6999e55..0000000 --- a/packages/explorer-view/src/parts/NewFolder/NewFolder.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as NewDirent from '../NewDirent/NewDirent.ts' - -export const newFolder = (state: ExplorerState): Promise => { - return NewDirent.newDirent(state, ExplorerEditingType.CreateFolder) -} diff --git a/packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts b/packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts deleted file mode 100644 index 2301642..0000000 --- a/packages/explorer-view/src/parts/NormalizeDecorations/NormalizeDecorations.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { FileDecoration } from '../FileDecoration/FileDecoration.ts' - -const isValid = (decoration: FileDecoration): boolean => { - return decoration && typeof decoration.decoration === 'string' && typeof decoration.uri === 'string' -} - -export const normalizeDecorations = (decorations: readonly FileDecoration[]): readonly FileDecoration[] => { - if (!decorations || !Array.isArray(decorations)) { - return [] - } - return decorations.filter(isValid) -} diff --git a/packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts b/packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts deleted file mode 100644 index 4a17326..0000000 --- a/packages/explorer-view/src/parts/NormalizeDirentType/NormalizeDirentType.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { DELTA_EDITING } from '../DeltaEditing/DeltaEditing.ts' - -export const normalizeDirentType = (direntType: number): number => { - if (direntType > DELTA_EDITING) { - return direntType - DELTA_EDITING - } - return direntType -} diff --git a/packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts b/packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts deleted file mode 100644 index 63b424f..0000000 --- a/packages/explorer-view/src/parts/OpenContainingFolder/OpenContainingFolder.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getContainingFolder } from '../GetContainingFolder/GetContainingFolder.ts' -import { openNativeFolder } from '../OpenNativeFolder/OpenNativeFolder.ts' - -export const openContainingFolder = async (state: ExplorerState): Promise => { - const { focusedIndex, items, pathSeparator, root } = state - const path = getContainingFolder(root, items, focusedIndex, pathSeparator) - await openNativeFolder(path) - return state -} diff --git a/packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts b/packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts deleted file mode 100644 index c3cb011..0000000 --- a/packages/explorer-view/src/parts/OpenDiff/OpenDiff.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const openDiff = async (leftUri: string, rightUri: string, focus: boolean): Promise => { - await RendererWorker.openUri(`diff://${leftUri}<->${rightUri}`, focus) -} diff --git a/packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts b/packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts deleted file mode 100644 index aed078f..0000000 --- a/packages/explorer-view/src/parts/OpenFolder/OpenFolder.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const openFolder = async (): Promise => { - await RendererWorker.invoke(`Dialog.openFolder`) -} diff --git a/packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts b/packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts deleted file mode 100644 index 2be83fa..0000000 --- a/packages/explorer-view/src/parts/OpenNativeFolder/OpenNativeFolder.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const openNativeFolder = async (path: string): Promise => { - await RendererWorker.invoke('OpenNativeFolder.openNativeFolder', /* path */ path) -} diff --git a/packages/explorer-view/src/parts/OpenUri/OpenUri.ts b/packages/explorer-view/src/parts/OpenUri/OpenUri.ts deleted file mode 100644 index 3c67189..0000000 --- a/packages/explorer-view/src/parts/OpenUri/OpenUri.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const openUri = async (uri: string, focus: boolean): Promise => { - await RendererWorker.openUri(uri, /* focus */ focus) -} diff --git a/packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts b/packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts deleted file mode 100644 index f10a24b..0000000 --- a/packages/explorer-view/src/parts/OrderDirents/OrderDirents.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import { isTopLevel } from '../IsTopLevel/IsTopLevel.ts' - -export const orderDirents = (dirents: readonly ExplorerItem[]): readonly ExplorerItem[] => { - if (dirents.length === 0) { - return dirents - } - - const withDeepChildren = (parent: ExplorerItem, processed: Set): ExplorerItem[] => { - if (processed.has(parent.path)) { - return [] - } - processed.add(parent.path) - - const children = [] - for (const dirent of dirents) { - if (dirent.depth === parent.depth + 1 && dirent.path.startsWith(parent.path)) { - children.push(...withDeepChildren(dirent, processed)) - } - } - return [parent, ...children] - } - - const topLevelDirents = dirents.filter(isTopLevel) - const processed = new Set() - const ordered = topLevelDirents.flatMap((dirent) => withDeepChildren(dirent, processed)) - return ordered -} diff --git a/packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts b/packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts deleted file mode 100644 index 876b473..0000000 --- a/packages/explorer-view/src/parts/PasteHandler/PasteHandler.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { NativeFilesResult } from '../NativeFilesResult/NativeFilesResult.ts' - -export interface PasteHandler { - (state: ExplorerState, nativeFiles: NativeFilesResult): Promise -} diff --git a/packages/explorer-view/src/parts/Path/Path.ts b/packages/explorer-view/src/parts/Path/Path.ts deleted file mode 100644 index 435a6d3..0000000 --- a/packages/explorer-view/src/parts/Path/Path.ts +++ /dev/null @@ -1,26 +0,0 @@ -export const dirname = (pathSeparator: string, path: string): string => { - const index = path.lastIndexOf(pathSeparator) - if (index === -1) { - return path - } - return path.slice(0, index) -} - -export const dirname2 = (path: string): string => { - return dirname('/', path) -} - -export const join = (pathSeparator: string, ...parts: readonly string[]): string => { - return parts.join(pathSeparator) -} - -export const getBaseName = (pathSeparator: string, path: string): string => { - return path.slice(path.lastIndexOf(pathSeparator) + 1) -} - -export const join2 = (path: string, childPath: string): string => { - if (path.endsWith('/') || childPath.startsWith('/')) { - return `${path}${childPath}` - } - return `${path}/${childPath}` -} diff --git a/packages/explorer-view/src/parts/PathPart/PathPart.ts b/packages/explorer-view/src/parts/PathPart/PathPart.ts deleted file mode 100644 index 2edfea0..0000000 --- a/packages/explorer-view/src/parts/PathPart/PathPart.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface PathPart { - readonly depth: number - readonly expanded?: boolean - readonly path: string - readonly pathSeparator: string - readonly root: string -} diff --git a/packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts b/packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts deleted file mode 100644 index af10cfd..0000000 --- a/packages/explorer-view/src/parts/PathSeparatorType/PathSeparatorType.ts +++ /dev/null @@ -1 +0,0 @@ -export const Slash = '/' diff --git a/packages/explorer-view/src/parts/PlatformType/PlatformType.ts b/packages/explorer-view/src/parts/PlatformType/PlatformType.ts deleted file mode 100644 index a38fa00..0000000 --- a/packages/explorer-view/src/parts/PlatformType/PlatformType.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const Web = 1 - -export const Electron = 2 - -export const Remote = 3 - -export const Test = 4 diff --git a/packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts b/packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts deleted file mode 100644 index 082383d..0000000 --- a/packages/explorer-view/src/parts/PromiseStatus/PromiseStatus.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const Fulfilled = 'fulfilled' - -export const Rejected = 'rejected' diff --git a/packages/explorer-view/src/parts/Px/Px.ts b/packages/explorer-view/src/parts/Px/Px.ts deleted file mode 100644 index a7dc278..0000000 --- a/packages/explorer-view/src/parts/Px/Px.ts +++ /dev/null @@ -1 +0,0 @@ -export { px, position } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/RawDirent/RawDirent.ts b/packages/explorer-view/src/parts/RawDirent/RawDirent.ts deleted file mode 100644 index fb6836f..0000000 --- a/packages/explorer-view/src/parts/RawDirent/RawDirent.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface RawDirent { - readonly name: string - readonly type: number -} diff --git a/packages/explorer-view/src/parts/Refresh/Refresh.ts b/packages/explorer-view/src/parts/Refresh/Refresh.ts deleted file mode 100644 index 23316ce..0000000 --- a/packages/explorer-view/src/parts/Refresh/Refresh.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getExpandedDirents } from '../GetExpandedDirents/GetExpandedDirents.ts' -import { getPathDirentsMap } from '../GetPathDirentsMap/GetPathDirentsMap.ts' -import { getPaths } from '../GetPaths/GetPaths.ts' -import { getProtoMap } from '../GetProtoMap/GetProtoMap.ts' -import { sortPathDirentsMap } from '../SortPathDirentsMap/SortPathDirentsMap.ts' - -export const refresh = async (state: ExplorerState): Promise => { - const { focusedIndex, items, root } = state - const expandedDirents = getExpandedDirents(items) - const expandedPaths = getPaths(expandedDirents) - const allPaths = [root, ...expandedPaths] - const pathToDirents = await getPathDirentsMap(allPaths) - const sortedPathDirents = sortPathDirentsMap(pathToDirents) - const newItems = getProtoMap(root, sortedPathDirents, expandedPaths) - let newFocusedIndex = focusedIndex - if (focusedIndex >= newItems.length) { - newFocusedIndex = newItems.length - 1 - } - return { - ...state, - focusedIndex: newFocusedIndex, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts b/packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts deleted file mode 100644 index 8422b04..0000000 --- a/packages/explorer-view/src/parts/RefreshChildDirents/RefreshChildDirents.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' - -export const refreshChildDirent = async ( - folder: ExplorerItem, - dirent: any, - pathSeparator: string, - expandedFolders: readonly string[], -): Promise => { - const path = folder.path.endsWith(pathSeparator) ? `${folder.path}${dirent.name}` : `${folder.path}${pathSeparator}${dirent.name}` - const isExpandedFolder = expandedFolders.includes(path) - let type = DirentType.File - if (dirent.type === 'directory') { - type = isExpandedFolder ? DirentType.DirectoryExpanded : DirentType.Directory - } - - const item: ExplorerItem = { - depth: folder.depth + 1, - name: dirent.name, - path, - selected: false, - type, - } - - if (isExpandedFolder && dirent.type === 'directory') { - const nestedItems = await refreshChildDirents(item, pathSeparator, expandedFolders) - return [item, ...nestedItems] - } - - return [item] -} - -export const refreshChildDirents = async ( - folder: ExplorerItem, - pathSeparator: string, - expandedFolders: readonly string[], -): Promise => { - const childDirents = await FileSystem.readDirWithFileTypes(folder.path) - const childItems = await Promise.all( - childDirents.map(async (dirent) => { - return refreshChildDirent(folder, dirent, pathSeparator, expandedFolders) - }), - ) - return childItems.flat() -} diff --git a/packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts b/packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts deleted file mode 100644 index 7a58e39..0000000 --- a/packages/explorer-view/src/parts/RefreshWorkspace/RefreshWorkspace.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const refreshWorkspace = async (): Promise => { - // TODO maybe pass an application id to this? - try { - await RendererWorker.invoke('Layout.handleWorkspaceRefresh') - } catch { - // ignore - } -} diff --git a/packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts b/packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts deleted file mode 100644 index aa39ca6..0000000 --- a/packages/explorer-view/src/parts/RemoveDirent/RemoveDirent.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' -import * as ConfirmDelete from '../ConfirmDelete/ConfirmDelete.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import { getPaths } from '../GetPaths/GetPaths.ts' -import { getSelectedItems } from '../GetSelectedItems/GetSelectedItems.ts' -import * as Refresh from '../Refresh/Refresh.ts' -import { showErrorAlert } from '../ShowErrorAlert/ShowErrorAlert.ts' - -export const removeDirent = async (state: ExplorerState): Promise => { - const { confirmDelete, focusedIndex, items } = state - const selectedItems = getSelectedItems(items, focusedIndex) - if (selectedItems.length === 0) { - return state - } - const toRemove = getPaths(selectedItems) - - if (confirmDelete) { - const confirmed = await ConfirmDelete.confirmDelete(toRemove) - if (!confirmed) { - return state - } - } - const fileOperations: readonly FileOperation[] = toRemove.map((item) => { - return { - path: item, - type: FileOperationType.Remove, - } - }) - // TODO use bulk edit and explorer refresh - const errorMessage = await ApplyFileOperations.applyFileOperations(fileOperations) - if (errorMessage) { - await showErrorAlert(errorMessage) - return state - } - const newState = await Refresh.refresh(state) - return { - ...newState, - focus: FocusId.List, - focused: true, - } -} diff --git a/packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts b/packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts deleted file mode 100644 index aeb3a12..0000000 --- a/packages/explorer-view/src/parts/RenameDirent/RenameDirent.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import { getNewDirentsForRename } from '../GetNewDirentsForRename/GetNewDirentsForRename.ts' -import { getRenameSelectionRange } from '../GetRenameSelectionRange/GetRenameSelectionRange.ts' -import * as InputSource from '../InputSource/InputSource.ts' - -export const renameDirent = async (state: ExplorerState): Promise => { - const { focusedIndex, icons, items, minLineY } = state - if (items.length === 0) { - return state - } - const item = items[focusedIndex] - const newItems = getNewDirentsForRename(items, focusedIndex) - const { end, start } = getRenameSelectionRange(item.name) - return { - ...state, - editingIcon: icons[focusedIndex - minLineY], - editingIndex: focusedIndex, - editingSelectionEnd: end, - editingSelectionStart: start, - editingType: ExplorerEditingType.Rename, - editingValue: item.name, - focus: FocusId.Input, - inputSource: InputSource.Script, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/Render2/Render2.ts b/packages/explorer-view/src/parts/Render2/Render2.ts deleted file mode 100644 index 436e2fe..0000000 --- a/packages/explorer-view/src/parts/Render2/Render2.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as ApplyRender from '../ApplyRender/ApplyRender.ts' -import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' - -export const render2 = (uid: number, diffResult: readonly number[]): readonly any[] => { - const { newState, oldState } = ExplorerStates.get(uid) - ExplorerStates.set(uid, newState, newState) - const commands = ApplyRender.applyRender(oldState, newState, diffResult) - return commands -} diff --git a/packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts b/packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts deleted file mode 100644 index 607ca80..0000000 --- a/packages/explorer-view/src/parts/RenderActions2/RenderActions2.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { VirtualDomNode } from '../VirtualDomNode/VirtualDomNode.ts' -import * as ExplorerStates from '../ExplorerStates/ExplorerStates.ts' -import * as ViewletExplorerActions from '../GetActions/GetActions.ts' -import * as GetActionsVirtualDom from '../GetActionsVirtualDom/GetActionsVirtualDom.ts' - -export const renderActions = (uid: number): readonly VirtualDomNode[] => { - const { newState } = ExplorerStates.get(uid) - const actions = ViewletExplorerActions.getActions(newState.root) - const dom = GetActionsVirtualDom.getActionsVirtualDom(actions) - return dom -} diff --git a/packages/explorer-view/src/parts/RenderCss/RenderCss.ts b/packages/explorer-view/src/parts/RenderCss/RenderCss.ts deleted file mode 100644 index 983e3df..0000000 --- a/packages/explorer-view/src/parts/RenderCss/RenderCss.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ViewletCommand } from '@lvce-editor/constants' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getCss } from '../GetCss/GetCss.ts' -import * as GetErrorMessagePosition from '../GetErrorMessagePosition/GetErrorMessagePosition.ts' -import { getScrollBarSize } from '../GetScrollBarSize/GetScrollBarSize.ts' -import { getScrollBarTop } from '../GetScrollBarTop/GetScrollBarTop.ts' -import { getUniqueIndents } from '../GetUniqueIndents/GetUniqueIndents.ts' - -export const renderCss = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { - const { deltaY, focusedIndex, height, itemHeight, items, minLineY, uid, visibleExplorerItems, width } = newState - const uniqueIndents = getUniqueIndents(visibleExplorerItems) - const contentHeight = items.length * itemHeight - const scrollBarTop = getScrollBarTop(height, contentHeight, deltaY) - const scrollBarHeight = getScrollBarSize(height, contentHeight, 20) - const indent = 8 - const padding = 10 - const fileIconWidth = 16 - const defaultPaddingLeft = 0 - const chevronSpace = 22 - const depth = items[focusedIndex]?.depth || 0 - const { errorMessageWidth, left, top } = GetErrorMessagePosition.getErrorMessagePosition( - itemHeight, - focusedIndex, - minLineY, - depth, - indent, - fileIconWidth, - padding + defaultPaddingLeft + chevronSpace, - width, - ) - const css = getCss(scrollBarHeight, scrollBarTop, uniqueIndents, left, top, errorMessageWidth) - return [ViewletCommand.SetCss, uid, css] -} diff --git a/packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts b/packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts deleted file mode 100644 index 70f05fa..0000000 --- a/packages/explorer-view/src/parts/RenderDragData/RenderDragData.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getDragData } from '../GetDragData/GetDragData.ts' - -export const renderDragData = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { - const { focusedIndex, items, uid } = newState - const selected = items.filter((item, index) => item.selected || index === focusedIndex) - const urls = selected.map((item) => item.path) - const dragData = getDragData(urls) - return ['Viewlet.setDragData', uid, dragData] -} diff --git a/packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts b/packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts deleted file mode 100644 index ad84631..0000000 --- a/packages/explorer-view/src/parts/RenderEditingSelection/RenderEditingSelection.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { Renderer } from '../Renderer/Renderer.ts' -import * as InputName from '../InputName/InputName.ts' - -export const renderEditingSelection: Renderer = (oldState: ExplorerState, newState: ExplorerState): any => { - const { editingSelectionEnd, editingSelectionStart, uid } = newState - return ['Viewlet.setSelectionByName', uid, InputName.ExplorerInput, editingSelectionStart, editingSelectionEnd] -} diff --git a/packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts b/packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts deleted file mode 100644 index 69558ad..0000000 --- a/packages/explorer-view/src/parts/RenderEventListeners/RenderEventListeners.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { EventExpression } from '@lvce-editor/constants' -import type { DomEventListener } from '../DomEventListener/DomEventListener.ts' -import * as DomEventListenersFunctions from '../DomEventListenerFunctions/DomEventListenerFunctions.ts' - -export const renderEventListeners = (): readonly DomEventListener[] => { - return [ - { - name: DomEventListenersFunctions.HandleInputBlur, - params: ['handleInputBlur'], - }, - { - name: DomEventListenersFunctions.HandleListFocus, - params: ['handleFocus', EventExpression.IsTrusted, EventExpression.EventTargetClassName], - }, - { - name: DomEventListenersFunctions.HandleListBlur, - params: ['handleBlur'], - }, - { - name: DomEventListenersFunctions.HandleClick, - params: [ - 'handleClickAt', - EventExpression.DefaultPrevented, - EventExpression.Button, - EventExpression.CtrlKey, - EventExpression.ShiftKey, - EventExpression.ClientX, - EventExpression.ClientY, - ], - preventDefault: true, - }, - { - name: DomEventListenersFunctions.HandleInputClick, - params: ['handleInputClick'], - preventDefault: true, - }, - { - name: DomEventListenersFunctions.HandleClickOpenFolder, - params: ['handleClickOpenFolder'], - preventDefault: true, - }, - { - name: DomEventListenersFunctions.HandlePointerDown, - params: ['handlePointerDown', EventExpression.Button, EventExpression.ClientX, EventExpression.ClientY], - }, - { - name: DomEventListenersFunctions.HandleDoubleClick, - params: ['handleDoubleClick', EventExpression.ClientX, EventExpression.ClientY], - }, - { - name: DomEventListenersFunctions.HandleEditingInput, - params: ['updateEditingValue', EventExpression.TargetValue], - }, - { - name: DomEventListenersFunctions.HandleContextMenu, - params: ['handleContextMenu', EventExpression.Button, EventExpression.ClientX, EventExpression.ClientY], - preventDefault: true, - }, - { - name: DomEventListenersFunctions.HandleContextMenuWelcome, - params: ['handleContextMenuWelcome'], - preventDefault: true, - }, - { - name: DomEventListenersFunctions.HandleWheel, - params: ['handleWheel', EventExpression.DeltaMode, EventExpression.DeltaY], - passive: true, - }, - { - name: DomEventListenersFunctions.HandleDragOver, - params: ['handleDragOver', EventExpression.ClientX, EventExpression.ClientY], - preventDefault: true, - }, - { - name: DomEventListenersFunctions.HandleDrop, - params: ['handleDrop', EventExpression.ClientX, EventExpression.ClientY, EventExpression.DataTransferFiles2, EventExpression.DataTransferFiles], - preventDefault: true, - }, - { - name: DomEventListenersFunctions.HandleDragLeave, - params: ['handleDragLeave'], - }, - { - name: DomEventListenersFunctions.HandleButtonClick, - params: ['handleButtonClick', EventExpression.TargetName], - }, - { - name: DomEventListenersFunctions.HandleDragEnd, - params: ['handleDragEnd'], - }, - { - // @ts-ignore - dragEffect: 'copyMove', - name: DomEventListenersFunctions.HandleDragStart, - params: ['handleDragStart'], - }, - ] -} diff --git a/packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts b/packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts deleted file mode 100644 index a3d89f3..0000000 --- a/packages/explorer-view/src/parts/RenderFocus/RenderFocus.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ViewletCommand } from '@lvce-editor/constants' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import * as InputName from '../InputName/InputName.ts' -import * as InputSource from '../InputSource/InputSource.ts' - -export const renderFocus = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { - if (newState.inputSource === InputSource.User) { - return [] - } - if (newState.focus === FocusId.Input) { - return [ViewletCommand.FocusElementByName, InputName.ExplorerInput] - } - if (newState.focus === FocusId.List) { - return [ViewletCommand.FocusSelector, '.ListItems'] - } - // TODO - // 1. when focused, focus the outer list element - // 2. when focused, set focus context in renderer worker - return [] -} diff --git a/packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts b/packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts deleted file mode 100644 index c7ef35f..0000000 --- a/packages/explorer-view/src/parts/RenderFocusContext/RenderFocusContext.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ViewletCommand, WhenExpression } from '@lvce-editor/constants' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusId from '../FocusId/FocusId.ts' - -export const renderFocusContext = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { - const { uid } = newState - if (newState.focus === FocusId.Input) { - return [ViewletCommand.SetFocusContext, uid, WhenExpression.FocusExplorerEditBox] - } - if (newState.focus === FocusId.List) { - return [ViewletCommand.SetFocusContext, uid, WhenExpression.FocusExplorer] - } - return [] -} diff --git a/packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts b/packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts deleted file mode 100644 index f84c899..0000000 --- a/packages/explorer-view/src/parts/RenderIncremental/RenderIncremental.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ViewletCommand } from '@lvce-editor/constants' -import { diffTree } from '@lvce-editor/virtual-dom-worker' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { renderItems } from '../RenderItems/RenderItems.ts' - -export const renderIncremental = (oldState: ExplorerState, newState: ExplorerState): any => { - const oldDom = renderItems(oldState, oldState)[2] - const newDom = renderItems(newState, newState)[2] - const patches = diffTree(oldDom, newDom) - return [ViewletCommand.SetPatches, newState.uid, patches] -} diff --git a/packages/explorer-view/src/parts/RenderItems/RenderItems.ts b/packages/explorer-view/src/parts/RenderItems/RenderItems.ts deleted file mode 100644 index 0d9a085..0000000 --- a/packages/explorer-view/src/parts/RenderItems/RenderItems.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ViewletCommand } from '@lvce-editor/constants' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetExplorerVirtualDom from '../GetExplorerVirtualDom/GetExplorerVirtualDom.ts' -import * as GetLoadErrorMessage from '../GetLoadErrorMessage/GetLoadErrorMessage.ts' - -export const renderItems = (oldState: ExplorerState, newState: ExplorerState): any => { - const { dropTargets, editingErrorMessage, focused, focusedIndex, height, initial, itemHeight, items, root, width } = newState - const visibleDirents = newState.visibleExplorerItems - const isWide = width > 450 - const contentHeight = items.length * itemHeight - const loadErrorMessage = GetLoadErrorMessage.getLoadErrorMessage(newState) - const showOpenAnotherFolderButton = GetLoadErrorMessage.shouldShowOpenAnotherFolderButton(newState) - if (initial) { - return [ViewletCommand.SetDom2, newState.uid, []] - } - const dom = GetExplorerVirtualDom.getExplorerVirtualDom( - visibleDirents, - focusedIndex, - root, - isWide, - focused, - dropTargets, - height, - contentHeight, - editingErrorMessage, - loadErrorMessage, - showOpenAnotherFolderButton, - ) - return [ViewletCommand.SetDom2, newState.uid, dom] -} diff --git a/packages/explorer-view/src/parts/RenderValue/RenderValue.ts b/packages/explorer-view/src/parts/RenderValue/RenderValue.ts deleted file mode 100644 index 42a5007..0000000 --- a/packages/explorer-view/src/parts/RenderValue/RenderValue.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as FocusId from '../FocusId/FocusId.ts' -import * as InputName from '../InputName/InputName.ts' -import * as InputSource from '../InputSource/InputSource.ts' - -export const renderValue = (oldState: ExplorerState, newState: ExplorerState): readonly any[] => { - if (newState.inputSource === InputSource.User) { - return [] - } - if (newState.focus === FocusId.Input) { - return ['Viewlet.setValueByName', InputName.ExplorerInput, newState.editingValue] - } - return [] -} diff --git a/packages/explorer-view/src/parts/Renderer/Renderer.ts b/packages/explorer-view/src/parts/Renderer/Renderer.ts deleted file mode 100644 index d67e331..0000000 --- a/packages/explorer-view/src/parts/Renderer/Renderer.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export interface Renderer { - (oldState: ExplorerState, newState: ExplorerState): readonly any[] -} diff --git a/packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts b/packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts deleted file mode 100644 index 7b5f6ca..0000000 --- a/packages/explorer-view/src/parts/RequestFileIcons/RequestFileIcons.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { IconThemeWorker } from '@lvce-editor/rpc-registry' -import type { IconRequest } from '../IconRequest/IconRequest.ts' -import { toSimpleIconRequest } from '../ToSimpleIconRequest/ToSimpleIconRequest.ts' - -export const requestFileIcons = async (requests: readonly IconRequest[]): Promise => { - if (requests.length === 0) { - return [] - } - const simpleRequests = requests.map(toSimpleIconRequest) - const icons = await IconThemeWorker.getIcons(simpleRequests) - return icons -} diff --git a/packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts b/packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts deleted file mode 100644 index 26129f0..0000000 --- a/packages/explorer-view/src/parts/ResetEditing/ResetEditing.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' - -export const resetEditing = { - editingErrorMessage: '', - editingIcon: '', - editingIndex: -1, - editingSelection: { - end: 0, - start: 0, - }, - editingType: ExplorerEditingType.None, - editingValue: '', -} diff --git a/packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts b/packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts deleted file mode 100644 index 767ee6f..0000000 --- a/packages/explorer-view/src/parts/ResolveSymbolicLinks/ResolveSymbolicLinks.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as DirentType from '../DirentType/DirentType.ts' -import * as ErrorCodes from '../ErrorCodes/ErrorCodes.ts' -import * as FileSystem from '../FileSystem/FileSystem.ts' -import * as GetSymlinkType from '../GetSymlinkType/GetSymlinkType.ts' -import * as IsSymbolicLink from '../IsSymbolicLink/IsSymbolicLink.ts' - -// TODO maybe resolving of symbolic links should happen in shared process? -// so that there is less code and less work in the frontend -const resolveSymbolicLink = async (uri: string, rawDirent: any): Promise => { - try { - // TODO support windows paths - const absolutePath = uri + '/' + rawDirent.name - const type = await FileSystem.stat(absolutePath) - const symLinkType = GetSymlinkType.getSymlinkType(type) - return { - name: rawDirent.name, - type: symLinkType, - } - } catch (error) { - // @ts-ignore - if (error && error.code === ErrorCodes.ENOENT) { - return { - name: rawDirent.name, - type: DirentType.SymLinkFile, - } - } - console.error(`Failed to resolve symbolic link for ${rawDirent.name}: ${error}`) - return rawDirent - } -} - -export const resolveSymbolicLinks = async (uri: string, rawDirents: readonly any[]): Promise => { - const promises = [] - for (const rawDirent of rawDirents) { - if (IsSymbolicLink.isSymbolicLink(rawDirent)) { - const resolvedDirent = resolveSymbolicLink(uri, rawDirent) - promises.push(resolvedDirent) - } else { - promises.push(rawDirent) - } - } - const resolvedDirents = await Promise.all(promises) - return resolvedDirents -} diff --git a/packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts b/packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts deleted file mode 100644 index 39c061a..0000000 --- a/packages/explorer-view/src/parts/RestoreDirentType/RestoreDirentType.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as DirentType from '../DirentType/DirentType.ts' - -export const restoreDirentType = (rawDirentType: number, path: string, expandedPaths: readonly string[]): number => { - if (rawDirentType === DirentType.Directory && expandedPaths.includes(path)) { - return DirentType.DirectoryExpanded - } - return rawDirentType -} diff --git a/packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts b/packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts deleted file mode 100644 index b0265b7..0000000 --- a/packages/explorer-view/src/parts/RestoreExpandedState/RestoreExpandedState.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as Character from '../Character/Character.ts' -import { getChildDirentsRaw } from '../GetChildDirentsRaw/GetChildDirentsRaw.ts' -import { getSavedChildDirents } from '../GetSavedChildDirents/GetSavedChildDirents.ts' -import * as PromiseStatus from '../PromiseStatus/PromiseStatus.ts' - -const createDirents = ( - root: string, - expandedDirentPaths: readonly string[], - expandedDirentChildren: any, - excluded: readonly string[], - pathSeparator: string, -): readonly any[] => { - const dirents = [] - const map = Object.create(null) - for (let i = 0; i < expandedDirentPaths.length; i++) { - const path = expandedDirentPaths[i] - const children = expandedDirentChildren[i] - if (children.status === PromiseStatus.Fulfilled) { - map[path] = children.value - } - } - dirents.push(...getSavedChildDirents(map, root, 1, excluded, pathSeparator)) - return dirents -} - -const getSavedExpandedPaths = (savedState: any, root: string): any => { - if (savedState && savedState.root !== root) { - return [] - } - if (savedState && savedState.expandedPaths && Array.isArray(savedState.expandedPaths)) { - return savedState.expandedPaths - } - return [] -} - -export const restoreExpandedState = async (savedState: any, root: any, pathSeparator: any, excluded: any): Promise => { - // TODO read all opened folders in parallel - // ignore ENOENT errors - // ignore ENOTDIR errors - // merge all dirents - // restore scroll location - const expandedPaths = getSavedExpandedPaths(savedState, root) - if (root === Character.EmptyString) { - return [] - } - const expandedDirentPaths = [root, ...expandedPaths] - const expandedDirentChildren = await Promise.allSettled(expandedDirentPaths.map(getChildDirentsRaw)) - if (expandedDirentChildren[0].status === PromiseStatus.Rejected) { - throw expandedDirentChildren[0].reason - } - const dirents = createDirents(root, expandedDirentPaths, expandedDirentChildren, excluded, pathSeparator) - return dirents -} diff --git a/packages/explorer-view/src/parts/RestoreState/RestoreState.ts b/packages/explorer-view/src/parts/RestoreState/RestoreState.ts deleted file mode 100644 index a7c7fde..0000000 --- a/packages/explorer-view/src/parts/RestoreState/RestoreState.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { RestoredState } from '../RestoredState/RestoredState.ts' -import { hasProperty } from '../HasProperty/HasProperty.ts' - -const getSavedMinLineY = (savedState: unknown): number => { - if (hasProperty(savedState, 'minLineY') && typeof savedState.minLineY === 'number') { - return savedState.minLineY - } - return 0 -} -const getSavedDeltaY = (savedState: unknown): number => { - if (hasProperty(savedState, 'deltaY') && typeof savedState.deltaY === 'number') { - return savedState.deltaY - } - return 0 -} - -const getSavedWorkspacePath = (savedState: unknown): string => { - if (hasProperty(savedState, 'workspacePath') && typeof savedState.workspacePath === 'string') { - return savedState.workspacePath - } - return '' -} - -export const restoreState = (savedState: unknown): RestoredState => { - if (!savedState) { - return { - deltaY: 0, - minLineY: 0, - root: '', - } - } - - const root = getSavedWorkspacePath(savedState) - const minLineY = getSavedMinLineY(savedState) - const deltaY = getSavedDeltaY(savedState) - return { - deltaY, - minLineY, - root, - } -} diff --git a/packages/explorer-view/src/parts/RestoredState/RestoredState.ts b/packages/explorer-view/src/parts/RestoredState/RestoredState.ts deleted file mode 100644 index 48d0137..0000000 --- a/packages/explorer-view/src/parts/RestoredState/RestoredState.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface RestoredState { - readonly deltaY: number - readonly minLineY: number - readonly root: string -} diff --git a/packages/explorer-view/src/parts/RevealItem/RevealItem.ts b/packages/explorer-view/src/parts/RevealItem/RevealItem.ts deleted file mode 100644 index f93b797..0000000 --- a/packages/explorer-view/src/parts/RevealItem/RevealItem.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as Assert from '../Assert/Assert.ts' -import * as GetIndex from '../GetIndex/GetIndex.ts' -import * as IsUriWithinRoot from '../IsUriWithinRoot/IsUriWithinRoot.ts' -import * as RevealItemHidden from '../RevealItemHidden/RevealItemHidden.ts' -import * as RevealItemVisible from '../RevealItemVisible/RevealItemVisible.ts' - -export const revealItem = async (state: ExplorerState, uri: string): Promise => { - Assert.object(state) - Assert.string(uri) - const { items, pathSeparator, root } = state - if (!IsUriWithinRoot.isUriWithinRoot(root, uri, pathSeparator)) { - return state - } - const index = GetIndex.getIndex(items, uri) - if (index === -1) { - return RevealItemHidden.revealItemHidden(state, uri) - } - return RevealItemVisible.revealItemVisible(state, index) -} diff --git a/packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts b/packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts deleted file mode 100644 index 49885b7..0000000 --- a/packages/explorer-view/src/parts/RevealItemHidden/RevealItemHidden.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getIndex } from '../GetIndex/GetIndex.ts' -import { getPathParts } from '../GetPathParts/GetPathParts.ts' -import { getPathPartsChildren } from '../GetPathPartsChildren/GetPathPartsChildren.ts' -import { getPathPartsToReveal } from '../GetPathPartsToReveal/GetPathPartsToReveal.ts' -import { mergeVisibleWithHiddenItems } from '../MergeVisibleWithHiddenItems/MergeVisibleWithHiddenItems.ts' -import { orderDirents } from '../OrderDirents/OrderDirents.ts' -import { scrollInto } from '../ScrollInto/ScrollInto.ts' - -// TODO maybe just insert items into explorer and refresh whole explorer -export const revealItemHidden = async (state: ExplorerState, uri: string): Promise => { - const { items, maxLineY, minLineY, pathSeparator, root } = state - const pathParts = getPathParts(root, uri, pathSeparator) - if (pathParts.length === 0) { - return state - } - const pathPartsToReveal = getPathPartsToReveal(root, pathParts, items) - const pathPartsChildren = await getPathPartsChildren(pathPartsToReveal) - const pathPartsChildrenFlat = pathPartsChildren.flat() - const orderedPathParts = orderDirents(pathPartsChildrenFlat) - const mergedDirents = mergeVisibleWithHiddenItems(items, orderedPathParts) - const index = getIndex(mergedDirents, uri) - if (index === -1) { - throw new Error(`File not found in explorer ${uri}`) - } - const { newMaxLineY, newMinLineY } = scrollInto(index, minLineY, maxLineY) - return { - ...state, - focused: true, - focusedIndex: index, - items: mergedDirents, - maxLineY: newMaxLineY, - minLineY: newMinLineY, - } -} From 7f09e675c9ae907742f3728350f55d58c96c4375 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:33:45 +0200 Subject: [PATCH 07/17] post --- .../RevealItemVisible/RevealItemVisible.ts | 14 -- .../explorer-view/src/parts/RpcId/RpcId.ts | 1 - .../src/parts/RpcRegistry/RpcRegistry.ts | 1 - .../src/parts/SaveState/SaveState.ts | 16 -- .../src/parts/SavedState/SavedState.ts | 7 - .../src/parts/ScrollInto/ScrollInto.ts | 23 --- .../ScrollIntoResult/ScrollIntoResult.ts | 4 - .../src/parts/SelectAll/SelectAll.ts | 15 -- .../src/parts/SelectDown/SelectDown.ts | 30 ---- .../SelectForCompare/SelectForCompare.ts | 13 -- .../src/parts/SelectIndices/SelectIndices.ts | 13 -- .../src/parts/SelectUp/SelectUp.ts | 18 --- .../src/parts/Selection/Selection.ts | 4 - .../SendMessagePortToFileSystemWorker.ts | 5 - .../SendMessagePortToIconThemeWorker.ts | 5 - .../src/parts/SetDeltaY/SetDeltaY.ts | 24 --- .../src/parts/SetFocus/SetFocus.ts | 5 - .../src/parts/Settings/Settings.ts | 6 - .../src/parts/Severity/Severity.ts | 4 - .../parts/ShowErrorAlert/ShowErrorAlert.ts | 5 - .../SortExplorerItems/SortExplorerItems.ts | 6 - .../SortPathDirentsMap/SortPathDirentsMap.ts | 11 -- .../src/parts/Terminate/Terminate.ts | 3 - .../src/parts/Timeout/Timeout.ts | 5 - .../ToCollapsedDirent/ToCollapsedDirent.ts | 12 -- .../parts/ToDisplayDirent/ToDisplayDirent.ts | 24 --- .../ToDisplayDirents/ToDisplayDirents.ts | 23 --- .../ToSimpleIconRequest.ts | 9 -- .../ToggleIndividualSelection.ts | 20 --- packages/explorer-view/src/parts/Tree/Tree.ts | 5 - .../src/parts/TreeItem/TreeItem.ts | 4 - .../src/parts/TreeToArray/TreeToArray.ts | 9 -- .../TreeToArrayInternal.ts | 27 ---- .../src/parts/TreeUpdate/TreeUpdate.ts | 3 - .../src/parts/UiStrings/UiStrings.ts | 34 ---- .../UpdateDirentsAtPath.ts | 34 ---- .../UpdateEditingValue/UpdateEditingValue.ts | 25 --- .../UpdateExplorerAfterFileOperations.ts | 57 ------- .../parts/UpdateIconCache/UpdateIconCache.ts | 15 -- .../src/parts/UpdateIcons/UpdateIcons.ts | 13 -- .../src/parts/UpdateRoot/UpdateRoot.ts | 24 --- .../src/parts/UpdateTree/UpdateTree.ts | 13 -- .../src/parts/UpdateTree2/UpdateTree2.ts | 12 -- .../UploadFileSystemHandles.ts | 54 ------- .../explorer-view/src/parts/VError/VError.ts | 1 - .../ValidateFileName/ValidateFileName.ts | 150 ------------------ .../ValidateFileName2/ValidateFileName2.ts | 32 ---- .../ValidateFileNameResult.ts | 4 - .../ValidateFolderCopy/ValidateFolderCopy.ts | 17 -- .../ValidateOperations/ValidateOperations.ts | 16 -- .../src/parts/ViewletAction/ViewletAction.ts | 10 -- .../VirtualDomElements/VirtualDomElements.ts | 5 - .../VirtualDomHelpers/VirtualDomHelpers.ts | 1 - .../parts/VirtualDomNode/VirtualDomNode.ts | 1 - .../VisibleExplorerItem.ts | 20 --- .../parts/WhenExpression/WhenExpression.ts | 2 - packages/server/package.json | 1 - packages/server/src/postinstall.js | 39 ----- 58 files changed, 954 deletions(-) delete mode 100644 packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts delete mode 100644 packages/explorer-view/src/parts/RpcId/RpcId.ts delete mode 100644 packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts delete mode 100644 packages/explorer-view/src/parts/SaveState/SaveState.ts delete mode 100644 packages/explorer-view/src/parts/SavedState/SavedState.ts delete mode 100644 packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts delete mode 100644 packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts delete mode 100644 packages/explorer-view/src/parts/SelectAll/SelectAll.ts delete mode 100644 packages/explorer-view/src/parts/SelectDown/SelectDown.ts delete mode 100644 packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts delete mode 100644 packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts delete mode 100644 packages/explorer-view/src/parts/SelectUp/SelectUp.ts delete mode 100644 packages/explorer-view/src/parts/Selection/Selection.ts delete mode 100644 packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts delete mode 100644 packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts delete mode 100644 packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts delete mode 100644 packages/explorer-view/src/parts/SetFocus/SetFocus.ts delete mode 100644 packages/explorer-view/src/parts/Settings/Settings.ts delete mode 100644 packages/explorer-view/src/parts/Severity/Severity.ts delete mode 100644 packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts delete mode 100644 packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts delete mode 100644 packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts delete mode 100644 packages/explorer-view/src/parts/Terminate/Terminate.ts delete mode 100644 packages/explorer-view/src/parts/Timeout/Timeout.ts delete mode 100644 packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts delete mode 100644 packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts delete mode 100644 packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts delete mode 100644 packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts delete mode 100644 packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts delete mode 100644 packages/explorer-view/src/parts/Tree/Tree.ts delete mode 100644 packages/explorer-view/src/parts/TreeItem/TreeItem.ts delete mode 100644 packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts delete mode 100644 packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts delete mode 100644 packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts delete mode 100644 packages/explorer-view/src/parts/UiStrings/UiStrings.ts delete mode 100644 packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts delete mode 100644 packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts delete mode 100644 packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts delete mode 100644 packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts delete mode 100644 packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts delete mode 100644 packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts delete mode 100644 packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts delete mode 100644 packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts delete mode 100644 packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts delete mode 100644 packages/explorer-view/src/parts/VError/VError.ts delete mode 100644 packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts delete mode 100644 packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts delete mode 100644 packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts delete mode 100644 packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts delete mode 100644 packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts delete mode 100644 packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts delete mode 100644 packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts delete mode 100644 packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts delete mode 100644 packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts delete mode 100644 packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts delete mode 100644 packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts delete mode 100644 packages/server/src/postinstall.js diff --git a/packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts b/packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts deleted file mode 100644 index b4e8641..0000000 --- a/packages/explorer-view/src/parts/RevealItemVisible/RevealItemVisible.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ScrollInto from '../ScrollInto/ScrollInto.ts' - -export const revealItemVisible = (state: ExplorerState, index: number): ExplorerState => { - const { maxLineY, minLineY } = state - const { newMaxLineY, newMinLineY } = ScrollInto.scrollInto(index, minLineY, maxLineY) - return { - ...state, - focused: true, - focusedIndex: index, - maxLineY: newMaxLineY, - minLineY: newMinLineY, - } -} diff --git a/packages/explorer-view/src/parts/RpcId/RpcId.ts b/packages/explorer-view/src/parts/RpcId/RpcId.ts deleted file mode 100644 index e6e564a..0000000 --- a/packages/explorer-view/src/parts/RpcId/RpcId.ts +++ /dev/null @@ -1 +0,0 @@ -export const RendererWorker = 1 diff --git a/packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts b/packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts deleted file mode 100644 index 260ee61..0000000 --- a/packages/explorer-view/src/parts/RpcRegistry/RpcRegistry.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@lvce-editor/rpc-registry' diff --git a/packages/explorer-view/src/parts/SaveState/SaveState.ts b/packages/explorer-view/src/parts/SaveState/SaveState.ts deleted file mode 100644 index bf9c2eb..0000000 --- a/packages/explorer-view/src/parts/SaveState/SaveState.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { SavedState } from '../SavedState/SavedState.ts' -import * as GetPath from '../GetPath/GetPath.ts' -import * as IsExpandedDirectory from '../IsExpandedDirectory/IsExpandedDirectory.ts' - -export const saveState = (state: ExplorerState): SavedState => { - const { deltaY, items, maxLineY, minLineY, root } = state - const expandedPaths = items.filter(IsExpandedDirectory.isExpandedDirectory).map(GetPath.getPath) - return { - deltaY, - expandedPaths, - maxLineY, - minLineY, - root, - } -} diff --git a/packages/explorer-view/src/parts/SavedState/SavedState.ts b/packages/explorer-view/src/parts/SavedState/SavedState.ts deleted file mode 100644 index b9344cb..0000000 --- a/packages/explorer-view/src/parts/SavedState/SavedState.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface SavedState { - readonly deltaY: number - readonly expandedPaths: readonly string[] - readonly maxLineY: number - readonly minLineY: number - readonly root: string -} diff --git a/packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts b/packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts deleted file mode 100644 index fa9beb4..0000000 --- a/packages/explorer-view/src/parts/ScrollInto/ScrollInto.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ScrollIntoResult } from '../ScrollIntoResult/ScrollIntoResult.ts' - -export const scrollInto = (index: number, minLineY: number, maxLineY: number): ScrollIntoResult => { - const diff = maxLineY - minLineY - const smallerHalf = Math.floor(diff / 2) - const largerHalf = diff - smallerHalf - if (index < minLineY) { - return { - newMaxLineY: index + largerHalf, - newMinLineY: index - smallerHalf, - } - } - if (index >= maxLineY) { - return { - newMaxLineY: index + largerHalf, - newMinLineY: index - smallerHalf, - } - } - return { - newMaxLineY: maxLineY, - newMinLineY: minLineY, - } -} diff --git a/packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts b/packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts deleted file mode 100644 index 26cf9e8..0000000 --- a/packages/explorer-view/src/parts/ScrollIntoResult/ScrollIntoResult.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ScrollIntoResult { - readonly newMaxLineY: number - readonly newMinLineY: number -} diff --git a/packages/explorer-view/src/parts/SelectAll/SelectAll.ts b/packages/explorer-view/src/parts/SelectAll/SelectAll.ts deleted file mode 100644 index d347680..0000000 --- a/packages/explorer-view/src/parts/SelectAll/SelectAll.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -// TODO select all should only select all items in the current folder -// and when calling it next item, expand selection to its parent folder -export const selectAll = (state: ExplorerState): ExplorerState => { - const { items } = state - const newItems = items.map((item) => ({ - ...item, - selected: true, - })) - return { - ...state, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/SelectDown/SelectDown.ts b/packages/explorer-view/src/parts/SelectDown/SelectDown.ts deleted file mode 100644 index 41bbd3b..0000000 --- a/packages/explorer-view/src/parts/SelectDown/SelectDown.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -const getLastSelectedIndex = (items: readonly ExplorerItem[]): number => { - let lastSelectedIndex = -1 - for (let index = 0; index < items.length; index++) { - if (items[index].selected) { - lastSelectedIndex = index - } - } - return lastSelectedIndex -} - -export const selectDown = (state: ExplorerState): ExplorerState => { - const { focusedIndex, items } = state - const lastSelectedIndex = getLastSelectedIndex(items) - const targetIndex = lastSelectedIndex === -1 ? focusedIndex : lastSelectedIndex - if (targetIndex >= items.length - 1) { - return state - } - const newItems = items.map((item, i) => ({ - ...item, - selected: i === targetIndex + 1 ? true : item.selected || i === focusedIndex, - })) - return { - ...state, - focusedIndex: targetIndex + 1, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts b/packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts deleted file mode 100644 index 77fbe2e..0000000 --- a/packages/explorer-view/src/parts/SelectForCompare/SelectForCompare.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetFocusedFile from '../GetFocusedFile/GetFocusedFile.ts' - -export const selectForCompare = (state: ExplorerState): ExplorerState => { - const focusedFile = GetFocusedFile.getFocusedFile(state) - if (!focusedFile) { - return state - } - return { - ...state, - compareSourceUri: focusedFile.path, - } -} diff --git a/packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts b/packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts deleted file mode 100644 index ebffff3..0000000 --- a/packages/explorer-view/src/parts/SelectIndices/SelectIndices.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const setSelectedIndices = (state: ExplorerState, indices: number[]): ExplorerState => { - const { items } = state - const newItems = items.map((item, i) => ({ - ...item, - selected: indices.includes(i), - })) - return { - ...state, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/SelectUp/SelectUp.ts b/packages/explorer-view/src/parts/SelectUp/SelectUp.ts deleted file mode 100644 index 702f50d..0000000 --- a/packages/explorer-view/src/parts/SelectUp/SelectUp.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const selectUp = (state: ExplorerState): ExplorerState => { - const { focusedIndex, items } = state - const firstSelectedIndex = items.findIndex((item) => item.selected) - const targetIndex = firstSelectedIndex === -1 ? focusedIndex : firstSelectedIndex - if (targetIndex <= 0) { - return state - } - const newItems = items.map((item, i) => ({ - ...item, - selected: i === targetIndex - 1 ? true : item.selected, - })) - return { - ...state, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/Selection/Selection.ts b/packages/explorer-view/src/parts/Selection/Selection.ts deleted file mode 100644 index 5d81d28..0000000 --- a/packages/explorer-view/src/parts/Selection/Selection.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Selection { - readonly end: number - readonly start: number -} diff --git a/packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts b/packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts deleted file mode 100644 index c35850b..0000000 --- a/packages/explorer-view/src/parts/SendMessagePortToFileSystemWorker/SendMessagePortToFileSystemWorker.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const sendMessagePortToFileSystemWorker = async (port: any): Promise => { - await RendererWorker.sendMessagePortToFileSystemWorker(port, 0) -} diff --git a/packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts b/packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts deleted file mode 100644 index 8186bd1..0000000 --- a/packages/explorer-view/src/parts/SendMessagePortToIconThemeWorker/SendMessagePortToIconThemeWorker.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const sendMessagePortToIconThemeWorker = async (port: any): Promise => { - await RendererWorker.sendMessagePortToIconThemeWorker(port, 0) -} diff --git a/packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts b/packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts deleted file mode 100644 index d18eed8..0000000 --- a/packages/explorer-view/src/parts/SetDeltaY/SetDeltaY.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const setDeltaY = async (state: ExplorerState, deltaY: number): Promise => { - if (!Number.isFinite(deltaY)) { - return state - } - const { height, itemHeight, items } = state - if (deltaY < 0) { - deltaY = 0 - } else if (deltaY > items.length * itemHeight - height) { - deltaY = Math.max(items.length * itemHeight - height, 0) - } - if (state.deltaY === deltaY) { - return state - } - const minLineY = Math.round(deltaY / itemHeight) - const maxLineY = minLineY + Math.round(height / itemHeight) - return { - ...state, - deltaY, - maxLineY, - minLineY, - } -} diff --git a/packages/explorer-view/src/parts/SetFocus/SetFocus.ts b/packages/explorer-view/src/parts/SetFocus/SetFocus.ts deleted file mode 100644 index a723a52..0000000 --- a/packages/explorer-view/src/parts/SetFocus/SetFocus.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const setFocus = (key: number): Promise => { - return RendererWorker.invoke('Focus.setFocus', key) -} diff --git a/packages/explorer-view/src/parts/Settings/Settings.ts b/packages/explorer-view/src/parts/Settings/Settings.ts deleted file mode 100644 index 8ef1d39..0000000 --- a/packages/explorer-view/src/parts/Settings/Settings.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface Settings { - readonly confirmDelete: boolean - readonly confirmPaste: boolean - readonly sourceControlDecorations: boolean - readonly useChevrons: boolean -} diff --git a/packages/explorer-view/src/parts/Severity/Severity.ts b/packages/explorer-view/src/parts/Severity/Severity.ts deleted file mode 100644 index 13162c2..0000000 --- a/packages/explorer-view/src/parts/Severity/Severity.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const None = 0 -export const Info = 1 -export const Warning = 2 -export const Error = 3 diff --git a/packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts b/packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts deleted file mode 100644 index 8014dba..0000000 --- a/packages/explorer-view/src/parts/ShowErrorAlert/ShowErrorAlert.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RendererWorker } from '@lvce-editor/rpc-registry' - -export const showErrorAlert = async (errorMessage: string): Promise => { - await RendererWorker.confirm(errorMessage) -} diff --git a/packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts b/packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts deleted file mode 100644 index e7d52d9..0000000 --- a/packages/explorer-view/src/parts/SortExplorerItems/SortExplorerItems.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as CompareDirent from '../CompareDirent/CompareDirent.ts' - -export const sortExplorerItems = (rawDirents: readonly RawDirent[]): readonly RawDirent[] => { - return rawDirents.toSorted(CompareDirent.compareDirent) -} diff --git a/packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts b/packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts deleted file mode 100644 index dfe4080..0000000 --- a/packages/explorer-view/src/parts/SortPathDirentsMap/SortPathDirentsMap.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as SortExplorerItems from '../SortExplorerItems/SortExplorerItems.ts' - -export const sortPathDirentsMap = (map: Record): Record => { - const sortedMap: Record = Object.create(null) - for (const [key, value] of Object.entries(map)) { - const sorted = SortExplorerItems.sortExplorerItems(value) - sortedMap[key] = sorted - } - return sortedMap -} diff --git a/packages/explorer-view/src/parts/Terminate/Terminate.ts b/packages/explorer-view/src/parts/Terminate/Terminate.ts deleted file mode 100644 index d47184c..0000000 --- a/packages/explorer-view/src/parts/Terminate/Terminate.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const terminate = (): void => { - globalThis.close() -} diff --git a/packages/explorer-view/src/parts/Timeout/Timeout.ts b/packages/explorer-view/src/parts/Timeout/Timeout.ts deleted file mode 100644 index 39a09dc..0000000 --- a/packages/explorer-view/src/parts/Timeout/Timeout.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const sleep = async (duration: number): Promise => { - const { promise, resolve } = Promise.withResolvers() - setTimeout(resolve, duration) - await promise -} diff --git a/packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts b/packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts deleted file mode 100644 index b75aee8..0000000 --- a/packages/explorer-view/src/parts/ToCollapsedDirent/ToCollapsedDirent.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import * as DirentType from '../DirentType/DirentType.ts' - -export const toCollapsedDirent = (dirent: ExplorerItem): ExplorerItem => { - if (dirent.type === DirentType.DirectoryExpanded) { - return { - ...dirent, - type: DirentType.Directory, - } - } - return dirent -} diff --git a/packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts b/packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts deleted file mode 100644 index 128a400..0000000 --- a/packages/explorer-view/src/parts/ToDisplayDirent/ToDisplayDirent.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import { join2 } from '../Path/Path.ts' - -// TODO figure out whether this uses too much memory (name,path -> redundant, depth could be computed on demand) -export const toDisplayDirent = ( - parentPath: string, - parentDepth: number, - rawDirentType: number, - rawDirentName: string, - index: number, - length: number, -): ExplorerItem => { - const path = join2(parentPath, rawDirentName) - return { - depth: parentDepth + 1, - icon: '', - name: rawDirentName, - path, // TODO storing absolute path might be too costly, could also store relative path here - posInSet: index + 1, - selected: false, - setSize: length, - type: rawDirentType, - } -} diff --git a/packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts b/packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts deleted file mode 100644 index 383f37e..0000000 --- a/packages/explorer-view/src/parts/ToDisplayDirents/ToDisplayDirents.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as SortExplorerItems from '../SortExplorerItems/SortExplorerItems.ts' -import { toDisplayDirent } from '../ToDisplayDirent/ToDisplayDirent.ts' - -export const toDisplayDirents = ( - pathSeparator: string, - rawDirents: readonly RawDirent[], - parentDirentPath: string, - parentDirentDepth: number, - excluded: readonly string[], - expanded: boolean = false, -): readonly ExplorerItem[] => { - rawDirents = SortExplorerItems.sortExplorerItems(rawDirents) - const result: ExplorerItem[] = [] - const visibleItems = rawDirents.filter((item) => !excluded.includes(item.name)) - const count = visibleItems.length - for (let i = 0; i < visibleItems.length; i++) { - const rawDirent = visibleItems[i] - result.push(toDisplayDirent(parentDirentPath, parentDirentDepth, rawDirent.type, rawDirent.name, i, count)) - } - return result -} diff --git a/packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts b/packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts deleted file mode 100644 index 019e67c..0000000 --- a/packages/explorer-view/src/parts/ToSimpleIconRequest/ToSimpleIconRequest.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { IconRequest } from '../IconRequest/IconRequest.ts' -import { getSimpleIconRequestType } from '../GetSimpleIconRequestType/GetSimpleIconRequestType.ts' - -export const toSimpleIconRequest = (request: IconRequest): any => { - return { - name: request.name, - type: getSimpleIconRequestType(request.type), - } -} diff --git a/packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts b/packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts deleted file mode 100644 index 034b649..0000000 --- a/packages/explorer-view/src/parts/ToggleIndividualSelection/ToggleIndividualSelection.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' - -export const toggleIndividualSelection = async (state: ExplorerState, index: number): Promise => { - const { items } = state - - // If index is out of range, do nothing - if (index < 0 || index >= items.length) { - return state - } - - const newItems = items.map((item, i) => ({ - ...item, - selected: i === index ? !item.selected : item.selected, - })) - - return { - ...state, - items: newItems, - } -} diff --git a/packages/explorer-view/src/parts/Tree/Tree.ts b/packages/explorer-view/src/parts/Tree/Tree.ts deleted file mode 100644 index 8503737..0000000 --- a/packages/explorer-view/src/parts/Tree/Tree.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { TreeItem } from '../TreeItem/TreeItem.ts' - -export interface Tree { - readonly [key: string]: readonly TreeItem[] -} diff --git a/packages/explorer-view/src/parts/TreeItem/TreeItem.ts b/packages/explorer-view/src/parts/TreeItem/TreeItem.ts deleted file mode 100644 index 20b326c..0000000 --- a/packages/explorer-view/src/parts/TreeItem/TreeItem.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface TreeItem { - readonly name: string - readonly type: number -} diff --git a/packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts b/packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts deleted file mode 100644 index 8f03bcf..0000000 --- a/packages/explorer-view/src/parts/TreeToArray/TreeToArray.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { Tree } from '../Tree/Tree.ts' -import { treeToArrayInternal } from '../TreeToArrayInternal/TreeToArrayInternal.ts' - -export const treeToArray = (map: Tree, root: string): readonly ExplorerItem[] => { - const items: ExplorerItem[] = [] - treeToArrayInternal(map, root, items, '', 1) - return items -} diff --git a/packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts b/packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts deleted file mode 100644 index a2fc8e9..0000000 --- a/packages/explorer-view/src/parts/TreeToArrayInternal/TreeToArrayInternal.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { Tree } from '../Tree/Tree.ts' -import { join2 } from '../Path/Path.ts' - -export const treeToArrayInternal = (map: Tree, root: string, items: ExplorerItem[], path: string, depth: number): void => { - const children = map[path] - if (!children) { - return - } - const count = children.length - for (let i = 0; i < count; i++) { - const child = children[i] - const childPath = join2(path, child.name) - const absolutePath = join2(root, childPath) - items.push({ - depth, - icon: '', - name: child.name, - path: absolutePath, - posInSet: i + 1, - selected: false, - setSize: count, - type: child.type, - }) - treeToArrayInternal(map, root, items, childPath, depth + 1) - } -} diff --git a/packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts b/packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts deleted file mode 100644 index e09928e..0000000 --- a/packages/explorer-view/src/parts/TreeUpdate/TreeUpdate.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface TreeUpdate { - [key: string]: readonly any[] -} diff --git a/packages/explorer-view/src/parts/UiStrings/UiStrings.ts b/packages/explorer-view/src/parts/UiStrings/UiStrings.ts deleted file mode 100644 index 0a504d6..0000000 --- a/packages/explorer-view/src/parts/UiStrings/UiStrings.ts +++ /dev/null @@ -1,34 +0,0 @@ -export const CollapseAllFoldersInExplorer = 'Collapse All Folders in Explorer' -export const Copy = 'Copy' -export const CopyPath = 'Copy Path' -export const CopyRelativePath = 'Copy Relative Path' -export const CompareWithSelected = 'Compare with Selected' -export const Cut = 'Cut' -export const Delete = 'Delete' -export const DeleteConfirmationMultiple = 'Are you sure you want to delete {0} items?' -export const DeleteConfirmationSingle = 'Are you sure you want to delete "{0}"?' -export const Explorer = 'Explorer' -export const FileNameCannotStartWithSlash = 'A file or folder name cannot start with a slash.' -export const FileOrFolderAlreadyExists = 'A file or folder **{PH1}** already exists at this location. Please choose a different name.' -export const FileOrFolderNameMustBeProvider = 'A file or folder name must be provided.' -export const FileCannotStartWithSlash = 'A file cannot start with slash.' -export const FileCannotStartWithDot = 'A file or folder name cannot start with a dot.' -export const FileCannotStartWithBackSlash = 'A file or folder name cannot start with a backslash.' -export const FilesExplorer = 'Files Explorer' -export const LeadingOrTrailingWhitespaceDetected = 'Leading or trailing whitespace detected in file or folder name.' -export const NewFile = 'New File...' -export const NewFolder = 'New Folder...' -export const NoFolderOpen = 'No Folder Open' -export const OpenAnotherFolder = 'Open another folder' -export const OpenContainingFolder = 'Open Containing Folder' -export const OpenFolder = 'Open folder' -export const OpenInIntegratedTerminal = 'Open in integrated Terminal' -export const Paste = 'Paste' -export const PasteConfirmation = 'Are you sure you want to paste these files?' -export const RefreshExplorer = 'Refresh Explorer' -export const RemoveFolderFromWorkspace = 'Remove folder from workspace' -export const Rename = 'Rename' -export const SelectForCompare = 'Select for Compare' -export const TheNameIsNotValid = 'The name **{0}** is not valid as a file or folder name. Please choose a different name.' -export const TypeAFileName = 'Type file name. Press Enter to confirm or Escape to cancel.' // TODO use keybinding -export const YouHaveNotYetOpenedAFolder = 'You have not yet opened a folder.' diff --git a/packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts b/packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts deleted file mode 100644 index a8ecb9c..0000000 --- a/packages/explorer-view/src/parts/UpdateDirentsAtPath/UpdateDirentsAtPath.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { RawDirent } from '../RawDirent/RawDirent.ts' -import * as CompareDirent from '../CompareDirent/CompareDirent.ts' -import { createTree } from '../CreateTree/CreateTree.ts' -import { join2 } from '../Path/Path.ts' -import { treeToArray } from '../TreeToArray/TreeToArray.ts' - -export const updateDirentsAtPath = ( - items: readonly ExplorerItem[], - path: string, - root: string, - newDirents: readonly RawDirent[], -): readonly ExplorerItem[] => { - const sortedDirents = newDirents - .map((dirent, index) => ({ - depth: 0, // TODO - icon: '', - name: dirent.name, - path: join2(path, dirent.name), - posInSet: index + 1, - selected: false, - setSize: newDirents.length, - type: dirent.type, - })) - .toSorted(CompareDirent.compareDirent) - - const tree = createTree(items, root) - const updatedTree = { - ...tree, - [path]: sortedDirents, - } - const newItems = treeToArray(updatedTree, root) - return newItems -} diff --git a/packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts b/packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts deleted file mode 100644 index 5a456c6..0000000 --- a/packages/explorer-view/src/parts/UpdateEditingValue/UpdateEditingValue.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as ExplorerEditingType from '../ExplorerEditingType/ExplorerEditingType.ts' -import { getEditingIcon } from '../GetEditingIcon/GetEditingIcon.ts' -import { getSiblingFileNames } from '../GetSiblingFileNames/GetSiblingFileNames.ts' -import * as InputSource from '../InputSource/InputSource.ts' -import * as ValidateFileName2 from '../ValidateFileName2/ValidateFileName2.ts' - -export const updateEditingValue = async (state: ExplorerState, value: string, inputSource: number = InputSource.User): Promise => { - const { editingIndex, editingType, focusedIndex, items, pathSeparator, root } = state - const editingIcon = await getEditingIcon(editingType, value, items[editingIndex]?.type) - - // Get sibling file names for validation during file/folder creation - let siblingFileNames: readonly string[] = [] - if (editingType === ExplorerEditingType.CreateFile || editingType === ExplorerEditingType.CreateFolder) { - siblingFileNames = getSiblingFileNames(items, focusedIndex, root, pathSeparator) - } - - const editingErrorMessage = ValidateFileName2.validateFileName2(value, siblingFileNames) - return { - ...state, - editingErrorMessage, - editingIcon, - editingValue: value, - } -} diff --git a/packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts b/packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts deleted file mode 100644 index b9adeca..0000000 --- a/packages/explorer-view/src/parts/UpdateExplorerAfterFileOperations/UpdateExplorerAfterFileOperations.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import { createTree } from '../CreateTree/CreateTree.ts' -import * as GetFileIcons from '../GetFileIcons/GetFileIcons.ts' -import * as GetIndex from '../GetIndex/GetIndex.ts' -import * as GetExplorerMaxLineY from '../GetMaxLineY/GetMaxLineY.ts' -import { getParentFolder } from '../GetParentFolder/GetParentFolder.ts' -import { getPathParts } from '../GetPathParts/GetPathParts.ts' -import { getPathPartsChildren } from '../GetPathPartsChildren/GetPathPartsChildren.ts' -import { mergeTrees } from '../MergeTrees/MergeTrees.ts' -import { join2 } from '../Path/Path.ts' -import { treeToArray } from '../TreeToArray/TreeToArray.ts' - -export interface ExplorerUpdateResult { - readonly newFileIconCache: FileIconCache - readonly newFocusedIndex: number - readonly newIcons: readonly string[] - readonly newItems: readonly ExplorerItem[] - readonly newMaxLineY: number - readonly newMinLineY: number -} - -export const updateExplorerAfterFileOperations = async ( - state: ExplorerState, - operations: readonly FileOperation[], -): Promise => { - const { editingValue, fileIconCache, focusedIndex, height, itemHeight, items, minLineY, pathSeparator, root } = state - const newFileName = editingValue - const parentFolder = getParentFolder(items, focusedIndex, root, pathSeparator) - const absolutePath = join2(parentFolder, newFileName) - - // TODO based on operations, find out which paths need to be updated - // then read the direcories that need to be updated - // and update the explorer - const pathPaths = getPathParts(root, absolutePath, pathSeparator) - const children = await getPathPartsChildren(pathPaths) - const tree = createTree(items, root) - const childTree = createTree(children, root) - const merged = mergeTrees(tree, childTree) - const newItems = treeToArray(merged, root) - const dirents = newItems - const newFocusedIndex = GetIndex.getIndex(newItems, absolutePath) - const maxLineY = GetExplorerMaxLineY.getExplorerMaxLineY(minLineY, height, itemHeight, dirents.length) - const visible = dirents.slice(minLineY, maxLineY) - const { icons, newFileIconCache } = await GetFileIcons.getFileIcons(visible, fileIconCache) - - return { - newFileIconCache, - newFocusedIndex, - newIcons: icons, - newItems: dirents, - newMaxLineY: maxLineY, - newMinLineY: minLineY, - } -} diff --git a/packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts b/packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts deleted file mode 100644 index ace7194..0000000 --- a/packages/explorer-view/src/parts/UpdateIconCache/UpdateIconCache.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { FileIconCache } from '../FileIconCache/FileIconCache.ts' -import type { IconRequest } from '../IconRequest/IconRequest.ts' - -export const updateIconCache = (iconCache: FileIconCache, missingRequests: readonly IconRequest[], newIcons: readonly string[]): FileIconCache => { - if (missingRequests.length === 0) { - return iconCache - } - const newFileIconCache = { ...iconCache } - for (let i = 0; i < missingRequests.length; i++) { - const request = missingRequests[i] - const icon = newIcons[i] - newFileIconCache[request.path] = icon - } - return newFileIconCache -} diff --git a/packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts b/packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts deleted file mode 100644 index fff10de..0000000 --- a/packages/explorer-view/src/parts/UpdateIcons/UpdateIcons.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import * as GetFileIcons from '../GetFileIcons/GetFileIcons.ts' - -export const updateIcons = async (state: ExplorerState): Promise => { - const { items, maxLineY, minLineY } = state - const visible = items.slice(minLineY, maxLineY) - const { icons, newFileIconCache } = await GetFileIcons.getFileIcons(visible, Object.create(null)) - return { - ...state, - fileIconCache: newFileIconCache, - icons, - } -} diff --git a/packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts b/packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts deleted file mode 100644 index 80a7683..0000000 --- a/packages/explorer-view/src/parts/UpdateRoot/UpdateRoot.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ExplorerState } from '../ExplorerState/ExplorerState.ts' -import { getTopLevelDirents } from '../GetTopLevelDirents/GetTopLevelDirents.ts' -import { mergeDirents } from '../MergeDirents/MergeDirents.ts' - -// TODO add lots of tests for this -export const updateRoot = async (state1: ExplorerState): Promise => { - // @ts-ignore - if (state1.disposed) { - return state1 - } - // const file = nativeFiles.files[0] - const topLevelDirents = await getTopLevelDirents(state1.root, state1.pathSeparator, []) - // const state2 = Viewlet.getState('Explorer') - // // TODO what if root changes while reading directories? - // if (state2.disposed || state2.root !== state1.root) { - // return state2 - // } - const newDirents = mergeDirents(state1.items, topLevelDirents) - const state3 = { - ...state1, - items: newDirents, - } - return state3 -} diff --git a/packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts b/packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts deleted file mode 100644 index 2467584..0000000 --- a/packages/explorer-view/src/parts/UpdateTree/UpdateTree.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const updateTree = ( - tree: Record, - path: string, - newDirents: readonly ExplorerItem[], -): Record => { - const updatedTree = { - ...tree, - [path]: newDirents, - } - return updatedTree -} diff --git a/packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts b/packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts deleted file mode 100644 index 62ee59b..0000000 --- a/packages/explorer-view/src/parts/UpdateTree2/UpdateTree2.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ExplorerItem } from '../ExplorerItem/ExplorerItem.ts' - -export const updateTree2 = ( - tree: Record, - update: Record, -): Record => { - const updatedTree = { - ...tree, - ...update, - } - return updatedTree -} diff --git a/packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts b/packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts deleted file mode 100644 index 602ee02..0000000 --- a/packages/explorer-view/src/parts/UploadFileSystemHandles/UploadFileSystemHandles.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as ApplyFileOperations from '../ApplyFileOperations/ApplyFileOperations.ts' -import { createUploadTree } from '../CreateUploadTree/CreateUploadTree.ts' -import * as GetFileOperations from '../GetFileOperations/GetFileOperations.ts' - -export interface DroppedFileItem { - readonly kind: 'file' - readonly value: FileSystemFileHandle -} - -export type DroppedItem = DroppedFileItem | FileSystemHandle -export type DroppedArgs = readonly DroppedFileItem[] | readonly FileSystemHandle[] - -export const isDroppedFile = (item: DroppedItem): item is DroppedFileItem => { - return item.kind === 'file' && 'value' in item -} - -export const getFileSystemHandle = (item: DroppedItem): FileSystemHandle => { - if (isDroppedFile(item)) { - return item.value - } - return item -} - -export const getDroppedName = (item: DroppedItem): string => { - if (isDroppedFile(item)) { - return item.value.name - } - return item.name -} - -const getFileSystemHandlesNormalized = (fileSystemHandles: DroppedArgs): readonly FileSystemHandle[] => { - const normalized: FileSystemHandle[] = [] - for (const item of fileSystemHandles) { - normalized.push(getFileSystemHandle(item)) - } - return normalized -} - -export const uploadFileSystemHandles = async (root: string, pathSeparator: string, fileSystemHandles: DroppedArgs): Promise => { - if (fileSystemHandles.length === 0) { - return true - } - const fileSystemHandlesNormalized = getFileSystemHandlesNormalized(fileSystemHandles) - const uploadTree = await createUploadTree(root, fileSystemHandlesNormalized) - const fileOperations = GetFileOperations.getFileOperations(root, uploadTree) - await ApplyFileOperations.applyFileOperations(fileOperations) - - // TODO - // 1. in electron, use webutils.getPathForFile to see if a path is available - // 2. else, walk all files and folders recursively and upload all of them (if there are many, show a progress bar) - - // TODO send file system operations to renderer worker - return true -} diff --git a/packages/explorer-view/src/parts/VError/VError.ts b/packages/explorer-view/src/parts/VError/VError.ts deleted file mode 100644 index a261b97..0000000 --- a/packages/explorer-view/src/parts/VError/VError.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@lvce-editor/verror' diff --git a/packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts b/packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts deleted file mode 100644 index a80700f..0000000 --- a/packages/explorer-view/src/parts/ValidateFileName/ValidateFileName.ts +++ /dev/null @@ -1,150 +0,0 @@ -// copied from https://github.com/microsoft/vscode/blob/85925efe02b1be4671c5f37af8386a75a8b35ecc/src/vs/workbench/contrib/files/browser/fileActions.ts by Microsoft (License MIT) -// as well as from https://github.com/microsoft/vscode/blob/b012ab96ad1677c00d3061cf7f20953b57b393a5/src/vs/base/common/strings.ts by Microsoft (License MIT) - -import type { ValidateFileNameResult } from '../ValidateFileNameResult/ValidateFileNameResult.ts' -import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' -import { hasLeadingOrTrailingWhitespace } from '../HasLeadingOrTrailingWhitespace/HasLeadingOrTrailingWhitespace.ts' -import { isValidBasename } from '../IsValidBaseName/IsValidBaseName.ts' -import * as Severity from '../Severity/Severity.ts' - -/** - * @returns New array with all falsy values removed. The original array IS NOT modified. - */ -export function coalesce(array: ReadonlyArray): T[] { - return array.filter((e): e is T => !!e) -} - -/** - * Removes all occurrences of needle from the beginning and end of haystack. - * @param haystack string to trim - * @param needle the thing to trim (default is a blank) - */ -export function trim(haystack: string, needle: string = ' '): string { - const trimmed = ltrim(haystack, needle) - return rtrim(trimmed, needle) -} - -/** - * Removes all occurrences of needle from the beginning of haystack. - * @param haystack string to trim - * @param needle the thing to trim - */ -export function ltrim(haystack: string, needle: string): string { - if (!haystack || !needle) { - return haystack - } - - const needleLen = needle.length - if (needleLen === 0 || haystack.length === 0) { - return haystack - } - - let offset = 0 - - while (haystack.indexOf(needle, offset) === offset) { - offset = offset + needleLen - } - return haystack.slice(Math.max(0, offset)) -} - -/** - * Removes all occurrences of needle from the end of haystack. - * @param haystack string to trim - * @param needle the thing to trim - */ -export function rtrim(haystack: string, needle: string): string { - if (!haystack || !needle) { - return haystack - } - - const needleLen = needle.length, - haystackLen = haystack.length - - if (needleLen === 0 || haystackLen === 0) { - return haystack - } - - let offset = haystackLen - - while (true) { - const idx = haystack.lastIndexOf(needle, offset - 1) - if (idx === -1 || idx + needleLen !== offset) { - break - } - if (idx === 0) { - return '' - } - offset = idx - } - - return haystack.slice(0, Math.max(0, offset)) -} - -function getWellFormedFileName(filename: string): string { - if (!filename) { - return filename - } - - // Trim tabs - filename = trim(filename, '\t') - - // Remove trailing slashes - filename = rtrim(filename, '/') - filename = rtrim(filename, '\\') - - return filename -} - -export function validateFileName(name: string, existingName: string, siblingFileNames: readonly string[]): ValidateFileNameResult { - // Produce a well formed file name - name = getWellFormedFileName(name) - - // Name not provided - if (!name || name.length === 0 || /^\s+$/.test(name)) { - return { - content: ExplorerStrings.fileOrFolderNameMustBeProvided(), - severity: Severity.Error, - } - } - - // Relative paths only - if (name[0] === '/' || name[0] === '\\') { - return { - content: ExplorerStrings.fileNameCannotStartWithSlash(), - severity: Severity.Error, - } - } - - const names = coalesce(name.split(/[\\/]/)) - - if (name !== existingName) { - // Do not allow to overwrite existing file - const child = siblingFileNames.find((sibling) => sibling === name) - if (child) { - return { - content: ExplorerStrings.fileOrFolderAlreadyExists(name), - severity: Severity.Error, - } - } - } - - // Check for invalid file name. - if (names.some((folderName) => !isValidBasename(folderName, false))) { - return { - content: ExplorerStrings.theNameIsNotValid(), - severity: Severity.Error, - } - } - - if (names.some(hasLeadingOrTrailingWhitespace)) { - return { - content: ExplorerStrings.leadingOrTrailingWhitespaceDetected(), - severity: Severity.Warning, - } - } - - return { - content: '', - severity: 0, - } -} diff --git a/packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts b/packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts deleted file mode 100644 index 5c5e0a3..0000000 --- a/packages/explorer-view/src/parts/ValidateFileName2/ValidateFileName2.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as Character from '../Character/Character.ts' -import * as ExplorerStrings from '../ExplorerStrings/ExplorerStrings.ts' - -export const validateFileName2 = (name: string, siblingFileNames: readonly string[] = []): string => { - if (!name) { - const editingErrorMessage = ExplorerStrings.fileOrFolderNameMustBeProvided() - return editingErrorMessage - } - if (name.startsWith(Character.Slash)) { - return ExplorerStrings.fileCannotStartWithSlash() - } - if (name.startsWith(Character.BackSlash)) { - return ExplorerStrings.fileCannotStartWithBackSlash() - } - - // Disallow reserved directory names - if (name === '.' || name === '..' || name === '...') { - return ExplorerStrings.theNameIsNotValid() - } - - // Disallow any filename starting with ../ - if (name.startsWith('../')) { - return ExplorerStrings.theNameIsNotValid() - } - - // Check if file already exists - if (siblingFileNames.includes(name)) { - return ExplorerStrings.fileOrFolderAlreadyExists(name) - } - - return '' -} diff --git a/packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts b/packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts deleted file mode 100644 index 093eab9..0000000 --- a/packages/explorer-view/src/parts/ValidateFileNameResult/ValidateFileNameResult.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ValidateFileNameResult { - readonly content: string - readonly severity: number -} diff --git a/packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts b/packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts deleted file mode 100644 index ee19a40..0000000 --- a/packages/explorer-view/src/parts/ValidateFolderCopy/ValidateFolderCopy.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as Path from '../Path/Path.ts' - -export const validateFolderCopy = (sourcePath: string, targetPath: string): string | null => { - // Remove trailing separators for comparison - const normalizedSource = sourcePath.replace(/[/\\]+$/, '') - const normalizedTarget = targetPath.replace(/[/\\]+$/, '') - - // Check if the target path is a subfolder of the source path - if (normalizedTarget.startsWith(normalizedSource + '/') || normalizedTarget.startsWith(normalizedSource + '\\')) { - // Extract folder name using the appropriate path separator - const pathSeparator = normalizedSource.includes('\\') ? '\\' : '/' - const folderName = Path.getBaseName(pathSeparator, normalizedSource) - return `Cannot copy folder ${folderName} into a subfolder of itself` - } - - return null -} diff --git a/packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts b/packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts deleted file mode 100644 index a6ba1a3..0000000 --- a/packages/explorer-view/src/parts/ValidateOperations/ValidateOperations.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { FileOperation } from '../FileOperation/FileOperation.ts' -import * as FileOperationType from '../FileOperationType/FileOperationType.ts' -import * as ValidateFolderCopy from '../ValidateFolderCopy/ValidateFolderCopy.ts' - -export const validateOperations = (operations: readonly FileOperation[]): readonly string[] => { - const errors: string[] = [] - for (const operation of operations) { - if (operation.type === FileOperationType.Copy) { - const errorMessage = ValidateFolderCopy.validateFolderCopy(operation.from, operation.path) - if (errorMessage) { - errors.push(errorMessage) - } - } - } - return errors -} diff --git a/packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts b/packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts deleted file mode 100644 index 9543643..0000000 --- a/packages/explorer-view/src/parts/ViewletAction/ViewletAction.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface ViewletAction { - readonly badgeText?: string - readonly command: string - readonly icon?: string - readonly id: string - readonly name?: string - readonly placeholder?: string - readonly type: number - readonly value?: string -} diff --git a/packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts b/packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts deleted file mode 100644 index 87d8651..0000000 --- a/packages/explorer-view/src/parts/VirtualDomElements/VirtualDomElements.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const Button = 1 -export const Div = 4 -export const Input = 6 -export const Img = 17 -export const P = 50 diff --git a/packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts b/packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts deleted file mode 100644 index b16588a..0000000 --- a/packages/explorer-view/src/parts/VirtualDomHelpers/VirtualDomHelpers.ts +++ /dev/null @@ -1 +0,0 @@ -export { text } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts b/packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts deleted file mode 100644 index c8af396..0000000 --- a/packages/explorer-view/src/parts/VirtualDomNode/VirtualDomNode.ts +++ /dev/null @@ -1 +0,0 @@ -export type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker' diff --git a/packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts b/packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts deleted file mode 100644 index f590d17..0000000 --- a/packages/explorer-view/src/parts/VisibleExplorerItem/VisibleExplorerItem.ts +++ /dev/null @@ -1,20 +0,0 @@ -export interface VisibleExplorerItem { - readonly ariaExpanded: string | undefined // TODO make it always string - readonly chevron: number - readonly className: string - readonly decoration?: string - readonly depth: number - readonly hasEditingError: boolean - readonly icon: string - readonly id: string | undefined // TODO make it always string - readonly indent: number - readonly index: number - readonly isCut: boolean - readonly isEditing: boolean - readonly isIgnored: boolean - readonly name: string - readonly path: string - readonly posInSet: number - readonly selected: boolean - readonly setSize: number -} diff --git a/packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts b/packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts deleted file mode 100644 index faaebcc..0000000 --- a/packages/explorer-view/src/parts/WhenExpression/WhenExpression.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const FocusExplorer = 13 -export const FocusExplorerEditBox = 14 diff --git a/packages/server/package.json b/packages/server/package.json index 4b6f5ee..bdf7068 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -4,7 +4,6 @@ "main": "index.js", "type": "module", "scripts": { - "postinstall": "node src/postinstall.js", "dev": "node ./node_modules/@lvce-editor/server/bin/server.js --test-path=../e2e" }, "keywords": [], diff --git a/packages/server/src/postinstall.js b/packages/server/src/postinstall.js deleted file mode 100644 index 03c4559..0000000 --- a/packages/server/src/postinstall.js +++ /dev/null @@ -1,39 +0,0 @@ -import { readFile, readdir, writeFile } from 'node:fs/promises' -import { join } from 'node:path' -import { pathToFileURL } from 'node:url' - -const __dirname = import.meta.dirname - -const root = join(__dirname, '..', '..', '..') - -export const getRemoteUrl = (path) => { - const url = pathToFileURL(path).toString().slice(8) - return `/remote/${url}` -} - -const nodeModulesPath = join(root, 'packages', 'server', 'node_modules') - -const workerPath = join(root, '.tmp', 'dist', 'dist', 'explorerViewWorkerMain.js') - -const serverStaticPath = join(nodeModulesPath, '@lvce-editor', 'static-server', 'static') - -const RE_COMMIT_HASH = /^[a-z\d]+$/ -const isCommitHash = (dirent) => { - return dirent.length === 7 && dirent.match(RE_COMMIT_HASH) -} - -const dirents = await readdir(serverStaticPath) -const commitHash = dirents.find(isCommitHash) || '' -const rendererWorkerMainPath = join(serverStaticPath, commitHash, 'packages', 'renderer-worker', 'dist', 'rendererWorkerMain.js') - -const content = await readFile(rendererWorkerMainPath, 'utf-8') - -const remoteUrl = getRemoteUrl(workerPath) -if (!content.includes('// const explorerWorkerUrl = ')) { - const occurrence = `const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\`` - const replacement = `// const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\` -const explorerWorkerUrl = \`${remoteUrl}\`` - - const newContent = content.replace(occurrence, replacement) - await writeFile(rendererWorkerMainPath, newContent) -} From 8953c2312a6dd3ec3abf97031209dc404193107e Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:34:21 +0200 Subject: [PATCH 08/17] e2e --- package-lock.json | 14157 ---------------- package.json | 2 +- .../extension.json | 10 - .../main.js | 31 - .../extension.json | 10 - .../main.js | 33 - .../extension.json | 10 - .../main.js | 32 - .../extension.json | 10 - .../main.js | 30 - .../extension.json | 3 - .../main.js | 36 - .../extension.json | 3 - .../main.js | 36 - .../extension.json | 10 - .../main.js | 29 - .../fixtures/sample.icon-theme/extension.json | 8 - .../sample.icon-theme/icon-theme.json | 6 - .../sample.icon-theme/icons/default_file.svg | 3 - .../icons/default_folder.svg | 3 - .../extension.json | 10 - .../main.js | 50 - .../extension.json | 10 - .../main.js | 50 - .../extension.json | 10 - .../sample.source-control-decoration/main.js | 57 - ...t.explorer-accept-edit-when-not-editing.ts | 33 - .../e2e/src/viewlet.explorer-accessibility.ts | 69 - ...k-empty-space-clears-multiple-selection.ts | 27 - ...orer-click-empty-space-clears-selection.ts | 24 - .../e2e/src/viewlet.explorer-collapse-all.ts | 23 - ...orer-context-menu-compare-with-selected.ts | 21 - ...et.explorer-context-menu-copy-path-file.ts | 20 - ...et.explorer-context-menu-copy-path-root.ts | 19 - ...er-context-menu-copy-relative-path-file.ts | 20 - ...copy-relative-path-root-no-focused-item.ts | 20 - ...t-menu-create-file-error-already-exists.ts | 23 - ...menu-create-folder-error-already-exists.ts | 23 - ...rer-context-menu-delete-file-with-focus.ts | 24 - ...ewlet.explorer-context-menu-delete-file.ts | 24 - ...context-menu-paste-root-no-focused-item.ts | 27 - ...ntext-menu-remove-folder-from-workspace.ts | 17 - ...xplorer-context-menu-select-for-compare.ts | 20 - .../viewlet.explorer-copy-and-paste-file.ts | 31 - ...et.explorer-copy-and-paste-folder-error.ts | 22 - ...plorer-copy-and-paste-folder-with-items.ts | 34 - .../viewlet.explorer-copy-and-paste-folder.ts | 28 - ...let.explorer-copy-paste-error-scenarios.ts | 54 - .../src/viewlet.explorer-copy-path-empty.ts | 17 - .../src/viewlet.explorer-copy-path-file.ts | 20 - .../src/viewlet.explorer-copy-path-folder.ts | 18 - ...ewlet.explorer-create-file-blur-no-name.ts | 26 - .../src/viewlet.explorer-create-file-blur.ts | 26 - .../viewlet.explorer-create-file-cancel.ts | 27 - ...xplorer-create-file-different-languages.ts | 104 - ...er-create-file-double-click-empty-space.ts | 19 - ...plorer-create-file-error-already-exists.ts | 21 - ...r-file-name-cannot-start-with-backslash.ts | 29 - ...e-error-file-name-cannot-start-with-dot.ts | 29 - ...error-file-name-cannot-start-with-slash.ts | 29 - ...orer-create-file-error-no-name-provided.ts | 29 - ...mission-denied-escape-then-create-again.ts | 45 - ...-file-error-permission-denied-long-path.ts | 34 - ...rer-create-file-error-permission-denied.ts | 32 - ...explorer-create-file-explorer-collapses.ts | 23 - ...plorer-create-file-inside-closed-folder.ts | 27 - ...wlet.explorer-create-file-inside-folder.ts | 29 - .../viewlet.explorer-create-file-nested.ts | 35 - ...et.explorer-create-file-opens-in-editor.ts | 35 - ....explorer-create-file-starting-with-dot.ts | 27 - ...let.explorer-create-file-switch-folders.ts | 46 - ...plorer-create-file-when-file-is-focused.ts | 29 - ...plorer-create-file-with-emoji-extension.ts | 29 - ...viewlet.explorer-create-file-with-emoji.ts | 29 - ...lorer-create-file-with-greek-characters.ts | 29 - ...ewlet.explorer-create-file-with-newline.ts | 29 - ...rer-create-file-with-non-breaking-space.ts | 33 - ...iewlet.explorer-create-file-with-spaces.ts | 29 - .../e2e/src/viewlet.explorer-create-file.ts | 31 - ...explorer-create-folder-nested-150-times.ts | 53 - .../viewlet.explorer-create-folder-nested.ts | 33 - ...explorer-create-folder-with-backslashes.ts | 16 - .../e2e/src/viewlet.explorer-create-folder.ts | 29 - ...cut-and-paste-file-error-already-exists.ts | 33 - .../viewlet.explorer-cut-and-paste-file.ts | 36 - ...iewlet.explorer-cut-and-paste-two-files.ts | 39 - ...wlet.explorer-cut-and-paste-two-folders.ts | 39 - .../e2e/src/viewlet.explorer-cut-cancel.ts | 25 - .../viewlet.explorer-deeply-nested-folders.ts | 28 - ...et.explorer-delete-file-empty-workspace.ts | 16 - .../src/viewlet.explorer-delete-file-error.ts | 31 - ...et.explorer-delete-file-no-focused-item.ts | 21 - .../e2e/src/viewlet.explorer-delete-file.ts | 23 - ...ewlet.explorer-delete-folder-with-items.ts | 28 - .../e2e/src/viewlet.explorer-delete-folder.ts | 20 - .../src/viewlet.explorer-delete-last-file.ts | 18 - ....explorer-delete-multiple-files-at-once.ts | 28 - ...e-multiple-files-focuses-remaining-item.ts | 27 - .../viewlet.explorer-delete-multiple-files.ts | 58 - ...et.explorer-delete-nested-middle-folder.ts | 33 - ...wlet.explorer-drag-drop-error-scenarios.ts | 66 - .../viewlet.explorer-drag-file-into-folder.ts | 31 - ...orer-drop-empty-handles-empty-workspace.ts | 18 - ...er-drop-file-and-folder-empty-workspace.ts | 34 - ...wlet.explorer-drop-file-empty-workspace.ts | 23 - .../e2e/src/viewlet.explorer-drop-file.ts | 27 - ...et.explorer-drop-folder-empty-workspace.ts | 28 - ...viewlet.explorer-drop-folder-with-files.ts | 35 - .../e2e/src/viewlet.explorer-drop-folder.ts | 28 - ...plorer-drop-two-folders-empty-workspace.ts | 40 - .../src/viewlet.explorer-empty-workspace.ts | 23 - .../e2e/src/viewlet.explorer-expand-all.ts | 53 - scripts/update-dependencies.sh | 0 113 files changed, 1 insertion(+), 17256 deletions(-) delete mode 100644 package-lock.json delete mode 100644 packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json delete mode 100644 packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-permission/extension.json delete mode 100644 packages/e2e/fixtures/sample.file-system-provider-permission/main.js delete mode 100644 packages/e2e/fixtures/sample.icon-theme/extension.json delete mode 100644 packages/e2e/fixtures/sample.icon-theme/icon-theme.json delete mode 100644 packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg delete mode 100644 packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg delete mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json delete mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js delete mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json delete mode 100644 packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js delete mode 100644 packages/e2e/fixtures/sample.source-control-decoration/extension.json delete mode 100644 packages/e2e/fixtures/sample.source-control-decoration/main.js delete mode 100644 packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts delete mode 100644 packages/e2e/src/viewlet.explorer-accessibility.ts delete mode 100644 packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts delete mode 100644 packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts delete mode 100644 packages/e2e/src/viewlet.explorer-collapse-all.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-path-empty.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-path-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-copy-path-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-blur.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-cancel.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-different-languages.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-nested.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-newline.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-folder-nested.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts delete mode 100644 packages/e2e/src/viewlet.explorer-create-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts delete mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts delete mode 100644 packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts delete mode 100644 packages/e2e/src/viewlet.explorer-cut-cancel.ts delete mode 100644 packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-file-error.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-last-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-multiple-files.ts delete mode 100644 packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-empty-workspace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-expand-all.ts mode change 100644 => 100755 scripts/update-dependencies.sh diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 99c6ac9..0000000 --- a/package-lock.json +++ /dev/null @@ -1,14157 +0,0 @@ -{ - "name": "@lvce-editor/explorer-view-monorepo", - "version": "0.0.0-dev", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@lvce-editor/explorer-view-monorepo", - "version": "0.0.0-dev", - "hasInstallScript": true, - "license": "MIT", - "devDependencies": { - "@lerna/legacy-package-management": "^8.2.4", - "@lvce-editor/eslint-config": "^11.2.0", - "eslint": "^10.2.0", - "lerna": "^8.2.4", - "prettier": "^3.8.4", - "typescript": "^6.0.3" - } - }, - "node_modules/@altano/repository-tools": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@altano/repository-tools/-/repository-tools-2.0.3.tgz", - "integrity": "sha512-cSR/ZYDF6Wp9OeAJMyLYYN1GenAAhV17W+w38ELP+3c5Ltsy9jkkCymi33nz/qnXyef3n6Fbr1h2yt3dvUN5sQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@cspell/cspell-bundled-dicts": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-10.0.1.tgz", - "integrity": "sha512-WvkSDNX4Uyyj/ZgbPO6L38iFNMfK1EqsH1FteRiI2qLz6QZMXRFrIt12OqiWIplzZDDaVpBH9FCJOPJll0fjCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-ada": "^4.1.1", - "@cspell/dict-al": "^1.1.1", - "@cspell/dict-aws": "^4.0.17", - "@cspell/dict-bash": "^4.2.2", - "@cspell/dict-companies": "^3.2.11", - "@cspell/dict-cpp": "^7.0.2", - "@cspell/dict-cryptocurrencies": "^5.0.5", - "@cspell/dict-csharp": "^4.0.8", - "@cspell/dict-css": "^4.1.1", - "@cspell/dict-dart": "^2.3.2", - "@cspell/dict-data-science": "^2.0.13", - "@cspell/dict-django": "^4.1.6", - "@cspell/dict-docker": "^1.1.17", - "@cspell/dict-dotnet": "^5.0.13", - "@cspell/dict-elixir": "^4.0.8", - "@cspell/dict-en_us": "^4.4.33", - "@cspell/dict-en-common-misspellings": "^2.1.12", - "@cspell/dict-en-gb-mit": "^3.1.22", - "@cspell/dict-filetypes": "^3.0.18", - "@cspell/dict-flutter": "^1.1.1", - "@cspell/dict-fonts": "^4.0.6", - "@cspell/dict-fsharp": "^1.1.1", - "@cspell/dict-fullstack": "^3.2.9", - "@cspell/dict-gaming-terms": "^1.1.2", - "@cspell/dict-git": "^3.1.0", - "@cspell/dict-golang": "^6.0.26", - "@cspell/dict-google": "^1.0.9", - "@cspell/dict-haskell": "^4.0.6", - "@cspell/dict-html": "^4.0.15", - "@cspell/dict-html-symbol-entities": "^4.0.5", - "@cspell/dict-java": "^5.0.12", - "@cspell/dict-julia": "^1.1.1", - "@cspell/dict-k8s": "^1.0.12", - "@cspell/dict-kotlin": "^1.1.1", - "@cspell/dict-latex": "^5.1.0", - "@cspell/dict-lorem-ipsum": "^4.0.5", - "@cspell/dict-lua": "^4.0.8", - "@cspell/dict-makefile": "^1.0.5", - "@cspell/dict-markdown": "^2.0.16", - "@cspell/dict-monkeyc": "^1.0.12", - "@cspell/dict-node": "^5.0.9", - "@cspell/dict-npm": "^5.2.38", - "@cspell/dict-php": "^4.1.1", - "@cspell/dict-powershell": "^5.0.15", - "@cspell/dict-public-licenses": "^2.0.16", - "@cspell/dict-python": "^4.2.26", - "@cspell/dict-r": "^2.1.1", - "@cspell/dict-ruby": "^5.1.1", - "@cspell/dict-rust": "^4.1.2", - "@cspell/dict-scala": "^5.0.9", - "@cspell/dict-shell": "^1.1.2", - "@cspell/dict-software-terms": "^5.2.2", - "@cspell/dict-sql": "^2.2.1", - "@cspell/dict-svelte": "^1.0.7", - "@cspell/dict-swift": "^2.0.6", - "@cspell/dict-terraform": "^1.1.3", - "@cspell/dict-typescript": "^3.2.3", - "@cspell/dict-vue": "^3.0.5", - "@cspell/dict-zig": "^1.0.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-performance-monitor": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-performance-monitor/-/cspell-performance-monitor-10.0.1.tgz", - "integrity": "sha512-9tVcHXwRnbazUv4WSG0h3MqV4+LgmLNgSALAQUflPPW0EMxTf7C4Dmv9cgxJyCEQrdnVKCr58nPPaahhz9LJUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-pipe": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-10.0.1.tgz", - "integrity": "sha512-HPeXMD9AZ3V/qPkvQaPcak+C7cJ2z7JTHN8smd6J8L2aThLRky2cHc2OyeaHPSHB7WA47b4z2n5u5nawZhv5VQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-resolver": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-10.0.1.tgz", - "integrity": "sha512-PIzkZHD1fGUQx1XteK2d1iQ0Mzq/maYcoB4jkvAiiR6WqP3MWYNKFdI9z+R5pOq5KgMfW+5Ig1q0oSR6h8irlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "global-directory": "^5.0.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-service-bus": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-10.0.1.tgz", - "integrity": "sha512-y6NcIGP2IdXaBL4PVH8vxsr7K27wzz3Ech87UtUtrDSXAiVEOvXgAIknEOUVp59rTlUE8Rn4IRURC6f/hgMyfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-types": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-10.0.1.tgz", - "integrity": "sha512-kLgLShnWADDVreKC63pBrWkcvxgZzFIfO34Jhx/SWfuOIA3cD8AXT+HjyuLfoGJ7mUb58hv2kUziKzEy4INb1w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/dict-ada": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", - "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-al": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", - "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-aws": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.17.tgz", - "integrity": "sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-bash": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.3.tgz", - "integrity": "sha512-ljUZoKHbDqw5Sx0qpL2qTUlmkmr+vhZH/sCNrNaBZKTbdgiswErSnIF1jRbGmEitJNxHRHWsuZyVgnTGfVO1Yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-shell": "1.2.0" - } - }, - "node_modules/@cspell/dict-companies": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.11.tgz", - "integrity": "sha512-0cmafbcz2pTHXLd59eLR1gvDvN6aWAOM0+cIL4LLF9GX9yB2iKDNrKsvs4tJRqutoaTdwNFBbV0FYv+6iCtebQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cpp": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-7.0.2.tgz", - "integrity": "sha512-dfbeERiVNeqmo/npivdR6rDiBCqZi3QtjH2Z0HFcXwpdj6i97dX1xaKyK2GUsO/p4u1TOv63Dmj5Vm48haDpuA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cryptocurrencies": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", - "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-csharp": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.8.tgz", - "integrity": "sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-css": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.2.tgz", - "integrity": "sha512-+ylGoKdwZ2sVOCOnU2Eq5wDZx+RaVX3HoKyNHGGsFvhSw6IidQ6tH/mAPKBDofViHJoWCPNlklE0lTr6MDG3QA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-dart": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.2.tgz", - "integrity": "sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-data-science": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.14.tgz", - "integrity": "sha512-jl6Ds4u5u5JT+yY30pWQpAbdCHfy3lCcNkLbpL/AZKoUaLEoXbaYsps9xQtvD7DyaiXxiLZkdH2yHHXtoFtZyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-django": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.6.tgz", - "integrity": "sha512-SdbSFDGy9ulETqNz15oWv2+kpWLlk8DJYd573xhIkeRdcXOjskRuxjSZPKfW7O3NxN/KEf3gm3IevVOiNuFS+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-docker": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.17.tgz", - "integrity": "sha512-OcnVTIpHIYYKhztNTyK8ShAnXTfnqs43hVH6p0py0wlcwRIXe5uj4f12n7zPf2CeBI7JAlPjEsV0Rlf4hbz/xQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-dotnet": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.13.tgz", - "integrity": "sha512-xPp7jMnFpOri7tzmqmm/dXMolXz1t2bhNqxYkOyMqXhvs08oc7BFs+EsbDY0X7hqiISgeFZGNqn0dOCr+ncPYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-elixir": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.8.tgz", - "integrity": "sha512-CyfphrbMyl4Ms55Vzuj+mNmd693HjBFr9hvU+B2YbFEZprE5AG+EXLYTMRWrXbpds4AuZcvN3deM2XVB80BN/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-en_us": { - "version": "4.4.35", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.35.tgz", - "integrity": "sha512-xWpxBCc/FzzMMo/A+0qwARVaIIhR0Ql8yhhv4rvsvg+GfQF+LG9yzg2GwTM5N2rjvzmM3nKuR9zxFZq2I6fJSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-en-common-misspellings": { - "version": "2.1.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.1.12.tgz", - "integrity": "sha512-14Eu6QGqyksqOd4fYPuRb58lK1Va7FQK9XxFsRKnZU8LhL3N+kj7YKDW+7aIaAN/0WGEqslGP6lGbQzNti8Akw==", - "dev": true, - "license": "CC BY-SA 4.0" - }, - "node_modules/@cspell/dict-en-gb-mit": { - "version": "3.1.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb-mit/-/dict-en-gb-mit-3.1.24.tgz", - "integrity": "sha512-Oowb/Uzkh7OmDRdCcETzMc9imEb4IpLlHJXoYjX8A8DS2X/54gqSjI915JFB8hKtFjBko5OM0BLQ+6cZhFEMmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-filetypes": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.18.tgz", - "integrity": "sha512-yU7RKD/x1IWmDLzWeiItMwgV+6bUcU/af23uS0+uGiFUbsY1qWV/D4rxlAAO6Z7no3J2z8aZOkYIOvUrJq0Rcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-flutter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.1.tgz", - "integrity": "sha512-UlOzRcH2tNbFhZmHJN48Za/2/MEdRHl2BMkCWZBYs+30b91mWvBfzaN4IJQU7dUZtowKayVIF9FzvLZtZokc5A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fonts": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.6.tgz", - "integrity": "sha512-aR/0csY01dNb0A1tw/UmN9rKgHruUxsYsvXu6YlSBJFu60s26SKr/k1o4LavpHTQ+lznlYMqAvuxGkE4Flliqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fsharp": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.1.tgz", - "integrity": "sha512-imhs0u87wEA4/cYjgzS0tAyaJpwG7vwtC8UyMFbwpmtw+/bgss+osNfyqhYRyS/ehVCWL17Ewx2UPkexjKyaBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fullstack": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.9.tgz", - "integrity": "sha512-diZX+usW5aZ4/b2T0QM/H/Wl9aNMbdODa1Jq0ReBr/jazmNeWjd+PyqeVgzd1joEaHY+SAnjrf/i9CwKd2ZtWQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-gaming-terms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.2.tgz", - "integrity": "sha512-9XnOvaoTBscq0xuD6KTEIkk9hhdfBkkvJAIsvw3JMcnp1214OCGW8+kako5RqQ2vTZR3Tnf3pc57o7VgkM0q1Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-git": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.1.0.tgz", - "integrity": "sha512-KEt9zGkxqGy2q1nwH4CbyqTSv5nadpn8BAlDnzlRcnL0Xb3LX9xTgSGShKvzb0bw35lHoYyLWN2ZKAqbC4pgGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-golang": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.26.tgz", - "integrity": "sha512-YKA7Xm5KeOd14v5SQ4ll6afe9VSy3a2DWM7L9uBq4u3lXToRBQ1W5PRa+/Q9udd+DTURyVVnQ+7b9cnOlNxaRg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-google": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.9.tgz", - "integrity": "sha512-biL65POqialY0i4g6crj7pR6JnBkbsPovB2WDYkj3H4TuC/QXv7Pu5pdPxeUJA6TSCHI7T5twsO4VSVyRxD9CA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-haskell": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.6.tgz", - "integrity": "sha512-ib8SA5qgftExpYNjWhpYIgvDsZ/0wvKKxSP+kuSkkak520iPvTJumEpIE+qPcmJQo4NzdKMN8nEfaeci4OcFAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-html": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.15.tgz", - "integrity": "sha512-GJYnYKoD9fmo2OI0aySEGZOjThnx3upSUvV7mmqUu8oG+mGgzqm82P/f7OqsuvTaInZZwZbo+PwJQd/yHcyFIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-html-symbol-entities": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.5.tgz", - "integrity": "sha512-429alTD4cE0FIwpMucvSN35Ld87HCyuM8mF731KU5Rm4Je2SG6hmVx7nkBsLyrmH3sQukTcr1GaiZsiEg8svPA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-java": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.12.tgz", - "integrity": "sha512-qPSNhTcl7LGJ5Qp6VN71H8zqvRQK04S08T67knMq9hTA8U7G1sTKzLmBaDOFhq17vNX/+rT+rbRYp+B5Nwza1A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-julia": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.1.tgz", - "integrity": "sha512-WylJR9TQ2cgwd5BWEOfdO3zvDB+L7kYFm0I9u0s9jKHWQ6yKmfKeMjU9oXxTBxIufhCXm92SKwwVNAC7gjv+yA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-k8s": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.12.tgz", - "integrity": "sha512-2LcllTWgaTfYC7DmkMPOn9GsBWsA4DZdlun4po8s2ysTP7CPEnZc1ZfK6pZ2eI4TsZemlUQQ+NZxMe9/QutQxg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-kotlin": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.1.tgz", - "integrity": "sha512-J3NzzfgmxRvEeOe3qUXnSJQCd38i/dpF9/t3quuWh6gXM+krsAXP75dY1CzDmS8mrJAlBdVBeAW5eAZTD8g86Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-latex": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-5.1.0.tgz", - "integrity": "sha512-qxT4guhysyBt0gzoliXYEBYinkAdEtR2M7goRaUH0a7ltCsoqqAeEV8aXYRIdZGcV77gYSobvu3jJL038tlPAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-lorem-ipsum": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.5.tgz", - "integrity": "sha512-9a4TJYRcPWPBKkQAJ/whCu4uCAEgv/O2xAaZEI0n4y1/l18Yyx8pBKoIX5QuVXjjmKEkK7hi5SxyIsH7pFEK9Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-lua": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.8.tgz", - "integrity": "sha512-N4PkgNDMu9JVsRu7JBS/3E/dvfItRgk9w5ga2dKq+JupP2Y3lojNaAVFhXISh4Y0a6qXDn2clA6nvnavQ/jjLA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-makefile": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.5.tgz", - "integrity": "sha512-4vrVt7bGiK8Rx98tfRbYo42Xo2IstJkAF4tLLDMNQLkQ86msDlYSKG1ZCk8Abg+EdNcFAjNhXIiNO+w4KflGAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-markdown": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.17.tgz", - "integrity": "sha512-H8bAxih6U8NOnSPL7R8My+tqjaB4tmnJTjERuz4zYqmf+cH+5xshX3UVgKlwWFcyjsYfv/zEDuRdMctQv1q6HQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@cspell/dict-css": "^4.1.2", - "@cspell/dict-html": "^4.0.15", - "@cspell/dict-html-symbol-entities": "^4.0.5", - "@cspell/dict-typescript": "^3.2.3" - } - }, - "node_modules/@cspell/dict-monkeyc": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.12.tgz", - "integrity": "sha512-MN7Vs11TdP5mbdNFQP5x2Ac8zOBm97ARg6zM5Sb53YQt/eMvXOMvrep7+/+8NJXs0jkp70bBzjqU4APcqBFNAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-node": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.9.tgz", - "integrity": "sha512-hO+ga+uYZ/WA4OtiMEyKt5rDUlUyu3nXMf8KVEeqq2msYvAPdldKBGH7lGONg6R/rPhv53Rb+0Y1SLdoK1+7wQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-npm": { - "version": "5.2.41", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.41.tgz", - "integrity": "sha512-To3xsfRmMBYVXtWVEdUgV35M9a/JZ54dSuoY6m6D3uHKKL3I326Wmy4xifZ3PU8MQaWhyEH7zbIcUEtKwTQMcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-php": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.1.1.tgz", - "integrity": "sha512-EXelI+4AftmdIGtA8HL8kr4WlUE11OqCSVlnIgZekmTkEGSZdYnkFdiJ5IANSALtlQ1mghKjz+OFqVs6yowgWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-powershell": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.15.tgz", - "integrity": "sha512-l4S5PAcvCFcVDMJShrYD0X6Huv9dcsQPlsVsBGbH38wvuN7gS7+GxZFAjTNxDmTY1wrNi1cCatSg6Pu2BW4rgg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-public-licenses": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.16.tgz", - "integrity": "sha512-EQRrPvEOmwhwWezV+W7LjXbIBjiy6y/shrET6Qcpnk3XANTzfvWflf9PnJ5kId/oKWvihFy0za0AV1JHd03pSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-python": { - "version": "4.2.27", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.27.tgz", - "integrity": "sha512-Rj6xQgYS4X6ienjgAZF+njA0GRY4oSPouJWv0vfikCTn6EWlfk0V6Dy1HP3Migj1O+IC2NmespgVq+BZNSp8OA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-data-science": "^2.0.14" - } - }, - "node_modules/@cspell/dict-r": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.1.tgz", - "integrity": "sha512-71Ka+yKfG4ZHEMEmDxc6+blFkeTTvgKbKAbwiwQAuKl3zpqs1Y0vUtwW2N4b3LgmSPhV3ODVY0y4m5ofqDuKMw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-ruby": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.1.1.tgz", - "integrity": "sha512-LHrp84oEV6q1ZxPPyj4z+FdKyq1XAKYPtmGptrd+uwHbrF/Ns5+fy6gtSi7pS+uc0zk3JdO9w/tPK+8N1/7WUA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-rust": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.1.2.tgz", - "integrity": "sha512-O1FHrumYcO+HZti3dHfBPUdnDFkI+nbYK3pxYmiM1sr+G0ebOd6qchmswS0Wsc6ZdEVNiPYJY/gZQR6jfW3uOg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-scala": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.9.tgz", - "integrity": "sha512-AjVcVAELgllybr1zk93CJ5wSUNu/Zb5kIubymR/GAYkMyBdYFCZ3Zbwn4Zz8GJlFFAbazABGOu0JPVbeY59vGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-shell": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.2.0.tgz", - "integrity": "sha512-PVctvT22lJ49niMiakO8xieY7ELCAzjSqhejWR7bAMb5AZ9F4WDEs+XdGMnoVHWeXq7K5rcepLPmEJb+37zzIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-software-terms": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.2.2.tgz", - "integrity": "sha512-0CaYd6TAsKtEoA7tNswm1iptEblTzEe3UG8beG2cpSTHk7afWIVMtJLgXDv0f/Li67Lf3Z1Jf3JeXR7GsJ2TRw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-sql": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.1.tgz", - "integrity": "sha512-qDHF8MpAYCf4pWU8NKbnVGzkoxMNrFqBHyG/dgrlic5EQiKANCLELYtGlX5auIMDLmTf1inA0eNtv74tyRJ/vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-svelte": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.7.tgz", - "integrity": "sha512-hGZsGqP0WdzKkdpeVLBivRuSNzOTvN036EBmpOwxH+FTY2DuUH7ecW+cSaMwOgmq5JFSdTcbTNFlNC8HN8lhaQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-swift": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.6.tgz", - "integrity": "sha512-PnpNbrIbex2aqU1kMgwEKvCzgbkHtj3dlFLPMqW1vSniop7YxaDTtvTUO4zA++ugYAEL+UK8vYrBwDPTjjvSnA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-terraform": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.3.tgz", - "integrity": "sha512-gr6wxCydwSFyyBKhBA2xkENXtVFToheqYYGFvlMZXWjviynXmh+NK/JTvTCk/VHk3+lzbO9EEQKee6VjrAUSbA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-typescript": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz", - "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-vue": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.5.tgz", - "integrity": "sha512-Mqutb8jbM+kIcywuPQCCaK5qQHTdaByoEO2J9LKFy3sqAdiBogNkrplqUK0HyyRFgCfbJUgjz3N85iCMcWH0JA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-zig": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-zig/-/dict-zig-1.0.0.tgz", - "integrity": "sha512-XibBIxBlVosU06+M6uHWkFeT0/pW5WajDRYdXG2CgHnq85b0TI/Ks0FuBJykmsgi2CAD3Qtx8UHFEtl/DSFnAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dynamic-import": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-10.0.1.tgz", - "integrity": "sha512-mP1gdq00aIcH8HxNMqnH11X6BKxLcneDtFgl/ecjIKnaGKwi44m8AndP5Kr4ODaYdl8UUw9O3dJh7KaQXnLHZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "10.0.1", - "import-meta-resolve": "^4.2.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/eslint-plugin": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/eslint-plugin/-/eslint-plugin-10.0.1.tgz", - "integrity": "sha512-VgRVWIWyM5bz2d7eC3/F4ON1fhMdrFB0R6slXmJewDDbJMDloSsMsWCSktiFET3a0TX/DTjOGGDzBN9tqGDGPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-types": "10.0.1", - "@cspell/url": "10.0.1", - "cspell-lib": "10.0.1", - "synckit": "^0.11.13" - }, - "engines": { - "node": ">=22.18.0" - }, - "peerDependencies": { - "eslint": "^8 || ^9 || ^10" - } - }, - "node_modules/@cspell/filetypes": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-10.0.1.tgz", - "integrity": "sha512-Z5S35giU5IW49fBBq6BksUbE8PC4IYPfaKuwl5Nl9jkf/OkAKiBmCowKX45NzRUQInwK/GSqqIUifrNeI6LdLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/rpc": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/rpc/-/rpc-10.0.1.tgz", - "integrity": "sha512-axSRKv3zEAmBm66iD/FV/MPmE4/Yf7c3PZiwTW894Yd3iEhtn3KPKeTrqQ2/tDrhB1Z2qTsap/Hue0MK4o5WXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/strong-weak-map": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-10.0.1.tgz", - "integrity": "sha512-lenN1DVyPi8nJLSMSJJ670ddTjyiruLueuSZO1qLcxBqUhgxDt/mALu9N/1m6WdOVcg6m/5cLiZVg2KOo2UzRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/url": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/url/-/url-10.0.1.tgz", - "integrity": "sha512-abYYgI29wJhWIfWTYrYuzRYDcHQUQ1N5ylnhxYn1NJnIQMqUWGLbDmt12JABtZ+R6h6UNatQrS7rhP86etvJyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@e18e/eslint-plugin": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@e18e/eslint-plugin/-/eslint-plugin-0.5.1.tgz", - "integrity": "sha512-mqUozeyNI9xvJbjrOO7y765dT7Kud3bwCm/DHwctxdEngPdJWQaS9BNGgpM1wCCzZfOtlKQh4ZRhm3VRomT9KA==", - "dev": true, - "license": "MIT", - "dependencies": { - "empathic": "^2.0.1", - "module-replacements": "^3.0.0-beta.8", - "semver": "^7.8.2" - }, - "peerDependencies": { - "eslint": "^9.0.0 || ^10.0.0", - "oxlint": "^1.68.0" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "oxlint": { - "optional": true - } - } - }, - "node_modules/@e18e/eslint-plugin/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", - "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.5", - "debug": "^4.3.1", - "minimatch": "^10.2.4" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/config-array/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", - "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/core": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", - "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/css": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/css/-/css-1.3.0.tgz", - "integrity": "sha512-MwY657chvFQWtXmO86syZgD+JpWlzDq7VkKZyi65PwHDbhELQPMzPXh5s8rhrjptG6FCuls0puCmlXk66+14uA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1", - "@eslint/css-tree": "^4.0.4", - "@eslint/plugin-kit": "^0.7.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/css-tree": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-4.0.4.tgz", - "integrity": "sha512-nxMparyhqVWQvadx9x8dIfubfIPOE+X2b2waua8fzdnM9vdp9rgVtwEZlG0TmCwEUz/d/f40fzvO/eqBwdxz0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdn-data": "2.28.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/js": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", - "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "eslint": "^10.0.0" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/@eslint/json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@eslint/json/-/json-2.0.0.tgz", - "integrity": "sha512-P32ZJMIopNWQd1SFhd0tgjfA/hgzUuVSqHmMi2273QaLWHWimXq6V+qL4DNKnjGzO/aNECtYW+rEJ/pWB6uP+w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.1", - "@humanwhocodes/momoa": "^3.3.10", - "natural-compare": "^1.4.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/markdown": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@eslint/markdown/-/markdown-8.0.2.tgz", - "integrity": "sha512-W+/0qHp0WbvFEljUvvECNpSWrUHpBWIWwp7F3QqEwQKmaRCmfEWvk6VfUia9pTQ0th6HyBGBsPfg/kG3/aQxLA==", - "dev": true, - "license": "MIT", - "workspaces": [ - "examples/*" - ], - "dependencies": { - "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.1", - "github-slugger": "^2.0.0", - "mdast-util-from-markdown": "^2.0.2", - "mdast-util-frontmatter": "^2.0.1", - "mdast-util-gfm": "^3.1.0", - "mdast-util-math": "^3.0.0", - "micromark-extension-frontmatter": "^2.0.0", - "micromark-extension-gfm": "^3.0.0", - "micromark-extension-math": "^3.1.0", - "micromark-util-normalize-identifier": "^2.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/object-schema": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", - "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", - "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1", - "levn": "^0.4.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/momoa": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.10.tgz", - "integrity": "sha512-KWiFQpSAqEIyrTXko3hFNLeQvSK8zXlJQzhhxsyVn58WFRYXST99b3Nqnu+ttOtjds2Pl2grUHGpe2NzhPynuQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@hutson/parse-repository-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", - "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/@jest/diff-sequences": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", - "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lerna/create": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.2.4.tgz", - "integrity": "sha512-A8AlzetnS2WIuhijdAzKUyFpR5YbLLfV3luQ4lzBgIBgRfuoBDZeF+RSZPhra+7A6/zTUlrbhKZIOi/MNhqgvQ==", - "deprecated": "This package is an implementation detail of Lerna and is no longer published separately.", - "dev": true, - "license": "MIT", - "dependencies": { - "@npmcli/arborist": "7.5.4", - "@npmcli/package-json": "5.2.0", - "@npmcli/run-script": "8.1.0", - "@nx/devkit": ">=17.1.2 < 21", - "@octokit/plugin-enterprise-rest": "6.0.1", - "@octokit/rest": "20.1.2", - "aproba": "2.0.0", - "byte-size": "8.1.1", - "chalk": "4.1.0", - "clone-deep": "4.0.1", - "cmd-shim": "6.0.3", - "color-support": "1.1.3", - "columnify": "1.6.0", - "console-control-strings": "^1.1.0", - "conventional-changelog-core": "5.0.1", - "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "9.0.0", - "dedent": "1.5.3", - "execa": "5.0.0", - "fs-extra": "^11.2.0", - "get-stream": "6.0.0", - "git-url-parse": "14.0.0", - "glob-parent": "6.0.2", - "graceful-fs": "4.2.11", - "has-unicode": "2.0.1", - "ini": "^1.3.8", - "init-package-json": "6.0.3", - "inquirer": "^8.2.4", - "is-ci": "3.0.1", - "is-stream": "2.0.0", - "js-yaml": "4.1.0", - "libnpmpublish": "9.0.9", - "load-json-file": "6.2.0", - "make-dir": "4.0.0", - "minimatch": "3.0.5", - "multimatch": "5.0.0", - "node-fetch": "2.6.7", - "npm-package-arg": "11.0.2", - "npm-packlist": "8.0.2", - "npm-registry-fetch": "^17.1.0", - "nx": ">=17.1.2 < 21", - "p-map": "4.0.0", - "p-map-series": "2.1.0", - "p-queue": "6.6.2", - "p-reduce": "^2.1.0", - "pacote": "^18.0.6", - "pify": "5.0.0", - "read-cmd-shim": "4.0.0", - "resolve-from": "5.0.0", - "rimraf": "^4.4.1", - "semver": "^7.3.4", - "set-blocking": "^2.0.0", - "signal-exit": "3.0.7", - "slash": "^3.0.0", - "ssri": "^10.0.6", - "string-width": "^4.2.3", - "tar": "6.2.1", - "temp-dir": "1.0.0", - "through": "2.3.8", - "tinyglobby": "0.2.12", - "upath": "2.0.1", - "uuid": "^10.0.0", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "5.0.1", - "wide-align": "1.1.5", - "write-file-atomic": "5.0.1", - "write-pkg": "4.0.0", - "yargs": "17.7.2", - "yargs-parser": "21.1.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-darwin-arm64": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.8.4.tgz", - "integrity": "sha512-8Y7+4wj1qoZsuDRpnuiHzSIsMt3VqtJ0su8dgd/MyGccvvi4pndan2R5yTiVw/wmbMxtBmZ6PO6Z8dgSIrMVog==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-darwin-x64": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.8.4.tgz", - "integrity": "sha512-2lfuxRc56QWnAysMhcD03tpCPiRzV1+foUq0MhV2sSBIybXmgV4wHLkPZNhlBCl4FNXrWiZiN1OJ2X9AGiOdug==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-freebsd-x64": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.8.4.tgz", - "integrity": "sha512-99vnUXZy+OUBHU+8Yhabre2qafepKg9GKkQkhmXvJGqOmuIsepK7wirUFo2PiVM8YhS6UV2rv6hKAZcQ7skYyg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.8.4.tgz", - "integrity": "sha512-dht73zpnpzEUEzMHFQs4mfiwZH3WcJgQNWkD5p7WkeJewHq2Yyd0eG5Jg3kB7wnFtwPUV1eNJRM5rephgylkLA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm64-gnu": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.8.4.tgz", - "integrity": "sha512-syXxbJZ0yPaqzVmB28QJgUtaarSiW/PQmv/5Z2Ps8rCi7kYylISPVNjP1NNiIOcGDRWbHqoBfM0bEGPfSp0rBQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm64-musl": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.8.4.tgz", - "integrity": "sha512-AlZZFolS/S0FahRKG7rJ0Z9CgmIkyzHgGaoy3qNEMDEjFhR3jt2ZZSLp90W7zjgrxojOo90ajNMrg2UmtcQRDA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-linux-x64-gnu": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.8.4.tgz", - "integrity": "sha512-MSu+xVNdR95tuuO+eL/a/ZeMlhfrZ627On5xaCZXnJ+lFxNg/S4nlKZQk0Eq5hYALCd/GKgFGasRdlRdOtvGPg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-linux-x64-musl": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.8.4.tgz", - "integrity": "sha512-KxpQpyLCgIIHWZ4iRSUN9ohCwn1ZSDASbuFCdG3mohryzCy8WrPkuPcb+68J3wuQhmA5w//Xpp/dL0hHoit9zQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-win32-arm64-msvc": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.8.4.tgz", - "integrity": "sha512-ffLBrxM9ibk+eWSY995kiFFRTSRb9HkD5T1s/uZyxV6jfxYPaZDBAWAETDneyBXps7WtaOMu+kVZlXQ3X+TfIA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/@nx/nx-win32-x64-msvc": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.8.4.tgz", - "integrity": "sha512-JxuuZc4h8EBqoYAiRHwskimpTJx70yn4lhIRFBoW5ICkxXW1Rw0yip/1UVsWRHXg/x9BxmH7VVazdfaQWmGu6A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@lerna/create/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@lerna/create/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@lerna/create/node_modules/nx": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/nx/-/nx-20.8.4.tgz", - "integrity": "sha512-/++x0OM3/UTmDR+wmPeV13tSxeTr+QGzj3flgtH9DiOPmQnn2CjHWAMZiOhcSh/hHoE/V3ySL4757InQUsVtjQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@napi-rs/wasm-runtime": "0.2.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.2", - "@zkochan/js-yaml": "0.0.7", - "axios": "^1.8.3", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "front-matter": "^4.0.2", - "ignore": "^5.0.4", - "jest-diff": "^29.4.1", - "jsonc-parser": "3.2.0", - "lines-and-columns": "2.0.3", - "minimatch": "9.0.3", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "ora": "5.3.0", - "resolve.exports": "2.0.3", - "semver": "^7.5.3", - "string-width": "^4.2.3", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "yaml": "^2.6.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "20.8.4", - "@nx/nx-darwin-x64": "20.8.4", - "@nx/nx-freebsd-x64": "20.8.4", - "@nx/nx-linux-arm-gnueabihf": "20.8.4", - "@nx/nx-linux-arm64-gnu": "20.8.4", - "@nx/nx-linux-arm64-musl": "20.8.4", - "@nx/nx-linux-x64-gnu": "20.8.4", - "@nx/nx-linux-x64-musl": "20.8.4", - "@nx/nx-win32-arm64-msvc": "20.8.4", - "@nx/nx-win32-x64-msvc": "20.8.4" - }, - "peerDependencies": { - "@swc-node/register": "^1.8.0", - "@swc/core": "^1.3.85" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } - } - }, - "node_modules/@lerna/create/node_modules/nx/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@lerna/create/node_modules/ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@lerna/create/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@lerna/legacy-package-management": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/@lerna/legacy-package-management/-/legacy-package-management-8.2.4.tgz", - "integrity": "sha512-NSujwnA8bH7qSGAtNXp9JqGE8nxelKEIg0q5E6vLJfaTq/TcNyFjvesYTpNjPEdZ3eMneBG3nV5ccryo1ddUHg==", - "deprecated": "In v9 of lerna, released in September 2025, the `lerna bootstrap`, `lerna add` and `lerna link` commands were finally fully removed after over 2 years of being deprecated. If you are still using these commands, please migrate to using your package manager's long-supported `workspaces` feature. You may find https://lerna.js.org/docs/legacy-package-management useful for this transition.", - "dev": true, - "license": "MIT", - "dependencies": { - "@npmcli/arborist": "7.5.4", - "@npmcli/package-json": "5.2.0", - "@npmcli/run-script": "8.1.0", - "@nx/devkit": ">=17.1.2 < 21", - "@octokit/rest": "20.1.2", - "aproba": "2.0.0", - "byte-size": "8.1.1", - "chalk": "4.1.0", - "clone-deep": "4.0.1", - "cmd-shim": "6.0.3", - "color-support": "1.1.3", - "columnify": "1.6.0", - "console-control-strings": "^1.1.0", - "conventional-changelog-core": "5.0.1", - "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "9.0.0", - "dedent": "1.5.3", - "execa": "5.0.0", - "file-url": "3.0.0", - "find-up": "5.0.0", - "fs-extra": "^11.2.0", - "get-port": "5.1.1", - "get-stream": "6.0.0", - "git-url-parse": "14.0.0", - "glob-parent": "6.0.2", - "graceful-fs": "4.2.11", - "has-unicode": "2.0.1", - "ini": "^1.3.8", - "inquirer": "8.2.4", - "is-ci": "3.0.1", - "is-stream": "2.0.0", - "libnpmpublish": "9.0.9", - "load-json-file": "6.2.0", - "make-dir": "4.0.0", - "minimatch": "3.0.5", - "multimatch": "5.0.0", - "node-fetch": "2.6.7", - "npm-package-arg": "11.0.2", - "npm-packlist": "8.0.2", - "npm-registry-fetch": "^17.1.0", - "p-map": "4.0.0", - "p-map-series": "2.1.0", - "p-queue": "6.6.2", - "p-waterfall": "2.1.1", - "pacote": "^18.0.6", - "pify": "5.0.0", - "pretty-format": "29.4.3", - "read-cmd-shim": "4.0.0", - "resolve-from": "5.0.0", - "rimraf": "^4.4.1", - "semver": "7.5.2", - "set-blocking": "^2.0.0", - "signal-exit": "3.0.7", - "slash": "3.0.0", - "ssri": "^10.0.6", - "string-width": "^4.2.3", - "tar": "6.2.1", - "temp-dir": "1.0.0", - "tempy": "1.0.0", - "through": "2.3.8", - "tinyglobby": "0.2.12", - "upath": "2.0.1", - "uuid": "^10.0.0", - "wide-align": "1.1.5", - "write-file-atomic": "5.0.1", - "write-pkg": "4.0.0", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@lvce-editor/eslint-config": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-config/-/eslint-config-11.2.0.tgz", - "integrity": "sha512-T6SkTON8D2FJnv7kbr5Uye7gWuacQREvI9XSd40PQyyteY/UZzAMD+8bMWaL11G5E2AG4imrVMVtX1cQG+W4Vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/eslint-plugin": "10.0.1", - "@e18e/eslint-plugin": "^0.5.0", - "@eslint/css": "1.3.0", - "@eslint/js": "10.0.1", - "@eslint/json": "2.0.0", - "@eslint/markdown": "8.0.2", - "@lvce-editor/eslint-plugin-e2e": "11.2.0", - "@lvce-editor/eslint-plugin-github-actions": "11.2.0", - "@lvce-editor/eslint-plugin-nvmrc": "11.2.0", - "@lvce-editor/eslint-plugin-regex": "11.2.0", - "@lvce-editor/eslint-plugin-rpc": "11.2.0", - "@lvce-editor/eslint-plugin-tsconfig": "11.2.0", - "eslint-plugin-jest": "29.15.2", - "eslint-plugin-n": "18.0.1", - "eslint-plugin-package-json": "1.3.0", - "eslint-plugin-perfectionist": "5.9.0", - "eslint-plugin-sonarjs": "4.0.3", - "eslint-plugin-unicorn": "64.0.0", - "eslint-plugin-yml": "3.4.0", - "typescript-eslint": "8.60.1" - }, - "peerDependencies": { - "eslint": "^10" - } - }, - "node_modules/@lvce-editor/eslint-plugin-e2e": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-e2e/-/eslint-plugin-e2e-11.2.0.tgz", - "integrity": "sha512-K/brulzQ8VgOJQWQ3RNjMFeUGLCNTRwFv7H8p6UJZcQqSCGmFc69lgG8Yjnz0CVdVcJm+KvumNdr1x7tqJcXZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lvce-editor/eslint-plugin-github-actions": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-github-actions/-/eslint-plugin-github-actions-11.2.0.tgz", - "integrity": "sha512-5v1lqcHnyGPBQlR3xnoTXN5FX1q2cB+DvTcNoNwuz1EPK4eJyeRj6DZiT5BaR5Qa5DTyhsaG3ZLcmOLAi9qZ8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-compat-utils": "0.6.5", - "yaml-eslint-parser": "2.0.0" - } - }, - "node_modules/@lvce-editor/eslint-plugin-nvmrc": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-nvmrc/-/eslint-plugin-nvmrc-11.2.0.tgz", - "integrity": "sha512-d8sm80TXioU9kBR283SFJIPgIWPoCf+1VgrL1EPzkmmtx2XQaJ/k8u47eJctFLmcEPDFt8LbaxIV2HDX36/s0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lvce-editor/eslint-plugin-regex": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-regex/-/eslint-plugin-regex-11.2.0.tgz", - "integrity": "sha512-e9u7yxWBWilqXLZNdm5mAPLkHW6uYnhXG5lKkE4ZHkcKmR018xP0ta/5iHB7B+u8cJ4gqwrXFsHFl3oJTINerQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lvce-editor/eslint-plugin-rpc": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-rpc/-/eslint-plugin-rpc-11.2.0.tgz", - "integrity": "sha512-DMvBVADJHw0qmx6A5Q7czGF5F6qMs67UV4eCvjowYKl+6MwafuZexFFRRUKVQR7tx6zGk0kLEfv7AS2NIZAOKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lvce-editor/eslint-plugin-tsconfig": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-tsconfig/-/eslint-plugin-tsconfig-11.2.0.tgz", - "integrity": "sha512-6jWkzuAKLc2jCKGfzZRQbLKvYDh2F4BVX7Z7MDel9GdUMGGenc0X7qlRZ0MTT3A6CROaN/wmFFEu1lrcuqQDEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint/json": "2.0.0" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", - "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emnapi/core": "^1.1.0", - "@emnapi/runtime": "^1.1.0", - "@tybys/wasm-util": "^0.9.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", - "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", - "dev": true, - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/arborist": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.5.4.tgz", - "integrity": "sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^3.1.1", - "@npmcli/installed-package-contents": "^2.1.0", - "@npmcli/map-workspaces": "^3.0.2", - "@npmcli/metavuln-calculator": "^7.1.1", - "@npmcli/name-from-folder": "^2.0.0", - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.1.0", - "@npmcli/query": "^3.1.0", - "@npmcli/redact": "^2.0.0", - "@npmcli/run-script": "^8.1.0", - "bin-links": "^4.0.4", - "cacache": "^18.0.3", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^7.0.2", - "json-parse-even-better-errors": "^3.0.2", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^10.2.2", - "minimatch": "^9.0.4", - "nopt": "^7.2.1", - "npm-install-checks": "^6.2.0", - "npm-package-arg": "^11.0.2", - "npm-pick-manifest": "^9.0.1", - "npm-registry-fetch": "^17.0.1", - "pacote": "^18.0.6", - "parse-conflict-json": "^3.0.0", - "proc-log": "^4.2.0", - "proggy": "^2.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "read-package-json-fast": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^10.0.6", - "treeverse": "^3.0.0", - "walk-up-path": "^3.0.1" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/arborist/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@npmcli/arborist/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", - "dev": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", - "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^7.0.0", - "ini": "^4.1.3", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^9.0.0", - "proc-log": "^4.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git/node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", - "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/map-workspaces": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz", - "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^2.0.0", - "glob": "^10.2.2", - "minimatch": "^9.0.0", - "read-package-json-fast": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@npmcli/metavuln-calculator": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.1.tgz", - "integrity": "sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==", - "dev": true, - "license": "ISC", - "dependencies": { - "cacache": "^18.0.0", - "json-parse-even-better-errors": "^3.0.0", - "pacote": "^18.0.0", - "proc-log": "^4.1.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/name-from-folder": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", - "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", - "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^5.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^7.0.0", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "proc-log": "^4.0.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/promise-spawn": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", - "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/query": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-3.1.0.tgz", - "integrity": "sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/redact": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz", - "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", - "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "node-gyp": "^10.0.0", - "proc-log": "^4.0.0", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@nx/devkit": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-20.8.4.tgz", - "integrity": "sha512-3r+6QmIXXAWL6K7m8vAbW31aniAZmZAZXeMhOhWcJoOAU7ggpCQaM8JP8/kO5ov/Bmhyf0i/SSVXI6kwiR5WNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ejs": "^3.1.7", - "enquirer": "~2.3.6", - "ignore": "^5.0.4", - "minimatch": "9.0.3", - "semver": "^7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0", - "yargs-parser": "21.1.1" - }, - "peerDependencies": { - "nx": ">= 19 <= 21" - } - }, - "node_modules/@nx/devkit/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@nx/devkit/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@nx/devkit/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-21.6.11.tgz", - "integrity": "sha512-4hXhV7ShXIlfPEjjm7dJY383xM2vTcnkKr5FUncAU08GKkkL67ib5CMlQADtdi32ewfCZntqiT8gUfFFSNvKtA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@nx/nx-darwin-x64": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-21.6.11.tgz", - "integrity": "sha512-VxjKkzyhdO47X7d4JPx/f6HslERKetFmouDUBIoqbKDPVWpRegGMsRKcMYh4l61usxI1Qa2U4Ec6MgO5Fnm41g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@nx/nx-freebsd-x64": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-21.6.11.tgz", - "integrity": "sha512-3jDn7Tb3FMFfeFTM/XKAcI+J92kDLNmxUS/N/n/+kF/XYLPgMUZQqSeDpVifk4fgy0BCoH8DSMQIqTQau6dV/g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true - }, - "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-21.6.11.tgz", - "integrity": "sha512-37tpiVod5FN/EAuCGh+uad/6nsfDFze02OjYReUPKeYPs8Q7Ac/V9j4kn/y5uZhKSle+9+sa2QR/K79B0+lNxw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-21.6.11.tgz", - "integrity": "sha512-r+czH0OtldQqFm2B6BBBUPW8aO+sBMvpZCgN855vko30WaCeXo8Fkuk71rQMxByz0jnoCxSnzLtEWVZm1rmJYA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@nx/nx-linux-arm64-musl": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-21.6.11.tgz", - "integrity": "sha512-0FAPyWEGPCukXxR1qowvFx6Q/cU906vwPlAQtcbrBU1e2H2aMUslk9EmL8iHb5MsHdmGcFyFemwr9oN8gxmz4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-21.6.11.tgz", - "integrity": "sha512-+bWJWXJ8tdddl1L3bTKE0VmvTmdsk4zzUr6P9ts9hXQbwoWqMcuA6LNqOhUfzVOL3VioirRMtKMfFuUAUhi3Yg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-21.6.11.tgz", - "integrity": "sha512-Mh09mLc+yeJk7DKfx7x6XfB+bm2dP1/7gyUuRQj4WjkT+Il2ZponyTuH8LmX06Jpr7efAAFk+8lBXeleV7XvMw==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-21.6.11.tgz", - "integrity": "sha512-d7ZeCCDwaeyKiWD2JLSSxMSuSHHwIdpbnMtZtzRE6tDdAgs6e9F36/OBNQB3IRXH8V6QKOy2OGDyWeOKr01X9A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@nx/nx-win32-x64-msvc": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-21.6.11.tgz", - "integrity": "sha512-otHSkhyoGilttV4RRkVmLLGb2W+Ia4b90lWxLnEm9jAAKmA9O2FUG2vAvKDHNcqTyDwwCcHfHxslgnR1u/3OIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@octokit/auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", - "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", - "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.1.0", - "@octokit/request": "^8.4.1", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/endpoint": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", - "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/graphql": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", - "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/request": "^8.4.1", - "@octokit/types": "^13.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-enterprise-rest": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", - "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "11.4.4-cjs.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.4-cjs.2.tgz", - "integrity": "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.7.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-request-log": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", - "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "13.3.2-cjs.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.2-cjs.1.tgz", - "integrity": "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.8.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "^5" - } - }, - "node_modules/@octokit/request": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", - "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^9.0.6", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", - "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/rest": { - "version": "20.1.2", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.2.tgz", - "integrity": "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/core": "^5.0.2", - "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", - "@octokit/plugin-request-log": "^4.0.0", - "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@ota-meshi/ast-token-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@ota-meshi/ast-token-store/-/ast-token-store-0.3.0.tgz", - "integrity": "sha512-XRO0zi2NIUKq2lUk3T1ecFSld1fMWRKE6naRFGkgkdeosx7IslyUKNv5Dcb5PJTja9tHJoFu0v/7yEpAkrkrTg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/core": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", - "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/@sigstore/bundle": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", - "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", - "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.3.tgz", - "integrity": "sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@sigstore/sign": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", - "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^2.3.2", - "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "make-fetch-happen": "^13.0.1", - "proc-log": "^4.2.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/tuf": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", - "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2", - "tuf-js": "^2.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/verify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", - "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^2.3.2", - "@sigstore/core": "^1.1.0", - "@sigstore/protobuf-specs": "^0.3.2" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.10", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", - "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", - "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/esrecurse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", - "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/katex": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", - "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/type-utils": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.60.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", - "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", - "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", - "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.61.1", - "@typescript-eslint/types": "^8.61.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", - "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", - "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", - "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", - "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", - "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", - "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.61.1", - "@typescript-eslint/tsconfig-utils": "8.61.1", - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", - "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.61.1", - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", - "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.61.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", - "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=18.12.0" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", - "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/add-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", - "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/aggregate-error/node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-differ": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true, - "license": "MIT" - }, - "node_modules/array-timsort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", - "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/axios/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/axios/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.37", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", - "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/bin-links": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.4.tgz", - "integrity": "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==", - "dev": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "read-cmd-shim": "^4.0.0", - "write-file-atomic": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/byte-size": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz", - "integrity": "sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "18.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", - "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001799", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", - "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/change-case": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", - "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", - "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/clean-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", - "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/clean-regexp/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cmd-shim": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.3.tgz", - "integrity": "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/columnify": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", - "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/comment-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-5.0.0.tgz", - "integrity": "sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-timsort": "^1.0.3", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", - "dev": true, - "license": "ISC" - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "dev": true, - "engines": [ - "node >= 6.0" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/conventional-changelog-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-5.0.1.tgz", - "integrity": "sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "add-stream": "^1.0.0", - "conventional-changelog-writer": "^6.0.0", - "conventional-commits-parser": "^4.0.0", - "dateformat": "^3.0.3", - "get-pkg-repo": "^4.2.1", - "git-raw-commits": "^3.0.0", - "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^5.0.0", - "normalize-package-data": "^3.0.3", - "read-pkg": "^3.0.0", - "read-pkg-up": "^3.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-preset-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz", - "integrity": "sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-changelog-writer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz", - "integrity": "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "conventional-commits-filter": "^3.0.0", - "dateformat": "^3.0.3", - "handlebars": "^4.7.7", - "json-stringify-safe": "^5.0.1", - "meow": "^8.1.2", - "semver": "^7.0.0", - "split": "^1.0.1" - }, - "bin": { - "conventional-changelog-writer": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-commits-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", - "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-commits-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", - "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.3.5", - "meow": "^8.1.2", - "split2": "^3.2.2" - }, - "bin": { - "conventional-commits-parser": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-recommended-bump": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-7.0.1.tgz", - "integrity": "sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==", - "dev": true, - "license": "MIT", - "dependencies": { - "concat-stream": "^2.0.0", - "conventional-changelog-preset-loader": "^3.0.0", - "conventional-commits-filter": "^3.0.0", - "conventional-commits-parser": "^4.0.0", - "git-raw-commits": "^3.0.0", - "git-semver-tags": "^5.0.0", - "meow": "^8.1.2" - }, - "bin": { - "conventional-recommended-bump": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/core-js-compat": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", - "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cspell-config-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-10.0.1.tgz", - "integrity": "sha512-hMpo/0j6k7pbiqrLDOLJKD2IGP9XwhjKf2miiM6p84Xeo4nyuFZaxxDCQ68R851HSYFrrdltgpoipMbj1h2Tnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-types": "10.0.1", - "comment-json": "^5.0.0", - "smol-toml": "^1.6.1", - "yaml": "^2.9.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-dictionary": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-10.0.1.tgz", - "integrity": "sha512-3cZ659vgsZWkzGQJR/sNqGDVt/OnvTSieLKI76V++4t1bHJfochb9ZrrwsuMsb1VPGiyqClUP1/O6WrefF/FVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "cspell-trie-lib": "10.0.1", - "fast-equals": "^6.0.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-glob": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-10.0.1.tgz", - "integrity": "sha512-7bII9J3aSSpZDwhx7w+zfQXbMxHZQ3be0ilUp5bHrsjz6o07v/NqOHMGcwKdPn1sw2dxDz9sv057xE5pqXnSdw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "10.0.1", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-grammar": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-10.0.1.tgz", - "integrity": "sha512-xC9AFYmaI9wsO//a7S5tdDGKGJVD5UEEsTg+Up2fi7lPfXIryisYmV6tePNL1SEg0idYss4ja8LUZ3Mib09BjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1" - }, - "bin": { - "cspell-grammar": "bin.mjs" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-io": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-10.0.1.tgz", - "integrity": "sha512-8C2ka07faxflnaqEBO3pektS21XViE/SEHT7F5ZD1ou7FyMR5u3xawTBJSczClfsxLt/WYeztBYrpmGAjmjksw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-service-bus": "10.0.1", - "@cspell/url": "10.0.1" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-10.0.1.tgz", - "integrity": "sha512-RpsIPiLzc4/YMW8BMRKpyJ81x439qjYWcqgdKeXnMkbKM88J9PexzutfFf/4v97v96KzfNitEzMpbI0uj8OeUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-bundled-dicts": "10.0.1", - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-resolver": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "@cspell/dynamic-import": "10.0.1", - "@cspell/filetypes": "10.0.1", - "@cspell/rpc": "10.0.1", - "@cspell/strong-weak-map": "10.0.1", - "@cspell/url": "10.0.1", - "cspell-config-lib": "10.0.1", - "cspell-dictionary": "10.0.1", - "cspell-glob": "10.0.1", - "cspell-grammar": "10.0.1", - "cspell-io": "10.0.1", - "cspell-trie-lib": "10.0.1", - "env-paths": "^4.0.0", - "gensequence": "^8.0.8", - "import-fresh": "^4.0.0", - "resolve-from": "^5.0.0", - "vscode-languageserver-textdocument": "^1.0.12", - "vscode-uri": "^3.1.0", - "xdg-basedir": "^5.1.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-lib/node_modules/env-paths": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", - "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-safe-filename": "^0.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cspell-lib/node_modules/import-fresh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-4.0.0.tgz", - "integrity": "sha512-Fpi660c7VPDM3fPKYovStd9IP1CPOikf6v/dGxJJMmHPcwYQIMJ4W7kO1avBYEpMqkCh+Dx3Ln6H7VYqgztLjw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.15" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cspell-trie-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-10.0.1.tgz", - "integrity": "sha512-BFvhalSkRQFjKrZ//FKK7fRGrZFpifnxB5AwCkzsIsBZqicsfafcQ1xP21qpb0QqyV/IomjNgviG+tRJs+0rMw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - }, - "peerDependencies": { - "@cspell/cspell-types": "10.0.1" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dev": true, - "license": "MIT", - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/del/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/del/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/del/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-indent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", - "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/detect-newline": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz", - "integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dir-glob/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-expand": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", - "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^16.4.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.372", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", - "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==", - "dev": true, - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/empathic": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", - "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz", - "integrity": "sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, - "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT" - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", - "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", - "dev": true, - "license": "MIT", - "workspaces": [ - "packages/*" - ], - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.5", - "@eslint/config-helpers": "^0.6.0", - "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.2", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.2", - "eslint-visitor-keys": "^5.0.1", - "espree": "^11.2.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-compat-utils": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.5.tgz", - "integrity": "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-compat-utils/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-fix-utils": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/eslint-fix-utils/-/eslint-fix-utils-0.4.2.tgz", - "integrity": "sha512-n7ZTcwwkP5scedlhvWMcqxED+O1NzXcj5Rxn/0kJQMP88k02vRcBfQ1qsk/JHb6Aw8bajFoetFCCBiNIcNCsvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@types/estree": ">=1", - "eslint": ">=8" - }, - "peerDependenciesMeta": { - "@types/estree": { - "optional": true - } - } - }, - "node_modules/eslint-json-compat-utils": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/eslint-json-compat-utils/-/eslint-json-compat-utils-0.2.3.tgz", - "integrity": "sha512-RbBmDFyu7FqnjE8F0ZxPNzx5UaptdeS9Uu50r7A+D7s/+FCX+ybiyViYEgFUaFIFqSWJgZRTpL5d8Kanxxl2lQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "esquery": "^1.6.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": "*", - "jsonc-eslint-parser": "^2.4.0 || ^3.0.0" - }, - "peerDependenciesMeta": { - "@eslint/json": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-es-x": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", - "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/ota-meshi", - "https://opencollective.com/eslint" - ], - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.11.0", - "eslint-compat-utils": "^0.5.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": ">=8" - } - }, - "node_modules/eslint-plugin-es-x/node_modules/eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-plugin-es-x/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-jest": { - "version": "29.15.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.2.tgz", - "integrity": "sha512-kEN4r9RZl1xcsb4arGq89LrcVdOUFII/JSCwtTPJyv16mDwmPrcuEQwpxqZHeINvcsd7oK5O/rhdGlxFRaZwvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/utils": "^8.0.0" - }, - "engines": { - "node": "^20.12.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^8.0.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "jest": "*", - "typescript": ">=4.8.4 <7.0.0" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-n": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.0.1.tgz", - "integrity": "sha512-q3ARhk+eZRc7myR0KHx+R3/GJeOHF+Ir6PK95Pu2tEX8Sl/4BIpmmVLva2kPrjC2gCmn6WHlHm+3yeo6Rxhycw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.5.0", - "enhanced-resolve": "^5.17.1", - "eslint-plugin-es-x": "^7.8.0", - "get-tsconfig": "^4.8.1", - "globals": "^15.11.0", - "globrex": "^0.1.2", - "ignore": "^5.3.2", - "semver": "^7.6.3" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": ">=8.57.1", - "ts-declaration-location": "^1.0.6", - "typescript": ">=5.0.0" - }, - "peerDependenciesMeta": { - "ts-declaration-location": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-package-json": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-package-json/-/eslint-plugin-package-json-1.3.0.tgz", - "integrity": "sha512-YC4lXD7sZJ5Pj8NrK9npvIBzMH9WMrkXb4VaBXRqyxTriCwqFcEJMX51K3TjkzLiXS3eUQ3CzimKWNPiSpq5tA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@altano/repository-tools": "^2.0.1", - "change-case": "^5.4.4", - "detect-indent": "^7.0.2", - "detect-newline": "^4.0.1", - "eslint-fix-utils": "~0.4.1", - "eslint-json-compat-utils": "^0.2.3", - "jsonc-eslint-parser": "^3.1.0", - "package-json-validator": "^1.5.0", - "semver": "^7.7.3", - "sort-object-keys": "^2.0.0", - "sort-package-json": "^3.4.0" - }, - "engines": { - "node": "^22.22.2 || >=24.15.0" - }, - "peerDependencies": { - "@eslint/json": ">=1.0.0", - "eslint": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@eslint/json": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-package-json/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-perfectionist": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-5.9.0.tgz", - "integrity": "sha512-8TWzg02zmnBdZwCkWLi8jhzqXI+fE7Z/RwV8SL6xD45tJ8Bp3wGuYL2XtQgfe/Wd0eBqOUX+s6ey73IyszvKTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/utils": "^8.58.2", - "natural-orderby": "^5.0.0" - }, - "engines": { - "node": "^20.0.0 || >=22.0.0" - }, - "peerDependencies": { - "eslint": "^8.45.0 || ^9.0.0 || ^10.0.0" - } - }, - "node_modules/eslint-plugin-sonarjs": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-4.0.3.tgz", - "integrity": "sha512-5drkJKLC9qQddIiaATV0e8+ygbUc7b0Ti6VB7M2d3jmKNh3X0RaiIJYTs3dr9xnlhlrxo+/s1FoO3Jgv6O/c7g==", - "dev": true, - "license": "LGPL-3.0-only", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "builtin-modules": "^3.3.0", - "bytes": "^3.1.2", - "functional-red-black-tree": "^1.0.1", - "globals": "^17.4.0", - "jsx-ast-utils-x": "^0.1.0", - "lodash.merge": "^4.6.2", - "minimatch": "^10.2.5", - "scslre": "^0.3.0", - "semver": "^7.7.4", - "ts-api-utils": "^2.5.0", - "typescript": ">=5" - }, - "peerDependencies": { - "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/globals": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", - "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-unicorn": { - "version": "64.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-64.0.0.tgz", - "integrity": "sha512-rNZwalHh8i0UfPlhNwg5BTUO1CMdKNmjqe+TgzOTZnpKoi8VBgsW7u9qCHIdpxEzZ1uwrJrPF0uRb7l//K38gA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "@eslint-community/eslint-utils": "^4.9.1", - "change-case": "^5.4.4", - "ci-info": "^4.4.0", - "clean-regexp": "^1.0.0", - "core-js-compat": "^3.49.0", - "find-up-simple": "^1.0.1", - "globals": "^17.4.0", - "indent-string": "^5.0.0", - "is-builtin-module": "^5.0.0", - "jsesc": "^3.1.0", - "pluralize": "^8.0.0", - "regexp-tree": "^0.1.27", - "regjsparser": "^0.13.0", - "semver": "^7.7.4", - "strip-indent": "^4.1.1" - }, - "engines": { - "node": "^20.10.0 || >=21.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" - }, - "peerDependencies": { - "eslint": ">=9.38.0" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/globals": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", - "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-yml": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-3.4.0.tgz", - "integrity": "sha512-j6U3ESrAkidkvNb3HFN2UMxke46GNp6bsJokabXCICcgomSy3YU4oED9cjzkZ58nYxWD5qnWV1b/2YlqyWMOxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint/core": "^1.0.1", - "@eslint/plugin-kit": "^0.7.0", - "@ota-meshi/ast-token-store": "^0.3.0", - "diff-sequences": "^29.0.0", - "escape-string-regexp": "5.0.0", - "natural-compare": "^1.4.0", - "yaml-eslint-parser": "^2.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "eslint": ">=9.38.0" - } - }, - "node_modules/eslint-plugin-yml/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-scope": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", - "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/espree": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", - "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.16.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/execa": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", - "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", - "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-equals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.0.0.tgz", - "integrity": "sha512-PFhhIGgdM79r5Uztdj9Zb6Tt1zKafqVfdMGwVca1z5z6fbX7DmsySSuJd8HiP6I1j505DCS83cLxo5rmSNeVEA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fault": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", - "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/file-url": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz", - "integrity": "sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/filelist": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", - "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up-simple": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", - "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", - "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.4", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/front-matter": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", - "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^3.13.1" - } - }, - "node_modules/front-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/front-matter/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", - "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/gensequence": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-8.0.8.tgz", - "integrity": "sha512-omMVniXEXpdx/vKxGnPRoO2394Otlze28TyxECbFVyoSpZ9H3EO7lemjcB12OpQJzRW4e5tt/dL1rOxry6aMHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-pkg-repo": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", - "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@hutson/parse-repository-url": "^3.0.0", - "hosted-git-info": "^4.0.0", - "through2": "^2.0.0", - "yargs": "^16.2.0" - }, - "bin": { - "get-pkg-repo": "src/cli.js" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-pkg-repo/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/get-pkg-repo/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-pkg-repo/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-pkg-repo/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-pkg-repo/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/get-port": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", - "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-tsconfig": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", - "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/git-hooks-list": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.2.1.tgz", - "integrity": "sha512-WNvqJjOxxs/8ZP9+DWdwWJ7cDsd60NHf39XnD82pDVrKO5q7xfPqpkK6hwEAmBa/ZSEE4IOoR75EzbbIuwGlMw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/fisker/git-hooks-list?sponsor=1" - } - }, - "node_modules/git-raw-commits": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", - "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", - "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", - "dev": true, - "license": "MIT", - "dependencies": { - "dargs": "^7.0.0", - "meow": "^8.1.2", - "split2": "^3.2.2" - }, - "bin": { - "git-raw-commits": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/git-remote-origin-url/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/git-semver-tags": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-5.0.1.tgz", - "integrity": "sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==", - "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", - "dev": true, - "license": "MIT", - "dependencies": { - "meow": "^8.1.2", - "semver": "^7.0.0" - }, - "bin": { - "git-semver-tags": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/git-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", - "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-ssh": "^1.4.0", - "parse-url": "^8.1.0" - } - }, - "node_modules/git-url-parse": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-14.0.0.tgz", - "integrity": "sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "git-up": "^7.0.0" - } - }, - "node_modules/gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", - "dev": true, - "license": "BSD", - "dependencies": { - "ini": "^1.3.2" - } - }, - "node_modules/github-slugger": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", - "dev": true, - "license": "ISC" - }, - "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/global-directory": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", - "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "6.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/global-directory/node_modules/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true, - "license": "MIT" - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/handlebars": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-walk": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", - "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", - "dev": true, - "license": "ISC", - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC" - }, - "node_modules/init-package-json": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-6.0.3.tgz", - "integrity": "sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^5.0.0", - "npm-package-arg": "^11.0.0", - "promzard": "^1.0.0", - "read": "^3.0.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ip-address": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", - "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-builtin-module": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", - "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-modules": "^5.0.0" - }, - "engines": { - "node": ">=18.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-builtin-module/node_modules/builtin-modules": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.2.0.tgz", - "integrity": "sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-ci/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-safe-filename": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", - "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-ssh": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", - "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", - "dev": true, - "license": "MIT", - "dependencies": { - "protocols": "^2.0.1" - } - }, - "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "text-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", - "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", - "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stringify-nice": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", - "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", - "dev": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "license": "ISC" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-eslint-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-3.1.0.tgz", - "integrity": "sha512-75EA7EWZExL/j+MDKQrRbdzcRI2HOkRlmUw8fZJc1ioqFEOvBsq7Rt+A6yCxOt9w/TYNpkt52gC6nm/g5tFIng==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.5.0", - "eslint-visitor-keys": "^5.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "license": "MIT" - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/jsx-ast-utils-x": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/jsx-ast-utils-x/-/jsx-ast-utils-x-0.1.0.tgz", - "integrity": "sha512-eQQBjBnsVtGacsG9uJNB8qOr3yA8rga4wAaGG1qRcBzSIvfhERLrWxMAM1hp5fcS6Abo8M4+bUBTekYR0qTPQw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/just-diff": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", - "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", - "dev": true, - "license": "MIT" - }, - "node_modules/just-diff-apply": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", - "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/katex": { - "version": "0.16.47", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", - "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", - "dev": true, - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" - ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" - }, - "bin": { - "katex": "cli.js" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lerna": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-8.2.4.tgz", - "integrity": "sha512-0gaVWDIVT7fLfprfwpYcQajb7dBJv3EGavjG7zvJ+TmGx3/wovl5GklnSwM2/WeE0Z2wrIz7ndWhBcDUHVjOcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@lerna/create": "8.2.4", - "@npmcli/arborist": "7.5.4", - "@npmcli/package-json": "5.2.0", - "@npmcli/run-script": "8.1.0", - "@nx/devkit": ">=17.1.2 < 21", - "@octokit/plugin-enterprise-rest": "6.0.1", - "@octokit/rest": "20.1.2", - "aproba": "2.0.0", - "byte-size": "8.1.1", - "chalk": "4.1.0", - "clone-deep": "4.0.1", - "cmd-shim": "6.0.3", - "color-support": "1.1.3", - "columnify": "1.6.0", - "console-control-strings": "^1.1.0", - "conventional-changelog-angular": "7.0.0", - "conventional-changelog-core": "5.0.1", - "conventional-recommended-bump": "7.0.1", - "cosmiconfig": "9.0.0", - "dedent": "1.5.3", - "envinfo": "7.13.0", - "execa": "5.0.0", - "fs-extra": "^11.2.0", - "get-port": "5.1.1", - "get-stream": "6.0.0", - "git-url-parse": "14.0.0", - "glob-parent": "6.0.2", - "graceful-fs": "4.2.11", - "has-unicode": "2.0.1", - "import-local": "3.1.0", - "ini": "^1.3.8", - "init-package-json": "6.0.3", - "inquirer": "^8.2.4", - "is-ci": "3.0.1", - "is-stream": "2.0.0", - "jest-diff": ">=29.4.3 < 30", - "js-yaml": "4.1.0", - "libnpmaccess": "8.0.6", - "libnpmpublish": "9.0.9", - "load-json-file": "6.2.0", - "make-dir": "4.0.0", - "minimatch": "3.0.5", - "multimatch": "5.0.0", - "node-fetch": "2.6.7", - "npm-package-arg": "11.0.2", - "npm-packlist": "8.0.2", - "npm-registry-fetch": "^17.1.0", - "nx": ">=17.1.2 < 21", - "p-map": "4.0.0", - "p-map-series": "2.1.0", - "p-pipe": "3.1.0", - "p-queue": "6.6.2", - "p-reduce": "2.1.0", - "p-waterfall": "2.1.1", - "pacote": "^18.0.6", - "pify": "5.0.0", - "read-cmd-shim": "4.0.0", - "resolve-from": "5.0.0", - "rimraf": "^4.4.1", - "semver": "^7.3.8", - "set-blocking": "^2.0.0", - "signal-exit": "3.0.7", - "slash": "3.0.0", - "ssri": "^10.0.6", - "string-width": "^4.2.3", - "tar": "6.2.1", - "temp-dir": "1.0.0", - "through": "2.3.8", - "tinyglobby": "0.2.12", - "typescript": ">=3 < 6", - "upath": "2.0.1", - "uuid": "^10.0.0", - "validate-npm-package-license": "3.0.4", - "validate-npm-package-name": "5.0.1", - "wide-align": "1.1.5", - "write-file-atomic": "5.0.1", - "write-pkg": "4.0.0", - "yargs": "17.7.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "lerna": "dist/cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/lerna/node_modules/@nx/nx-darwin-arm64": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.8.4.tgz", - "integrity": "sha512-8Y7+4wj1qoZsuDRpnuiHzSIsMt3VqtJ0su8dgd/MyGccvvi4pndan2R5yTiVw/wmbMxtBmZ6PO6Z8dgSIrMVog==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-darwin-x64": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.8.4.tgz", - "integrity": "sha512-2lfuxRc56QWnAysMhcD03tpCPiRzV1+foUq0MhV2sSBIybXmgV4wHLkPZNhlBCl4FNXrWiZiN1OJ2X9AGiOdug==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-freebsd-x64": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.8.4.tgz", - "integrity": "sha512-99vnUXZy+OUBHU+8Yhabre2qafepKg9GKkQkhmXvJGqOmuIsepK7wirUFo2PiVM8YhS6UV2rv6hKAZcQ7skYyg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.8.4.tgz", - "integrity": "sha512-dht73zpnpzEUEzMHFQs4mfiwZH3WcJgQNWkD5p7WkeJewHq2Yyd0eG5Jg3kB7wnFtwPUV1eNJRM5rephgylkLA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-linux-arm64-gnu": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.8.4.tgz", - "integrity": "sha512-syXxbJZ0yPaqzVmB28QJgUtaarSiW/PQmv/5Z2Ps8rCi7kYylISPVNjP1NNiIOcGDRWbHqoBfM0bEGPfSp0rBQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-linux-arm64-musl": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.8.4.tgz", - "integrity": "sha512-AlZZFolS/S0FahRKG7rJ0Z9CgmIkyzHgGaoy3qNEMDEjFhR3jt2ZZSLp90W7zjgrxojOo90ajNMrg2UmtcQRDA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-linux-x64-gnu": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.8.4.tgz", - "integrity": "sha512-MSu+xVNdR95tuuO+eL/a/ZeMlhfrZ627On5xaCZXnJ+lFxNg/S4nlKZQk0Eq5hYALCd/GKgFGasRdlRdOtvGPg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-linux-x64-musl": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.8.4.tgz", - "integrity": "sha512-KxpQpyLCgIIHWZ4iRSUN9ohCwn1ZSDASbuFCdG3mohryzCy8WrPkuPcb+68J3wuQhmA5w//Xpp/dL0hHoit9zQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-win32-arm64-msvc": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.8.4.tgz", - "integrity": "sha512-ffLBrxM9ibk+eWSY995kiFFRTSRb9HkD5T1s/uZyxV6jfxYPaZDBAWAETDneyBXps7WtaOMu+kVZlXQ3X+TfIA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/@nx/nx-win32-x64-msvc": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.8.4.tgz", - "integrity": "sha512-JxuuZc4h8EBqoYAiRHwskimpTJx70yn4lhIRFBoW5ICkxXW1Rw0yip/1UVsWRHXg/x9BxmH7VVazdfaQWmGu6A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/lerna/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/lerna/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/lerna/node_modules/nx": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/nx/-/nx-20.8.4.tgz", - "integrity": "sha512-/++x0OM3/UTmDR+wmPeV13tSxeTr+QGzj3flgtH9DiOPmQnn2CjHWAMZiOhcSh/hHoE/V3ySL4757InQUsVtjQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@napi-rs/wasm-runtime": "0.2.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.2", - "@zkochan/js-yaml": "0.0.7", - "axios": "^1.8.3", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "front-matter": "^4.0.2", - "ignore": "^5.0.4", - "jest-diff": "^29.4.1", - "jsonc-parser": "3.2.0", - "lines-and-columns": "2.0.3", - "minimatch": "9.0.3", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "ora": "5.3.0", - "resolve.exports": "2.0.3", - "semver": "^7.5.3", - "string-width": "^4.2.3", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "yaml": "^2.6.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "20.8.4", - "@nx/nx-darwin-x64": "20.8.4", - "@nx/nx-freebsd-x64": "20.8.4", - "@nx/nx-linux-arm-gnueabihf": "20.8.4", - "@nx/nx-linux-arm64-gnu": "20.8.4", - "@nx/nx-linux-arm64-musl": "20.8.4", - "@nx/nx-linux-x64-gnu": "20.8.4", - "@nx/nx-linux-x64-musl": "20.8.4", - "@nx/nx-win32-arm64-msvc": "20.8.4", - "@nx/nx-win32-x64-msvc": "20.8.4" - }, - "peerDependencies": { - "@swc-node/register": "^1.8.0", - "@swc/core": "^1.3.85" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } - } - }, - "node_modules/lerna/node_modules/nx/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/lerna/node_modules/ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lerna/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lerna/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/libnpmaccess": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-8.0.6.tgz", - "integrity": "sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^17.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/libnpmpublish": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-9.0.9.tgz", - "integrity": "sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==", - "dev": true, - "license": "ISC", - "dependencies": { - "ci-info": "^4.0.0", - "normalize-package-data": "^6.0.1", - "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^17.0.1", - "proc-log": "^4.2.0", - "semver": "^7.3.7", - "sigstore": "^2.2.0", - "ssri": "^10.0.6" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/lines-and-columns": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", - "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/load-json-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", - "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^5.0.0", - "strip-bom": "^4.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/load-json-file/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", - "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "proc-log": "^4.2.0", - "promise-retry": "^2.0.1", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-frontmatter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", - "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "escape-string-regexp": "^5.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-extension-frontmatter": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-math": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", - "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "longest-streak": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.1.0", - "unist-util-remove-position": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdn-data": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.28.1.tgz", - "integrity": "sha512-U9w+PzSZ00Z5m9rZ5ARVFL5xOfuCHdKYi/1RRwDCJsboFgJDNT3zT6PIPD7mZQYaQLhsZM3GfDRgSMRHhSmVng==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/meow/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/meow/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/meow/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-frontmatter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", - "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fault": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-math": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", - "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/katex": "^0.16.0", - "devlop": "^1.0.0", - "katex": "^0.16.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-fetch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", - "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/module-replacements": { - "version": "3.0.0-beta.8", - "resolved": "https://registry.npmjs.org/module-replacements/-/module-replacements-3.0.0-beta.8.tgz", - "integrity": "sha512-sc8TepP9elxoOBXEpxmhPzKKjTjbswHVcmsKGbgvm3k6jZlLu/WMV/Lfmga6IGMgHU/V3WtY2s6VEgM4nTElUQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/multimatch": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", - "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/multimatch/node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true, - "license": "ISC" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-orderby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-5.0.0.tgz", - "integrity": "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.3.1.tgz", - "integrity": "sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^4.1.0", - "semver": "^7.3.5", - "tar": "^6.2.1", - "which": "^4.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/node-machine-id": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", - "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", - "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/normalize-package-data": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", - "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-bundled": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", - "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-install-checks": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", - "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^4.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-packlist": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", - "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", - "dev": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^6.0.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", - "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^11.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", - "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^2.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^13.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minizlib": "^2.1.2", - "npm-package-arg": "^11.0.0", - "proc-log": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nx": { - "version": "21.6.11", - "resolved": "https://registry.npmjs.org/nx/-/nx-21.6.11.tgz", - "integrity": "sha512-AAgJGhS+7xlsmZF6ArKX1vgONxf7IymUYZ1BxGXHVa5927rGfgKoMaPOgwwtvN0OL3o/QYaNGwlDfIzCvlpOLQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@napi-rs/wasm-runtime": "0.2.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.2", - "@zkochan/js-yaml": "0.0.7", - "axios": "^1.12.0", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "front-matter": "^4.0.2", - "ignore": "^5.0.4", - "jest-diff": "^30.0.2", - "jsonc-parser": "3.2.0", - "lines-and-columns": "2.0.3", - "minimatch": "9.0.3", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "ora": "5.3.0", - "resolve.exports": "2.0.3", - "semver": "^7.5.3", - "string-width": "^4.2.3", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tree-kill": "^1.2.2", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "yaml": "^2.6.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "21.6.11", - "@nx/nx-darwin-x64": "21.6.11", - "@nx/nx-freebsd-x64": "21.6.11", - "@nx/nx-linux-arm-gnueabihf": "21.6.11", - "@nx/nx-linux-arm64-gnu": "21.6.11", - "@nx/nx-linux-arm64-musl": "21.6.11", - "@nx/nx-linux-x64-gnu": "21.6.11", - "@nx/nx-linux-x64-musl": "21.6.11", - "@nx/nx-win32-arm64-msvc": "21.6.11", - "@nx/nx-win32-x64-msvc": "21.6.11" - }, - "peerDependencies": { - "@swc-node/register": "^1.8.0", - "@swc/core": "^1.3.85" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } - } - }, - "node_modules/nx/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/nx/node_modules/@sinclair/typebox": { - "version": "0.34.49", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", - "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/nx/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/nx/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/nx/node_modules/jest-diff": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", - "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/diff-sequences": "30.4.0", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.4.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/nx/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nx/node_modules/ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nx/node_modules/pretty-format": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/schemas": "30.4.1", - "ansi-styles": "^5.2.0", - "react-is-18": "npm:react-is@^18.3.1", - "react-is-19": "npm:react-is@^19.2.5" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/nx/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/nx/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map-series": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz", - "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-pipe": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", - "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-queue": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", - "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.4", - "p-timeout": "^3.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-reduce": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", - "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-waterfall": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz", - "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-reduce": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/package-json-validator": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/package-json-validator/-/package-json-validator-1.5.2.tgz", - "integrity": "sha512-eHXskJQU4aCiSfjhRfTVtCJ+22/EzLHgYgZv5Gj3teb3NJrnTMzq5BnKAWKvR+PLpknCO1PmOCImDuO+dX4Vaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "npm-package-arg": "^13.0.2", - "semver": "^7.7.2", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^7.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/package-json-validator/node_modules/hosted-git-info": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", - "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/package-json-validator/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/package-json-validator/node_modules/npm-package-arg": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", - "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^9.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/package-json-validator/node_modules/proc-log": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", - "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/package-json-validator/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/package-json-validator/node_modules/validate-npm-package-name": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", - "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/pacote": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", - "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^5.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/package-json": "^5.1.0", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^8.0.0", - "cacache": "^18.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^11.0.0", - "npm-packlist": "^8.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^17.0.0", - "proc-log": "^4.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^2.2.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-conflict-json": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz", - "integrity": "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-json/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/parse-json/node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/parse-path": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", - "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "protocols": "^2.0.0" - } - }, - "node_modules/parse-url": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", - "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse-path": "^7.0.0" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", - "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", - "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/proggy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proggy/-/proggy-2.0.0.tgz", - "integrity": "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/promise-all-reject-late": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", - "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", - "dev": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/promise-call-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.2.tgz", - "integrity": "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==", - "dev": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/promzard": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-1.0.2.tgz", - "integrity": "sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "read": "^3.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/protocols": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", - "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-is-18": { - "name": "react-is", - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/react-is-19": { - "name": "react-is", - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", - "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/read": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz", - "integrity": "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==", - "dev": true, - "license": "ISC", - "dependencies": { - "mute-stream": "^1.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-cmd-shim": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", - "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/read-pkg/node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/read/node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/redent/node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/redent/node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/refa": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", - "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.8.0" - }, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/regexp-ast-analysis": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", - "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.8.0", - "refa": "^0.12.1" - }, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/regexp-tree": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", - "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", - "dev": true, - "license": "MIT", - "bin": { - "regexp-tree": "bin/regexp-tree" - } - }, - "node_modules/regjsparser": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", - "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.7.tgz", - "integrity": "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/scslre": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", - "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.8.0", - "refa": "^0.12.0", - "regexp-ast-analysis": "^0.7.0" - }, - "engines": { - "node": "^14.0.0 || >=16.0.0" - } - }, - "node_modules/semver": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", - "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/sigstore": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", - "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^2.3.2", - "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "@sigstore/sign": "^2.3.2", - "@sigstore/tuf": "^2.3.4", - "@sigstore/verify": "^1.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/smol-toml": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", - "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 18" - }, - "funding": { - "url": "https://github.com/sponsors/cyyynthia" - } - }, - "node_modules/socks": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", - "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^10.1.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/sort-object-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-2.1.0.tgz", - "integrity": "sha512-SOiEnthkJKPv2L6ec6HMwhUcN0/lppkeYuN1x63PbyPRrgSPIuBJCiYxYyvWRTtjMlOi14vQUCGUJqS6PLVm8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/sort-package-json": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.7.1.tgz", - "integrity": "sha512-ssk1HG7whF8N/T1IsNAQrtHG5Cbdi0rAgRJZXYBr9hF5xaHnBNzUx/W6LcthEW7FhOwvZssbESZuO+GxssqAyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-indent": "^7.0.2", - "detect-newline": "^4.0.1", - "git-hooks-list": "^4.1.1", - "is-plain-obj": "^4.1.0", - "semver": "^7.7.3", - "sort-object-keys": "^2.0.1", - "tinyglobby": "^0.2.15" - }, - "bin": { - "sort-package-json": "cli.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/sort-package-json/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sort-package-json/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sort-package-json/node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", - "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "license": "ISC", - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/ssri": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", - "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/synckit": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", - "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.3.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, - "node_modules/tapable": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", - "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/temp-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tempy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.0.tgz", - "integrity": "sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "del": "^6.0.0", - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.4.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tmp": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", - "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/treeverse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", - "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tuf-js": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", - "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tufjs/models": "2.0.1", - "debug": "^4.3.4", - "make-fetch-happen": "^13.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", - "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.60.1", - "@typescript-eslint/parser": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", - "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/typescript-eslint/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typescript-eslint/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typescript-eslint/node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-remove-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", - "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", - "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/upath": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", - "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-name": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", - "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" - }, - "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/walk-up-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", - "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", - "dev": true, - "license": "ISC" - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/write-json-file": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", - "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-indent": "^5.0.0", - "graceful-fs": "^4.1.15", - "make-dir": "^2.1.0", - "pify": "^4.0.1", - "sort-keys": "^2.0.0", - "write-file-atomic": "^2.4.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/write-json-file/node_modules/detect-indent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/write-json-file/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/write-json-file/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/write-json-file/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/write-json-file/node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/write-pkg": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz", - "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", - "dev": true, - "license": "MIT", - "dependencies": { - "sort-keys": "^2.0.0", - "type-fest": "^0.4.1", - "write-json-file": "^3.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/write-pkg/node_modules/type-fest": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", - "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=6" - } - }, - "node_modules/xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yaml-eslint-parser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-2.0.0.tgz", - "integrity": "sha512-h0uDm97wvT2bokfwwTmY6kJ1hp6YDFL0nRHwNKz8s/VD1FH/vvZjAKoMUE+un0eaYBSG7/c6h+lJTP+31tjgTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^5.0.0", - "yaml": "^2.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - } - } -} diff --git a/package.json b/package.json index 3ca96cb..57fd4f9 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@lerna/legacy-package-management": "^8.2.4", - "@lvce-editor/eslint-config": "^11.2.0", + "@lvce-editor/eslint-config": "^12.3.0", "eslint": "^10.2.0", "lerna": "^8.2.4", "prettier": "^3.8.4", diff --git a/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json b/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json deleted file mode 100644 index 3cbd42b..0000000 --- a/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js b/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js deleted file mode 100644 index 6b4225f..0000000 --- a/packages/e2e/fixtures/sample-file-system-provider-read-folder-error/main.js +++ /dev/null @@ -1,31 +0,0 @@ -const contents = Object.create(null) - -class FileNotFoundError extends Error { - constructor(uri) { - super(`File not found`) - this.name = 'FileNotFoundError' - this.code = 'ENOENT' - } -} - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - }, - rename(oldUri, newUri) {}, - readFile(uri) { - return contents[uri] - }, - pathSeparator: '/', - readDirWithFileTypes(uri) { - throw new FileNotFoundError(uri) - }, - remove(uri) { - throw new Error(`oops`) - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json deleted file mode 100644 index 3cbd42b..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js deleted file mode 100644 index 5d88002..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path/main.js +++ /dev/null @@ -1,33 +0,0 @@ -const contents = Object.create(null) - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - - if (uri.endsWith('/file4.txt')) { - throw new Error(`Error: Failed to write to file "${uri}": EACCES: permission denied, open '${uri}'`) - } - }, - rename(oldUri, newUri) { - throw new Error(`Permission Denied`) - }, - readFile(uri) {}, - pathSeparator: '/', - readDirWithFileTypes(uri) { - const results = [] - for (const [key, value] of Object.entries(contents)) { - if (key.startsWith(uri)) { - results.push({ - type: 7, - name: key.slice(key.lastIndexOf('/')), - }) - } - } - return results - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json deleted file mode 100644 index 3cbd42b..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js b/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js deleted file mode 100644 index f7e987f..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-create-file-error-permission-denied/main.js +++ /dev/null @@ -1,32 +0,0 @@ -const contents = Object.create(null) - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - if (uri === '/file4.txt') { - throw new Error(`Permission Denied`) - } - }, - rename(oldUri, newUri) { - throw new Error(`Permission Denied`) - }, - readFile(uri) {}, - pathSeparator: '/', - readDirWithFileTypes(uri) { - const results = [] - for (const [key, value] of Object.entries(contents)) { - if (key.startsWith(uri)) { - results.push({ - type: 7, - name: key.slice(key.lastIndexOf('/')), - }) - } - } - return results - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json b/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json deleted file mode 100644 index 3cbd42b..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js b/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js deleted file mode 100644 index ab3c426..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-delete-file-error/main.js +++ /dev/null @@ -1,30 +0,0 @@ -const contents = Object.create(null) - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - }, - rename(oldUri, newUri) {}, - readFile(uri) {}, - pathSeparator: '/', - readDirWithFileTypes(uri) { - const results = [] - for (const [key, value] of Object.entries(contents)) { - if (key.startsWith(uri)) { - results.push({ - type: 7, - name: key.slice(key.lastIndexOf('/')), - }) - } - } - return results - }, - remove(uri) { - throw new Error(`oops`) - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json deleted file mode 100644 index 600e5f1..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/extension.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "test" -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js deleted file mode 100644 index c6e9859..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-10m-items/main.js +++ /dev/null @@ -1,36 +0,0 @@ -// @ts-nocheck -const rootUri = 'extension-host://xyz://' -const folderUri = `${rootUri}stress-folder` -const folderEntry = { - type: 2, - name: 'stress-folder', -} -const totalItems = 10_000_000 - -const fileSystemProvider = { - id: 'xyz', - pathSeparator: '/', - rename() {}, - readFile() { - return '' - }, - writeFile() {}, - readDirWithFileTypes(uri) { - if (uri === rootUri) { - return [folderEntry] - } - if (uri === folderUri) { - return Array.from({ length: totalItems }, (_, index) => { - return { - type: 1, - name: `item-${index.toString().padStart(8, '0')}.txt`, - } - }) - } - return [] - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json deleted file mode 100644 index 600e5f1..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/extension.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "test" -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js b/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js deleted file mode 100644 index 27af635..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-expand-folder-1m-items/main.js +++ /dev/null @@ -1,36 +0,0 @@ -// @ts-nocheck -const rootUri = 'extension-host://xyz://' -const folderUri = `${rootUri}stress-folder` -const folderEntry = { - type: 2, - name: 'stress-folder', -} -const totalItems = 1_000_000 - -const fileSystemProvider = { - id: 'xyz', - pathSeparator: '/', - rename() {}, - readFile() { - return '' - }, - writeFile() {}, - readDirWithFileTypes(uri) { - if (uri === rootUri) { - return [folderEntry] - } - if (uri === folderUri) { - return Array.from({ length: totalItems }, (_, index) => { - return { - type: 1, - name: `item-${index.toString().padStart(7, '0')}.txt`, - } - }) - } - return [] - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-permission/extension.json b/packages/e2e/fixtures/sample.file-system-provider-permission/extension.json deleted file mode 100644 index 3cbd42b..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-permission/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample.file-system-provider-permission/main.js b/packages/e2e/fixtures/sample.file-system-provider-permission/main.js deleted file mode 100644 index b0a026b..0000000 --- a/packages/e2e/fixtures/sample.file-system-provider-permission/main.js +++ /dev/null @@ -1,29 +0,0 @@ -const contents = Object.create(null) - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - }, - rename(oldUri, newUri) { - throw new Error(`Permission Denied`) - }, - readFile(uri) {}, - pathSeparator: '/', - readDirWithFileTypes(uri) { - const results = [] - for (const [key, value] of Object.entries(contents)) { - if (key.startsWith(uri)) { - results.push({ - type: 7, - name: key.slice(key.lastIndexOf('/')), - }) - } - } - return results - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) -} diff --git a/packages/e2e/fixtures/sample.icon-theme/extension.json b/packages/e2e/fixtures/sample.icon-theme/extension.json deleted file mode 100644 index 9233c12..0000000 --- a/packages/e2e/fixtures/sample.icon-theme/extension.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "iconThemes": [ - { - "id": "test-icon-theme", - "path": "icon-theme.json" - } - ] -} diff --git a/packages/e2e/fixtures/sample.icon-theme/icon-theme.json b/packages/e2e/fixtures/sample.icon-theme/icon-theme.json deleted file mode 100644 index c53d17b..0000000 --- a/packages/e2e/fixtures/sample.icon-theme/icon-theme.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "iconDefinitions": { - "_file": "/icons/default_file.svg", - "_folder": "/icons/default_folder.svg" - } -} diff --git a/packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg b/packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg deleted file mode 100644 index e916d41..0000000 --- a/packages/e2e/fixtures/sample.icon-theme/icons/default_file.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg b/packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg deleted file mode 100644 index d28e7dd..0000000 --- a/packages/e2e/fixtures/sample.icon-theme/icons/default_folder.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json b/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json deleted file mode 100644 index 95b15b6..0000000 --- a/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz", "onSourceControl:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js b/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js deleted file mode 100644 index 73bf887..0000000 --- a/packages/e2e/fixtures/sample.source-control-decoration-invalid-null/main.js +++ /dev/null @@ -1,50 +0,0 @@ -const contents = Object.create(null) - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - }, - mkdir(uri) { - contents[uri] = '' - }, - rename(oldUri, newUri) {}, - readFile(uri) {}, - exists(uri) { - return false - }, - pathSeparator: '/', - readDirWithFileTypes(uri) { - const results = [] - for (const [key, value] of Object.entries(contents)) { - if (key.startsWith(uri)) { - results.push({ - type: 7, - name: key.slice(key.lastIndexOf('/') + 1), - }) - } - } - return results - }, -} - -const sourceControlProvider = { - id: 'xyz', - getChangedFiles() { - return [] - }, - getBadgeCount() { - return 0 - }, - getFileDecorations(uris) { - return null - }, - isActive() { - return true - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) - vscode.registerSourceControlProvider(sourceControlProvider) -} diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json b/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json deleted file mode 100644 index 95b15b6..0000000 --- a/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz", "onSourceControl:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js b/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js deleted file mode 100644 index 3b3b85e..0000000 --- a/packages/e2e/fixtures/sample.source-control-decoration-invalid-object/main.js +++ /dev/null @@ -1,50 +0,0 @@ -const contents = Object.create(null) - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - }, - mkdir(uri) { - contents[uri] = '' - }, - rename(oldUri, newUri) {}, - readFile(uri) {}, - exists(uri) { - return false - }, - pathSeparator: '/', - readDirWithFileTypes(uri) { - const results = [] - for (const [key, value] of Object.entries(contents)) { - if (key.startsWith(uri)) { - results.push({ - type: 7, - name: key.slice(key.lastIndexOf('/') + 1), - }) - } - } - return results - }, -} - -const sourceControlProvider = { - id: 'xyz', - getChangedFiles() { - return [] - }, - getBadgeCount() { - return 0 - }, - getFileDecorations(uris) { - return {} - }, - isActive() { - return true - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) - vscode.registerSourceControlProvider(sourceControlProvider) -} diff --git a/packages/e2e/fixtures/sample.source-control-decoration/extension.json b/packages/e2e/fixtures/sample.source-control-decoration/extension.json deleted file mode 100644 index 95b15b6..0000000 --- a/packages/e2e/fixtures/sample.source-control-decoration/extension.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browser": "main.js", - "main": "main.js", - "activation": ["onFileSystem:xyz", "onSourceControl:xyz"], - "fileSystems": [ - { - "scheme": "xyz" - } - ] -} diff --git a/packages/e2e/fixtures/sample.source-control-decoration/main.js b/packages/e2e/fixtures/sample.source-control-decoration/main.js deleted file mode 100644 index 8f344c6..0000000 --- a/packages/e2e/fixtures/sample.source-control-decoration/main.js +++ /dev/null @@ -1,57 +0,0 @@ -const contents = Object.create(null) - -const fileSystemProvider = { - id: 'xyz', - writeFile(uri, content) { - contents[uri] = content - }, - mkdir(uri) { - contents[uri] = '' - }, - rename(oldUri, newUri) {}, - readFile(uri) {}, - exists(uri) { - return false - }, - pathSeparator: '/', - readDirWithFileTypes(uri) { - const results = [] - for (const [key, value] of Object.entries(contents)) { - if (key.startsWith(uri)) { - results.push({ - type: 7, - name: key.slice(key.lastIndexOf('/') + 1), - }) - } - } - return results - }, -} - -const sourceControlProvider = { - id: 'xyz', - getChangedFiles() { - return [] - }, - getBadgeCount() { - return 0 - }, - getFileDecorations(uris) { - const filtered = uris.filter((uri) => uri.endsWith('a')) - const decorations = filtered.map((item) => { - return { - decoration: 'ignored', - uri: item, - } - }) - return decorations - }, - isActive() { - return true - }, -} - -export const activate = () => { - vscode.registerFileSystemProvider(fileSystemProvider) - vscode.registerSourceControlProvider(sourceControlProvider) -} diff --git a/packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts b/packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts deleted file mode 100644 index cbb4484..0000000 --- a/packages/e2e/src/viewlet.explorer-accept-edit-when-not-editing.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-accept-edit-when-not-editing' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - call acceptEdit when not in editing mode - await Explorer.acceptEdit() - - // assert - should not cause any errors and explorer should remain unchanged - const items = Locator('.TreeItem') - await expect(items).toHaveCount(3) - - const file1 = Locator('text=file1.txt') - await expect(file1).toBeVisible() - - const file2 = Locator('text=file2.txt') - await expect(file2).toBeVisible() - - const file3 = Locator('text=file3.txt') - await expect(file3).toBeVisible() - - // assert - no input box should be visible since we're not in editing mode - const inputBox = Locator('input') - await expect(inputBox).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-accessibility.ts b/packages/e2e/src/viewlet.explorer-accessibility.ts deleted file mode 100644 index 8b91f15..0000000 --- a/packages/e2e/src/viewlet.explorer-accessibility.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' -// manual accessibility tests - -// explorer -// nvda says: "Files explorer tree" -// windows narrator says: "Files explorer, tree" -// orca says: "Files explorer tree" - -// explorer item -// nvda says: "sample folder, collapsed, two of five, level 1" -// windows narrator says: "sample folder, two of five, collapsed, selected, heading level 1" ❌ -// orca says: "sample-folder, collapsed" - -export const name = 'viewlet.explorer-accessibility' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/languages`) - await FileSystem.mkdir(`${tmpDir}/sample-folder`) - await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') - await FileSystem.writeFile(`${tmpDir}/languages/index.html`, 'div') - await FileSystem.writeFile(`${tmpDir}/sample-folder/a.txt`, '') - await FileSystem.writeFile(`${tmpDir}/sample-folder/b.txt`, '') - await FileSystem.writeFile(`${tmpDir}/sample-folder/c.txt`, '') - - // act - await Workspace.setPath(tmpDir) - - const titleLanguages = '/languages' - const treeItemLanguages = Locator(`.TreeItem[title$="${titleLanguages}"]`) - await expect(treeItemLanguages).toHaveAttribute('tabindex', null) - await expect(treeItemLanguages).toHaveAttribute('role', 'treeitem') - await expect(treeItemLanguages).toHaveAttribute('aria-level', '1') - await expect(treeItemLanguages).toHaveAttribute('aria-posinset', '1') - await expect(treeItemLanguages).toHaveAttribute('aria-setsize', '3') - await expect(treeItemLanguages).toHaveAttribute('aria-expanded', 'false') - - const titleSampleFolder = '/sample-folder' - const treeItemSampleFolder = Locator(`.TreeItem[title$="${titleSampleFolder}"]`) - await expect(treeItemSampleFolder).toHaveAttribute('tabindex', null) - await expect(treeItemSampleFolder).toHaveAttribute('role', 'treeitem') - await expect(treeItemSampleFolder).toHaveAttribute('aria-level', '1') - await expect(treeItemSampleFolder).toHaveAttribute('aria-posinset', '2') - await expect(treeItemSampleFolder).toHaveAttribute('aria-setsize', '3') - await expect(treeItemSampleFolder).toHaveAttribute('aria-expanded', 'false') - - const titleTest = '/test.txt' - const treeItemTestTxt = Locator(`.TreeItem[title$="${titleTest}"]`) - await expect(treeItemTestTxt).toHaveAttribute('tabindex', null) - await expect(treeItemTestTxt).toHaveAttribute('aria-level', '1') - await expect(treeItemTestTxt).toHaveAttribute('aria-posinset', '3') - await expect(treeItemTestTxt).toHaveAttribute('aria-setsize', '3') - // await expect(treeItemTestTxt).not.toHaveAttribute('aria-expanded', 'false') // TODO - - await Explorer.handleClick(0) - await expect(treeItemLanguages).toHaveAttribute('aria-level', '1') - await expect(treeItemLanguages).toHaveAttribute('aria-posinset', '1') - await expect(treeItemLanguages).toHaveAttribute('aria-setsize', '3') - await expect(treeItemLanguages).toHaveAttribute('aria-expanded', 'true') - - const titleIndexHtml = '/languages/index.html' - const treeItemIndexHtml = Locator(`.TreeItem[title$="${titleIndexHtml}"]`) - await expect(treeItemIndexHtml).toHaveAttribute('tabindex', null) - await expect(treeItemIndexHtml).toHaveAttribute('aria-level', '2') - await expect(treeItemIndexHtml).toHaveAttribute('aria-posinset', '1') - await expect(treeItemIndexHtml).toHaveAttribute('aria-setsize', '1') - // await expect(treeItemIndexHtml).not.toHaveAttribute('aria-expanded', 'false') // TODO -} diff --git a/packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts b/packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts deleted file mode 100644 index 58b8e26..0000000 --- a/packages/e2e/src/viewlet.explorer-click-empty-space-clears-multiple-selection.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-click-empty-space-clears-multiple-selection' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.selectIndices([0, 1]) - - const focusedListItems = Locator('.Explorer .ListItems.FocusOutline') - const file1 = Locator('.TreeItem').nth(0) - const file2 = Locator('.TreeItem').nth(1) - const file3 = Locator('.TreeItem').nth(2) - - // act - await Explorer.handleClickAt(false, 0, false, false, 20, 10_000) - - // assert - await expect(focusedListItems).toBeVisible() - await expect(file1).toHaveClass('TreeItem') - await expect(file2).toHaveClass('TreeItem') - await expect(file3).toHaveClass('TreeItem') -} diff --git a/packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts b/packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts deleted file mode 100644 index 8bc7abb..0000000 --- a/packages/e2e/src/viewlet.explorer-click-empty-space-clears-selection.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-click-empty-space-clears-selection' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await Workspace.setPath(tmpDir) - await Explorer.selectIndices([0]) - - const focusedListItems = Locator('.Explorer .ListItems.FocusOutline') - const file1 = Locator('.TreeItem').nth(0) - const file2 = Locator('.TreeItem').nth(1) - - // act - await Explorer.handleClickAt(false, 0, false, false, 20, 10_000) - - // assert - await expect(focusedListItems).toBeVisible() - await expect(file1).toHaveClass('TreeItem') - await expect(file2).toHaveClass('TreeItem') -} diff --git a/packages/e2e/src/viewlet.explorer-collapse-all.ts b/packages/e2e/src/viewlet.explorer-collapse-all.ts deleted file mode 100644 index d5310f7..0000000 --- a/packages/e2e/src/viewlet.explorer-collapse-all.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-collapse-all' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a/b`) - await FileSystem.mkdir(`${tmpDir}/a/b/c`) - await FileSystem.mkdir(`${tmpDir}/a/b/c/d`) - await Workspace.setPath(tmpDir) - await Explorer.expandRecursively() - await Explorer.focusLast() - - // act - await Explorer.collapseAll() - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - await expect(treeItems).toHaveCount(1) - await expect(firstTreeItem).toHaveText('a') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts b/packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts deleted file mode 100644 index 181b2bf..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-compare-with-selected.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-compare-with-selected' - -export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'left') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'right') - await Workspace.setPath(tmpDir) - await Explorer.openContextMenu(0) - await ContextMenu.selectItem('Select for Compare') - - // act - await Explorer.openContextMenu(1) - await ContextMenu.selectItem('Compare with Selected') - - // assert - const diffEditor = Locator('.DiffEditor') - await expect(diffEditor).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts deleted file mode 100644 index 918269f..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-copy-path-file.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-copy-path-file' - -export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.expandRecursively() - - // act - await Explorer.openContextMenu(1) - await ContextMenu.selectItem('Copy Path') - - // assert - await ClipBoard.shouldHaveText('memfs:///workspace/a/b.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts deleted file mode 100644 index 2535d0d..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-copy-path-root.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-copy-path-root' - -export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(-1) - - // act - await Explorer.openContextMenu(-1) - await ContextMenu.selectItem('Copy Path') - - // assert - await ClipBoard.shouldHaveText('memfs:///workspace') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts deleted file mode 100644 index 5997c03..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-file.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-copy-relative-path-file' - -export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.expandRecursively() - - // act - await Explorer.openContextMenu(1) - await ContextMenu.selectItem('Copy Relative Path') - - // assert - await ClipBoard.shouldHaveText('a/b.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts b/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts deleted file mode 100644 index 18c361b..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-copy-relative-path-root-no-focused-item' - -export const test: Test = async ({ ClipBoard, ContextMenu, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(-1) - await ClipBoard.writeText('unchanged') - - // act - await Explorer.openContextMenu(-1) - await ContextMenu.selectItem('Copy Relative Path') - - // assert - await ClipBoard.shouldHaveText('unchanged') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts deleted file mode 100644 index 10d5e28..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-create-file-error-already-exists.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-create-file-error-already-exists' - -export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(-1) - - // act - await Explorer.openContextMenu(-1) - await ContextMenu.selectItem('New File...') - await Explorer.updateEditingValue('file1.txt') - - // assert - const inputBox = Locator('input') - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('A file or folder **file1.txt** already exists at this location. Please choose a different name.') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts deleted file mode 100644 index 49bdf7e..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-create-folder-error-already-exists.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-create-folder-error-already-exists' - -export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/folder1`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(-1) - - // act - await Explorer.openContextMenu(-1) - await ContextMenu.selectItem('New Folder...') - await Explorer.updateEditingValue('folder1') - - // assert - const inputBox = Locator('input') - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('A file or folder **folder1** already exists at this location. Please choose a different name.') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts b/packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts deleted file mode 100644 index 3d45ab6..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-delete-file-with-focus.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-delete-file-with-focus' - -export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(2) - await Workspace.setPath(tmpDir) - - // act - await Explorer.openContextMenu(0) - await ContextMenu.selectItem('Delete') - - // assert - const file1 = Locator('text=file1.txt') - await expect(file1).toBeHidden() - const listItems = Locator('.Explorer .ListItems') - await expect(listItems).toBeFocused() -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts b/packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts deleted file mode 100644 index b4431d7..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-delete-file.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-delete-file' - -export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - await Workspace.setPath(tmpDir) - - // act - await Explorer.openContextMenu(0) - await ContextMenu.selectItem('Delete') - - // assert - const file1 = Locator('text=file1.txt') - await expect(file1).toBeHidden() - const listItems = Locator('.Explorer .ListItems') - await expect(listItems).toBeFocused() -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts b/packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts deleted file mode 100644 index dbcfb8d..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-paste-root-no-focused-item.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-paste-root-no-focused-item' - -export const test: Test = async ({ ClipBoard, ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - await Explorer.handleCopy() - await Explorer.focusIndex(-1) - - // act - await Explorer.openContextMenu(-1) - await ContextMenu.selectItem('Paste') - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('file.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts b/packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts deleted file mode 100644 index f54a0d6..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-remove-folder-from-workspace.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-remove-folder-from-workspace' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - - // act - await Explorer.openContextMenu(-1) - - // assert - const menuItem = Locator('text=Remove folder from workspace') - await expect(menuItem).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts b/packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts deleted file mode 100644 index a63c95c..0000000 --- a/packages/e2e/src/viewlet.explorer-context-menu-select-for-compare.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-context-menu-select-for-compare' - -export const test: Test = async ({ ContextMenu, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await Workspace.setPath(tmpDir) - await Explorer.openContextMenu(0) - await ContextMenu.selectItem('Select for Compare') - - // act - await Explorer.openContextMenu(1) - - // assert - const compareWithSelected = Locator('text=Compare with Selected') - await expect(compareWithSelected).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts deleted file mode 100644 index d9df069..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-and-paste-file.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-and-paste-file' - -export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') - await FileSystem.mkdir(`${tmpDir}/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - - // act - await Explorer.handleCopy() - await Explorer.focusIndex(-1) - await Explorer.handlePaste() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - await expect(file1).toHaveAttribute('aria-expanded', 'true') - const file3 = Locator('.TreeItem').nth(1) - await expect(file3).toHaveText('b') - await expect(file3).toHaveAttribute('aria-expanded', 'false') // TODO should be true - const file4 = Locator('.TreeItem').nth(2) - await expect(file4).toHaveText('file.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts deleted file mode 100644 index 95728d9..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-error.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-and-paste-folder-error' - -export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.mkdir(`${tmpDir}/a/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - - // act - await Explorer.handleCopy() - await Explorer.focusIndex(1) - await Explorer.handlePaste() - - // assert - // TODO error message should be displayed -} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts deleted file mode 100644 index dd06566..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder-with-items.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-and-paste-folder-with-items' - -export const skip = 1 - -export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/file.txt`, '') - await FileSystem.mkdir(`${tmpDir}/a/c`) - await FileSystem.mkdir(`${tmpDir}/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - - // act - await Explorer.handleCopy() - await Explorer.focusIndex(3) - await Explorer.handlePaste() - await Explorer.expandAll() - - // assert - const treeItems = Locator('.TreeItem') - await expect(treeItems).toHaveCount(2) - const file1 = treeItems.nth(0) - await expect(file1).toHaveText('b') - await expect(file1).toHaveAttribute('aria-expanded', 'true') - const file2 = treeItems.nth(1) - await expect(file2).toHaveText('a') - // await expect(file1).toHaveAttribute('aria-expanded', 'false') -} diff --git a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts b/packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts deleted file mode 100644 index ad95428..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-and-paste-folder.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-and-paste-folder' - -export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.mkdir(`${tmpDir}/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - - // act - await Explorer.handleCopy() - await Explorer.focusIndex(1) - await Explorer.handlePaste() - await Explorer.expandAll() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('b') - await expect(file1).toHaveAttribute('aria-expanded', 'true') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('a') - // await expect(file1).toHaveAttribute('aria-expanded', 'false') -} diff --git a/packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts b/packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts deleted file mode 100644 index 3a3c6d7..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-paste-error-scenarios.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-paste-error-scenarios' -export const skip = 1 - -export const test: Test = async ({ ClipBoard, Command, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/source`) - await FileSystem.writeFile(`${tmpDir}/source/file.txt`, 'content') - await FileSystem.mkdir(`${tmpDir}/target`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - - // Test 1: Copy file to read-only directory - await Command.execute('FileSystem.setReadOnly', `${tmpDir}/target`, true) - await Explorer.handleCopy() - await Explorer.focusIndex(2) - await Explorer.handlePaste() - - // Should show error message for read-only target - const errorMessage = Locator('.ErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('Permission denied') - - // Test 2: Paste without copying anything first - await Explorer.handlePaste() - await expect(errorMessage).toBeVisible() - - // Test 3: Copy non-existent file (simulate file deletion after copy) - await Command.execute('FileSystem.setReadOnly', `${tmpDir}/target`, false) - await Explorer.handleCopy() - await Command.execute('FileSystem.deleteFile', `${tmpDir}/source/file.txt`) - await Explorer.focusIndex(2) - await Explorer.handlePaste() - - // Should handle missing source gracefully - await expect(errorMessage).toBeVisible() - - // Test 4: Copy file with invalid characters in name - await FileSystem.writeFile(`${tmpDir}/source/invalid|file.txt`, 'content') - await Explorer.focusIndex(1) - await Explorer.expandRecursively() - await Explorer.focusIndex(2) - await Explorer.handleCopy() - await Explorer.focusIndex(3) - await Explorer.handlePaste() - - // Should handle invalid characters - await expect(errorMessage).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-copy-path-empty.ts b/packages/e2e/src/viewlet.explorer-copy-path-empty.ts deleted file mode 100644 index a065108..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-path-empty.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-path-empty' - -export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await Workspace.setPath(tmpDir) - await Explorer.expandRecursively() - - // act - await Explorer.copyPath() - - // assert - await ClipBoard.shouldHaveText('memfs:///workspace') -} diff --git a/packages/e2e/src/viewlet.explorer-copy-path-file.ts b/packages/e2e/src/viewlet.explorer-copy-path-file.ts deleted file mode 100644 index 67b34c7..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-path-file.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-path-file' - -export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - - // act - await Explorer.copyPath() - - // assert - await ClipBoard.shouldHaveText('memfs:///workspace/a/b.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-copy-path-folder.ts b/packages/e2e/src/viewlet.explorer-copy-path-folder.ts deleted file mode 100644 index 4fa4164..0000000 --- a/packages/e2e/src/viewlet.explorer-copy-path-folder.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-copy-path-folder' - -export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - - // act - await Explorer.copyPath() - - // assert - await ClipBoard.shouldHaveText('memfs:///workspace/a') -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts b/packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts deleted file mode 100644 index 043bda9..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-blur-no-name.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-blur-no-name' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.handleInputBlur() - - // assert - await expect(inputBox).toBeHidden() - const items = Locator('.TreeItem') - await expect(items).toHaveCount(1) -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-blur.ts b/packages/e2e/src/viewlet.explorer-create-file-blur.ts deleted file mode 100644 index ebdbcf1..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-blur.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-blur' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('created.txt') - await Explorer.handleInputBlur() - - // assert - const newFile = Locator('.Explorer').locator('text=created.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-cancel.ts b/packages/e2e/src/viewlet.explorer-create-file-cancel.ts deleted file mode 100644 index d1286ee..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-cancel.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-cancel' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('created.txt') - await Explorer.cancelEdit() - - // assert - await expect(inputBox).toBeHidden() - const items = Locator('.TreeItem') - await expect(items).toHaveCount(1) -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-different-languages.ts b/packages/e2e/src/viewlet.explorer-create-file-different-languages.ts deleted file mode 100644 index d385a9d..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-different-languages.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-different-languages' - -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - - await Workspace.setPath(tmpDir) - - // Test 1: Create file with German characters - await Explorer.newFile() - const inputBox1 = Locator('input') - await expect(inputBox1).toBeVisible() - await expect(inputBox1).toBeFocused() - await Explorer.updateEditingValue('Müller.txt') - await Explorer.acceptEdit() - const newFile1 = Locator('.Explorer').locator('text=Müller.txt') - await expect(newFile1).toBeVisible() - - // Test 2: Create file with French characters - await Explorer.newFile() - const inputBox2 = Locator('input') - await expect(inputBox2).toBeVisible() - await expect(inputBox2).toBeFocused() - await Explorer.updateEditingValue('Français.txt') - await Explorer.acceptEdit() - const newFile2 = Locator('.Explorer').locator('text=Français.txt') - await expect(newFile2).toBeVisible() - - // Test 3: Create file with Spanish characters - await Explorer.newFile() - const inputBox3 = Locator('input') - await expect(inputBox3).toBeVisible() - await expect(inputBox3).toBeFocused() - await Explorer.updateEditingValue('Niño.txt') - await Explorer.acceptEdit() - const newFile3 = Locator('.Explorer').locator('text=Niño.txt') - await expect(newFile3).toBeVisible() - - // Test 4: Create file with Russian characters - await Explorer.newFile() - const inputBox4 = Locator('input') - await expect(inputBox4).toBeVisible() - await expect(inputBox4).toBeFocused() - await Explorer.updateEditingValue('Русский.txt') - await Explorer.acceptEdit() - const newFile4 = Locator('.Explorer').locator('text=Русский.txt') - await expect(newFile4).toBeVisible() - - // Test 5: Create file with Chinese characters - await Explorer.newFile() - const inputBox5 = Locator('input') - await expect(inputBox5).toBeVisible() - await expect(inputBox5).toBeFocused() - await Explorer.updateEditingValue('中文.txt') - await Explorer.acceptEdit() - const newFile5 = Locator('.Explorer').locator('text=中文.txt') - await expect(newFile5).toBeVisible() - - // Test 6: Create file with Japanese characters - await Explorer.newFile() - const inputBox6 = Locator('input') - await expect(inputBox6).toBeVisible() - await expect(inputBox6).toBeFocused() - await Explorer.updateEditingValue('こんにちは.txt') - await Explorer.acceptEdit() - const newFile6 = Locator('.Explorer').locator('text=こんにちは.txt') - await expect(newFile6).toBeVisible() - - // Test 7: Create file with Korean characters - await Explorer.newFile() - const inputBox7 = Locator('input') - await expect(inputBox7).toBeVisible() - await expect(inputBox7).toBeFocused() - await Explorer.updateEditingValue('안녕하세요.txt') - await Explorer.acceptEdit() - const newFile7 = Locator('.Explorer').locator('text=안녕하세요.txt') - await expect(newFile7).toBeVisible() - - // Test 8: Create file with Arabic characters - await Explorer.newFile() - const inputBox8 = Locator('input') - await expect(inputBox8).toBeVisible() - await expect(inputBox8).toBeFocused() - await Explorer.updateEditingValue('العربية.txt') - await Explorer.acceptEdit() - const newFile8 = Locator('.Explorer').locator('text=العربية.txt') - await expect(newFile8).toBeVisible() - - // Test 9: Create file with Hebrew characters - await Explorer.newFile() - const inputBox9 = Locator('input') - await expect(inputBox9).toBeVisible() - await expect(inputBox9).toBeFocused() - await Explorer.updateEditingValue('עברית.txt') - await Explorer.acceptEdit() - const newFile9 = Locator('.Explorer').locator('text=עברית.txt') - await expect(newFile9).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts b/packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts deleted file mode 100644 index 3395f97..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-double-click-empty-space.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-double-click-empty-space' - -export const test: Test = async ({ Command, expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - - // act - await Command.execute('Explorer.handleClickAt', false, 0, false, false, 20, 100) - await Command.execute('Explorer.handleDoubleClick', 20, 100) - - // assert - const inputBox = Locator('.Explorer input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts deleted file mode 100644 index a8a05df..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-already-exists.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-already-exists' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - await Explorer.newFile() - - // act - await Explorer.updateEditingValue('file1.txt') - - // assert - const inputBox = Locator('input') - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText(`A file or folder **file1.txt** already exists at this location. Please choose a different name.`) -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts deleted file mode 100644 index b45b36c..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-file-name-cannot-start-with-backslash' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('\\') - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('A file or folder name cannot start with a backslash.') -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts deleted file mode 100644 index 68672d0..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-dot.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-file-name-cannot-start-with-slash' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('.') - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('The name **{0}** is not valid as a file or folder name. Please choose a different name.') -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts b/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts deleted file mode 100644 index ee97c1c..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-file-name-cannot-start-with-slash.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-file-name-cannot-start-with-slash' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('/') - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('A file or folder name cannot start with a slash.') -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts b/packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts deleted file mode 100644 index ff37082..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-no-name-provided.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-no-name-provided' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.acceptEdit() - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('A file or folder name must be provided.') -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts deleted file mode 100644 index 40f1f54..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-escape-then-create-again.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-permission-denied-escape-then-create-again' - -export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { - // arrange - const uri = import.meta.resolve('../fixtures/sample.file-system-provider-create-file-error-permission-denied') - await Extension.addWebExtension(uri) - const prefix = 'extension-host://xyz://' - await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') - await Workspace.setPath(`${prefix}/`) - - const inputBox = Locator('input') - const errorMessage = Locator('.ExplorerErrorMessage') - const items = Locator('.TreeItem') - - // act - await Explorer.newFile() - await Explorer.updateEditingValue('file4.txt') - await Explorer.acceptEdit() - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('Error: Failed to execute file system provider: Permission Denied') - - // act - await Explorer.cancelEdit() - - // assert - await expect(inputBox).toBeHidden() - await expect(items).toHaveCount(3) - - // act - await Explorer.newFile() - - // assert - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - await expect(inputBox).toHaveValue('') - await expect(errorMessage).toBeHidden() - await expect(items).toHaveCount(4) -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts deleted file mode 100644 index c2a329f..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied-long-path.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-permission-denied' - -export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { - // arrange - const uri = import.meta.resolve('../fixtures/sample.file-system-provider-create-file-error-permission-denied-long-path') - await Extension.addWebExtension(uri) - const prefix = 'extension-host://xyz://' - await FileSystem.writeFile(`${prefix}/usr/lib/lvce/resources/app/playground/file1.txt`, 'content 1') - await FileSystem.writeFile(`${prefix}/usr/lib/lvce/resources/app/playground/file2.txt`, 'content 2') - await FileSystem.writeFile(`${prefix}/usr/lib/lvce/resources/app/playground/file3.txt`, 'content 3') - await Workspace.setPath(`${prefix}/`) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('file4.txt') - await Explorer.acceptEdit() - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText( - `Error: Failed to execute file system provider: Error: Failed to write to file "/file4.txt": EACCES: permission denied, open '/file4.txt'`, - ) -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts b/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts deleted file mode 100644 index 27feb5a..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-error-permission-denied.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-permission-denied' - -export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { - // arrange - const uri = import.meta.resolve('../fixtures/sample.file-system-provider-create-file-error-permission-denied') - await Extension.addWebExtension(uri) - const prefix = 'extension-host://xyz://' - await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') - await Workspace.setPath(`${prefix}/`) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('file4.txt') - await Explorer.acceptEdit() - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('Error: Failed to execute file system provider: Permission Denied') -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts b/packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts deleted file mode 100644 index b25283b..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-explorer-collapses.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-explorer-collapses' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.newFile() - const inputBox = Locator('input') - await Explorer.updateEditingValue('test-file.txt') - - // act - await Explorer.collapseAll() - - // assert - await expect(inputBox).toBeHidden() - - // TODO focus should be at on tree -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts b/packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts deleted file mode 100644 index 8592c1b..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-inside-closed-folder.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-inside-closed-folder' - -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/folder1`) - await FileSystem.writeFile(`${tmpDir}/folder1/existing.txt`, 'content') - await FileSystem.mkdir(`${tmpDir}/folder2`) - await FileSystem.mkdir(`${tmpDir}/folder2/nested`) - await FileSystem.writeFile(`${tmpDir}/folder2/nested/file.txt`, 'content') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(1) - - // act - await Explorer.newFile() - - // assert - const folder2 = Locator('.Explorer').locator('text=folder2') - await expect(folder2).toBeVisible() - await expect(folder2).toHaveAttribute('aria-expanded', 'true') - const newFile = Locator('.Explorer').locator('text=created.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts b/packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts deleted file mode 100644 index 53ae187..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-inside-folder.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-inside-folder' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.mkdir(`${tmpDir}/b`) - await FileSystem.mkdir(`${tmpDir}/c`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('created.txt') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=created.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-nested.ts b/packages/e2e/src/viewlet.explorer-create-file-nested.ts deleted file mode 100644 index 555298f..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-nested.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-nested' - -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('a/b/created.txt') - await Explorer.acceptEdit() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('b') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).toHaveText('created.txt') - const file4 = Locator('.TreeItem').nth(3) - await expect(file4).toHaveText('file1.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts b/packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts deleted file mode 100644 index 3304370..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-opens-in-editor.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-opens-in-editor' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - input box is visible - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - create new file - await Explorer.updateEditingValue('new-file.txt') - await Explorer.acceptEdit() - - // assert - file is visible in explorer - const newFile = Locator('.Explorer').locator('text=new-file.txt') - await expect(newFile).toBeVisible() - - // assert - input should be hidden after accepting - await expect(inputBox).toBeHidden() - - // assert - file should be opened in editor (check for editor tab or editor view) - // The file should be opened, which means there should be an editor tab or editor content visible - const editorTab = Locator('[title*="new-file.txt"]').first() - await expect(editorTab).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts b/packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts deleted file mode 100644 index 9653161..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-starting-with-dot.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-starting-with-dot' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('.editorconfig') - - // assert - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts b/packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts deleted file mode 100644 index 9a0099c..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-switch-folders.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-switch-folders' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.mkdir(`${tmpDir}/b`) - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - - // act - start creating file in folder a - await Explorer.focusIndex(0) // focus on folder a - await Explorer.newFile() - - // assert - input should be visible in folder a - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - type some content for the file in folder a - await inputBox.type('file-in-a.txt') - - // act - switch to folder b and start creating file there - await Explorer.focusIndex(1) // focus on folder b - await Explorer.newFile() - - // assert - only one input should be visible (the new one in folder b) - const inputBoxes = Locator('input') - await expect(inputBoxes).toHaveCount(1) - await expect(inputBoxes).toBeVisible() - await expect(inputBoxes).toBeFocused() - - // act - type content for the file in folder b - await inputBoxes.type('file-in-b.txt') - await Explorer.updateEditingValue('file-in-b.txt') - await Explorer.acceptEdit() - - // assert - file should be created in folder b - const newFile = Locator('.Explorer').locator('text=file-in-b.txt') - await expect(newFile).toBeVisible() - - // assert - no input should be visible after accepting - await expect(inputBoxes).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts b/packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts deleted file mode 100644 index 5db01fc..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-when-file-is-focused.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-when-file-is-focused' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('created.txt') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=created.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts b/packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts deleted file mode 100644 index 72e3b8f..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-with-emoji-extension.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-with-emoji-extension' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('created.😀') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=created.😀') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts b/packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts deleted file mode 100644 index 4f8c992..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-with-emoji.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-with-emoji' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('🚀 rocket.txt') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=🚀 rocket.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts b/packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts deleted file mode 100644 index a3aed74..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-with-greek-characters.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-with-greek-characters' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('αρχείο.txt') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=αρχείο.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-newline.ts b/packages/e2e/src/viewlet.explorer-create-file-with-newline.ts deleted file mode 100644 index 3bff927..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-with-newline.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-with-newline' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('file\nwith\nnewline.txt') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=file\nwith\nnewline.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts b/packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts deleted file mode 100644 index e6e3cb3..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-with-non-breaking-space.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-with-non-breaking-space' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - const fileName = `my\u00A0file.txt` - await Explorer.updateEditingValue(fileName) - await Explorer.acceptEdit() - - // assert - const dirents = await FileSystem.readDir(tmpDir) - const hasCreatedFile = dirents.some((dirent) => dirent.name === fileName) - if (!hasCreatedFile) { - throw new Error(`Expected directory to contain ${JSON.stringify(fileName)} but got ${JSON.stringify(dirents)}`) - } -} diff --git a/packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts b/packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts deleted file mode 100644 index 9e473be..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file-with-spaces.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-with-spaces' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('my file with spaces.txt') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=my file with spaces.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-file.ts b/packages/e2e/src/viewlet.explorer-create-file.ts deleted file mode 100644 index 6110bfd..0000000 --- a/packages/e2e/src/viewlet.explorer-create-file.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file' - -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('created.txt') - await Explorer.acceptEdit() - - // assert - const newFile = Locator('.Explorer').locator('text=created.txt') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts b/packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts deleted file mode 100644 index 49d7744..0000000 --- a/packages/e2e/src/viewlet.explorer-create-folder-nested-150-times.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-folder-nested-150-times' - -const depth = 150 - -const getFolderName = (index: number): string => { - return `folder-${index.toString().padStart(3, '0')}` -} - -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - - const inputBox = Locator('input') - - // act - for (let index = 0; index < depth; index++) { - const folderName = getFolderName(index) - - if (index > 0) { - await Explorer.focusIndex(index - 1) - } - await Explorer.newFolder() - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - await Explorer.updateEditingValue(folderName) - await Explorer.acceptEdit() - await expect(inputBox).toBeHidden() - } - - // assert - const treeItems = Locator('.TreeItem') - await expect(treeItems).toHaveCount(depth + 1) - - const deepestFolder = Locator('.TreeItem', { hasText: getFolderName(depth - 1) }) - await expect(deepestFolder).toBeVisible() - - let currentPath = tmpDir - for (let index = 0; index < depth; index++) { - const folderName = getFolderName(index) - const dirents = await FileSystem.readDir(currentPath) - const hasFolder = dirents.some((dirent) => dirent.name === folderName) - if (!hasFolder) { - throw new Error(`Expected ${JSON.stringify(currentPath)} to contain ${JSON.stringify(folderName)} but got ${JSON.stringify(dirents)}`) - } - currentPath = `${currentPath}/${folderName}` - } -} diff --git a/packages/e2e/src/viewlet.explorer-create-folder-nested.ts b/packages/e2e/src/viewlet.explorer-create-folder-nested.ts deleted file mode 100644 index 20b6ac9..0000000 --- a/packages/e2e/src/viewlet.explorer-create-folder-nested.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-folder-nested' - -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - await Explorer.newFolder() - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('a/b/c') - await Explorer.acceptEdit() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - await expect(file1).toHaveAttribute('aria-expanded', 'true') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('b') - await expect(file2).toHaveAttribute('aria-expanded', 'true') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).toHaveText('c') - await expect(file3).toHaveAttribute('aria-expanded', 'false') - const file4 = Locator('.TreeItem').nth(3) - await expect(file4).toHaveText('file1.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts b/packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts deleted file mode 100644 index 4acbecd..0000000 --- a/packages/e2e/src/viewlet.explorer-create-folder-with-backslashes.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-folder-with-backslashes' - -export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/\\eee\\`) - - // act - await Workspace.setPath(tmpDir) - - // assert - const newFolder = Locator('.Explorer').locator('text=\\eee\\') - await expect(newFolder).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-create-folder.ts b/packages/e2e/src/viewlet.explorer-create-folder.ts deleted file mode 100644 index abe76e5..0000000 --- a/packages/e2e/src/viewlet.explorer-create-folder.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-folder' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFolder() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('folder') - await Explorer.acceptEdit() - - // assert - const newFolder = Locator('.Explorer').locator('text=folder') - await expect(newFolder).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts deleted file mode 100644 index 00741d6..0000000 --- a/packages/e2e/src/viewlet.explorer-cut-and-paste-file-error-already-exists.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-cut-and-paste-file-error-already-exists' - -export const test: Test = async ({ ClipBoard, Explorer, FileSystem, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') - await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(2) - - // act - await Explorer.handleCut() - await Explorer.focusIndex(0) - await Explorer.handlePaste() - - // TODO should show error message that destination already exists - // assert - // const file1 = Locator('.TreeItem').nth(0) - // await expect(file1).toHaveText('a') - // await expect(file1).toHaveAttribute('aria-expanded', 'true') - // // TODO should be hidden - // const file2 = Locator('.TreeItem').nth(1) - // await expect(file2).toHaveText('b') - // await expect(file2).toHaveAttribute('aria-expanded', 'true') - // const file3 = Locator('.TreeItem').nth(2) - // await expect(file3).toHaveText('file.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts deleted file mode 100644 index 73bb696..0000000 --- a/packages/e2e/src/viewlet.explorer-cut-and-paste-file.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-cut-and-paste-file' - -export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') - await FileSystem.mkdir(`${tmpDir}/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - - // act - await Explorer.handleCut() - await Explorer.focusIndex(2) - await Explorer.handlePaste() - - // TODO folder should expanded automatically - await Explorer.focusIndex(1) - await Explorer.expandRecursively() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - await expect(file1).toHaveAttribute('aria-expanded', 'true') - // TODO should be hidden - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('b') - await expect(file2).toHaveAttribute('aria-expanded', 'true') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).toHaveText('file.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts deleted file mode 100644 index c8f09a2..0000000 --- a/packages/e2e/src/viewlet.explorer-cut-and-paste-two-files.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-cut-and-paste-two-files' - -export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/file-1.txt`, 'content') - await FileSystem.writeFile(`${tmpDir}/a/file-2.txt`, 'content') - await FileSystem.mkdir(`${tmpDir}/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - - // act - await Explorer.selectIndices([1, 2]) - await Explorer.handleCut() - await Explorer.focusIndex(3) - await Explorer.handlePaste() - - // TODO folder should expanded automatically - await Explorer.focusIndex(1) - await Explorer.expandRecursively() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - await expect(file1).toHaveAttribute('aria-expanded', 'true') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('b') - await expect(file2).toHaveAttribute('aria-expanded', 'true') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).toHaveText('file-1.txt') - const file4 = Locator('.TreeItem').nth(3) - await expect(file4).toHaveText('file-2.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts b/packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts deleted file mode 100644 index 7eff1d0..0000000 --- a/packages/e2e/src/viewlet.explorer-cut-and-paste-two-folders.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-cut-and-paste-two-folders' - -export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.mkdir(`${tmpDir}/a/c`) - await FileSystem.mkdir(`${tmpDir}/a/d`) - await FileSystem.mkdir(`${tmpDir}/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - - // act - await Explorer.selectIndices([1, 2]) - await Explorer.handleCut() - await Explorer.focusIndex(3) - await Explorer.handlePaste() - - // TODO folder should expanded automatically - await Explorer.focusIndex(1) - await Explorer.expandRecursively() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - await expect(file1).toHaveAttribute('aria-expanded', 'true') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('b') - await expect(file2).toHaveAttribute('aria-expanded', 'true') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).toHaveText('c') - const file4 = Locator('.TreeItem').nth(3) - await expect(file4).toHaveText('d') -} diff --git a/packages/e2e/src/viewlet.explorer-cut-cancel.ts b/packages/e2e/src/viewlet.explorer-cut-cancel.ts deleted file mode 100644 index 5e69d37..0000000 --- a/packages/e2e/src/viewlet.explorer-cut-cancel.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-cut-cancel' - -export const test: Test = async ({ ClipBoard, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - await ClipBoard.enableMemoryClipBoard() - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/file.txt`, 'content') - await FileSystem.mkdir(`${tmpDir}/b`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - await Explorer.focusIndex(1) - - // act - await Explorer.handleCut() - const treeItem = Locator('.TreeItem[data-index="1"]') - const treeItemLabel = treeItem.locator('.Label') - await expect(treeItemLabel).toHaveClass('LabelCut') - - await Explorer.handleEscape() - await expect(treeItemLabel).toHaveJSProperty('className', 'Label') -} diff --git a/packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts b/packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts deleted file mode 100644 index 07450a7..0000000 --- a/packages/e2e/src/viewlet.explorer-deeply-nested-folders.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-deeply-nested-folders' - -const depth = 1200 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - let currentPath = tmpDir - for (let i = 0; i < depth; i++) { - currentPath = `${currentPath}/a` - await FileSystem.mkdir(currentPath) - } - await FileSystem.writeFile(`${currentPath}/deep-file.txt`, 'deep') - - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - - // act - await Explorer.expandRecursively() - await Explorer.focusIndex(depth) - - // assert - const deepFile = Locator('.TreeItem', { hasText: 'deep-file.txt' }) - await expect(deepFile).toBeVisible() - await expect(deepFile).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts deleted file mode 100644 index cbf69a0..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-file-empty-workspace.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-file-empty-workspace' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await Workspace.setPath(tmpDir) - - // act - await Explorer.removeDirent() - - // assert - const listItems = Locator('.Explorer .ListItems') - await expect(listItems).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-delete-file-error.ts b/packages/e2e/src/viewlet.explorer-delete-file-error.ts deleted file mode 100644 index 7f64cdb..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-file-error.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-file-error' - -export const test: Test = async ({ Dialog, expect: _expect, Explorer, Extension, FileSystem, Locator: _Locator, Workspace }) => { - // arrange - // @ts-ignore - let _message: string = '' - // @ts-ignore - await Dialog.mockConfirm((message: string) => { - _message = message - return true - }) - const uri = import.meta.resolve('../fixtures/sample.file-system-provider-delete-file-error') - await Extension.addWebExtension(uri) - const prefix = 'extension-host://xyz://' - await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') - await Workspace.setPath(prefix) - await Explorer.focusFirst() - - // act - await Explorer.removeDirent() - - // assert - const expectedMessage = 'Error: Failed to execute file system provider: oops' - if (_message !== expectedMessage) { - throw new Error(`expected confirm message to be `) - } -} diff --git a/packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts b/packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts deleted file mode 100644 index 10b36b1..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-file-no-focused-item.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-file-no-focused-item' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') - await FileSystem.writeFile(`${tmpDir}/file-2.txt`, 'b') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(-1) - - // act - await Explorer.removeDirent() - - // assert - const file1 = Locator('.TreeItem', { hasText: 'file-1.txt' }) - const file2 = Locator('.TreeItem', { hasText: 'file-2.txt' }) - await expect(file1).toBeVisible() - await expect(file2).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-delete-file.ts b/packages/e2e/src/viewlet.explorer-delete-file.ts deleted file mode 100644 index 4f7a821..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-file.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-last-file' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - - // act - await Explorer.removeDirent() - - // assert - const file1 = Locator('text=file1.txt') - await expect(file1).toBeHidden() - const listItems = Locator('.Explorer .ListItems') - await expect(listItems).toBeFocused() - // TODO explorer should have focus outline -} diff --git a/packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts b/packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts deleted file mode 100644 index cbcad40..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-folder-with-items.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-folder-with-items' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/folder-1`) - await FileSystem.writeFile(`${tmpDir}/folder-1/a.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-1/b.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-1/c.txt`, '') - await FileSystem.mkdir(`${tmpDir}/folder-2`) - await FileSystem.mkdir(`${tmpDir}/folder-3`) - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - await Explorer.expandAll() - - // act - await Explorer.removeDirent() - - // assert - const fileA = Locator('text=a.txt') - const fileB = Locator('text=a.txt') - const fileC = Locator('text=a.txt') - await expect(fileA).toBeHidden() - await expect(fileB).toBeHidden() - await expect(fileC).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-delete-folder.ts b/packages/e2e/src/viewlet.explorer-delete-folder.ts deleted file mode 100644 index b114e38..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-folder.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-folder' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/folder-1`) - await FileSystem.mkdir(`${tmpDir}/folder-2`) - await FileSystem.mkdir(`${tmpDir}/folder-3`) - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusFirst() - await Explorer.removeDirent() - - // assert - const file1 = Locator('text=folder-1') - await expect(file1).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-delete-last-file.ts b/packages/e2e/src/viewlet.explorer-delete-last-file.ts deleted file mode 100644 index ec3c7a3..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-last-file.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-file' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - - // act - await Explorer.removeDirent() - - // assert - const file1 = Locator('text=file1.txt') - await expect(file1).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts b/packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts deleted file mode 100644 index 2d5d250..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-multiple-files-at-once.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-multiple-files' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - const explorer = Locator('.Explorer') - const file1 = explorer.locator('text=file1.txt') - const file2 = explorer.locator('text=file2.txt') - const file3 = explorer.locator('text=file3.txt') - await Explorer.focus() - await Explorer.selectIndices([0, 1]) - - // act - await Explorer.removeDirent() - - // assert - await expect(file1).toBeHidden() - await expect(file2).toBeHidden() - await expect(file3).toBeVisible() - - // TODO file3 should be focused -} diff --git a/packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts b/packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts deleted file mode 100644 index 5013812..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-multiple-files-focuses-remaining-item.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-multiple-files-focuses-remaining-item' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.selectIndices([0, 1]) - - const file1 = Locator('.TreeItem', { hasText: 'file1.txt' }) - const file2 = Locator('.TreeItem', { hasText: 'file2.txt' }) - const file3 = Locator('.TreeItem', { hasText: 'file3.txt' }) - - // act - await Explorer.removeDirent() - - // assert - await expect(file1).toBeHidden() - await expect(file2).toBeHidden() - await expect(file3).toBeVisible() - await expect(file3).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-delete-multiple-files.ts b/packages/e2e/src/viewlet.explorer-delete-multiple-files.ts deleted file mode 100644 index 52d05d9..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-multiple-files.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-multiple-files' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - const explorer = Locator('.Explorer') - const file1 = explorer.locator('text=file1.txt') - const file2 = explorer.locator('text=file2.txt') - const file3 = explorer.locator('text=file3.txt') - - // act - await Explorer.focus() - - // assert - // TODO - // await expect(explorer).toHaveClass('FocusOutline') - // await expect(explorer).toBeFocused() - - // act - await Explorer.focusIndex(2) - - // assert - // TODO - // await expect(file3).toHaveClass('FocusOutline') - - // act - await Explorer.removeDirent() - - // assert - await expect(file3).toBeHidden() - // TODO - // await expect(file2).toHaveClass('FocusOutline') - - // act - await Explorer.removeDirent() - // await KeyBoard.press('Delete') - - // assert - await expect(file2).toBeHidden() - // TODO - // await expect(file1).toHaveClass('FocusOutline') - - // act - await Explorer.removeDirent() - - // assert - await expect(file1).toBeHidden() - // TODO - // await expect(explorer).toHaveClass('FocusOutline') -} diff --git a/packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts b/packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts deleted file mode 100644 index 4611872..0000000 --- a/packages/e2e/src/viewlet.explorer-delete-nested-middle-folder.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-delete-nested-middle-folder' - -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a/b/c/d`) - await FileSystem.writeFile(`${tmpDir}/a/b/c/d/e.txt`, 'deep') - await Workspace.setPath(tmpDir) - - const topLevelFolder = Locator(`.TreeItem[title$="/a"]`) - const parentFolder = Locator(`.TreeItem[title$="/a/b"]`) - const deletedFolder = Locator(`.TreeItem[title$="/a/b/c"]`) - const deletedChildFolder = Locator(`.TreeItem[title$="/a/b/c/d"]`) - const deletedDescendantFile = Locator(`.TreeItem[title$="/a/b/c/d/e.txt"]`) - - await Explorer.focusFirst() - await Explorer.expandRecursively() - await Explorer.focusIndex(2) - - // act - await Explorer.removeDirent() - - // assert - await expect(topLevelFolder).toBeVisible() - await expect(parentFolder).toHaveId('TreeItemActive') - await expect(deletedFolder).toBeHidden() - await expect(deletedChildFolder).toBeHidden() - await expect(deletedDescendantFile).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts b/packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts deleted file mode 100644 index 1979825..0000000 --- a/packages/e2e/src/viewlet.explorer-drag-drop-error-scenarios.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drag-drop-error-scenarios' - -export const skip = 1 - -export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.mkdir(`${tmpDir}/readonly-dir`) - await Workspace.setPath(tmpDir) - - // Test 1: Drop file on read-only directory - await Command.execute('FileSystem.setReadOnly', `${tmpDir}/readonly-dir`, true) - - const directory = await navigator.storage.getDirectory() - const fileHandle = await directory.getFileHandle('test-file.txt', { create: true }) - const file = await fileHandle.getFile() - const fileList = [file] - const id = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) - - // Try to drop on read-only directory - await Explorer.handleDrop(2, 0, [id], fileList) - - // Should show error message - const errorMessage = Locator('.ErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('Permission denied') - - // Test 2: Drop with invalid file handle - const invalidId = 999_999 // Use number instead of string - await Explorer.handleDrop(0, 0, [invalidId], fileList) - - // Should handle invalid handle gracefully - await expect(errorMessage).toBeVisible() - - // Test 3: Drop file on itself (same location) - await Command.execute('FileSystem.setReadOnly', `${tmpDir}/readonly-dir`, false) - await Explorer.handleDrop(0, 0, [id], fileList) - - // Should handle or show appropriate message - const fileItem = Locator('.TreeItem', { hasText: 'test-file.txt' }) - await expect(fileItem).toBeVisible() - - // Test 4: Drop multiple files where one is invalid - const fileHandle2 = await directory.getFileHandle('test-file2.txt', { create: true }) - const file2 = await fileHandle2.getFile() - const fileList2 = [file, file2] - const id2 = await Command.execute('FileSystemHandle.addFileHandle', fileHandle2) - - // Delete one file after adding to handles to simulate error - await Command.execute('FileSystemHandle.removeFileHandle', id2) - - await Explorer.handleDrop(0, 0, [id, 999_999], fileList2) - - // Should handle partial failure gracefully - await expect(errorMessage).toBeVisible() - - // Test 5: Drop on non-existent target - await Explorer.handleDrop(999, 0, [id], fileList) - - // Should handle invalid target gracefully - await expect(errorMessage).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts b/packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts deleted file mode 100644 index d93a471..0000000 --- a/packages/e2e/src/viewlet.explorer-drag-file-into-folder.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drag-file-into-folder' - -export const skip = 1 - -export const test: Test = async ({ Explorer, FileSystem, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/new`) - await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(1) - await Explorer.handleDragOverIndex(1) - - // act - - // const opfsRoot = await navigator.storage.getDirectory() - // const fileHandle = await opfsRoot.getFileHandle('my first file', { - // create: true, - // }) - // console.log({ fileHandle }) - // const fileHandles = [fileHandle] - // const files = [] - // const paths = [] - // const index = 0 - // await Command.execute('Explorer.handleDropIndex', fileHandles, files, paths, index) - // await Explorer.handleDrop() - - // TODO drop file into folder and verify it is moved -} diff --git a/packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts deleted file mode 100644 index c097c63..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-empty-handles-empty-workspace.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-empty-handles-empty-workspace' - -export const test: Test = async ({ expect, Explorer, Locator, Workspace }) => { - // arrange - await Workspace.setPath('') - const welcomeMessage = Locator('.Explorer .WelcomeMessage') - const treeItems = Locator('.TreeItem') - - // act - await Explorer.handleDrop(5000, 5000, [], []) - - // assert - await expect(welcomeMessage).toBeVisible() - await expect(welcomeMessage).toHaveText('You have not yet opened a folder.') - await expect(treeItems).toHaveCount(0) -} diff --git a/packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts deleted file mode 100644 index a9b3509..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-file-and-folder-empty-workspace.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-file-and-folder-empty-workspace' - -export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { - // arrange - await Workspace.setPath('') - const opfsRoot = await navigator.storage.getDirectory() - const fileHandle = await opfsRoot.getFileHandle('dropped-file.txt', { - create: true, - }) - const directoryHandle = await opfsRoot.getDirectoryHandle('mixed-dropped-workspace-folder', { - create: true, - }) - const nestedFileHandle = await directoryHandle.getFileHandle('folder-inside.txt', { - create: true, - }) - const writable = await nestedFileHandle.createWritable({ keepExistingData: false }) - await writable.write('folder') - await writable.close() - const fileId = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) - const directoryId = await Command.execute('FileSystemHandle.addFileHandle', directoryHandle) - const welcomeMessage = Locator('.Explorer .WelcomeMessage') - const nestedFile = Locator('.TreeItem[aria-label="folder-inside.txt"]') - const droppedFile = Locator('.TreeItem[aria-label="dropped-file.txt"]') - - // act - await Explorer.handleDrop(5000, 5000, [fileId, directoryId], []) - - // assert - await expect(welcomeMessage).toBeHidden() - await expect(nestedFile).toBeVisible() - await expect(droppedFile).toHaveCount(0) -} diff --git a/packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts deleted file mode 100644 index 6c57eaa..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-file-empty-workspace.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-file-empty-workspace' - -export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { - // arrange - await Workspace.setPath('') - const opfsRoot = await navigator.storage.getDirectory() - const fileHandle = await opfsRoot.getFileHandle('dropped-file.txt', { - create: true, - }) - const id = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) - const welcomeMessage = Locator('.Explorer .WelcomeMessage') - const treeItems = Locator('.TreeItem') - - // act - await Explorer.handleDrop(5000, 5000, [id], []) - - // assert - await expect(welcomeMessage).toBeVisible() - await expect(welcomeMessage).toHaveText('You have not yet opened a folder.') - await expect(treeItems).toHaveCount(0) -} diff --git a/packages/e2e/src/viewlet.explorer-drop-file.ts b/packages/e2e/src/viewlet.explorer-drop-file.ts deleted file mode 100644 index f7701b2..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-file.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-file' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/new`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.handleDragOverIndex(0) - const opfsRoot = await navigator.storage.getDirectory() - const fileHandle = await opfsRoot.getFileHandle('my first file', { - create: true, - }) - const fileHandles = [fileHandle] - const files = [] - const paths = [] - const index = 0 - - // act - await Explorer.handleDropIndex(fileHandles, files, paths, index) - - // assert - const newFile = Locator('.TreeItem[aria-label="my first file"]') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts deleted file mode 100644 index 4488442..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-folder-empty-workspace.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-folder-empty-workspace' - -export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { - // arrange - await Workspace.setPath('') - const opfsRoot = await navigator.storage.getDirectory() - const directoryHandle = await opfsRoot.getDirectoryHandle('dropped-workspace-folder', { - create: true, - }) - const nestedFileHandle = await directoryHandle.getFileHandle('inside.txt', { - create: true, - }) - const writable = await nestedFileHandle.createWritable({ keepExistingData: false }) - await writable.write('hello world') - await writable.close() - const id = await Command.execute('FileSystemHandle.addFileHandle', directoryHandle) - const welcomeMessage = Locator('.Explorer .WelcomeMessage') - - // act - await Explorer.handleDrop(5000, 5000, [id], []) - - // assert - await expect(welcomeMessage).toBeHidden() - const nestedFile = Locator('.TreeItem[aria-label="inside.txt"]') - await expect(nestedFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts b/packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts deleted file mode 100644 index 2b1f678..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-folder-with-files.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-folder-with-files' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/new`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.handleDragOverIndex(0) - const opfsRoot = await navigator.storage.getDirectory() - const directoryHandle = await opfsRoot.getDirectoryHandle('my first folder', { - create: true, - }) - const nestedFileHandle = await directoryHandle.getFileHandle('my first nested file', { create: true }) - const writable = await nestedFileHandle.createWritable({ keepExistingData: false }) - await writable.write('hello world') - await writable.close() - const fileHandles = [directoryHandle] - const files = [] - const paths = [] - const index = 0 - - // act - await Explorer.handleDropIndex(fileHandles, files, paths, index) - await Explorer.expandRecursively() - - // assert - const newFolder = Locator('.TreeItem[aria-label="my first folder"]') - await expect(newFolder).toBeVisible() - await expect(newFolder).toHaveAttribute('aria-expanded', 'true') - const newFile = Locator('.TreeItem[aria-label="my first nested file"]') - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-drop-folder.ts b/packages/e2e/src/viewlet.explorer-drop-folder.ts deleted file mode 100644 index 5a893b0..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-folder.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-file' - -export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/new`) - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - await Explorer.handleDragOverIndex(0) - - // act - const opfsRoot = await navigator.storage.getDirectory() - const directoryHandle = await opfsRoot.getDirectoryHandle('my first folder', { - create: true, - }) - const fileHandles = [directoryHandle] - const files = [] - const paths = [] - const index = 0 - await Command.execute('Explorer.handleDropIndex', fileHandles, files, paths, index) - - // assert - const newFolder = Locator('.TreeItem[aria-label="my first folder"]') - await expect(newFolder).toBeVisible() - await expect(newFolder).toHaveAttribute('aria-expanded', 'false') -} diff --git a/packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts deleted file mode 100644 index 6ab51fc..0000000 --- a/packages/e2e/src/viewlet.explorer-drop-two-folders-empty-workspace.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-drop-two-folders-empty-workspace' - -export const test: Test = async ({ Command, expect, Explorer, Locator, Workspace }) => { - // arrange - await Workspace.setPath('') - const opfsRoot = await navigator.storage.getDirectory() - const firstDirectoryHandle = await opfsRoot.getDirectoryHandle('first-dropped-workspace-folder', { - create: true, - }) - const firstNestedFileHandle = await firstDirectoryHandle.getFileHandle('first-inside.txt', { - create: true, - }) - const firstWritable = await firstNestedFileHandle.createWritable({ keepExistingData: false }) - await firstWritable.write('first') - await firstWritable.close() - const secondDirectoryHandle = await opfsRoot.getDirectoryHandle('second-dropped-workspace-folder', { - create: true, - }) - const secondNestedFileHandle = await secondDirectoryHandle.getFileHandle('second-inside.txt', { - create: true, - }) - const secondWritable = await secondNestedFileHandle.createWritable({ keepExistingData: false }) - await secondWritable.write('second') - await secondWritable.close() - const firstId = await Command.execute('FileSystemHandle.addFileHandle', firstDirectoryHandle) - const secondId = await Command.execute('FileSystemHandle.addFileHandle', secondDirectoryHandle) - const welcomeMessage = Locator('.Explorer .WelcomeMessage') - const firstNestedFile = Locator('.TreeItem[aria-label="first-inside.txt"]') - const secondNestedFile = Locator('.TreeItem[aria-label="second-inside.txt"]') - - // act - await Explorer.handleDrop(5000, 5000, [firstId, secondId], []) - - // assert - await expect(welcomeMessage).toBeHidden() - await expect(firstNestedFile).toBeVisible() - await expect(secondNestedFile).toHaveCount(0) -} diff --git a/packages/e2e/src/viewlet.explorer-empty-workspace.ts b/packages/e2e/src/viewlet.explorer-empty-workspace.ts deleted file mode 100644 index 9885ed9..0000000 --- a/packages/e2e/src/viewlet.explorer-empty-workspace.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-empty-workspace' - -export const test: Test = async ({ expect, Explorer, Locator, Workspace }) => { - // act - await Workspace.setPath('') - - // assert - const explorer = Locator('.Explorer') - await expect(explorer).toBeVisible() - const welcome = Locator('.Explorer .Welcome') - await expect(welcome).toBeVisible() - const welcomeMessage = Locator('.Explorer .WelcomeMessage') - await expect(welcomeMessage).toBeVisible() - await expect(welcomeMessage).toHaveText('You have not yet opened a folder.') - const openFolderButton = Locator('.Explorer .Button') - await expect(openFolderButton).toBeVisible() - await expect(openFolderButton).toHaveText('Open folder') - - await Explorer.handleDragOver(5000, 5000) - await expect(explorer).toHaveClass('DropTarget') -} diff --git a/packages/e2e/src/viewlet.explorer-expand-all.ts b/packages/e2e/src/viewlet.explorer-expand-all.ts deleted file mode 100644 index f4fe9a5..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-all.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-all' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/folder-1`) - await FileSystem.mkdir(`${tmpDir}/folder-2`) - await FileSystem.mkdir(`${tmpDir}/folder-3`) - await FileSystem.writeFile(`${tmpDir}/folder-1/a.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-1/b.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-1/c.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-2/a.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-2/b.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-2/c.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-3/a.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-3/b.txt`, '') - await FileSystem.writeFile(`${tmpDir}/folder-3/c.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - - // act - await Explorer.expandAll() - - // assert - const items = Locator('.TreeItem') - await expect(items).toHaveCount(12) - const itemOne = items.nth(0) - const itemTwo = items.nth(1) - const itemThree = items.nth(2) - const itemFour = items.nth(3) - const itemFive = items.nth(4) - const itemSix = items.nth(5) - const itemSeven = items.nth(6) - const itemEight = items.nth(7) - const itemNine = items.nth(8) - const itemTen = items.nth(9) - const itemEleven = items.nth(10) - const itemTwelve = items.nth(11) - await expect(itemOne).toHaveText('folder-1') - await expect(itemTwo).toHaveText('a.txt') - await expect(itemThree).toHaveText('b.txt') - await expect(itemFour).toHaveText('c.txt') - await expect(itemFive).toHaveText('folder-2') - await expect(itemSix).toHaveText('a.txt') - await expect(itemSeven).toHaveText('b.txt') - await expect(itemEight).toHaveText('c.txt') - await expect(itemNine).toHaveText('folder-3') - await expect(itemTen).toHaveText('a.txt') - await expect(itemEleven).toHaveText('b.txt') - await expect(itemTwelve).toHaveText('c.txt') -} diff --git a/scripts/update-dependencies.sh b/scripts/update-dependencies.sh old mode 100644 new mode 100755 From d13d84be5fa457a14a38ba5659c03368fe816bba Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:34:54 +0200 Subject: [PATCH 09/17] rename --- package-lock.json | 13324 ++++++++++++++++ packages/build/src/build-static.ts | 2 +- ...viewlet.explorer-expand-folder-10-items.ts | 35 - ...iewlet.explorer-expand-folder-100-items.ts | 29 - ...ewlet.explorer-expand-folder-100k-items.ts | 38 - ...iewlet.explorer-expand-folder-10k-items.ts | 38 - ...iewlet.explorer-expand-folder-10m-items.ts | 25 - ...viewlet.explorer-expand-folder-1m-items.ts | 25 - .../viewlet.explorer-expand-recursively.ts | 30 - ...let.explorer-file-system-provider-error.ts | 31 - ...lorer-file-system-provider-invalid-data.ts | 37 - ...ewlet.explorer-handle-copy-no-selection.ts | 18 - ...iewlet.explorer-handle-cut-no-selection.ts | 18 - .../src/viewlet.explorer-handle-drag-leave.ts | 25 - .../viewlet.explorer-handle-drag-over-all.ts | 19 - ...viewlet.explorer-handle-drag-over-files.ts | 28 - ...iewlet.explorer-handle-drag-over-folder.ts | 18 - ...rer-handle-drag-over-index-out-of-range.ts | 17 - ...et.explorer-handle-drag-over-index-root.ts | 18 - .../src/viewlet.explorer-handle-drag-over.ts | 19 - .../e2e/src/viewlet.explorer-handle-drop.ts | 26 - ...ewlet.explorer-handle-icon-theme-change.ts | 23 - ...er-ignored-file-decoration-invalid-null.ts | 23 - ...-ignored-file-decoration-invalid-object.ts | 23 - ...iewlet.explorer-ignored-file-decoration.ts | 26 - .../viewlet.explorer-keyboard-navigation.ts | 118 - ...et.explorer-large-directory-performance.ts | 52 - ...ewlet.explorer-long-file-name-500-emoji.ts | 21 - .../src/viewlet.explorer-long-file-name.ts | 17 - .../src/viewlet.explorer-many-files-20000.ts | 47 - ...xplorer-many-files-repeated-focus-jumps.ts | 32 - .../viewlet.explorer-many-folders-20000.ts | 47 - .../src/viewlet.explorer-mouse-navigation.ts | 42 - .../viewlet.explorer-new-file-called-twice.ts | 20 - ...ewlet.explorer-open-folder-enoent-error.ts | 25 - .../src/viewlet.explorer-read-folder-error.ts | 23 - packages/e2e/src/viewlet.explorer-refresh.ts | 25 - .../viewlet.explorer-rename-file-150-times.ts | 46 - ...t.explorer-rename-file-cancel-150-times.ts | 32 - .../viewlet.explorer-rename-file-cancel.ts | 35 - ...orer-rename-file-error-no-name-provided.ts | 32 - ...rer-rename-file-error-permission-denied.ts | 28 - ...explorer-rename-file-special-characters.ts | 75 - .../src/viewlet.explorer-rename-file-twice.ts | 27 - ...viewlet.explorer-rename-file-whitespace.ts | 31 - .../e2e/src/viewlet.explorer-rename-file.ts | 37 - .../viewlet.explorer-rename-folder-nested.ts | 39 - ...orer-rename-root-folder-no-indent-shift.ts | 34 - ...t.explorer-reveal-from-tab-context-menu.ts | 36 - ...iewlet.explorer-reveal-non-existent-uri.ts | 34 - packages/e2e/src/viewlet.explorer-scroll.ts | 43 - ...t.explorer-select-all-then-delete-files.ts | 21 - .../e2e/src/viewlet.explorer-select-all.ts | 24 - .../e2e/src/viewlet.explorer-select-down.ts | 24 - ...orer-select-multiple-files-individually.ts | 25 - ...plorer-select-multiple-files-with-mouse.ts | 24 - .../viewlet.explorer-select-multiple-files.ts | 23 - .../e2e/src/viewlet.explorer-select-up.ts | 24 - ...wlet.explorer-set-delta-y-invalid-value.ts | 27 - ...iewlet.explorer-sort-numeric-file-names.ts | 24 - .../src/viewlet.explorer-sorting-emojis.ts | 45 - ...orer-sorting-mixed-alphanumeric-special.ts | 45 - ...let.explorer-sorting-special-characters.ts | 45 - ...let.explorer-sorting-unicode-characters.ts | 45 - packages/e2e/src/viewlet.explorer-sorting.ts | 44 - packages/e2e/src/viewlet.explorer.empty.ts | 16 - packages/e2e/src/viewlet.explorer.open.ts | 19 - packages/server/package.json | 5 +- packages/server/package.json.lerna_backup | 15 + 69 files changed, 13341 insertions(+), 2067 deletions(-) create mode 100644 package-lock.json delete mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts delete mode 100644 packages/e2e/src/viewlet.explorer-expand-recursively.ts delete mode 100644 packages/e2e/src/viewlet.explorer-file-system-provider-error.ts delete mode 100644 packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-leave.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drag-over.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-drop.ts delete mode 100644 packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts delete mode 100644 packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts delete mode 100644 packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts delete mode 100644 packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts delete mode 100644 packages/e2e/src/viewlet.explorer-keyboard-navigation.ts delete mode 100644 packages/e2e/src/viewlet.explorer-large-directory-performance.ts delete mode 100644 packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts delete mode 100644 packages/e2e/src/viewlet.explorer-long-file-name.ts delete mode 100644 packages/e2e/src/viewlet.explorer-many-files-20000.ts delete mode 100644 packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts delete mode 100644 packages/e2e/src/viewlet.explorer-many-folders-20000.ts delete mode 100644 packages/e2e/src/viewlet.explorer-mouse-navigation.ts delete mode 100644 packages/e2e/src/viewlet.explorer-new-file-called-twice.ts delete mode 100644 packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts delete mode 100644 packages/e2e/src/viewlet.explorer-read-folder-error.ts delete mode 100644 packages/e2e/src/viewlet.explorer-refresh.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-150-times.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-cancel.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-twice.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-file.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-folder-nested.ts delete mode 100644 packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts delete mode 100644 packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts delete mode 100644 packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts delete mode 100644 packages/e2e/src/viewlet.explorer-scroll.ts delete mode 100644 packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts delete mode 100644 packages/e2e/src/viewlet.explorer-select-all.ts delete mode 100644 packages/e2e/src/viewlet.explorer-select-down.ts delete mode 100644 packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts delete mode 100644 packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts delete mode 100644 packages/e2e/src/viewlet.explorer-select-multiple-files.ts delete mode 100644 packages/e2e/src/viewlet.explorer-select-up.ts delete mode 100644 packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts delete mode 100644 packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts delete mode 100644 packages/e2e/src/viewlet.explorer-sorting-emojis.ts delete mode 100644 packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts delete mode 100644 packages/e2e/src/viewlet.explorer-sorting-special-characters.ts delete mode 100644 packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts delete mode 100644 packages/e2e/src/viewlet.explorer-sorting.ts delete mode 100644 packages/e2e/src/viewlet.explorer.empty.ts delete mode 100644 packages/e2e/src/viewlet.explorer.open.ts create mode 100644 packages/server/package.json.lerna_backup diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..674be07 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13324 @@ +{ + "name": "@lvce-editor/explorer-view-monorepo", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@lvce-editor/explorer-view-monorepo", + "version": "0.0.0-dev", + "hasInstallScript": true, + "license": "MIT", + "devDependencies": { + "@lerna/legacy-package-management": "^8.2.4", + "@lvce-editor/eslint-config": "^12.3.0", + "eslint": "^10.2.0", + "lerna": "^8.2.4", + "prettier": "^3.8.4", + "typescript": "^6.0.3" + } + }, + "node_modules/@altano/repository-tools": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@altano/repository-tools/-/repository-tools-2.0.3.tgz", + "integrity": "sha512-cSR/ZYDF6Wp9OeAJMyLYYN1GenAAhV17W+w38ELP+3c5Ltsy9jkkCymi33nz/qnXyef3n6Fbr1h2yt3dvUN5sQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspell/cspell-bundled-dicts": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-10.0.1.tgz", + "integrity": "sha512-WvkSDNX4Uyyj/ZgbPO6L38iFNMfK1EqsH1FteRiI2qLz6QZMXRFrIt12OqiWIplzZDDaVpBH9FCJOPJll0fjCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-ada": "^4.1.1", + "@cspell/dict-al": "^1.1.1", + "@cspell/dict-aws": "^4.0.17", + "@cspell/dict-bash": "^4.2.2", + "@cspell/dict-companies": "^3.2.11", + "@cspell/dict-cpp": "^7.0.2", + "@cspell/dict-cryptocurrencies": "^5.0.5", + "@cspell/dict-csharp": "^4.0.8", + "@cspell/dict-css": "^4.1.1", + "@cspell/dict-dart": "^2.3.2", + "@cspell/dict-data-science": "^2.0.13", + "@cspell/dict-django": "^4.1.6", + "@cspell/dict-docker": "^1.1.17", + "@cspell/dict-dotnet": "^5.0.13", + "@cspell/dict-elixir": "^4.0.8", + "@cspell/dict-en_us": "^4.4.33", + "@cspell/dict-en-common-misspellings": "^2.1.12", + "@cspell/dict-en-gb-mit": "^3.1.22", + "@cspell/dict-filetypes": "^3.0.18", + "@cspell/dict-flutter": "^1.1.1", + "@cspell/dict-fonts": "^4.0.6", + "@cspell/dict-fsharp": "^1.1.1", + "@cspell/dict-fullstack": "^3.2.9", + "@cspell/dict-gaming-terms": "^1.1.2", + "@cspell/dict-git": "^3.1.0", + "@cspell/dict-golang": "^6.0.26", + "@cspell/dict-google": "^1.0.9", + "@cspell/dict-haskell": "^4.0.6", + "@cspell/dict-html": "^4.0.15", + "@cspell/dict-html-symbol-entities": "^4.0.5", + "@cspell/dict-java": "^5.0.12", + "@cspell/dict-julia": "^1.1.1", + "@cspell/dict-k8s": "^1.0.12", + "@cspell/dict-kotlin": "^1.1.1", + "@cspell/dict-latex": "^5.1.0", + "@cspell/dict-lorem-ipsum": "^4.0.5", + "@cspell/dict-lua": "^4.0.8", + "@cspell/dict-makefile": "^1.0.5", + "@cspell/dict-markdown": "^2.0.16", + "@cspell/dict-monkeyc": "^1.0.12", + "@cspell/dict-node": "^5.0.9", + "@cspell/dict-npm": "^5.2.38", + "@cspell/dict-php": "^4.1.1", + "@cspell/dict-powershell": "^5.0.15", + "@cspell/dict-public-licenses": "^2.0.16", + "@cspell/dict-python": "^4.2.26", + "@cspell/dict-r": "^2.1.1", + "@cspell/dict-ruby": "^5.1.1", + "@cspell/dict-rust": "^4.1.2", + "@cspell/dict-scala": "^5.0.9", + "@cspell/dict-shell": "^1.1.2", + "@cspell/dict-software-terms": "^5.2.2", + "@cspell/dict-sql": "^2.2.1", + "@cspell/dict-svelte": "^1.0.7", + "@cspell/dict-swift": "^2.0.6", + "@cspell/dict-terraform": "^1.1.3", + "@cspell/dict-typescript": "^3.2.3", + "@cspell/dict-vue": "^3.0.5", + "@cspell/dict-zig": "^1.0.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-performance-monitor": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-performance-monitor/-/cspell-performance-monitor-10.0.1.tgz", + "integrity": "sha512-9tVcHXwRnbazUv4WSG0h3MqV4+LgmLNgSALAQUflPPW0EMxTf7C4Dmv9cgxJyCEQrdnVKCr58nPPaahhz9LJUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-pipe": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-10.0.1.tgz", + "integrity": "sha512-HPeXMD9AZ3V/qPkvQaPcak+C7cJ2z7JTHN8smd6J8L2aThLRky2cHc2OyeaHPSHB7WA47b4z2n5u5nawZhv5VQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-resolver": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-10.0.1.tgz", + "integrity": "sha512-PIzkZHD1fGUQx1XteK2d1iQ0Mzq/maYcoB4jkvAiiR6WqP3MWYNKFdI9z+R5pOq5KgMfW+5Ig1q0oSR6h8irlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-directory": "^5.0.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-service-bus": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-10.0.1.tgz", + "integrity": "sha512-y6NcIGP2IdXaBL4PVH8vxsr7K27wzz3Ech87UtUtrDSXAiVEOvXgAIknEOUVp59rTlUE8Rn4IRURC6f/hgMyfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/cspell-types": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-10.0.1.tgz", + "integrity": "sha512-kLgLShnWADDVreKC63pBrWkcvxgZzFIfO34Jhx/SWfuOIA3cD8AXT+HjyuLfoGJ7mUb58hv2kUziKzEy4INb1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/dict-ada": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", + "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-al": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", + "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-aws": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.17.tgz", + "integrity": "sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-bash": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.3.tgz", + "integrity": "sha512-ljUZoKHbDqw5Sx0qpL2qTUlmkmr+vhZH/sCNrNaBZKTbdgiswErSnIF1jRbGmEitJNxHRHWsuZyVgnTGfVO1Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-shell": "1.2.0" + } + }, + "node_modules/@cspell/dict-companies": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.11.tgz", + "integrity": "sha512-0cmafbcz2pTHXLd59eLR1gvDvN6aWAOM0+cIL4LLF9GX9yB2iKDNrKsvs4tJRqutoaTdwNFBbV0FYv+6iCtebQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cpp": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-7.0.2.tgz", + "integrity": "sha512-dfbeERiVNeqmo/npivdR6rDiBCqZi3QtjH2Z0HFcXwpdj6i97dX1xaKyK2GUsO/p4u1TOv63Dmj5Vm48haDpuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cryptocurrencies": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", + "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-csharp": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.8.tgz", + "integrity": "sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-css": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.2.tgz", + "integrity": "sha512-+ylGoKdwZ2sVOCOnU2Eq5wDZx+RaVX3HoKyNHGGsFvhSw6IidQ6tH/mAPKBDofViHJoWCPNlklE0lTr6MDG3QA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dart": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.2.tgz", + "integrity": "sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-data-science": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.14.tgz", + "integrity": "sha512-jl6Ds4u5u5JT+yY30pWQpAbdCHfy3lCcNkLbpL/AZKoUaLEoXbaYsps9xQtvD7DyaiXxiLZkdH2yHHXtoFtZyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-django": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.6.tgz", + "integrity": "sha512-SdbSFDGy9ulETqNz15oWv2+kpWLlk8DJYd573xhIkeRdcXOjskRuxjSZPKfW7O3NxN/KEf3gm3IevVOiNuFS+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-docker": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.17.tgz", + "integrity": "sha512-OcnVTIpHIYYKhztNTyK8ShAnXTfnqs43hVH6p0py0wlcwRIXe5uj4f12n7zPf2CeBI7JAlPjEsV0Rlf4hbz/xQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dotnet": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.13.tgz", + "integrity": "sha512-xPp7jMnFpOri7tzmqmm/dXMolXz1t2bhNqxYkOyMqXhvs08oc7BFs+EsbDY0X7hqiISgeFZGNqn0dOCr+ncPYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-elixir": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.8.tgz", + "integrity": "sha512-CyfphrbMyl4Ms55Vzuj+mNmd693HjBFr9hvU+B2YbFEZprE5AG+EXLYTMRWrXbpds4AuZcvN3deM2XVB80BN/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en_us": { + "version": "4.4.35", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.35.tgz", + "integrity": "sha512-xWpxBCc/FzzMMo/A+0qwARVaIIhR0Ql8yhhv4rvsvg+GfQF+LG9yzg2GwTM5N2rjvzmM3nKuR9zxFZq2I6fJSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en-common-misspellings": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.1.12.tgz", + "integrity": "sha512-14Eu6QGqyksqOd4fYPuRb58lK1Va7FQK9XxFsRKnZU8LhL3N+kj7YKDW+7aIaAN/0WGEqslGP6lGbQzNti8Akw==", + "dev": true, + "license": "CC BY-SA 4.0" + }, + "node_modules/@cspell/dict-en-gb-mit": { + "version": "3.1.24", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb-mit/-/dict-en-gb-mit-3.1.24.tgz", + "integrity": "sha512-Oowb/Uzkh7OmDRdCcETzMc9imEb4IpLlHJXoYjX8A8DS2X/54gqSjI915JFB8hKtFjBko5OM0BLQ+6cZhFEMmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-filetypes": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.18.tgz", + "integrity": "sha512-yU7RKD/x1IWmDLzWeiItMwgV+6bUcU/af23uS0+uGiFUbsY1qWV/D4rxlAAO6Z7no3J2z8aZOkYIOvUrJq0Rcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-flutter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.1.tgz", + "integrity": "sha512-UlOzRcH2tNbFhZmHJN48Za/2/MEdRHl2BMkCWZBYs+30b91mWvBfzaN4IJQU7dUZtowKayVIF9FzvLZtZokc5A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fonts": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.6.tgz", + "integrity": "sha512-aR/0csY01dNb0A1tw/UmN9rKgHruUxsYsvXu6YlSBJFu60s26SKr/k1o4LavpHTQ+lznlYMqAvuxGkE4Flliqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fsharp": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.1.tgz", + "integrity": "sha512-imhs0u87wEA4/cYjgzS0tAyaJpwG7vwtC8UyMFbwpmtw+/bgss+osNfyqhYRyS/ehVCWL17Ewx2UPkexjKyaBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fullstack": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.9.tgz", + "integrity": "sha512-diZX+usW5aZ4/b2T0QM/H/Wl9aNMbdODa1Jq0ReBr/jazmNeWjd+PyqeVgzd1joEaHY+SAnjrf/i9CwKd2ZtWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-gaming-terms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.2.tgz", + "integrity": "sha512-9XnOvaoTBscq0xuD6KTEIkk9hhdfBkkvJAIsvw3JMcnp1214OCGW8+kako5RqQ2vTZR3Tnf3pc57o7VgkM0q1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-git": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.1.0.tgz", + "integrity": "sha512-KEt9zGkxqGy2q1nwH4CbyqTSv5nadpn8BAlDnzlRcnL0Xb3LX9xTgSGShKvzb0bw35lHoYyLWN2ZKAqbC4pgGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-golang": { + "version": "6.0.26", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.26.tgz", + "integrity": "sha512-YKA7Xm5KeOd14v5SQ4ll6afe9VSy3a2DWM7L9uBq4u3lXToRBQ1W5PRa+/Q9udd+DTURyVVnQ+7b9cnOlNxaRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-google": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.9.tgz", + "integrity": "sha512-biL65POqialY0i4g6crj7pR6JnBkbsPovB2WDYkj3H4TuC/QXv7Pu5pdPxeUJA6TSCHI7T5twsO4VSVyRxD9CA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-haskell": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.6.tgz", + "integrity": "sha512-ib8SA5qgftExpYNjWhpYIgvDsZ/0wvKKxSP+kuSkkak520iPvTJumEpIE+qPcmJQo4NzdKMN8nEfaeci4OcFAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.15.tgz", + "integrity": "sha512-GJYnYKoD9fmo2OI0aySEGZOjThnx3upSUvV7mmqUu8oG+mGgzqm82P/f7OqsuvTaInZZwZbo+PwJQd/yHcyFIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html-symbol-entities": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.5.tgz", + "integrity": "sha512-429alTD4cE0FIwpMucvSN35Ld87HCyuM8mF731KU5Rm4Je2SG6hmVx7nkBsLyrmH3sQukTcr1GaiZsiEg8svPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-java": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.12.tgz", + "integrity": "sha512-qPSNhTcl7LGJ5Qp6VN71H8zqvRQK04S08T67knMq9hTA8U7G1sTKzLmBaDOFhq17vNX/+rT+rbRYp+B5Nwza1A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-julia": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.1.tgz", + "integrity": "sha512-WylJR9TQ2cgwd5BWEOfdO3zvDB+L7kYFm0I9u0s9jKHWQ6yKmfKeMjU9oXxTBxIufhCXm92SKwwVNAC7gjv+yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-k8s": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.12.tgz", + "integrity": "sha512-2LcllTWgaTfYC7DmkMPOn9GsBWsA4DZdlun4po8s2ysTP7CPEnZc1ZfK6pZ2eI4TsZemlUQQ+NZxMe9/QutQxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-kotlin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.1.tgz", + "integrity": "sha512-J3NzzfgmxRvEeOe3qUXnSJQCd38i/dpF9/t3quuWh6gXM+krsAXP75dY1CzDmS8mrJAlBdVBeAW5eAZTD8g86Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-latex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-5.1.0.tgz", + "integrity": "sha512-qxT4guhysyBt0gzoliXYEBYinkAdEtR2M7goRaUH0a7ltCsoqqAeEV8aXYRIdZGcV77gYSobvu3jJL038tlPAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lorem-ipsum": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.5.tgz", + "integrity": "sha512-9a4TJYRcPWPBKkQAJ/whCu4uCAEgv/O2xAaZEI0n4y1/l18Yyx8pBKoIX5QuVXjjmKEkK7hi5SxyIsH7pFEK9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lua": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.8.tgz", + "integrity": "sha512-N4PkgNDMu9JVsRu7JBS/3E/dvfItRgk9w5ga2dKq+JupP2Y3lojNaAVFhXISh4Y0a6qXDn2clA6nvnavQ/jjLA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-makefile": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.5.tgz", + "integrity": "sha512-4vrVt7bGiK8Rx98tfRbYo42Xo2IstJkAF4tLLDMNQLkQ86msDlYSKG1ZCk8Abg+EdNcFAjNhXIiNO+w4KflGAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-markdown": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.17.tgz", + "integrity": "sha512-H8bAxih6U8NOnSPL7R8My+tqjaB4tmnJTjERuz4zYqmf+cH+5xshX3UVgKlwWFcyjsYfv/zEDuRdMctQv1q6HQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@cspell/dict-css": "^4.1.2", + "@cspell/dict-html": "^4.0.15", + "@cspell/dict-html-symbol-entities": "^4.0.5", + "@cspell/dict-typescript": "^3.2.3" + } + }, + "node_modules/@cspell/dict-monkeyc": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.12.tgz", + "integrity": "sha512-MN7Vs11TdP5mbdNFQP5x2Ac8zOBm97ARg6zM5Sb53YQt/eMvXOMvrep7+/+8NJXs0jkp70bBzjqU4APcqBFNAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-node": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.9.tgz", + "integrity": "sha512-hO+ga+uYZ/WA4OtiMEyKt5rDUlUyu3nXMf8KVEeqq2msYvAPdldKBGH7lGONg6R/rPhv53Rb+0Y1SLdoK1+7wQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-npm": { + "version": "5.2.41", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.41.tgz", + "integrity": "sha512-To3xsfRmMBYVXtWVEdUgV35M9a/JZ54dSuoY6m6D3uHKKL3I326Wmy4xifZ3PU8MQaWhyEH7zbIcUEtKwTQMcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-php": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.1.1.tgz", + "integrity": "sha512-EXelI+4AftmdIGtA8HL8kr4WlUE11OqCSVlnIgZekmTkEGSZdYnkFdiJ5IANSALtlQ1mghKjz+OFqVs6yowgWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-powershell": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.15.tgz", + "integrity": "sha512-l4S5PAcvCFcVDMJShrYD0X6Huv9dcsQPlsVsBGbH38wvuN7gS7+GxZFAjTNxDmTY1wrNi1cCatSg6Pu2BW4rgg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-public-licenses": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.16.tgz", + "integrity": "sha512-EQRrPvEOmwhwWezV+W7LjXbIBjiy6y/shrET6Qcpnk3XANTzfvWflf9PnJ5kId/oKWvihFy0za0AV1JHd03pSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-python": { + "version": "4.2.27", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.27.tgz", + "integrity": "sha512-Rj6xQgYS4X6ienjgAZF+njA0GRY4oSPouJWv0vfikCTn6EWlfk0V6Dy1HP3Migj1O+IC2NmespgVq+BZNSp8OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-data-science": "^2.0.14" + } + }, + "node_modules/@cspell/dict-r": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.1.tgz", + "integrity": "sha512-71Ka+yKfG4ZHEMEmDxc6+blFkeTTvgKbKAbwiwQAuKl3zpqs1Y0vUtwW2N4b3LgmSPhV3ODVY0y4m5ofqDuKMw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-ruby": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.1.1.tgz", + "integrity": "sha512-LHrp84oEV6q1ZxPPyj4z+FdKyq1XAKYPtmGptrd+uwHbrF/Ns5+fy6gtSi7pS+uc0zk3JdO9w/tPK+8N1/7WUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-rust": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.1.2.tgz", + "integrity": "sha512-O1FHrumYcO+HZti3dHfBPUdnDFkI+nbYK3pxYmiM1sr+G0ebOd6qchmswS0Wsc6ZdEVNiPYJY/gZQR6jfW3uOg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-scala": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.9.tgz", + "integrity": "sha512-AjVcVAELgllybr1zk93CJ5wSUNu/Zb5kIubymR/GAYkMyBdYFCZ3Zbwn4Zz8GJlFFAbazABGOu0JPVbeY59vGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-shell": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.2.0.tgz", + "integrity": "sha512-PVctvT22lJ49niMiakO8xieY7ELCAzjSqhejWR7bAMb5AZ9F4WDEs+XdGMnoVHWeXq7K5rcepLPmEJb+37zzIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-software-terms": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.2.2.tgz", + "integrity": "sha512-0CaYd6TAsKtEoA7tNswm1iptEblTzEe3UG8beG2cpSTHk7afWIVMtJLgXDv0f/Li67Lf3Z1Jf3JeXR7GsJ2TRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-sql": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.1.tgz", + "integrity": "sha512-qDHF8MpAYCf4pWU8NKbnVGzkoxMNrFqBHyG/dgrlic5EQiKANCLELYtGlX5auIMDLmTf1inA0eNtv74tyRJ/vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-svelte": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.7.tgz", + "integrity": "sha512-hGZsGqP0WdzKkdpeVLBivRuSNzOTvN036EBmpOwxH+FTY2DuUH7ecW+cSaMwOgmq5JFSdTcbTNFlNC8HN8lhaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-swift": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.6.tgz", + "integrity": "sha512-PnpNbrIbex2aqU1kMgwEKvCzgbkHtj3dlFLPMqW1vSniop7YxaDTtvTUO4zA++ugYAEL+UK8vYrBwDPTjjvSnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-terraform": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.3.tgz", + "integrity": "sha512-gr6wxCydwSFyyBKhBA2xkENXtVFToheqYYGFvlMZXWjviynXmh+NK/JTvTCk/VHk3+lzbO9EEQKee6VjrAUSbA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-typescript": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz", + "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-vue": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.5.tgz", + "integrity": "sha512-Mqutb8jbM+kIcywuPQCCaK5qQHTdaByoEO2J9LKFy3sqAdiBogNkrplqUK0HyyRFgCfbJUgjz3N85iCMcWH0JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-zig": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-zig/-/dict-zig-1.0.0.tgz", + "integrity": "sha512-XibBIxBlVosU06+M6uHWkFeT0/pW5WajDRYdXG2CgHnq85b0TI/Ks0FuBJykmsgi2CAD3Qtx8UHFEtl/DSFnAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dynamic-import": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-10.0.1.tgz", + "integrity": "sha512-mP1gdq00aIcH8HxNMqnH11X6BKxLcneDtFgl/ecjIKnaGKwi44m8AndP5Kr4ODaYdl8UUw9O3dJh7KaQXnLHZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "10.0.1", + "import-meta-resolve": "^4.2.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/eslint-plugin": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/eslint-plugin/-/eslint-plugin-10.0.1.tgz", + "integrity": "sha512-VgRVWIWyM5bz2d7eC3/F4ON1fhMdrFB0R6slXmJewDDbJMDloSsMsWCSktiFET3a0TX/DTjOGGDzBN9tqGDGPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "10.0.1", + "@cspell/url": "10.0.1", + "cspell-lib": "10.0.1", + "synckit": "^0.11.13" + }, + "engines": { + "node": ">=22.18.0" + }, + "peerDependencies": { + "eslint": "^8 || ^9 || ^10" + } + }, + "node_modules/@cspell/filetypes": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-10.0.1.tgz", + "integrity": "sha512-Z5S35giU5IW49fBBq6BksUbE8PC4IYPfaKuwl5Nl9jkf/OkAKiBmCowKX45NzRUQInwK/GSqqIUifrNeI6LdLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/rpc": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/rpc/-/rpc-10.0.1.tgz", + "integrity": "sha512-axSRKv3zEAmBm66iD/FV/MPmE4/Yf7c3PZiwTW894Yd3iEhtn3KPKeTrqQ2/tDrhB1Z2qTsap/Hue0MK4o5WXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/strong-weak-map": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-10.0.1.tgz", + "integrity": "sha512-lenN1DVyPi8nJLSMSJJ670ddTjyiruLueuSZO1qLcxBqUhgxDt/mALu9N/1m6WdOVcg6m/5cLiZVg2KOo2UzRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@cspell/url": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cspell/url/-/url-10.0.1.tgz", + "integrity": "sha512-abYYgI29wJhWIfWTYrYuzRYDcHQUQ1N5ylnhxYn1NJnIQMqUWGLbDmt12JABtZ+R6h6UNatQrS7rhP86etvJyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@e18e/eslint-plugin": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@e18e/eslint-plugin/-/eslint-plugin-0.5.1.tgz", + "integrity": "sha512-mqUozeyNI9xvJbjrOO7y765dT7Kud3bwCm/DHwctxdEngPdJWQaS9BNGgpM1wCCzZfOtlKQh4ZRhm3VRomT9KA==", + "dev": true, + "license": "MIT", + "dependencies": { + "empathic": "^2.0.1", + "module-replacements": "^3.0.0-beta.8", + "semver": "^7.8.2" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0", + "oxlint": "^1.68.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "oxlint": { + "optional": true + } + } + }, + "node_modules/@e18e/eslint-plugin/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/css": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/css/-/css-1.3.0.tgz", + "integrity": "sha512-MwY657chvFQWtXmO86syZgD+JpWlzDq7VkKZyi65PwHDbhELQPMzPXh5s8rhrjptG6FCuls0puCmlXk66+14uA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "@eslint/css-tree": "^4.0.4", + "@eslint/plugin-kit": "^0.7.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/css-tree": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-4.0.4.tgz", + "integrity": "sha512-nxMparyhqVWQvadx9x8dIfubfIPOE+X2b2waua8fzdnM9vdp9rgVtwEZlG0TmCwEUz/d/f40fzvO/eqBwdxz0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.28.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@eslint/json/-/json-2.0.0.tgz", + "integrity": "sha512-P32ZJMIopNWQd1SFhd0tgjfA/hgzUuVSqHmMi2273QaLWHWimXq6V+qL4DNKnjGzO/aNECtYW+rEJ/pWB6uP+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanwhocodes/momoa": "^3.3.10", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/markdown": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@eslint/markdown/-/markdown-8.0.2.tgz", + "integrity": "sha512-W+/0qHp0WbvFEljUvvECNpSWrUHpBWIWwp7F3QqEwQKmaRCmfEWvk6VfUia9pTQ0th6HyBGBsPfg/kG3/aQxLA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "examples/*" + ], + "dependencies": { + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "github-slugger": "^2.0.0", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-frontmatter": "^2.0.1", + "mdast-util-gfm": "^3.1.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "micromark-extension-gfm": "^3.0.0", + "micromark-extension-math": "^3.1.0", + "micromark-util-normalize-identifier": "^2.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/momoa": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.10.tgz", + "integrity": "sha512-KWiFQpSAqEIyrTXko3hFNLeQvSK8zXlJQzhhxsyVn58WFRYXST99b3Nqnu+ttOtjds2Pl2grUHGpe2NzhPynuQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", + "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@jest/diff-sequences": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@lerna/create": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.2.4.tgz", + "integrity": "sha512-A8AlzetnS2WIuhijdAzKUyFpR5YbLLfV3luQ4lzBgIBgRfuoBDZeF+RSZPhra+7A6/zTUlrbhKZIOi/MNhqgvQ==", + "deprecated": "This package is an implementation detail of Lerna and is no longer published separately.", + "dev": true, + "license": "MIT", + "dependencies": { + "@npmcli/arborist": "7.5.4", + "@npmcli/package-json": "5.2.0", + "@npmcli/run-script": "8.1.0", + "@nx/devkit": ">=17.1.2 < 21", + "@octokit/plugin-enterprise-rest": "6.0.1", + "@octokit/rest": "20.1.2", + "aproba": "2.0.0", + "byte-size": "8.1.1", + "chalk": "4.1.0", + "clone-deep": "4.0.1", + "cmd-shim": "6.0.3", + "color-support": "1.1.3", + "columnify": "1.6.0", + "console-control-strings": "^1.1.0", + "conventional-changelog-core": "5.0.1", + "conventional-recommended-bump": "7.0.1", + "cosmiconfig": "9.0.0", + "dedent": "1.5.3", + "execa": "5.0.0", + "fs-extra": "^11.2.0", + "get-stream": "6.0.0", + "git-url-parse": "14.0.0", + "glob-parent": "6.0.2", + "graceful-fs": "4.2.11", + "has-unicode": "2.0.1", + "ini": "^1.3.8", + "init-package-json": "6.0.3", + "inquirer": "^8.2.4", + "is-ci": "3.0.1", + "is-stream": "2.0.0", + "js-yaml": "4.1.0", + "libnpmpublish": "9.0.9", + "load-json-file": "6.2.0", + "make-dir": "4.0.0", + "minimatch": "3.0.5", + "multimatch": "5.0.0", + "node-fetch": "2.6.7", + "npm-package-arg": "11.0.2", + "npm-packlist": "8.0.2", + "npm-registry-fetch": "^17.1.0", + "nx": ">=17.1.2 < 21", + "p-map": "4.0.0", + "p-map-series": "2.1.0", + "p-queue": "6.6.2", + "p-reduce": "^2.1.0", + "pacote": "^18.0.6", + "pify": "5.0.0", + "read-cmd-shim": "4.0.0", + "resolve-from": "5.0.0", + "rimraf": "^4.4.1", + "semver": "^7.3.4", + "set-blocking": "^2.0.0", + "signal-exit": "3.0.7", + "slash": "^3.0.0", + "ssri": "^10.0.6", + "string-width": "^4.2.3", + "tar": "6.2.1", + "temp-dir": "1.0.0", + "through": "2.3.8", + "tinyglobby": "0.2.12", + "upath": "2.0.1", + "uuid": "^10.0.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "5.0.1", + "wide-align": "1.1.5", + "write-file-atomic": "5.0.1", + "write-pkg": "4.0.0", + "yargs": "17.7.2", + "yargs-parser": "21.1.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-darwin-arm64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.8.4.tgz", + "integrity": "sha512-8Y7+4wj1qoZsuDRpnuiHzSIsMt3VqtJ0su8dgd/MyGccvvi4pndan2R5yTiVw/wmbMxtBmZ6PO6Z8dgSIrMVog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-darwin-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.8.4.tgz", + "integrity": "sha512-2lfuxRc56QWnAysMhcD03tpCPiRzV1+foUq0MhV2sSBIybXmgV4wHLkPZNhlBCl4FNXrWiZiN1OJ2X9AGiOdug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-freebsd-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.8.4.tgz", + "integrity": "sha512-99vnUXZy+OUBHU+8Yhabre2qafepKg9GKkQkhmXvJGqOmuIsepK7wirUFo2PiVM8YhS6UV2rv6hKAZcQ7skYyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.8.4.tgz", + "integrity": "sha512-dht73zpnpzEUEzMHFQs4mfiwZH3WcJgQNWkD5p7WkeJewHq2Yyd0eG5Jg3kB7wnFtwPUV1eNJRM5rephgylkLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.8.4.tgz", + "integrity": "sha512-syXxbJZ0yPaqzVmB28QJgUtaarSiW/PQmv/5Z2Ps8rCi7kYylISPVNjP1NNiIOcGDRWbHqoBfM0bEGPfSp0rBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-arm64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.8.4.tgz", + "integrity": "sha512-AlZZFolS/S0FahRKG7rJ0Z9CgmIkyzHgGaoy3qNEMDEjFhR3jt2ZZSLp90W7zjgrxojOo90ajNMrg2UmtcQRDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-x64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.8.4.tgz", + "integrity": "sha512-MSu+xVNdR95tuuO+eL/a/ZeMlhfrZ627On5xaCZXnJ+lFxNg/S4nlKZQk0Eq5hYALCd/GKgFGasRdlRdOtvGPg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-linux-x64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.8.4.tgz", + "integrity": "sha512-KxpQpyLCgIIHWZ4iRSUN9ohCwn1ZSDASbuFCdG3mohryzCy8WrPkuPcb+68J3wuQhmA5w//Xpp/dL0hHoit9zQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-win32-arm64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.8.4.tgz", + "integrity": "sha512-ffLBrxM9ibk+eWSY995kiFFRTSRb9HkD5T1s/uZyxV6jfxYPaZDBAWAETDneyBXps7WtaOMu+kVZlXQ3X+TfIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/@nx/nx-win32-x64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.8.4.tgz", + "integrity": "sha512-JxuuZc4h8EBqoYAiRHwskimpTJx70yn4lhIRFBoW5ICkxXW1Rw0yip/1UVsWRHXg/x9BxmH7VVazdfaQWmGu6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/create/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@lerna/create/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@lerna/create/node_modules/nx": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/nx/-/nx-20.8.4.tgz", + "integrity": "sha512-/++x0OM3/UTmDR+wmPeV13tSxeTr+QGzj3flgtH9DiOPmQnn2CjHWAMZiOhcSh/hHoE/V3ySL4757InQUsVtjQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@napi-rs/wasm-runtime": "0.2.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.2", + "@zkochan/js-yaml": "0.0.7", + "axios": "^1.8.3", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "front-matter": "^4.0.2", + "ignore": "^5.0.4", + "jest-diff": "^29.4.1", + "jsonc-parser": "3.2.0", + "lines-and-columns": "2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "resolve.exports": "2.0.3", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "yaml": "^2.6.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "20.8.4", + "@nx/nx-darwin-x64": "20.8.4", + "@nx/nx-freebsd-x64": "20.8.4", + "@nx/nx-linux-arm-gnueabihf": "20.8.4", + "@nx/nx-linux-arm64-gnu": "20.8.4", + "@nx/nx-linux-arm64-musl": "20.8.4", + "@nx/nx-linux-x64-gnu": "20.8.4", + "@nx/nx-linux-x64-musl": "20.8.4", + "@nx/nx-win32-arm64-msvc": "20.8.4", + "@nx/nx-win32-x64-msvc": "20.8.4" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/@lerna/create/node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@lerna/create/node_modules/ora": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/create/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/legacy-package-management": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@lerna/legacy-package-management/-/legacy-package-management-8.2.4.tgz", + "integrity": "sha512-NSujwnA8bH7qSGAtNXp9JqGE8nxelKEIg0q5E6vLJfaTq/TcNyFjvesYTpNjPEdZ3eMneBG3nV5ccryo1ddUHg==", + "deprecated": "In v9 of lerna, released in September 2025, the `lerna bootstrap`, `lerna add` and `lerna link` commands were finally fully removed after over 2 years of being deprecated. If you are still using these commands, please migrate to using your package manager's long-supported `workspaces` feature. You may find https://lerna.js.org/docs/legacy-package-management useful for this transition.", + "dev": true, + "license": "MIT", + "dependencies": { + "@npmcli/arborist": "7.5.4", + "@npmcli/package-json": "5.2.0", + "@npmcli/run-script": "8.1.0", + "@nx/devkit": ">=17.1.2 < 21", + "@octokit/rest": "20.1.2", + "aproba": "2.0.0", + "byte-size": "8.1.1", + "chalk": "4.1.0", + "clone-deep": "4.0.1", + "cmd-shim": "6.0.3", + "color-support": "1.1.3", + "columnify": "1.6.0", + "console-control-strings": "^1.1.0", + "conventional-changelog-core": "5.0.1", + "conventional-recommended-bump": "7.0.1", + "cosmiconfig": "9.0.0", + "dedent": "1.5.3", + "execa": "5.0.0", + "file-url": "3.0.0", + "find-up": "5.0.0", + "fs-extra": "^11.2.0", + "get-port": "5.1.1", + "get-stream": "6.0.0", + "git-url-parse": "14.0.0", + "glob-parent": "6.0.2", + "graceful-fs": "4.2.11", + "has-unicode": "2.0.1", + "ini": "^1.3.8", + "inquirer": "8.2.4", + "is-ci": "3.0.1", + "is-stream": "2.0.0", + "libnpmpublish": "9.0.9", + "load-json-file": "6.2.0", + "make-dir": "4.0.0", + "minimatch": "3.0.5", + "multimatch": "5.0.0", + "node-fetch": "2.6.7", + "npm-package-arg": "11.0.2", + "npm-packlist": "8.0.2", + "npm-registry-fetch": "^17.1.0", + "p-map": "4.0.0", + "p-map-series": "2.1.0", + "p-queue": "6.6.2", + "p-waterfall": "2.1.1", + "pacote": "^18.0.6", + "pify": "5.0.0", + "pretty-format": "29.4.3", + "read-cmd-shim": "4.0.0", + "resolve-from": "5.0.0", + "rimraf": "^4.4.1", + "semver": "7.5.2", + "set-blocking": "^2.0.0", + "signal-exit": "3.0.7", + "slash": "3.0.0", + "ssri": "^10.0.6", + "string-width": "^4.2.3", + "tar": "6.2.1", + "temp-dir": "1.0.0", + "tempy": "1.0.0", + "through": "2.3.8", + "tinyglobby": "0.2.12", + "upath": "2.0.1", + "uuid": "^10.0.0", + "wide-align": "1.1.5", + "write-file-atomic": "5.0.1", + "write-pkg": "4.0.0", + "yargs": "17.7.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@lvce-editor/eslint-config": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-config/-/eslint-config-12.3.0.tgz", + "integrity": "sha512-TlFG7Ub5Gdgv8K/hQ3S3akQmq0AYuafA06n3Q5IPmlGUWlxirxS9E+iRVqyM/ZsxrsJ2HWFQcjLHtk1zh8YXpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/eslint-plugin": "10.0.1", + "@e18e/eslint-plugin": "^0.5.1", + "@eslint/css": "1.3.0", + "@eslint/js": "10.0.1", + "@eslint/json": "2.0.0", + "@eslint/markdown": "8.0.2", + "@lvce-editor/eslint-plugin-e2e": "12.3.0", + "@lvce-editor/eslint-plugin-github-actions": "12.3.0", + "@lvce-editor/eslint-plugin-nvmrc": "12.3.0", + "@lvce-editor/eslint-plugin-regex": "12.3.0", + "@lvce-editor/eslint-plugin-rpc": "12.3.0", + "@lvce-editor/eslint-plugin-tsconfig": "12.3.0", + "eslint-plugin-jest": "29.15.2", + "eslint-plugin-n": "18.1.0", + "eslint-plugin-package-json": "1.3.0", + "eslint-plugin-perfectionist": "5.9.1", + "eslint-plugin-sonarjs": "4.0.3", + "eslint-plugin-unicorn": "67.0.0", + "eslint-plugin-yml": "3.4.0", + "typescript-eslint": "8.61.1" + }, + "peerDependencies": { + "eslint": "^10" + } + }, + "node_modules/@lvce-editor/eslint-plugin-e2e": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-e2e/-/eslint-plugin-e2e-12.3.0.tgz", + "integrity": "sha512-AtK4hRBRuxMDn6ff3zM+n4oVESRSPkqpKiLiv9WsLsgltmF2EhrRTP6LXR4dbkLmCDBGBWB2T+lJ2ifI8hSZYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/eslint-plugin-github-actions": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-github-actions/-/eslint-plugin-github-actions-12.3.0.tgz", + "integrity": "sha512-nZdPPD+q9KVGTuYjCcGzATmJ8KSGythamNw5oU6VvRrCo6r31pSAMo+iPXTw6CPiV/3EXs0J4feXOXu/6Hnvyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-compat-utils": "0.6.5", + "yaml-eslint-parser": "2.0.0" + } + }, + "node_modules/@lvce-editor/eslint-plugin-nvmrc": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-nvmrc/-/eslint-plugin-nvmrc-12.3.0.tgz", + "integrity": "sha512-V+OXACAQKh8Eqg5QIoK90abScb9QLBYLcd4upbCQVXoqiaJqWboe+ObwNKKCFvMSSF3n0N9e9JWCFKz1Xt3K/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.8.4" + } + }, + "node_modules/@lvce-editor/eslint-plugin-nvmrc/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lvce-editor/eslint-plugin-regex": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-regex/-/eslint-plugin-regex-12.3.0.tgz", + "integrity": "sha512-F9RmIp3nlO4/bnOgD8Yz5Lynru1AFI1VOxra28DT7ihLmTPFO/dqTcsDSM8UK+L2x/RP/Y7Ez8DG0ZHcNoKEIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/eslint-plugin-rpc": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-rpc/-/eslint-plugin-rpc-12.3.0.tgz", + "integrity": "sha512-EGKpXJ8hyv0hFJmgaH6/3ww4Esc2XywXcDeRmu0eQnioWc7SX04qLV38EpIjXfZMVhRUCBzBNkHF6arqmiX4DQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lvce-editor/eslint-plugin-tsconfig": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/eslint-plugin-tsconfig/-/eslint-plugin-tsconfig-12.3.0.tgz", + "integrity": "sha512-VP+FRjZQ4Oc9fDM/G+nc/G4SM3STmPicF8zpLt6PFC1GO5yTsCZPDq4UESXL0bK78DYBHLOopUWC1FxkdYSE2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/json": "2.0.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", + "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emnapi/core": "^1.1.0", + "@emnapi/runtime": "^1.1.0", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.5.4.tgz", + "integrity": "sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.1", + "@npmcli/installed-package-contents": "^2.1.0", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.1.1", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.1.0", + "@npmcli/query": "^3.1.0", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", + "bin-links": "^4.0.4", + "cacache": "^18.0.3", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.2", + "json-parse-even-better-errors": "^3.0.2", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^10.2.2", + "minimatch": "^9.0.4", + "nopt": "^7.2.1", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.2", + "npm-pick-manifest": "^9.0.1", + "npm-registry-fetch": "^17.0.1", + "pacote": "^18.0.6", + "parse-conflict-json": "^3.0.0", + "proc-log": "^4.2.0", + "proggy": "^2.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.6", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", + "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "ini": "^4.1.3", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^4.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz", + "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.1.tgz", + "integrity": "sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==", + "dev": true, + "license": "ISC", + "dependencies": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^18.0.0", + "proc-log": "^4.1.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", + "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", + "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^4.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", + "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/query": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-3.1.0.tgz", + "integrity": "sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz", + "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", + "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@nx/devkit": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-20.8.4.tgz", + "integrity": "sha512-3r+6QmIXXAWL6K7m8vAbW31aniAZmZAZXeMhOhWcJoOAU7ggpCQaM8JP8/kO5ov/Bmhyf0i/SSVXI6kwiR5WNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "minimatch": "9.0.3", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 19 <= 21" + } + }, + "node_modules/@nx/devkit/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@nx/devkit/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@nx/devkit/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/nx-darwin-arm64": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-21.6.11.tgz", + "integrity": "sha512-4hXhV7ShXIlfPEjjm7dJY383xM2vTcnkKr5FUncAU08GKkkL67ib5CMlQADtdi32ewfCZntqiT8gUfFFSNvKtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@nx/nx-darwin-x64": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-21.6.11.tgz", + "integrity": "sha512-VxjKkzyhdO47X7d4JPx/f6HslERKetFmouDUBIoqbKDPVWpRegGMsRKcMYh4l61usxI1Qa2U4Ec6MgO5Fnm41g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@nx/nx-freebsd-x64": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-21.6.11.tgz", + "integrity": "sha512-3jDn7Tb3FMFfeFTM/XKAcI+J92kDLNmxUS/N/n/+kF/XYLPgMUZQqSeDpVifk4fgy0BCoH8DSMQIqTQau6dV/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-21.6.11.tgz", + "integrity": "sha512-37tpiVod5FN/EAuCGh+uad/6nsfDFze02OjYReUPKeYPs8Q7Ac/V9j4kn/y5uZhKSle+9+sa2QR/K79B0+lNxw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-arm64-gnu": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-21.6.11.tgz", + "integrity": "sha512-r+czH0OtldQqFm2B6BBBUPW8aO+sBMvpZCgN855vko30WaCeXo8Fkuk71rQMxByz0jnoCxSnzLtEWVZm1rmJYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-arm64-musl": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-21.6.11.tgz", + "integrity": "sha512-0FAPyWEGPCukXxR1qowvFx6Q/cU906vwPlAQtcbrBU1e2H2aMUslk9EmL8iHb5MsHdmGcFyFemwr9oN8gxmz4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-x64-gnu": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-21.6.11.tgz", + "integrity": "sha512-+bWJWXJ8tdddl1L3bTKE0VmvTmdsk4zzUr6P9ts9hXQbwoWqMcuA6LNqOhUfzVOL3VioirRMtKMfFuUAUhi3Yg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-linux-x64-musl": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-21.6.11.tgz", + "integrity": "sha512-Mh09mLc+yeJk7DKfx7x6XfB+bm2dP1/7gyUuRQj4WjkT+Il2ZponyTuH8LmX06Jpr7efAAFk+8lBXeleV7XvMw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@nx/nx-win32-arm64-msvc": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-21.6.11.tgz", + "integrity": "sha512-d7ZeCCDwaeyKiWD2JLSSxMSuSHHwIdpbnMtZtzRE6tDdAgs6e9F36/OBNQB3IRXH8V6QKOy2OGDyWeOKr01X9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@nx/nx-win32-x64-msvc": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-21.6.11.tgz", + "integrity": "sha512-otHSkhyoGilttV4RRkVmLLGb2W+Ia4b90lWxLnEm9jAAKmA9O2FUG2vAvKDHNcqTyDwwCcHfHxslgnR1u/3OIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", + "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.4.1", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^8.4.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.4.4-cjs.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.4-cjs.2.tgz", + "integrity": "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.7.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", + "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "13.3.2-cjs.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.2-cjs.1.tgz", + "integrity": "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.8.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^5" + } + }, + "node_modules/@octokit/request": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", + "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^9.0.6", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", + "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/rest": { + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.2.tgz", + "integrity": "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^5.0.2", + "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", + "@octokit/plugin-request-log": "^4.0.0", + "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@ota-meshi/ast-token-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@ota-meshi/ast-token-store/-/ast-token-store-0.3.0.tgz", + "integrity": "sha512-XRO0zi2NIUKq2lUk3T1ecFSld1fMWRKE6naRFGkgkdeosx7IslyUKNv5Dcb5PJTja9tHJoFu0v/7yEpAkrkrTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sigstore/bundle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", + "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.3.tgz", + "integrity": "sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", + "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^13.0.1", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", + "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^2.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", + "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.1.tgz", + "integrity": "sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/type-utils": "8.61.1", + "@typescript-eslint/utils": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.61.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.1.tgz", + "integrity": "sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", + "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.61.1", + "@typescript-eslint/types": "^8.61.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", + "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", + "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.1.tgz", + "integrity": "sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/utils": "8.61.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", + "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", + "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.61.1", + "@typescript-eslint/tsconfig-utils": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", + "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", + "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", + "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", + "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.38", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", + "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bin-links": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.4.tgz", + "integrity": "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/byte-size": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz", + "integrity": "sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", + "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cmd-shim": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.3.tgz", + "integrity": "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/columnify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/comment-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-5.0.0.tgz", + "integrity": "sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "dev": true, + "license": "ISC" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-5.0.1.tgz", + "integrity": "sha512-Rvi5pH+LvgsqGwZPZ3Cq/tz4ty7mjijhr3qR4m9IBXNbxGGYgTVVO+duXzz9aArmHxFtwZ+LRkrNIMDQzgoY4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^6.0.0", + "conventional-commits-parser": "^4.0.0", + "dateformat": "^3.0.3", + "get-pkg-repo": "^4.2.1", + "git-raw-commits": "^3.0.0", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^5.0.0", + "normalize-package-data": "^3.0.3", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz", + "integrity": "sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz", + "integrity": "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-filter": "^3.0.0", + "dateformat": "^3.0.3", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "meow": "^8.1.2", + "semver": "^7.0.0", + "split": "^1.0.1" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-commits-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", + "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-commits-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", + "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.3.5", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-7.0.1.tgz", + "integrity": "sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^3.0.0", + "conventional-commits-filter": "^3.0.0", + "conventional-commits-parser": "^4.0.0", + "git-raw-commits": "^3.0.0", + "git-semver-tags": "^5.0.0", + "meow": "^8.1.2" + }, + "bin": { + "conventional-recommended-bump": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cspell-config-lib": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-10.0.1.tgz", + "integrity": "sha512-hMpo/0j6k7pbiqrLDOLJKD2IGP9XwhjKf2miiM6p84Xeo4nyuFZaxxDCQ68R851HSYFrrdltgpoipMbj1h2Tnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "10.0.1", + "comment-json": "^5.0.0", + "smol-toml": "^1.6.1", + "yaml": "^2.9.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-dictionary": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-10.0.1.tgz", + "integrity": "sha512-3cZ659vgsZWkzGQJR/sNqGDVt/OnvTSieLKI76V++4t1bHJfochb9ZrrwsuMsb1VPGiyqClUP1/O6WrefF/FVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-performance-monitor": "10.0.1", + "@cspell/cspell-pipe": "10.0.1", + "@cspell/cspell-types": "10.0.1", + "cspell-trie-lib": "10.0.1", + "fast-equals": "^6.0.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-glob": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-10.0.1.tgz", + "integrity": "sha512-7bII9J3aSSpZDwhx7w+zfQXbMxHZQ3be0ilUp5bHrsjz6o07v/NqOHMGcwKdPn1sw2dxDz9sv057xE5pqXnSdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "10.0.1", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-grammar": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-10.0.1.tgz", + "integrity": "sha512-xC9AFYmaI9wsO//a7S5tdDGKGJVD5UEEsTg+Up2fi7lPfXIryisYmV6tePNL1SEg0idYss4ja8LUZ3Mib09BjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "10.0.1", + "@cspell/cspell-types": "10.0.1" + }, + "bin": { + "cspell-grammar": "bin.mjs" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-io": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-10.0.1.tgz", + "integrity": "sha512-8C2ka07faxflnaqEBO3pektS21XViE/SEHT7F5ZD1ou7FyMR5u3xawTBJSczClfsxLt/WYeztBYrpmGAjmjksw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-service-bus": "10.0.1", + "@cspell/url": "10.0.1" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-lib": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-10.0.1.tgz", + "integrity": "sha512-RpsIPiLzc4/YMW8BMRKpyJ81x439qjYWcqgdKeXnMkbKM88J9PexzutfFf/4v97v96KzfNitEzMpbI0uj8OeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-bundled-dicts": "10.0.1", + "@cspell/cspell-performance-monitor": "10.0.1", + "@cspell/cspell-pipe": "10.0.1", + "@cspell/cspell-resolver": "10.0.1", + "@cspell/cspell-types": "10.0.1", + "@cspell/dynamic-import": "10.0.1", + "@cspell/filetypes": "10.0.1", + "@cspell/rpc": "10.0.1", + "@cspell/strong-weak-map": "10.0.1", + "@cspell/url": "10.0.1", + "cspell-config-lib": "10.0.1", + "cspell-dictionary": "10.0.1", + "cspell-glob": "10.0.1", + "cspell-grammar": "10.0.1", + "cspell-io": "10.0.1", + "cspell-trie-lib": "10.0.1", + "env-paths": "^4.0.0", + "gensequence": "^8.0.8", + "import-fresh": "^4.0.0", + "resolve-from": "^5.0.0", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-uri": "^3.1.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/cspell-lib/node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cspell-lib/node_modules/import-fresh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-4.0.0.tgz", + "integrity": "sha512-Fpi660c7VPDM3fPKYovStd9IP1CPOikf6v/dGxJJMmHPcwYQIMJ4W7kO1avBYEpMqkCh+Dx3Ln6H7VYqgztLjw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cspell-trie-lib": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-10.0.1.tgz", + "integrity": "sha512-BFvhalSkRQFjKrZ//FKK7fRGrZFpifnxB5AwCkzsIsBZqicsfafcQ1xP21qpb0QqyV/IomjNgviG+tRJs+0rMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.18.0" + }, + "peerDependencies": { + "@cspell/cspell-types": "10.0.1" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/del/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", + "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-newline": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz", + "integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.375", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz", + "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz", + "integrity": "sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", + "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.5.tgz", + "integrity": "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-fix-utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/eslint-fix-utils/-/eslint-fix-utils-0.4.2.tgz", + "integrity": "sha512-n7ZTcwwkP5scedlhvWMcqxED+O1NzXcj5Rxn/0kJQMP88k02vRcBfQ1qsk/JHb6Aw8bajFoetFCCBiNIcNCsvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/estree": ">=1", + "eslint": ">=8" + }, + "peerDependenciesMeta": { + "@types/estree": { + "optional": true + } + } + }, + "node_modules/eslint-json-compat-utils": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-json-compat-utils/-/eslint-json-compat-utils-0.2.3.tgz", + "integrity": "sha512-RbBmDFyu7FqnjE8F0ZxPNzx5UaptdeS9Uu50r7A+D7s/+FCX+ybiyViYEgFUaFIFqSWJgZRTpL5d8Kanxxl2lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esquery": "^1.6.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": "*", + "jsonc-eslint-parser": "^2.4.0 || ^3.0.0" + }, + "peerDependenciesMeta": { + "@eslint/json": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-es-x/node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-es-x/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "29.15.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.2.tgz", + "integrity": "sha512-kEN4r9RZl1xcsb4arGq89LrcVdOUFII/JSCwtTPJyv16mDwmPrcuEQwpxqZHeINvcsd7oK5O/rhdGlxFRaZwvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.0.0" + }, + "engines": { + "node": "^20.12.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "jest": "*", + "typescript": ">=4.8.4 <7.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-n": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.1.0.tgz", + "integrity": "sha512-hkUm9EtnFV2h2fE16jNVUfCVUqvPzI7fGLsFdun5lFt/pbmf2kCgDx6ymi9rx+NCUSggBmurJCZOfG20JBs/kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "globrex": "^0.1.2", + "ignore": "^5.3.2", + "semver": "^7.6.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.57.1", + "ts-declaration-location": "^1.0.6", + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "ts-declaration-location": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-package-json": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-package-json/-/eslint-plugin-package-json-1.3.0.tgz", + "integrity": "sha512-YC4lXD7sZJ5Pj8NrK9npvIBzMH9WMrkXb4VaBXRqyxTriCwqFcEJMX51K3TjkzLiXS3eUQ3CzimKWNPiSpq5tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@altano/repository-tools": "^2.0.1", + "change-case": "^5.4.4", + "detect-indent": "^7.0.2", + "detect-newline": "^4.0.1", + "eslint-fix-utils": "~0.4.1", + "eslint-json-compat-utils": "^0.2.3", + "jsonc-eslint-parser": "^3.1.0", + "package-json-validator": "^1.5.0", + "semver": "^7.7.3", + "sort-object-keys": "^2.0.0", + "sort-package-json": "^3.4.0" + }, + "engines": { + "node": "^22.22.2 || >=24.15.0" + }, + "peerDependencies": { + "@eslint/json": ">=1.0.0", + "eslint": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@eslint/json": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-package-json/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-perfectionist": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-5.9.1.tgz", + "integrity": "sha512-30mHLNfEhzwaq5cquyWgnzrNXvT8AzwIwyeH5aj4U5ajhHSF2uiO6i09xpMDLv7koaZVTjLsvYF4m3gK/15tyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.61.0", + "natural-orderby": "^5.0.0" + }, + "engines": { + "node": "^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "eslint": "^8.45.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-4.0.3.tgz", + "integrity": "sha512-5drkJKLC9qQddIiaATV0e8+ygbUc7b0Ti6VB7M2d3jmKNh3X0RaiIJYTs3dr9xnlhlrxo+/s1FoO3Jgv6O/c7g==", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "builtin-modules": "^3.3.0", + "bytes": "^3.1.2", + "functional-red-black-tree": "^1.0.1", + "globals": "^17.4.0", + "jsx-ast-utils-x": "^0.1.0", + "lodash.merge": "^4.6.2", + "minimatch": "^10.2.5", + "scslre": "^0.3.0", + "semver": "^7.7.4", + "ts-api-utils": "^2.5.0", + "typescript": ">=5" + }, + "peerDependencies": { + "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/globals": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "67.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-67.0.0.tgz", + "integrity": "sha512-XEYhNfAFFFYQLq++53iqpgIPFqvjasf5lsUJuCdmd/QvbRfcLbmPTjcTyVEXc5yBudWIg08SSEGgqJtEojk1ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "@eslint-community/eslint-utils": "^4.9.1", + "browserslist": "^4.28.2", + "change-case": "^5.4.4", + "ci-info": "^4.4.0", + "core-js-compat": "^3.49.0", + "detect-indent": "^7.0.2", + "find-up-simple": "^1.0.1", + "globals": "^17.6.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regjsparser": "^0.13.1", + "semver": "^7.8.4", + "strip-indent": "^4.1.1" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=10.4" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-yml": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-3.4.0.tgz", + "integrity": "sha512-j6U3ESrAkidkvNb3HFN2UMxke46GNp6bsJokabXCICcgomSy3YU4oED9cjzkZ58nYxWD5qnWV1b/2YlqyWMOxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/core": "^1.0.1", + "@eslint/plugin-kit": "^0.7.0", + "@ota-meshi/ast-token-store": "^0.3.0", + "diff-sequences": "^29.0.0", + "escape-string-regexp": "5.0.0", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^2.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=9.38.0" + } + }, + "node_modules/eslint-plugin-yml/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.0.0.tgz", + "integrity": "sha512-PFhhIGgdM79r5Uztdj9Zb6Tt1zKafqVfdMGwVca1z5z6fbX7DmsySSuJd8HiP6I1j505DCS83cLxo5rmSNeVEA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz", + "integrity": "sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, + "node_modules/front-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/front-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/gensequence": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-8.0.8.tgz", + "integrity": "sha512-omMVniXEXpdx/vKxGnPRoO2394Otlze28TyxECbFVyoSpZ9H3EO7lemjcB12OpQJzRW4e5tt/dL1rOxry6aMHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "get-pkg-repo": "src/cli.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-pkg-repo/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/get-pkg-repo/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/git-hooks-list": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.2.1.tgz", + "integrity": "sha512-WNvqJjOxxs/8ZP9+DWdwWJ7cDsd60NHf39XnD82pDVrKO5q7xfPqpkK6hwEAmBa/ZSEE4IOoR75EzbbIuwGlMw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/fisker/git-hooks-list?sponsor=1" + } + }, + "node_modules/git-raw-commits": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", + "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^7.0.0", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-remote-origin-url/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/git-semver-tags": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-5.0.1.tgz", + "integrity": "sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^8.1.2", + "semver": "^7.0.0" + }, + "bin": { + "git-semver-tags": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/git-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-ssh": "^1.4.0", + "parse-url": "^8.1.0" + } + }, + "node_modules/git-url-parse": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-14.0.0.tgz", + "integrity": "sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "git-up": "^7.0.0" + } + }, + "node_modules/gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", + "dev": true, + "license": "BSD", + "dependencies": { + "ini": "^1.3.2" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-directory": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", + "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "6.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", + "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/init-package-json": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-6.0.3.tgz", + "integrity": "sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^5.0.0", + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^3.0.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-builtin-module": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", + "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^5.0.0" + }, + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-builtin-module/node_modules/builtin-modules": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.2.0.tgz", + "integrity": "sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-safe-filename": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", + "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ssh": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", + "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.1" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-nice": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", + "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-eslint-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-3.1.0.tgz", + "integrity": "sha512-75EA7EWZExL/j+MDKQrRbdzcRI2HOkRlmUw8fZJc1ioqFEOvBsq7Rt+A6yCxOt9w/TYNpkt52gC6nm/g5tFIng==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^5.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsx-ast-utils-x": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils-x/-/jsx-ast-utils-x-0.1.0.tgz", + "integrity": "sha512-eQQBjBnsVtGacsG9uJNB8qOr3yA8rga4wAaGG1qRcBzSIvfhERLrWxMAM1hp5fcS6Abo8M4+bUBTekYR0qTPQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/just-diff": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", + "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", + "dev": true, + "license": "MIT" + }, + "node_modules/just-diff-apply": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", + "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lerna": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-8.2.4.tgz", + "integrity": "sha512-0gaVWDIVT7fLfprfwpYcQajb7dBJv3EGavjG7zvJ+TmGx3/wovl5GklnSwM2/WeE0Z2wrIz7ndWhBcDUHVjOcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lerna/create": "8.2.4", + "@npmcli/arborist": "7.5.4", + "@npmcli/package-json": "5.2.0", + "@npmcli/run-script": "8.1.0", + "@nx/devkit": ">=17.1.2 < 21", + "@octokit/plugin-enterprise-rest": "6.0.1", + "@octokit/rest": "20.1.2", + "aproba": "2.0.0", + "byte-size": "8.1.1", + "chalk": "4.1.0", + "clone-deep": "4.0.1", + "cmd-shim": "6.0.3", + "color-support": "1.1.3", + "columnify": "1.6.0", + "console-control-strings": "^1.1.0", + "conventional-changelog-angular": "7.0.0", + "conventional-changelog-core": "5.0.1", + "conventional-recommended-bump": "7.0.1", + "cosmiconfig": "9.0.0", + "dedent": "1.5.3", + "envinfo": "7.13.0", + "execa": "5.0.0", + "fs-extra": "^11.2.0", + "get-port": "5.1.1", + "get-stream": "6.0.0", + "git-url-parse": "14.0.0", + "glob-parent": "6.0.2", + "graceful-fs": "4.2.11", + "has-unicode": "2.0.1", + "import-local": "3.1.0", + "ini": "^1.3.8", + "init-package-json": "6.0.3", + "inquirer": "^8.2.4", + "is-ci": "3.0.1", + "is-stream": "2.0.0", + "jest-diff": ">=29.4.3 < 30", + "js-yaml": "4.1.0", + "libnpmaccess": "8.0.6", + "libnpmpublish": "9.0.9", + "load-json-file": "6.2.0", + "make-dir": "4.0.0", + "minimatch": "3.0.5", + "multimatch": "5.0.0", + "node-fetch": "2.6.7", + "npm-package-arg": "11.0.2", + "npm-packlist": "8.0.2", + "npm-registry-fetch": "^17.1.0", + "nx": ">=17.1.2 < 21", + "p-map": "4.0.0", + "p-map-series": "2.1.0", + "p-pipe": "3.1.0", + "p-queue": "6.6.2", + "p-reduce": "2.1.0", + "p-waterfall": "2.1.1", + "pacote": "^18.0.6", + "pify": "5.0.0", + "read-cmd-shim": "4.0.0", + "resolve-from": "5.0.0", + "rimraf": "^4.4.1", + "semver": "^7.3.8", + "set-blocking": "^2.0.0", + "signal-exit": "3.0.7", + "slash": "3.0.0", + "ssri": "^10.0.6", + "string-width": "^4.2.3", + "tar": "6.2.1", + "temp-dir": "1.0.0", + "through": "2.3.8", + "tinyglobby": "0.2.12", + "typescript": ">=3 < 6", + "upath": "2.0.1", + "uuid": "^10.0.0", + "validate-npm-package-license": "3.0.4", + "validate-npm-package-name": "5.0.1", + "wide-align": "1.1.5", + "write-file-atomic": "5.0.1", + "write-pkg": "4.0.0", + "yargs": "17.7.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "lerna": "dist/cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/lerna/node_modules/@nx/nx-darwin-arm64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.8.4.tgz", + "integrity": "sha512-8Y7+4wj1qoZsuDRpnuiHzSIsMt3VqtJ0su8dgd/MyGccvvi4pndan2R5yTiVw/wmbMxtBmZ6PO6Z8dgSIrMVog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-darwin-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.8.4.tgz", + "integrity": "sha512-2lfuxRc56QWnAysMhcD03tpCPiRzV1+foUq0MhV2sSBIybXmgV4wHLkPZNhlBCl4FNXrWiZiN1OJ2X9AGiOdug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-freebsd-x64": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.8.4.tgz", + "integrity": "sha512-99vnUXZy+OUBHU+8Yhabre2qafepKg9GKkQkhmXvJGqOmuIsepK7wirUFo2PiVM8YhS6UV2rv6hKAZcQ7skYyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.8.4.tgz", + "integrity": "sha512-dht73zpnpzEUEzMHFQs4mfiwZH3WcJgQNWkD5p7WkeJewHq2Yyd0eG5Jg3kB7wnFtwPUV1eNJRM5rephgylkLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-arm64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.8.4.tgz", + "integrity": "sha512-syXxbJZ0yPaqzVmB28QJgUtaarSiW/PQmv/5Z2Ps8rCi7kYylISPVNjP1NNiIOcGDRWbHqoBfM0bEGPfSp0rBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-arm64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.8.4.tgz", + "integrity": "sha512-AlZZFolS/S0FahRKG7rJ0Z9CgmIkyzHgGaoy3qNEMDEjFhR3jt2ZZSLp90W7zjgrxojOo90ajNMrg2UmtcQRDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-x64-gnu": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.8.4.tgz", + "integrity": "sha512-MSu+xVNdR95tuuO+eL/a/ZeMlhfrZ627On5xaCZXnJ+lFxNg/S4nlKZQk0Eq5hYALCd/GKgFGasRdlRdOtvGPg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-linux-x64-musl": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.8.4.tgz", + "integrity": "sha512-KxpQpyLCgIIHWZ4iRSUN9ohCwn1ZSDASbuFCdG3mohryzCy8WrPkuPcb+68J3wuQhmA5w//Xpp/dL0hHoit9zQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-win32-arm64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.8.4.tgz", + "integrity": "sha512-ffLBrxM9ibk+eWSY995kiFFRTSRb9HkD5T1s/uZyxV6jfxYPaZDBAWAETDneyBXps7WtaOMu+kVZlXQ3X+TfIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/@nx/nx-win32-x64-msvc": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.8.4.tgz", + "integrity": "sha512-JxuuZc4h8EBqoYAiRHwskimpTJx70yn4lhIRFBoW5ICkxXW1Rw0yip/1UVsWRHXg/x9BxmH7VVazdfaQWmGu6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/lerna/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/lerna/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/lerna/node_modules/nx": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/nx/-/nx-20.8.4.tgz", + "integrity": "sha512-/++x0OM3/UTmDR+wmPeV13tSxeTr+QGzj3flgtH9DiOPmQnn2CjHWAMZiOhcSh/hHoE/V3ySL4757InQUsVtjQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@napi-rs/wasm-runtime": "0.2.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.2", + "@zkochan/js-yaml": "0.0.7", + "axios": "^1.8.3", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "front-matter": "^4.0.2", + "ignore": "^5.0.4", + "jest-diff": "^29.4.1", + "jsonc-parser": "3.2.0", + "lines-and-columns": "2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "resolve.exports": "2.0.3", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "yaml": "^2.6.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "20.8.4", + "@nx/nx-darwin-x64": "20.8.4", + "@nx/nx-freebsd-x64": "20.8.4", + "@nx/nx-linux-arm-gnueabihf": "20.8.4", + "@nx/nx-linux-arm64-gnu": "20.8.4", + "@nx/nx-linux-arm64-musl": "20.8.4", + "@nx/nx-linux-x64-gnu": "20.8.4", + "@nx/nx-linux-x64-musl": "20.8.4", + "@nx/nx-win32-arm64-msvc": "20.8.4", + "@nx/nx-win32-x64-msvc": "20.8.4" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/lerna/node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lerna/node_modules/ora": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lerna/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lerna/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libnpmaccess": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-8.0.6.tgz", + "integrity": "sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^11.0.2", + "npm-registry-fetch": "^17.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/libnpmpublish": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-9.0.9.tgz", + "integrity": "sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==", + "dev": true, + "license": "ISC", + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.1", + "npm-package-arg": "^11.0.2", + "npm-registry-fetch": "^17.0.1", + "proc-log": "^4.2.0", + "semver": "^7.3.7", + "sigstore": "^2.2.0", + "ssri": "^10.0.6" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/load-json-file/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.28.1.tgz", + "integrity": "sha512-U9w+PzSZ00Z5m9rZ5ARVFL5xOfuCHdKYi/1RRwDCJsboFgJDNT3zT6PIPD7mZQYaQLhsZM3GfDRgSMRHhSmVng==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/module-replacements": { + "version": "3.0.0-beta.8", + "resolved": "https://registry.npmjs.org/module-replacements/-/module-replacements-3.0.0-beta.8.tgz", + "integrity": "sha512-sc8TepP9elxoOBXEpxmhPzKKjTjbswHVcmsKGbgvm3k6jZlLu/WMV/Lfmga6IGMgHU/V3WtY2s6VEgM4nTElUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/multimatch/node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-orderby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-5.0.0.tgz", + "integrity": "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.3.1.tgz", + "integrity": "sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^4.1.0", + "semver": "^7.3.5", + "tar": "^6.2.1", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-machine-id": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", + "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.48", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.48.tgz", + "integrity": "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", + "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", + "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^2.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nx": { + "version": "21.6.11", + "resolved": "https://registry.npmjs.org/nx/-/nx-21.6.11.tgz", + "integrity": "sha512-AAgJGhS+7xlsmZF6ArKX1vgONxf7IymUYZ1BxGXHVa5927rGfgKoMaPOgwwtvN0OL3o/QYaNGwlDfIzCvlpOLQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@napi-rs/wasm-runtime": "0.2.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.2", + "@zkochan/js-yaml": "0.0.7", + "axios": "^1.12.0", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "front-matter": "^4.0.2", + "ignore": "^5.0.4", + "jest-diff": "^30.0.2", + "jsonc-parser": "3.2.0", + "lines-and-columns": "2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "resolve.exports": "2.0.3", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tree-kill": "^1.2.2", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "yaml": "^2.6.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "21.6.11", + "@nx/nx-darwin-x64": "21.6.11", + "@nx/nx-freebsd-x64": "21.6.11", + "@nx/nx-linux-arm-gnueabihf": "21.6.11", + "@nx/nx-linux-arm64-gnu": "21.6.11", + "@nx/nx-linux-arm64-musl": "21.6.11", + "@nx/nx-linux-x64-gnu": "21.6.11", + "@nx/nx-linux-x64-musl": "21.6.11", + "@nx/nx-win32-arm64-msvc": "21.6.11", + "@nx/nx-win32-x64-msvc": "21.6.11" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/nx/node_modules/@jest/schemas": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/nx/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/nx/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/nx/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/nx/node_modules/jest-diff": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", + "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/diff-sequences": "30.4.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nx/node_modules/ora": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nx/node_modules/pretty-format": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "30.4.1", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/nx/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nx/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz", + "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-pipe": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", + "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-waterfall": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz", + "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/package-json-validator": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/package-json-validator/-/package-json-validator-1.5.2.tgz", + "integrity": "sha512-eHXskJQU4aCiSfjhRfTVtCJ+22/EzLHgYgZv5Gj3teb3NJrnTMzq5BnKAWKvR+PLpknCO1PmOCImDuO+dX4Vaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "npm-package-arg": "^13.0.2", + "semver": "^7.7.2", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/package-json-validator/node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/package-json-validator/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/package-json-validator/node_modules/npm-package-arg": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", + "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/package-json-validator/node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/package-json-validator/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/package-json-validator/node_modules/validate-npm-package-name": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", + "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/pacote": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", + "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/package-json": "^5.1.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^8.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-conflict-json": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz", + "integrity": "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-json/node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-path": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.0" + } + }, + "node_modules/parse-url": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-path": "^7.0.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", + "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/proggy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proggy/-/proggy-2.0.0.tgz", + "integrity": "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/promise-call-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.2.tgz", + "integrity": "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==", + "dev": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promzard": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-1.0.2.tgz", + "integrity": "sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "read": "^3.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/protocols": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/react-is-19": { + "name": "react-is", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", + "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/read": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz", + "integrity": "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-cmd-shim": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", + "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/refa": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", + "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-ast-analysis": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", + "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.1" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regjsparser": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", + "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.7.tgz", + "integrity": "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scslre": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", + "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.0", + "regexp-ast-analysis": "^0.7.0" + }, + "engines": { + "node": "^14.0.0 || >=16.0.0" + } + }, + "node_modules/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sigstore": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", + "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^2.3.2", + "@sigstore/tuf": "^2.3.4", + "@sigstore/verify": "^1.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/smol-toml": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", + "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sort-object-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-2.1.0.tgz", + "integrity": "sha512-SOiEnthkJKPv2L6ec6HMwhUcN0/lppkeYuN1x63PbyPRrgSPIuBJCiYxYyvWRTtjMlOi14vQUCGUJqS6PLVm8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/sort-package-json": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.7.1.tgz", + "integrity": "sha512-ssk1HG7whF8N/T1IsNAQrtHG5Cbdi0rAgRJZXYBr9hF5xaHnBNzUx/W6LcthEW7FhOwvZssbESZuO+GxssqAyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-indent": "^7.0.2", + "detect-newline": "^4.0.1", + "git-hooks-list": "^4.1.1", + "is-plain-obj": "^4.1.0", + "semver": "^7.7.3", + "sort-object-keys": "^2.0.1", + "tinyglobby": "^0.2.15" + }, + "bin": { + "sort-package-json": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/sort-package-json/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sort-package-json/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sort-package-json/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.3.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tempy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.0.tgz", + "integrity": "sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", + "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/treeverse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", + "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tuf-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", + "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "2.0.1", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.1.tgz", + "integrity": "sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.61.1", + "@typescript-eslint/parser": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/utils": "8.61.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true, + "license": "ISC" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/write-json-file": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", + "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.15", + "make-dir": "^2.1.0", + "pify": "^4.0.1", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-json-file/node_modules/detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/write-json-file/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-json-file/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/write-json-file/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/write-json-file/node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/write-pkg": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz", + "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sort-keys": "^2.0.0", + "type-fest": "^0.4.1", + "write-json-file": "^3.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/write-pkg/node_modules/type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=6" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yaml-eslint-parser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-2.0.0.tgz", + "integrity": "sha512-h0uDm97wvT2bokfwwTmY6kJ1hp6YDFL0nRHwNKz8s/VD1FH/vvZjAKoMUE+un0eaYBSG7/c6h+lJTP+31tjgTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^5.0.0", + "yaml": "^2.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/packages/build/src/build-static.ts b/packages/build/src/build-static.ts index 74a3f1e..b681e5b 100644 --- a/packages/build/src/build-static.ts +++ b/packages/build/src/build-static.ts @@ -9,7 +9,7 @@ const sharedProcessUrl = pathToFileURL(sharedProcessPath).toString() const sharedProcess = await import(sharedProcessUrl) -process.env.PATH_PREFIX = '/explorer-view' +process.env.PATH_PREFIX = '/pull-request-github' const { commitHash } = await sharedProcess.exportStatic({ root, extensionPath: '', diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts deleted file mode 100644 index dd15fba..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-folder-10-items.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-folder-10-items' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/stress-folder`) - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00000.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00001.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00002.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00003.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00004.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00005.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00006.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00007.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00008.txt`, '') - await FileSystem.writeFile(`${tmpDir}/stress-folder/item-00009.txt`, '') - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusFirst() - const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) - await expect(folder).toHaveId('TreeItemActive') - await Explorer.clickCurrent() - - // assert - await expect(folder).toHaveAttribute('aria-expanded', 'true') - const firstItem = Locator('.TreeItem', { hasText: 'item-00000.txt' }) - const lastItem = Locator('.TreeItem', { hasText: 'item-00009.txt' }) - await expect(firstItem).toBeVisible() - await Explorer.focusIndex(10) - await expect(lastItem).toBeVisible() - await expect(lastItem).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts deleted file mode 100644 index 59fba0b..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-folder-100-items.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-folder-100-items' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/stress-folder`) - for (let index = 0; index < 100; index++) { - const fileName = `item-${index.toString().padStart(5, '0')}.txt` - await FileSystem.writeFile(`${tmpDir}/stress-folder/${fileName}`, '') - } - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusFirst() - const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) - await expect(folder).toHaveId('TreeItemActive') - await Explorer.clickCurrent() - - // assert - await expect(folder).toHaveAttribute('aria-expanded', 'true') - const firstItem = Locator('.TreeItem', { hasText: 'item-00000.txt' }) - const lastItem = Locator('.TreeItem', { hasText: 'item-00099.txt' }) - await expect(firstItem).toBeVisible() - await Explorer.focusIndex(100) - await expect(lastItem).toBeVisible() - await expect(lastItem).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts deleted file mode 100644 index 8b3894f..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-folder-100k-items.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-folder-100k-items' - -export const skip = 1 - -const totalItems = 100_000 -const batchSize = 500 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/stress-folder`) - for (let start = 0; start < totalItems; start += batchSize) { - const end = Math.min(start + batchSize, totalItems) - await Promise.all( - Array.from({ length: end - start }, (_, index) => { - const number = start + index - const fileName = `item-${number.toString().padStart(6, '0')}.txt` - return FileSystem.writeFile(`${tmpDir}/stress-folder/${fileName}`, '') - }), - ) - } - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusFirst() - const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) - await expect(folder).toHaveId('TreeItemActive') - await Explorer.clickCurrent() - - // assert - await expect(folder).toHaveAttribute('aria-expanded', 'true') - const firstItem = Locator('.TreeItem', { hasText: 'item-000000.txt' }) - const secondItem = Locator('.TreeItem', { hasText: 'item-000001.txt' }) - await expect(firstItem).toBeVisible() - await expect(secondItem).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts deleted file mode 100644 index 0d3ca1e..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-folder-10k-items.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-folder-10k-items' - -const totalItems = 10_000 -const batchSize = 500 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/stress-folder`) - for (let start = 0; start < totalItems; start += batchSize) { - const end = Math.min(start + batchSize, totalItems) - await Promise.all( - Array.from({ length: end - start }, (_, index) => { - const number = start + index - const fileName = `item-${number.toString().padStart(5, '0')}.txt` - return FileSystem.writeFile(`${tmpDir}/stress-folder/${fileName}`, '') - }), - ) - } - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusFirst() - const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) - await expect(folder).toHaveId('TreeItemActive') - await Explorer.clickCurrent() - - // assert - await expect(folder).toHaveAttribute('aria-expanded', 'true') - const firstItem = Locator('.TreeItem', { hasText: 'item-00000.txt' }) - const lastItem = Locator('.TreeItem', { hasText: 'item-09999.txt' }) - await expect(firstItem).toBeVisible() - await Explorer.focusIndex(10_000) - await expect(lastItem).toBeVisible() - await expect(lastItem).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts deleted file mode 100644 index 972bd84..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-folder-10m-items.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-folder-10m-items' -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, Extension, Locator, Workspace }) => { - // arrange - const extensionUri = import.meta.resolve('../fixtures/sample.file-system-provider-expand-folder-10m-items') - await Extension.addWebExtension(extensionUri) - const workspacePath = 'extension-host://xyz://' - await Workspace.setPath(workspacePath) - - // act - await Explorer.focusFirst() - const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) - await expect(folder).toHaveId('TreeItemActive') - await Explorer.clickCurrent() - - // assert - await expect(folder).toHaveAttribute('aria-expanded', 'true') - const firstItem = Locator('.TreeItem', { hasText: 'item-00000000.txt' }) - const secondItem = Locator('.TreeItem', { hasText: 'item-00000001.txt' }) - await expect(firstItem).toBeVisible() - await expect(secondItem).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts b/packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts deleted file mode 100644 index a430ac6..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-folder-1m-items.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-folder-1m-items' -export const skip = 1 - -export const test: Test = async ({ expect, Explorer, Extension, Locator, Workspace }) => { - // arrange - const extensionUri = import.meta.resolve('../fixtures/sample.file-system-provider-expand-folder-1m-items') - await Extension.addWebExtension(extensionUri) - const workspacePath = 'extension-host://xyz://' - await Workspace.setPath(workspacePath) - - // act - await Explorer.focusFirst() - const folder = Locator('.TreeItem', { hasText: 'stress-folder' }) - await expect(folder).toHaveId('TreeItemActive') - await Explorer.clickCurrent() - - // assert - await expect(folder).toHaveAttribute('aria-expanded', 'true') - const firstItem = Locator('.TreeItem', { hasText: 'item-0000000.txt' }) - const secondItem = Locator('.TreeItem', { hasText: 'item-0000001.txt' }) - await expect(firstItem).toBeVisible() - await expect(secondItem).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-expand-recursively.ts b/packages/e2e/src/viewlet.explorer-expand-recursively.ts deleted file mode 100644 index 03847b2..0000000 --- a/packages/e2e/src/viewlet.explorer-expand-recursively.ts +++ /dev/null @@ -1,30 +0,0 @@ -// TODO maybe merge this test with the other explorer test, less end to end tests will run faster - -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-expand-recursively' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a/b`) - await FileSystem.writeFile(`${tmpDir}/a/b/c.txt`, 'ccccc') - await FileSystem.mkdir(`${tmpDir}/folder-1`) - await FileSystem.mkdir(`${tmpDir}/folder-2`) - await FileSystem.mkdir(`${tmpDir}/folder-3`) - await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - - // act - await Explorer.expandRecursively() - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - const secondTreeItem = treeItems.nth(1) - const thirdTreeItem = treeItems.nth(2) - await expect(firstTreeItem).toHaveText('a') - await expect(secondTreeItem).toHaveText('b') - await expect(thirdTreeItem).toHaveText('c.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-file-system-provider-error.ts b/packages/e2e/src/viewlet.explorer-file-system-provider-error.ts deleted file mode 100644 index 251052d..0000000 --- a/packages/e2e/src/viewlet.explorer-file-system-provider-error.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-file-system-provider-error' -export const skip = 1 - -export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') - await Workspace.setPath(tmpDir) - - // Mock file system provider to throw an error - await Command.execute('FileSystemProvider.setError', true) - - // act & assert - Try to expand directory when provider throws error - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - - // Should show error state or handle gracefully - const errorMessage = Locator('.ErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('File system provider error') - - // Reset error state - await Command.execute('FileSystemProvider.setError', false) - - // Should recover and work normally - await Explorer.refresh() - const fileItem = Locator('.TreeItem', { hasText: 'file.txt' }) - await expect(fileItem).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts b/packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts deleted file mode 100644 index 7b0782e..0000000 --- a/packages/e2e/src/viewlet.explorer-file-system-provider-invalid-data.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-file-system-provider-invalid-data' -export const skip = 1 - -export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file.txt`, 'content') - await Workspace.setPath(tmpDir) - - // Mock file system provider to return invalid data (null/undefined entries) - await Command.execute('FileSystemProvider.setInvalidData', true) - - // act & assert - Try to expand directory when provider returns invalid data - await Explorer.focusIndex(0) - await Explorer.expandRecursively() - - // Should handle invalid data gracefully and not crash - const treeItems = Locator('.TreeItem') - const firstItem = treeItems.first() - - // Should still show valid items, ignoring invalid ones - await expect(firstItem).toBeVisible() - - // Should not show broken UI elements - const brokenItems = Locator('.TreeItem[aria-label*="undefined"], .TreeItem[aria-label*="null"]') - await expect(brokenItems).toHaveCount(0) - - // Reset to normal data - await Command.execute('FileSystemProvider.setInvalidData', false) - await Explorer.refresh() - - // Should work normally after reset - const fileItem = Locator('.TreeItem', { hasText: 'file.txt' }) - await expect(fileItem).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts b/packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts deleted file mode 100644 index 1895a39..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-copy-no-selection.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-copy-no-selection' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(-1) - - // act - await Explorer.handleCopy() - - // assert - const file1 = Locator('.TreeItem', { hasText: 'file-1.txt' }) - await expect(file1).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts b/packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts deleted file mode 100644 index 9bf002c..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-cut-no-selection.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-cut-no-selection' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(-1) - - // act - await Explorer.handleCut() - - // assert - const file1 = Locator('.TreeItem', { hasText: 'file-1.txt' }) - await expect(file1).toHaveClass('TreeItem') -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-leave.ts b/packages/e2e/src/viewlet.explorer-handle-drag-leave.ts deleted file mode 100644 index 327838a..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drag-leave.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drag-leave' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.handleDragOver(5000, 5000) - - // assert - const explorer = Locator('.Explorer .ListItems') - await expect(explorer).toHaveClass('DropTarget') - - // act - await Explorer.handleDragLeave() - - // assert - // TODO -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts deleted file mode 100644 index 110833e..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drag-over-all.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drag-over-all' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.handleDragOver(5000, 5000) - - // assert - const explorer = Locator('.Explorer .ListItems') - await expect(explorer).toHaveClass('DropTarget') -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts deleted file mode 100644 index babc5ac..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drag-over-files.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drag-over-folder' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.writeFile(`${tmpDir}/a/b.txt`, '') - await FileSystem.writeFile(`${tmpDir}/a/c.txt`, '') - await FileSystem.writeFile(`${tmpDir}/a/d.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.expandRecursively() - - // act - await Explorer.handleDragOverIndex(2) - - // assert - const treeItems = Locator('.Explorer .TreeItem') - const treeItemOne = treeItems.nth(0) - await expect(treeItemOne).toHaveClass('DropTarget') - const treeItemTwo = treeItems.nth(1) - await expect(treeItemTwo).toHaveClass('DropTarget') - const treeItemThree = treeItems.nth(2) - await expect(treeItemThree).toHaveClass('DropTarget') - const treeItemFour = treeItems.nth(3) - await expect(treeItemFour).toHaveClass('DropTarget') -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts deleted file mode 100644 index d37a8ec..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drag-over-folder.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drag-over-folder' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await Workspace.setPath(tmpDir) - - // act - await Explorer.handleDragOverIndex(0) - - // assert - const treeItems = Locator('.Explorer .TreeItem') - const treeItemOne = treeItems.nth(0) - await expect(treeItemOne).toHaveClass('DropTarget') -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts deleted file mode 100644 index 2a4cb8a..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drag-over-index-out-of-range.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drag-over-index-out-of-range' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') - await Workspace.setPath(tmpDir) - - // act - await Explorer.handleDragOverIndex(999) - - // assert - const explorer = Locator('.Explorer .ListItems') - await expect(explorer).toHaveClass('DropTarget') -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts deleted file mode 100644 index 6075e74..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drag-over-index-root.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drag-over-index-root' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file-1.txt`, 'a') - await FileSystem.writeFile(`${tmpDir}/file-2.txt`, 'b') - await Workspace.setPath(tmpDir) - - // act - await Explorer.handleDragOverIndex(-1) - - // assert - const explorer = Locator('.Explorer .ListItems') - await expect(explorer).toHaveClass('DropTarget') -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drag-over.ts b/packages/e2e/src/viewlet.explorer-handle-drag-over.ts deleted file mode 100644 index 3a82e49..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drag-over.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drag-over' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.handleDragOver(5000, 5000) - - // assert - const explorer = Locator('.Explorer .ListItems') - await expect(explorer).toHaveClass('DropTarget') -} diff --git a/packages/e2e/src/viewlet.explorer-handle-drop.ts b/packages/e2e/src/viewlet.explorer-handle-drop.ts deleted file mode 100644 index 257cbe3..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-drop.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-handle-drop' - -export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - const directory = await navigator.storage.getDirectory() - const fileHandle = await directory.getFileHandle('dropped-file.txt', { - create: true, - }) - const file = await fileHandle.getFile() - const fileList = [file] - const id = await Command.execute('FileSystemHandle.addFileHandle', fileHandle) - - // act - await Explorer.handleDrop(0, 0, [id], fileList) - - // assert - const droppedFile = Locator('.TreeItem', { hasText: 'dropped-file.txt' }) - await expect(droppedFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts b/packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts deleted file mode 100644 index 922644b..0000000 --- a/packages/e2e/src/viewlet.explorer-handle-icon-theme-change.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-icon-theme.change' - -export const skip = 1 - -export const test: Test = async ({ BaseUrl, expect, Extension, FileSystem, IconTheme, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/test.xyz`, 'test') - await FileSystem.mkdir(`${tmpDir}/test-folder`) - await Workspace.setPath(tmpDir) - const extensionUri = import.meta.resolve('../fixtures/sample.icon-theme') - await Extension.addWebExtension(extensionUri) - - // act - await IconTheme.setIconTheme('test-icon-theme') - - // assert - const iconFile = Locator('.TreeItem[aria-label="test.xyz"] .FileIcon') - const baseUrl = BaseUrl.getBaseUrl() - await expect(iconFile).toHaveAttribute('src', `${baseUrl}packages/extension-host-worker-tests/fixtures/sample.icon-theme/icons/default_file.svg`) -} diff --git a/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts b/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts deleted file mode 100644 index 0bcbf9f..0000000 --- a/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-null.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-ignored-file-decoration-invalid-null' - -export const test: Test = async ({ expect, Extension, FileSystem, Locator, Settings, Workspace }) => { - // arrange - await Settings.update({ - 'explorer.sourceControlDecorations': true, - }) - const uri = import.meta.resolve('../fixtures/sample.source-control-decoration-invalid-null') - await Extension.addWebExtension(uri) - const tmpDir = 'extension-host://xyz://' - await FileSystem.writeFile(`${tmpDir}/a`, '') - await FileSystem.writeFile(`${tmpDir}/b`, '') - await FileSystem.writeFile(`${tmpDir}/.gitignore`, 'a') - - // act - await Workspace.setPath(tmpDir) - - // assert - const a = Locator('.TreeItem[aria-label="a"]') - await expect(a).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts b/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts deleted file mode 100644 index 1ff93ed..0000000 --- a/packages/e2e/src/viewlet.explorer-ignored-file-decoration-invalid-object.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-ignored-file-decoration-invalid-object' - -export const test: Test = async ({ expect, Extension, FileSystem, Locator, Settings, Workspace }) => { - // arrange - await Settings.update({ - 'explorer.sourceControlDecorations': true, - }) - const uri = import.meta.resolve('../fixtures/sample.source-control-decoration-invalid-object') - await Extension.addWebExtension(uri) - const tmpDir = 'extension-host://xyz://' - await FileSystem.writeFile(`${tmpDir}/a`, '') - await FileSystem.writeFile(`${tmpDir}/b`, '') - await FileSystem.writeFile(`${tmpDir}/.gitignore`, 'a') - - // act - await Workspace.setPath(tmpDir) - - // assert - const a = Locator('.TreeItem[aria-label="a"]') - await expect(a).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts b/packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts deleted file mode 100644 index 4653aa3..0000000 --- a/packages/e2e/src/viewlet.explorer-ignored-file-decoration.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-ignored-file-decoration' - -export const skip = 1 - -export const test: Test = async ({ expect, Extension, FileSystem, Locator, Settings, Workspace }) => { - // arrange - await Settings.update({ - 'explorer.sourceControlDecorations': true, - }) - const uri = import.meta.resolve('../fixtures/sample.source-control-decoration') - await Extension.addWebExtension(uri) - const tmpDir = 'extension-host://xyz://' - await FileSystem.writeFile(`${tmpDir}/a`, '') - await FileSystem.writeFile(`${tmpDir}/b`, '') - await FileSystem.writeFile(`${tmpDir}/.gitignore`, 'a') - - // act - await Workspace.setPath(tmpDir) - - // assert - const a = Locator('.TreeItem[aria-label="a"]') - await expect(a).toBeVisible() - await expect(a).toHaveClass('decoration-ignored') -} diff --git a/packages/e2e/src/viewlet.explorer-keyboard-navigation.ts b/packages/e2e/src/viewlet.explorer-keyboard-navigation.ts deleted file mode 100644 index 507bf14..0000000 --- a/packages/e2e/src/viewlet.explorer-keyboard-navigation.ts +++ /dev/null @@ -1,118 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-keyboard-navigation' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a/b`) - await FileSystem.writeFile(`${tmpDir}/a/b/c.txt`, 'ccccc') - await FileSystem.mkdir(`${tmpDir}/folder-1`) - await FileSystem.mkdir(`${tmpDir}/folder-2`) - await FileSystem.mkdir(`${tmpDir}/folder-3`) - await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(-1) - - // assert - // const explorer = Locator('.Explorer') - // await expect(explorer).toHaveClass('FocusOutline') - - // act - await Explorer.focusNext() - - // assert - const titleA = '/a' - const treeItemA = Locator(`.TreeItem[title$="${titleA}"]`) - await expect(treeItemA).toHaveId('TreeItemActive') - - // act - await Explorer.clickCurrent() - - // assert - const titleB = '/a/b' - const treeItemB = Locator(`.TreeItem[title$="${titleB}"]`) - await expect(treeItemB).toBeVisible() - await expect(treeItemA).toHaveId('TreeItemActive') - - // act - await Explorer.focusNext() - - // assert - await expect(treeItemB).toHaveId('TreeItemActive') - - // act - await Explorer.clickCurrent() - - // assert - const titleC = '/a/b/c.txt' - const treeItemC = Locator(`.TreeItem[title$="${titleC}"]`) - await expect(treeItemC).toBeVisible() - await expect(treeItemB).toHaveId('TreeItemActive') - - // act - await Explorer.focusNext() - - // assert - await expect(treeItemC).toHaveId('TreeItemActive') - - // act - await Explorer.clickCurrent() - - // assert - const editor = Locator('.Editor') - await expect(editor).toHaveText('ccccc') - - // act - await Explorer.handleArrowLeft() - - // assert - await expect(treeItemB).toHaveId('TreeItemActive') - await expect(treeItemC).toBeVisible() - - // act - await Explorer.handleArrowLeft() - - // assert - await expect(treeItemB).toHaveId('TreeItemActive') - await expect(treeItemC).toBeHidden() - - // act - await Explorer.handleArrowLeft() - - // assert - await expect(treeItemA).toHaveId('TreeItemActive') - await expect(treeItemB).toBeVisible() - - // act - await Explorer.handleArrowLeft() - - // assert - await expect(treeItemA).toHaveId('TreeItemActive') - await expect(treeItemB).toBeHidden() - - // act - await Explorer.focusLast() - - // assert - const titleTest = '/test.txt' - const treeItemTestTxt = Locator(`.TreeItem[title$="${titleTest}"]`) - await expect(treeItemTestTxt).toHaveId('TreeItemActive') - - // act - await Explorer.focusFirst() - - // assert - await expect(treeItemA).toHaveId('TreeItemActive') - - // act - await Explorer.removeDirent() - - // assert - await expect(treeItemA).toBeHidden() - const titleFolder1 = `/folder-1` - const treeItemFolder1 = Locator(`.TreeItem[title$="${titleFolder1}"]`) - await expect(treeItemFolder1).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-large-directory-performance.ts b/packages/e2e/src/viewlet.explorer-large-directory-performance.ts deleted file mode 100644 index 2d7afde..0000000 --- a/packages/e2e/src/viewlet.explorer-large-directory-performance.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-large-directory-performance' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - - // Create 10,000 files in the directory - const numbers = Array.from(Array(10_000), (_, index) => index) - await Promise.all( - numbers.map((number) => { - return FileSystem.writeFile(`${tmpDir}/file${number.toString().padStart(4, '0')}.txt`, `content ${number}`) - }), - ) - - await Workspace.setPath(tmpDir) - - // Test 1: Initial load performance - await Explorer.focusIndex(0) - // await Explorer.expandRecursively() - - // Should load within reasonable time - - // Test 2: Verify items are loaded - const firstItem = Locator('.TreeItem').nth(0) - await expect(firstItem).toBeVisible() - - // Test 3: Navigation performance in large list - await Explorer.focusIndex(100) - await Explorer.focusIndex(1000) - await Explorer.focusIndex(5000) - - // Should navigate quickly - - // Test 4: Verify specific items exist - const midItem = Locator('.TreeItem', { hasText: 'file5000.txt' }) - await expect(midItem).toBeVisible() - - // Test 5: Test scrolling by focusing different items - await Explorer.focusIndex(9000) - await Explorer.focusIndex(100) - - // TODO need to autoscroll to those locations - // Test 6: Verify explorer is still responsive - // const lastItem = Locator('.TreeItem', { hasText: 'file9999.txt' }) - // await expect(lastItem).toBeVisible() - - // // Test 7: Test selection performance - // await Explorer.focusIndex(0) - // await Explorer.focusIndex(5000) -} diff --git a/packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts b/packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts deleted file mode 100644 index 539fb9f..0000000 --- a/packages/e2e/src/viewlet.explorer-long-file-name-500-emoji.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-long-file-name-500-emoji' - -export const test: Test = async ({ expect, Extension, FileSystem, Locator, Workspace }) => { - // arrange - const uri = import.meta.resolve('../fixtures/sample.file-system-provider-permission') - await Extension.addWebExtension(uri) - const prefix = 'extension-host://xyz://' - const fileName = `${'😀'.repeat(500)}.txt` - await FileSystem.writeFile(`${prefix}/${fileName}`, '') - - // act - await Workspace.setPath(`${prefix}/`) - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - await expect(treeItems).toHaveCount(1) - await expect(firstTreeItem).toContainText(fileName) -} diff --git a/packages/e2e/src/viewlet.explorer-long-file-name.ts b/packages/e2e/src/viewlet.explorer-long-file-name.ts deleted file mode 100644 index 20ac829..0000000 --- a/packages/e2e/src/viewlet.explorer-long-file-name.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-long-file-name' - -export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - const fileName = `a`.repeat(100) + '.txt' - await FileSystem.writeFile(`${tmpDir}/${fileName}`, '') - - // act - await Workspace.setPath(tmpDir) - - // assert - const newFile = Locator(`text=${fileName}`) - await expect(newFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-many-files-20000.ts b/packages/e2e/src/viewlet.explorer-many-files-20000.ts deleted file mode 100644 index 09f9979..0000000 --- a/packages/e2e/src/viewlet.explorer-many-files-20000.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-many-files-20000' - -const totalFiles = 20_000 -const batchSize = 500 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - for (let start = 0; start < totalFiles; start += batchSize) { - const end = Math.min(start + batchSize, totalFiles) - await Promise.all( - Array.from({ length: end - start }, (_, index) => { - const number = start + index - const fileName = `file-${number.toString().padStart(5, '0')}.txt` - return FileSystem.writeFile(`${tmpDir}/${fileName}`, `content ${number}`) - }), - ) - } - - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(0) - - // assert - const firstFile = Locator('.TreeItem', { hasText: 'file-00000.txt' }) - await expect(firstFile).toBeVisible() - await expect(firstFile).toHaveId('TreeItemActive') - - // act - await Explorer.focusIndex(10_000) - - // assert - const middleFile = Locator('.TreeItem', { hasText: 'file-10000.txt' }) - await expect(middleFile).toBeVisible() - await expect(middleFile).toHaveId('TreeItemActive') - - // act - await Explorer.focusIndex(19_999) - - // assert - const lastFile = Locator('.TreeItem', { hasText: 'file-19999.txt' }) - await expect(lastFile).toBeVisible() - await expect(lastFile).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts b/packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts deleted file mode 100644 index 177562f..0000000 --- a/packages/e2e/src/viewlet.explorer-many-files-repeated-focus-jumps.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-many-files-repeated-focus-jumps' - -const totalFiles = 2000 -const batchSize = 250 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - for (let start = 0; start < totalFiles; start += batchSize) { - const end = Math.min(start + batchSize, totalFiles) - await Promise.all( - Array.from({ length: end - start }, (_, index) => { - const number = start + index - const fileName = `file-${number.toString().padStart(4, '0')}.txt` - return FileSystem.writeFile(`${tmpDir}/${fileName}`, `content ${number}`) - }), - ) - } - await Workspace.setPath(tmpDir) - - const indices = [0, 250, 1999, 125, 1500, 1, 1998] - - for (const index of indices) { - const fileName = `file-${index.toString().padStart(4, '0')}.txt` - const file = Locator('.TreeItem', { hasText: fileName }) - await Explorer.focusIndex(index) - await expect(file).toBeVisible() - await expect(file).toHaveId('TreeItemActive') - } -} diff --git a/packages/e2e/src/viewlet.explorer-many-folders-20000.ts b/packages/e2e/src/viewlet.explorer-many-folders-20000.ts deleted file mode 100644 index 2699100..0000000 --- a/packages/e2e/src/viewlet.explorer-many-folders-20000.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-many-folders-20000' - -const totalFolders = 20_000 -const batchSize = 500 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - for (let start = 0; start < totalFolders; start += batchSize) { - const end = Math.min(start + batchSize, totalFolders) - await Promise.all( - Array.from({ length: end - start }, (_, index) => { - const number = start + index - const folderName = `folder-${number.toString().padStart(5, '0')}` - return FileSystem.mkdir(`${tmpDir}/${folderName}`) - }), - ) - } - - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(0) - - // assert - const firstFolder = Locator('.TreeItem', { hasText: 'folder-00000' }) - await expect(firstFolder).toBeVisible() - await expect(firstFolder).toHaveId('TreeItemActive') - - // act - await Explorer.focusIndex(10_000) - - // assert - const middleFolder = Locator('.TreeItem', { hasText: 'folder-10000' }) - await expect(middleFolder).toBeVisible() - await expect(middleFolder).toHaveId('TreeItemActive') - - // act - await Explorer.focusIndex(19_999) - - // assert - const lastFolder = Locator('.TreeItem', { hasText: 'folder-19999' }) - await expect(lastFolder).toBeVisible() - await expect(lastFolder).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-mouse-navigation.ts b/packages/e2e/src/viewlet.explorer-mouse-navigation.ts deleted file mode 100644 index 9434cba..0000000 --- a/packages/e2e/src/viewlet.explorer-mouse-navigation.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-mouse-navigation' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a/b`) - await FileSystem.writeFile(`${tmpDir}/a/b/c.txt`, 'ccccc') - await FileSystem.mkdir(`${tmpDir}/folder-1`) - await FileSystem.mkdir(`${tmpDir}/folder-2`) - await FileSystem.mkdir(`${tmpDir}/folder-3`) - await FileSystem.writeFile(`${tmpDir}/test.txt`, 'div') - await Workspace.setPath(tmpDir) - - // act - await Explorer.handleClick(-1) - - // assert - // const explorer = Locator('.Explorer') - // await expect(explorer).toHaveClass('FocusOutline') - - // act - await Explorer.handleClick(0) - - // assert - const titleA = '/a' - const treeItemA = Locator(`.TreeItem[title$="${titleA}"]`) - await expect(treeItemA).toHaveId('TreeItemActive') - - // assert - const titleB = '/a/b' - const treeItemB = Locator(`.TreeItem[title$="${titleB}"]`) - await expect(treeItemB).toBeVisible() - await expect(treeItemA).toHaveId('TreeItemActive') - - // act - await Explorer.handleClick(1) - - // assert - await expect(treeItemB).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-new-file-called-twice.ts b/packages/e2e/src/viewlet.explorer-new-file-called-twice.ts deleted file mode 100644 index 5454fac..0000000 --- a/packages/e2e/src/viewlet.explorer-new-file-called-twice.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-new-file-called-twice' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.newFile() - await Explorer.newFile() - - // assert - const treeItems = Locator('.TreeItem') - await expect(treeItems).toHaveCount(4) -} diff --git a/packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts b/packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts deleted file mode 100644 index f359385..0000000 --- a/packages/e2e/src/viewlet.explorer-open-folder-enoent-error.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-open-folder-enoent-error' - -export const skip = 1 - -export const test: Test = async ({ Command, expect, FileSystem, Locator, SideBar, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - const missingFolder = `${tmpDir}/missing-folder` - await Workspace.setPath(missingFolder) - await SideBar.hide() - - // act - await Command.execute('Layout.showSideBar') - - // assert - const error = Locator('.Explorer .WelcomeMessage') - await expect(error).toBeVisible() - await expect(error).toHaveText(`Could not open "${missingFolder}" because the folder does not exist. It may have been moved or deleted.`) - - const openAnotherFolderButton = Locator('.Explorer .Button') - await expect(openAnotherFolderButton).toBeVisible() - await expect(openAnotherFolderButton).toHaveText('Open another folder') -} diff --git a/packages/e2e/src/viewlet.explorer-read-folder-error.ts b/packages/e2e/src/viewlet.explorer-read-folder-error.ts deleted file mode 100644 index 3f89e6f..0000000 --- a/packages/e2e/src/viewlet.explorer-read-folder-error.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-read-folder-error' - -export const test: Test = async ({ expect, Extension, FileSystem, Layout, Locator, SideBar, Workspace }) => { - // arrange - const uri = import.meta.resolve('../fixtures/sample-file-system-provider-read-folder-error') - await Extension.addWebExtension(uri) - const prefix = 'extension-host://xyz://' - await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${prefix}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${prefix}/file3.txt`, 'content 3') - await Workspace.setPath(`${prefix}/`) - await SideBar.hide() - - // act - await Layout.showSideBar() - - // assert - const error = Locator('.Explorer .WelcomeMessage') - await expect(error).toBeVisible() - await expect(error).toHaveText(`Could not open folder due to Failed to execute file system provider: FileNotFoundError: File not found.`) -} diff --git a/packages/e2e/src/viewlet.explorer-refresh.ts b/packages/e2e/src/viewlet.explorer-refresh.ts deleted file mode 100644 index d2e1792..0000000 --- a/packages/e2e/src/viewlet.explorer-refresh.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-refresh' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - // act - await Workspace.setPath(tmpDir) - - // assert - const file1 = Locator('.TreeItem[aria-label="file1.txt"]') - await expect(file1).toBeVisible() - - // act - await FileSystem.remove(`${tmpDir}/file1.txt`) - await Explorer.refresh() - - // assert - await expect(file1).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-150-times.ts b/packages/e2e/src/viewlet.explorer-rename-file-150-times.ts deleted file mode 100644 index 92e76bd..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-150-times.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file-150-times' - -const renameCount = 150 - -const getFileName = (index: number): string => { - return `file-${index.toString().padStart(3, '0')}.txt` -} - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/${getFileName(0)}`, 'content') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(0) - - const explorer = Locator('.Explorer') - const inputBox = explorer.locator('input') - - let currentFileName = getFileName(0) - - // act - for (let i = 1; i <= renameCount; i++) { - await Explorer.renameDirent() - await expect(inputBox).toHaveValue(currentFileName) - - const nextFileName = getFileName(i) - await Explorer.updateEditingValue(nextFileName) - await Explorer.acceptEdit() - - const renamedFile = Locator('.TreeItem', { hasText: nextFileName }) - await expect(renamedFile).toBeVisible() - await expect(renamedFile).toHaveId('TreeItemActive') - - currentFileName = nextFileName - } - - // assert - const finalFile = Locator('.TreeItem', { hasText: getFileName(renameCount) }) - const originalFile = Locator('.TreeItem', { hasText: getFileName(0) }) - await expect(inputBox).toBeHidden() - await expect(finalFile).toBeVisible() - await expect(finalFile).toHaveId('TreeItemActive') - await expect(originalFile).toBeHidden() -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts b/packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts deleted file mode 100644 index 1900dc6..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-cancel-150-times.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file-cancel-150-times' - -const iterations = 150 - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - const explorer = Locator('.Explorer') - const inputBox = explorer.locator('input') - - // act - for (let index = 0; index < iterations; index++) { - await Explorer.focusIndex(1) - await Explorer.renameDirent() - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - await Explorer.cancelEdit() - await expect(inputBox).toBeHidden() - } - - // assert - const file2 = Locator('.TreeItem', { hasText: 'file2.txt' }) - await expect(file2).toBeVisible() - await expect(file2).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-cancel.ts b/packages/e2e/src/viewlet.explorer-rename-file-cancel.ts deleted file mode 100644 index 6c85602..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-cancel.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file-cancel' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(1) - await Explorer.renameDirent() - - // assert - const explorer = Locator('.Explorer') - const inputBox = explorer.locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.cancelEdit() - - // assert - await expect(inputBox).toBeHidden() - - const file2 = Locator('.TreeItem', { hasText: 'file2.txt' }) - await expect(file2).toBeVisible() - - // TODO - // await expect(explorer).toBeFocused() - await expect(file2).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts b/packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts deleted file mode 100644 index 4407ab7..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-error-no-name-provided.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-create-file-error-no-name-provided' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(1) - await Explorer.renameDirent() - - // assert - const explorer = Locator('.Explorer') - const inputBox = explorer.locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('') - - // assert - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('A file or folder name must be provided.') -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts b/packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts deleted file mode 100644 index 266b5f3..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-error-permission-denied.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file-error-permission-denied' - -export const test: Test = async ({ expect, Explorer, Extension, FileSystem, Locator, Workspace }) => { - // arrange - const uri = import.meta.resolve('../fixtures/sample.file-system-provider-permission') - await Extension.addWebExtension(uri) - - const prefix = 'extension-host://xyz://' - await FileSystem.writeFile(`${prefix}/file1.txt`, 'content 1') - await Workspace.setPath(`${prefix}/`) - await Explorer.focusIndex(0) - - // act - await Explorer.rename() - await Explorer.updateEditingValue('file4.txt') - await Explorer.acceptEdit() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - await expect(inputBox).toHaveClass('InputValidationError') - const errorMessage = Locator('.ExplorerErrorMessage') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('Error: Failed to execute file system provider: Permission Denied') -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts b/packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts deleted file mode 100644 index 8a75a2c..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-special-characters.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file-special-characters' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/original1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/original2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/original3.txt`, 'content 3') - await FileSystem.writeFile(`${tmpDir}/original4.txt`, 'content 4') - await FileSystem.writeFile(`${tmpDir}/original5.txt`, 'content 5') - - await Workspace.setPath(tmpDir) - - // Test 1: Rename file to include brackets and parentheses - const explorer1 = Locator('.Explorer') - await Explorer.focusIndex(0) - await Explorer.renameDirent() - const inputBox1 = explorer1.locator('input') - await expect(inputBox1).toBeVisible() - await expect(inputBox1).toBeFocused() - await Explorer.updateEditingValue('renamed[1](test).txt') - await Explorer.acceptEdit() - const renamedFile1 = Locator('text=renamed[1](test).txt') - await expect(renamedFile1).toBeVisible() - - // Test 2: Rename file to include special symbols - const explorer2 = Locator('.Explorer') - await Explorer.focusIndex(0) - await Explorer.renameDirent() - const inputBox2 = explorer2.locator('input') - await expect(inputBox2).toBeVisible() - await expect(inputBox2).toBeFocused() - await Explorer.updateEditingValue('special@#$%&.txt') - await Explorer.acceptEdit() - const renamedFile2 = Locator('text=special@#$%&.txt') - await expect(renamedFile2).toBeVisible() - - // Test 3: Rename file to include Unicode characters - const explorer3 = Locator('.Explorer') - await Explorer.focusIndex(0) - await Explorer.renameDirent() - const inputBox3 = explorer3.locator('input') - await expect(inputBox3).toBeVisible() - await expect(inputBox3).toBeFocused() - await Explorer.updateEditingValue('файл.txt') - await Explorer.acceptEdit() - const renamedFile3 = Locator('text=файл.txt') - await expect(renamedFile3).toBeVisible() - - // Test 4: Rename file to include emoji - const explorer4 = Locator('.Explorer') - await Explorer.focusIndex(0) - await Explorer.renameDirent() - const inputBox4 = explorer4.locator('input') - await expect(inputBox4).toBeVisible() - await expect(inputBox4).toBeFocused() - await Explorer.updateEditingValue('🎉 celebration.txt') - await Explorer.acceptEdit() - const renamedFile4 = Locator('text=🎉 celebration.txt') - await expect(renamedFile4).toBeVisible() - - // Test 5: Rename file to include mixed characters - const explorer5 = Locator('.Explorer') - await Explorer.focusIndex(0) - await Explorer.renameDirent() - const inputBox5 = explorer5.locator('input') - await expect(inputBox5).toBeVisible() - await expect(inputBox5).toBeFocused() - await Explorer.updateEditingValue('mixéd-🌟-file@123.txt') - await Explorer.acceptEdit() - const renamedFile5 = Locator('text=mixéd-🌟-file@123.txt') - await expect(renamedFile5).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-twice.ts b/packages/e2e/src/viewlet.explorer-rename-file-twice.ts deleted file mode 100644 index d8504d9..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-twice.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file-twice' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(2) - - // act - await Explorer.renameDirent() - await Explorer.updateEditingValue('file4.txt') - await Explorer.acceptEdit() - await Explorer.renameDirent() - await Explorer.updateEditingValue('file3.txt') - await Explorer.acceptEdit() - - // assert - const file4 = Locator('.TreeItem', { hasText: 'file4.txt' }) - await expect(file4).toBeHidden() - const file3 = Locator('.TreeItem', { hasText: 'file3.txt' }) - await expect(file3).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts b/packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts deleted file mode 100644 index 6c5da0c..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file-whitespace.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file-whitespace' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/ `, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(0) - await Explorer.renameDirent() - - // assert - const explorer = Locator('.Explorer') - const inputBox = explorer.locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('file1.txt') - await Explorer.acceptEdit() - - // // assert - await expect(inputBox).toBeHidden() - const file1 = Locator('.TreeItem', { hasText: 'file1.txt' }) - await expect(file1).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-rename-file.ts b/packages/e2e/src/viewlet.explorer-rename-file.ts deleted file mode 100644 index a18d9b2..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-file.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-file' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(1) - await Explorer.renameDirent() - - // assert - const explorer = Locator('.Explorer') - const inputBox = explorer.locator('input') - await expect(inputBox).toHaveValue('file2.txt') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('file4.txt') - await Explorer.acceptEdit() - - // assert - await expect(inputBox).toBeHidden() - - const file4 = Locator('.TreeItem', { hasText: 'file4.txt' }) - await expect(file4).toBeVisible() - const listItems = explorer.locator('.ListItems') - await expect(listItems).toBeFocused() - await expect(file4).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-rename-folder-nested.ts b/packages/e2e/src/viewlet.explorer-rename-folder-nested.ts deleted file mode 100644 index 9852546..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-folder-nested.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-folder-nested' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/a`) - await FileSystem.mkdir(`${tmpDir}/a/b`) - await FileSystem.mkdir(`${tmpDir}/a/b/c`) - await FileSystem.writeFile(`${tmpDir}/file1.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.expandRecursively() - - // act - await Explorer.focusIndex(1) - await Explorer.renameDirent() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(inputBox).toBeFocused() - - // act - await Explorer.updateEditingValue('d') - await Explorer.acceptEdit() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveText('a') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveText('d') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).toHaveText('c') - const file4 = Locator('.TreeItem').nth(3) - await expect(file4).toHaveText('file1.txt') - - // TODO folder d should be expanded -} diff --git a/packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts b/packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts deleted file mode 100644 index 89fed86..0000000 --- a/packages/e2e/src/viewlet.explorer-rename-root-folder-no-indent-shift.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-rename-root-folder-no-indent-shift' - -export const test: Test = async ({ expect, Explorer, Extension, FileSystem, IconTheme, Locator, Settings, Workspace }) => { - // arrange - await Settings.update({ - 'explorer.useChevrons': true, - }) - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/folder-a`) - await FileSystem.writeFile(`${tmpDir}/file.txt`, '') - await Workspace.setPath(tmpDir) - const extensionUri = import.meta.resolve('../fixtures/sample.icon-theme') - await Extension.addWebExtension(extensionUri) - await IconTheme.setIconTheme('test-icon-theme') - - const folder = Locator('.TreeItem').nth(0) - await expect(folder).toHaveText('folder-a') - - // act - await Explorer.focusIndex(0) - - // assert - await expect(folder).toHaveJSProperty('className', 'TreeItem Indent-12 TreeItemActive') - - // act - await Explorer.renameDirent() - - // assert - const inputBox = Locator('input') - await expect(inputBox).toBeVisible() - await expect(folder).toHaveJSProperty('className', 'TreeItem Indent-12 TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts b/packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts deleted file mode 100644 index 95b0dc6..0000000 --- a/packages/e2e/src/viewlet.explorer-reveal-from-tab-context-menu.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-reveal-from-tab-context-menu' - -export const skip = 1 - -export const test: Test = async ({ Command, ContextMenu, expect, Explorer, FileSystem, Locator, Main, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - const firstFile = `${tmpDir}/a.txt` - const secondFile = `${tmpDir}/b.txt` - await FileSystem.writeFile(firstFile, 'content 1') - await FileSystem.writeFile(secondFile, 'content 2') - await Workspace.setPath(tmpDir) - - const firstTreeItem = Locator('.TreeItem[aria-label="a.txt"]') - const secondTreeItem = Locator('.TreeItem[aria-label="b.txt"]') - await expect(firstTreeItem).toBeVisible() - await expect(secondTreeItem).toBeVisible() - - await Explorer.focusIndex(0) - await expect(firstTreeItem).toHaveId('TreeItemActive') - - await Main.openUri(secondFile) - const tab = Locator('.MainTab[title$="b.txt"]') - await expect(tab).toBeVisible() - - // act - await Command.execute('Main.handleTabContextMenu', 0, 0, 0) - const closeMenuItem = Locator('text=Close').first() - await expect(closeMenuItem).toBeVisible() - await ContextMenu.selectItem('Reveal in Explorer') - - // assert - await expect(secondTreeItem).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts b/packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts deleted file mode 100644 index 5477383..0000000 --- a/packages/e2e/src/viewlet.explorer-reveal-non-existent-uri.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-reveal-non-existent-uri' - -export const skip = 1 - -export const test: Test = async ({ Command, expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await Workspace.setPath(tmpDir) - - await Explorer.newFile() - await Explorer.updateEditingValue('first.txt') - await Explorer.acceptEdit() - - await Explorer.newFile() - await Explorer.updateEditingValue('second.txt') - await Explorer.acceptEdit() - - const explorer = Locator('.Explorer') - const firstFile = Locator('.TreeItem[aria-label="first.txt"]') - const secondFile = Locator('.TreeItem[aria-label="second.txt"]') - await expect(explorer).toBeVisible() - await expect(firstFile).toBeVisible() - await expect(secondFile).toBeVisible() - - // act - await Command.execute('Explorer.reveal', 'non-existent:///some-file.txt') - - // assert - await expect(explorer).toBeVisible() - await expect(firstFile).toBeVisible() - await expect(secondFile).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer-scroll.ts b/packages/e2e/src/viewlet.explorer-scroll.ts deleted file mode 100644 index e6be04a..0000000 --- a/packages/e2e/src/viewlet.explorer-scroll.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-scroll' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - for (let i = 0; i < 100; i++) { - const fileName = `file-${i.toString().padStart(2, '0')}.txt` - await FileSystem.writeFile(`${tmpDir}/${fileName}`, '') - } - await Workspace.setPath(tmpDir) - const file00 = Locator('.TreeItem', { hasText: 'file-00.txt' }) - const file50 = Locator('.TreeItem', { hasText: 'file-50.txt' }) - const file99 = Locator('.TreeItem', { hasText: 'file-99.txt' }) - - // act - await Explorer.focusFirst() - - // assert - await expect(file00).toBeVisible() - await expect(file00).toHaveId('TreeItemActive') - - // act - await Explorer.focusIndex(50) - - // assert - await expect(file50).toBeVisible() - await expect(file50).toHaveId('TreeItemActive') - - // act - await Explorer.focusIndex(99) - - // assert - await expect(file99).toBeVisible() - await expect(file99).toHaveId('TreeItemActive') - - // act - await Explorer.focusFirst() - - // assert - await expect(file00).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts b/packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts deleted file mode 100644 index 98499d4..0000000 --- a/packages/e2e/src/viewlet.explorer-select-all-then-delete-files.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-select-all-then-delete-files' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - for (let index = 0; index < 10; index++) { - await FileSystem.writeFile(`${tmpDir}/file-${index}.txt`, `content ${index}`) - } - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(9) - - // act - await Explorer.selectAll() - await Explorer.removeDirent() - - // assert - const treeItems = Locator('.TreeItem') - await expect(treeItems).toHaveCount(0) -} diff --git a/packages/e2e/src/viewlet.explorer-select-all.ts b/packages/e2e/src/viewlet.explorer-select-all.ts deleted file mode 100644 index 9d098c5..0000000 --- a/packages/e2e/src/viewlet.explorer-select-all.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-select-all' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(2) - - // act - await Explorer.selectAll() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveClass('TreeItemActive') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveClass('TreeItemActive') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).not.toHaveClass('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-select-down.ts b/packages/e2e/src/viewlet.explorer-select-down.ts deleted file mode 100644 index 6847c36..0000000 --- a/packages/e2e/src/viewlet.explorer-select-down.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-select-down' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(1) - - // act - await Explorer.selectDown() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveClass('TreeItem') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveClass('TreeItemActive') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).not.toHaveClass('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts b/packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts deleted file mode 100644 index 6744bfb..0000000 --- a/packages/e2e/src/viewlet.explorer-select-multiple-files-individually.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-select-multiple-files-individually' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(2) - - // act - await Explorer.toggleIndividualSelection(1) - await Explorer.toggleIndividualSelection(2) - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveClass('TreeItem') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveClass('TreeItemActive') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).not.toHaveClass('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts b/packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts deleted file mode 100644 index 6460084..0000000 --- a/packages/e2e/src/viewlet.explorer-select-multiple-files-with-mouse.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-select-multiple-files-with-mouse' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - await Explorer.focusIndex(2) - - // act - await Explorer.handleClickAt(false, 0, false, true, 300, 0) - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveClass('TreeItemActive') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveClass('TreeItem') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).not.toHaveClass('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-select-multiple-files.ts b/packages/e2e/src/viewlet.explorer-select-multiple-files.ts deleted file mode 100644 index ecf68d1..0000000 --- a/packages/e2e/src/viewlet.explorer-select-multiple-files.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-select-multiple-files' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.selectIndices([0, 1]) - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveClass('TreeItemActive') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveClass('TreeItemActive') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).not.toHaveClass('TreeItem') -} diff --git a/packages/e2e/src/viewlet.explorer-select-up.ts b/packages/e2e/src/viewlet.explorer-select-up.ts deleted file mode 100644 index 80f68b2..0000000 --- a/packages/e2e/src/viewlet.explorer-select-up.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-select-up' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/file1.txt`, 'content 1') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, 'content 2') - await FileSystem.writeFile(`${tmpDir}/file3.txt`, 'content 3') - await Workspace.setPath(tmpDir) - - // act - await Explorer.focusIndex(1) - await Explorer.selectUp() - - // assert - const file1 = Locator('.TreeItem').nth(0) - await expect(file1).toHaveClass('TreeItemActive') - const file2 = Locator('.TreeItem').nth(1) - await expect(file2).toHaveClass('TreeItemActive') - const file3 = Locator('.TreeItem').nth(2) - await expect(file3).not.toHaveClass('TreeItem') -} diff --git a/packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts b/packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts deleted file mode 100644 index dfbbff5..0000000 --- a/packages/e2e/src/viewlet.explorer-set-delta-y-invalid-value.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-set-delta-y-invalid-value' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - for (let i = 0; i < 30; i++) { - const fileName = `file-${i.toString().padStart(2, '0')}.txt` - await FileSystem.writeFile(`${tmpDir}/${fileName}`, '') - } - await Workspace.setPath(tmpDir) - const file00 = Locator('.TreeItem', { hasText: 'file-00.txt' }) - - // act - await Explorer.setDeltaY('invalid' as any) - - // assert - await expect(file00).toBeVisible() - - await Explorer.focusIndex(29) - - // assert - const file29 = Locator('.TreeItem', { hasText: 'file-29.txt' }) - await expect(file29).toBeVisible() - await expect(file29).toHaveId('TreeItemActive') -} diff --git a/packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts b/packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts deleted file mode 100644 index 33e3998..0000000 --- a/packages/e2e/src/viewlet.explorer-sort-numeric-file-names.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-sort-numeric-file-names' - -export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.mkdir(`${tmpDir}/file-1.txt`) - await FileSystem.mkdir(`${tmpDir}/file-10.txt`) - await FileSystem.mkdir(`${tmpDir}/file-2.txt`) - - // act - await Workspace.setPath(tmpDir) - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - const secondTreeItem = treeItems.nth(1) - const thirdTreeItem = treeItems.nth(2) - await expect(treeItems).toHaveCount(3) - await expect(firstTreeItem).toHaveText('file-1.txt') - await expect(secondTreeItem).toHaveText('file-2.txt') - await expect(thirdTreeItem).toHaveText('file-10.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-sorting-emojis.ts b/packages/e2e/src/viewlet.explorer-sorting-emojis.ts deleted file mode 100644 index 763cd1f..0000000 --- a/packages/e2e/src/viewlet.explorer-sorting-emojis.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-sorting-emojis' - -export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/🚀 rocket.txt`, '') - await FileSystem.writeFile(`${tmpDir}/🌟 star.txt`, '') - await FileSystem.writeFile(`${tmpDir}/💎 diamond.txt`, '') - await FileSystem.writeFile(`${tmpDir}/🔥 fire.txt`, '') - await FileSystem.writeFile(`${tmpDir}/⚡ lightning.txt`, '') - await FileSystem.writeFile(`${tmpDir}/🌈 rainbow.txt`, '') - await FileSystem.writeFile(`${tmpDir}/🎯 target.txt`, '') - await FileSystem.writeFile(`${tmpDir}/💡 idea.txt`, '') - await FileSystem.writeFile(`${tmpDir}/🚀🚀 double-rocket.txt`, '') - await FileSystem.writeFile(`${tmpDir}/a-normal-file.txt`, '') - - // act - await Workspace.setPath(tmpDir) - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - const secondTreeItem = treeItems.nth(1) - const thirdTreeItem = treeItems.nth(2) - const fourthTreeItem = treeItems.nth(3) - const fifthTreeItem = treeItems.nth(4) - const sixthTreeItem = treeItems.nth(5) - const seventhTreeItem = treeItems.nth(6) - const eighthTreeItem = treeItems.nth(7) - const ninthTreeItem = treeItems.nth(8) - const tenthTreeItem = treeItems.nth(9) - await expect(treeItems).toHaveCount(10) - await expect(firstTreeItem).toHaveText('⚡ lightning.txt') - await expect(secondTreeItem).toHaveText('🌈 rainbow.txt') - await expect(thirdTreeItem).toHaveText('🌟 star.txt') - await expect(fourthTreeItem).toHaveText('🎯 target.txt') - await expect(fifthTreeItem).toHaveText('💎 diamond.txt') - await expect(sixthTreeItem).toHaveText('💡 idea.txt') - await expect(seventhTreeItem).toHaveText('🔥 fire.txt') - await expect(eighthTreeItem).toHaveText('🚀 rocket.txt') - await expect(ninthTreeItem).toHaveText('🚀🚀 double-rocket.txt') - await expect(tenthTreeItem).toHaveText('a-normal-file.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts b/packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts deleted file mode 100644 index f553502..0000000 --- a/packages/e2e/src/viewlet.explorer-sorting-mixed-alphanumeric-special.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-sorting-mixed-alphanumeric-special' - -export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/1file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/a-file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/b_file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/file1.txt`, '') - await FileSystem.writeFile(`${tmpDir}/file2.txt`, '') - await FileSystem.writeFile(`${tmpDir}/file@10.txt`, '') - await FileSystem.writeFile(`${tmpDir}/file#2.txt`, '') - await FileSystem.writeFile(`${tmpDir}/file$3.txt`, '') - await FileSystem.writeFile(`${tmpDir}/z-file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/10file.txt`, '') - - // act - await Workspace.setPath(tmpDir) - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - const secondTreeItem = treeItems.nth(1) - const thirdTreeItem = treeItems.nth(2) - const fourthTreeItem = treeItems.nth(3) - const fifthTreeItem = treeItems.nth(4) - const sixthTreeItem = treeItems.nth(5) - const seventhTreeItem = treeItems.nth(6) - const eighthTreeItem = treeItems.nth(7) - const ninthTreeItem = treeItems.nth(8) - const tenthTreeItem = treeItems.nth(9) - await expect(treeItems).toHaveCount(10) - await expect(firstTreeItem).toHaveText('1file.txt') - await expect(secondTreeItem).toHaveText('10file.txt') - await expect(thirdTreeItem).toHaveText('a-file.txt') - await expect(fourthTreeItem).toHaveText('b_file.txt') - await expect(fifthTreeItem).toHaveText('file@10.txt') - await expect(sixthTreeItem).toHaveText('file#2.txt') - await expect(seventhTreeItem).toHaveText('file$3.txt') - await expect(eighthTreeItem).toHaveText('file1.txt') - await expect(ninthTreeItem).toHaveText('file2.txt') - await expect(tenthTreeItem).toHaveText('z-file.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-sorting-special-characters.ts b/packages/e2e/src/viewlet.explorer-sorting-special-characters.ts deleted file mode 100644 index b8a25c2..0000000 --- a/packages/e2e/src/viewlet.explorer-sorting-special-characters.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-sorting-special-characters' - -export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/-file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/!file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/(file).txt`, '') - await FileSystem.writeFile(`${tmpDir}/[file].txt`, '') - await FileSystem.writeFile(`${tmpDir}/{file}.txt`, '') - await FileSystem.writeFile(`${tmpDir}/@file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/&file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/#file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/+file.txt`, '') - await FileSystem.writeFile(`${tmpDir}/$file.txt`, '') - - // act - await Workspace.setPath(tmpDir) - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - const secondTreeItem = treeItems.nth(1) - const thirdTreeItem = treeItems.nth(2) - const fourthTreeItem = treeItems.nth(3) - const fifthTreeItem = treeItems.nth(4) - const sixthTreeItem = treeItems.nth(5) - const seventhTreeItem = treeItems.nth(6) - const eighthTreeItem = treeItems.nth(7) - const ninthTreeItem = treeItems.nth(8) - const tenthTreeItem = treeItems.nth(9) - await expect(treeItems).toHaveCount(10) - await expect(firstTreeItem).toHaveText('-file.txt') - await expect(secondTreeItem).toHaveText('!file.txt') - await expect(thirdTreeItem).toHaveText('(file).txt') - await expect(fourthTreeItem).toHaveText('[file].txt') - await expect(fifthTreeItem).toHaveText('{file}.txt') - await expect(sixthTreeItem).toHaveText('@file.txt') - await expect(seventhTreeItem).toHaveText('&file.txt') - await expect(eighthTreeItem).toHaveText('#file.txt') - await expect(ninthTreeItem).toHaveText('+file.txt') - await expect(tenthTreeItem).toHaveText('$file.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts b/packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts deleted file mode 100644 index 6af6920..0000000 --- a/packages/e2e/src/viewlet.explorer-sorting-unicode-characters.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-sorting-unicode-characters' - -export const test: Test = async ({ expect, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/café.txt`, '') - await FileSystem.writeFile(`${tmpDir}/naïve.txt`, '') - await FileSystem.writeFile(`${tmpDir}/résumé.txt`, '') - await FileSystem.writeFile(`${tmpDir}/piñata.txt`, '') - await FileSystem.writeFile(`${tmpDir}/jalapeño.txt`, '') - await FileSystem.writeFile(`${tmpDir}/façade.txt`, '') - await FileSystem.writeFile(`${tmpDir}/séance.txt`, '') - await FileSystem.writeFile(`${tmpDir}/déjà.txt`, '') - await FileSystem.writeFile(`${tmpDir}/château.txt`, '') - await FileSystem.writeFile(`${tmpDir}/soirée.txt`, '') - - // act - await Workspace.setPath(tmpDir) - - // assert - const treeItems = Locator('.TreeItem') - const firstTreeItem = treeItems.nth(0) - const secondTreeItem = treeItems.nth(1) - const thirdTreeItem = treeItems.nth(2) - const fourthTreeItem = treeItems.nth(3) - const fifthTreeItem = treeItems.nth(4) - const sixthTreeItem = treeItems.nth(5) - const seventhTreeItem = treeItems.nth(6) - const eighthTreeItem = treeItems.nth(7) - const ninthTreeItem = treeItems.nth(8) - const tenthTreeItem = treeItems.nth(9) - await expect(treeItems).toHaveCount(10) - await expect(firstTreeItem).toHaveText('café.txt') - await expect(secondTreeItem).toHaveText('château.txt') - await expect(thirdTreeItem).toHaveText('déjà.txt') - await expect(fourthTreeItem).toHaveText('façade.txt') - await expect(fifthTreeItem).toHaveText('jalapeño.txt') - await expect(sixthTreeItem).toHaveText('naïve.txt') - await expect(seventhTreeItem).toHaveText('piñata.txt') - await expect(eighthTreeItem).toHaveText('résumé.txt') - await expect(ninthTreeItem).toHaveText('séance.txt') - await expect(tenthTreeItem).toHaveText('soirée.txt') -} diff --git a/packages/e2e/src/viewlet.explorer-sorting.ts b/packages/e2e/src/viewlet.explorer-sorting.ts deleted file mode 100644 index 361251e..0000000 --- a/packages/e2e/src/viewlet.explorer-sorting.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'viewlet.explorer-sorting' - -export const test: Test = async ({ expect, Explorer, FileSystem, Locator, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/1.txt`, '') - await FileSystem.writeFile(`${tmpDir}/2.txt`, '') - await FileSystem.writeFile(`${tmpDir}/3.txt`, '') - await FileSystem.writeFile(`${tmpDir}/4.txt`, '') - await FileSystem.writeFile(`${tmpDir}/5.txt`, '') - await FileSystem.writeFile(`${tmpDir}/6.txt`, '') - await FileSystem.writeFile(`${tmpDir}/7.txt`, '') - await FileSystem.writeFile(`${tmpDir}/8.txt`, '') - await FileSystem.writeFile(`${tmpDir}/9.txt`, '') - await FileSystem.writeFile(`${tmpDir}/10.txt`, '') - await Workspace.setPath(tmpDir) - await Explorer.focusFirst() - - // assert - const items = Locator('.TreeItem') - await expect(items).toHaveCount(10) - const itemOne = items.nth(0) - const itemTwo = items.nth(1) - const itemThree = items.nth(2) - const itemFour = items.nth(3) - const itemFive = items.nth(4) - const itemSix = items.nth(5) - const itemSeven = items.nth(6) - const itemEight = items.nth(7) - const itemNine = items.nth(8) - const itemTen = items.nth(9) - await expect(itemOne).toHaveText('1.txt') - await expect(itemTwo).toHaveText('2.txt') - await expect(itemThree).toHaveText('3.txt') - await expect(itemFour).toHaveText('4.txt') - await expect(itemFive).toHaveText('5.txt') - await expect(itemSix).toHaveText('6.txt') - await expect(itemSeven).toHaveText('7.txt') - await expect(itemEight).toHaveText('8.txt') - await expect(itemNine).toHaveText('9.txt') - await expect(itemTen).toHaveText('10.txt') -} diff --git a/packages/e2e/src/viewlet.explorer.empty.ts b/packages/e2e/src/viewlet.explorer.empty.ts deleted file mode 100644 index 274258b..0000000 --- a/packages/e2e/src/viewlet.explorer.empty.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'explorer.empty' - -export const test: Test = async ({ expect, FileSystem, Locator, SideBar, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await Workspace.setPath(tmpDir) - - // act - await SideBar.open('Explorer') - - // assert - const explorer = Locator('.Explorer') - await expect(explorer).toBeVisible() -} diff --git a/packages/e2e/src/viewlet.explorer.open.ts b/packages/e2e/src/viewlet.explorer.open.ts deleted file mode 100644 index c285f0c..0000000 --- a/packages/e2e/src/viewlet.explorer.open.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Test } from '@lvce-editor/test-with-playwright' - -export const name = 'explorer.open' - -export const test: Test = async ({ expect, FileSystem, Locator, SideBar, Workspace }) => { - // arrange - const tmpDir = await FileSystem.getTmpDir() - await FileSystem.writeFile(`${tmpDir}/test.css`, `abc`) - await Workspace.setPath(tmpDir) - - // act - await SideBar.open('Explorer') - - // assert - const explorer = Locator('.Explorer') - await expect(explorer).toBeVisible() - const file = explorer.locator('[aria-label="test.css"]') - await expect(file).toBeVisible() -} diff --git a/packages/server/package.json b/packages/server/package.json index bdf7068..f71c74e 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,11 +1,8 @@ { - "name": "@lvce-editor/explorer-view-server", + "name": "@lvce-editor/pull-request-github-server", "version": "0.0.0-dev", "main": "index.js", "type": "module", - "scripts": { - "dev": "node ./node_modules/@lvce-editor/server/bin/server.js --test-path=../e2e" - }, "keywords": [], "author": "", "license": "MIT", diff --git a/packages/server/package.json.lerna_backup b/packages/server/package.json.lerna_backup new file mode 100644 index 0000000..bdf7068 --- /dev/null +++ b/packages/server/package.json.lerna_backup @@ -0,0 +1,15 @@ +{ + "name": "@lvce-editor/explorer-view-server", + "version": "0.0.0-dev", + "main": "index.js", + "type": "module", + "scripts": { + "dev": "node ./node_modules/@lvce-editor/server/bin/server.js --test-path=../e2e" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@lvce-editor/server": "0.83.1" + } +} From 89a9795ee5785b79f417bf19fa411877f777f858 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:35:47 +0200 Subject: [PATCH 10/17] update --- packages/e2e/package-lock.json | 24 +- packages/e2e/package.json | 2 +- packages/explorer-view/package-lock.json | 40 +- packages/explorer-view/package.json | 4 +- packages/server/package-lock.json | 492 +++++++++------------- packages/server/package.json | 7 +- packages/server/package.json.lerna_backup | 15 - 7 files changed, 246 insertions(+), 338 deletions(-) delete mode 100644 packages/server/package.json.lerna_backup diff --git a/packages/e2e/package-lock.json b/packages/e2e/package-lock.json index 8031a18..2c6d2c8 100644 --- a/packages/e2e/package-lock.json +++ b/packages/e2e/package-lock.json @@ -9,18 +9,18 @@ "version": "0.0.0-dev", "license": "MIT", "devDependencies": { - "@lvce-editor/test-with-playwright": "^18.0.0" + "@lvce-editor/test-with-playwright": "^19.0.0" } }, "node_modules/@lvce-editor/test-with-playwright": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/test-with-playwright/-/test-with-playwright-18.0.0.tgz", - "integrity": "sha512-mgoFHKo4mkP08jFPQOcMjPignQOJw3pEhP+NghWOuDL4BLQ9b7W2pRIBb8D8Jqs+8eXfjjUaguts7dLava515g==", + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/test-with-playwright/-/test-with-playwright-19.0.0.tgz", + "integrity": "sha512-6X8qcNYjWhjefnao4QGAqNG2z85vUEqOukjstJoh0i9cQqSB4TapknCCMkQAFd+g7Ckvmz6cfQm61l+qub02xA==", "dev": true, "license": "MIT", "dependencies": { - "@lvce-editor/test-with-playwright-worker": "18.0.0", - "@lvce-editor/test-worker": "^16.0.0" + "@lvce-editor/test-with-playwright-worker": "19.0.0", + "@lvce-editor/test-worker": "^16.2.0" }, "bin": { "test-with-playwright": "bin/test-with-playwright.js" @@ -30,9 +30,9 @@ } }, "node_modules/@lvce-editor/test-with-playwright-worker": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/test-with-playwright-worker/-/test-with-playwright-worker-18.0.0.tgz", - "integrity": "sha512-pbeX0ipyA1EVUCrIkmotjtjIwNf7p7+ZONxwl49lf3bBRdwo08qc/ji8B0l+WuZ9QX1aRVuO/aCzhmxMnV5G2A==", + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/test-with-playwright-worker/-/test-with-playwright-worker-19.0.0.tgz", + "integrity": "sha512-HDX7TSVhVlp+O0Y9BccbHNuZd+656IwtNbAc43CJl7iapzlTO1en8dGh9W4SJn1VsH5bEzfTOwq8TrOrWuD1Gw==", "dev": true, "license": "MIT", "dependencies": { @@ -43,9 +43,9 @@ } }, "node_modules/@lvce-editor/test-worker": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/test-worker/-/test-worker-16.0.0.tgz", - "integrity": "sha512-iJkbCyXP8Tm1I5zDgkFHwr0kP6l/Vh1dBOqX7lPlC8k6olytvUCuqRE1xHDHcYmoCMQAgmS7ilb17YWenrZM5g==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/test-worker/-/test-worker-16.3.0.tgz", + "integrity": "sha512-yzIUvpFvSpMi5PC/Ig88FJtkaYFgLRI85dmLo2P4202E4MWIrukxMxzX28E1ERehc5cFrIJT/AwXWHQQhu7C4A==", "dev": true, "license": "MIT" }, diff --git a/packages/e2e/package.json b/packages/e2e/package.json index a10961d..f20bac0 100644 --- a/packages/e2e/package.json +++ b/packages/e2e/package.json @@ -10,6 +10,6 @@ "type-check": "tsc" }, "devDependencies": { - "@lvce-editor/test-with-playwright": "^18.0.0" + "@lvce-editor/test-with-playwright": "^19.0.0" } } diff --git a/packages/explorer-view/package-lock.json b/packages/explorer-view/package-lock.json index 233a29f..a444e51 100644 --- a/packages/explorer-view/package-lock.json +++ b/packages/explorer-view/package-lock.json @@ -1,11 +1,11 @@ { - "name": "@lvce-editor/explorer-view", + "name": "@lvce-editor/pull-request-view", "version": "0.0.0-dev", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@lvce-editor/explorer-view", + "name": "@lvce-editor/pull-request-view", "version": "0.0.0-dev", "license": "MIT", "devDependencies": { @@ -15,10 +15,10 @@ "@lvce-editor/i18n": "^2.1.0", "@lvce-editor/list": "^1.7.0", "@lvce-editor/rpc": "^6.4.0", - "@lvce-editor/rpc-registry": "^9.26.0", + "@lvce-editor/rpc-registry": "^9.27.0", "@lvce-editor/verror": "^1.7.0", "@lvce-editor/viewlet-registry": "^4.1.0", - "@lvce-editor/virtual-dom-worker": "^9.13.0", + "@lvce-editor/virtual-dom-worker": "^10.0.0", "jest": "^30.4.2", "ts-jest": "^29.4.11" } @@ -1063,9 +1063,9 @@ } }, "node_modules/@lvce-editor/rpc-registry": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/rpc-registry/-/rpc-registry-9.26.0.tgz", - "integrity": "sha512-l34xcpyv94Z4Op82menHE1Gnb/tlNd7551WCaqMeOTb6X5G/5QLe4DxmIAj/Q6aUt5d0c4TiuIV05vxq6fFv6Q==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/rpc-registry/-/rpc-registry-9.27.0.tgz", + "integrity": "sha512-rMqWoslwQb1H55QTwCgSbFVdc68YqQpK78ZjXmPxs+iQ9RFe+7qVl6mvfyiuFiRNe9avvln42vbt9WhaqWJiug==", "dev": true, "license": "MIT", "dependencies": { @@ -1092,13 +1092,13 @@ } }, "node_modules/@lvce-editor/virtual-dom-worker": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/virtual-dom-worker/-/virtual-dom-worker-9.13.0.tgz", - "integrity": "sha512-U22G4jStIuHidFFeo2gTTJu411OF8hs3fWamTan2GUxH2xjEa7xaVcdioDUEs7nfyi/h2utTbGxhXyuUTA73yw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/virtual-dom-worker/-/virtual-dom-worker-10.0.0.tgz", + "integrity": "sha512-qVUH7rIt/k/iVAZy8pGXK1deX87ILlYf1cTD8zIO7A8WELgTnkwQGE2uAYeZPKrbk1wk1Ud7wM0yAdqsCzDQyA==", "dev": true, "license": "MIT", "dependencies": { - "@lvce-editor/constants": "^5.13.0" + "@lvce-editor/constants": "^5.14.0" } }, "node_modules/@lvce-editor/web-socket-server": { @@ -1840,9 +1840,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.37", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", - "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", + "version": "2.10.38", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", + "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2223,9 +2223,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.372", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", - "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==", + "version": "1.5.375", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz", + "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==", "dev": true, "license": "ISC" }, @@ -3577,9 +3577,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", - "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "version": "2.0.48", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.48.tgz", + "integrity": "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==", "dev": true, "license": "MIT", "engines": { diff --git a/packages/explorer-view/package.json b/packages/explorer-view/package.json index c1b5557..24b976e 100644 --- a/packages/explorer-view/package.json +++ b/packages/explorer-view/package.json @@ -51,10 +51,10 @@ "@lvce-editor/i18n": "^2.1.0", "@lvce-editor/list": "^1.7.0", "@lvce-editor/rpc": "^6.4.0", - "@lvce-editor/rpc-registry": "^9.26.0", + "@lvce-editor/rpc-registry": "^9.27.0", "@lvce-editor/verror": "^1.7.0", "@lvce-editor/viewlet-registry": "^4.1.0", - "@lvce-editor/virtual-dom-worker": "^9.13.0", + "@lvce-editor/virtual-dom-worker": "^10.0.0", "jest": "^30.4.2", "ts-jest": "^29.4.11" } diff --git a/packages/server/package-lock.json b/packages/server/package-lock.json index bb29a73..10e4204 100644 --- a/packages/server/package-lock.json +++ b/packages/server/package-lock.json @@ -7,10 +7,9 @@ "": { "name": "@lvce-editor/explorer-view-server", "version": "0.0.0-dev", - "hasInstallScript": true, "license": "MIT", "dependencies": { - "@lvce-editor/server": "0.83.1" + "@lvce-editor/server": "0.84.0" } }, "node_modules/@babel/code-frame": { @@ -86,9 +85,9 @@ } }, "node_modules/@lvce-editor/extension-host-helper-process": { - "version": "0.83.1", - "resolved": "https://registry.npmjs.org/@lvce-editor/extension-host-helper-process/-/extension-host-helper-process-0.83.1.tgz", - "integrity": "sha512-OaAW43ZeuLuszCQKYTMtPlpAGABS5JIIbCBv+yDrg8WNbj6hYHsLV0d3DyjeGLInK3CqOiHBI2168IgtwlOUnA==", + "version": "0.84.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/extension-host-helper-process/-/extension-host-helper-process-0.84.0.tgz", + "integrity": "sha512-09ty8Cu3fCUZI9ey0l7B8E0ZQbLBw070TT1Ugggf5OIAG6+JWp3SCnxjDfh+IIAS6R57a9uMlmGuMjxjvW2jqQ==", "license": "MIT", "dependencies": { "@lvce-editor/assert": "^1.5.1", @@ -421,20 +420,13 @@ } }, "node_modules/@lvce-editor/ripgrep": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/ripgrep/-/ripgrep-4.1.0.tgz", - "integrity": "sha512-J57lVXxRIbyuz1YwOi/hiUOMF6KDuOvht5OkhxVQOU971uv3j2t5bNdD6flq0hKmWESlr18p6sO0RTj8WMDIEA==", - "hasInstallScript": true, + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/ripgrep/-/ripgrep-5.2.0.tgz", + "integrity": "sha512-5YBhdxdpUq7DCE50Hrj4iCbR8Icdgp21YzNBQV11ir9O1R9LxpP5PPTH/v4cM5V8TDd0xGobryB0LiN0NTdHxg==", "license": "MIT", "optional": true, "dependencies": { - "@lvce-editor/verror": "^1.7.0", - "execa": "^9.6.0", - "extract-zip": "^2.0.1", - "fs-extra": "^11.3.2", - "path-exists": "^5.0.0", - "tempy": "^3.1.0", - "xdg-basedir": "^5.1.0" + "@vscode/ripgrep": "1.18.0" }, "engines": { "node": ">=22" @@ -453,9 +445,9 @@ } }, "node_modules/@lvce-editor/rpc-registry": { - "version": "9.25.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/rpc-registry/-/rpc-registry-9.25.0.tgz", - "integrity": "sha512-GCXNiGhRi6oZIoO/BU3v7pbxfZDyB26RBV3/uuzuZ+F4njhAiMySseH3J7Wj2QhgFzgd0Bj3Ejg7360GooqJVQ==", + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/rpc-registry/-/rpc-registry-9.27.0.tgz", + "integrity": "sha512-rMqWoslwQb1H55QTwCgSbFVdc68YqQpK78ZjXmPxs+iQ9RFe+7qVl6mvfyiuFiRNe9avvln42vbt9WhaqWJiug==", "license": "MIT", "dependencies": { "@lvce-editor/assert": "^1.5.1", @@ -478,15 +470,15 @@ } }, "node_modules/@lvce-editor/search-process": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/search-process/-/search-process-13.1.0.tgz", - "integrity": "sha512-A4W+vb0UPkh8ZpeFf06LKeU7uJDnvI5ZnV0jsxbaPdp6y3icWPxOp6aYYpZierRHKgApuzjlP/eXbgfdKCf7UQ==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/search-process/-/search-process-15.0.0.tgz", + "integrity": "sha512-0TO9PmCefZ5ade5vyMqgkySZ8ojXcbgk9ebFMu2fsjKaEEaeFFl2fwi+ExsAQHEg5/51uJ1aeRcatwtCzq8eTw==", "license": "MIT", "optional": true, "dependencies": { - "@lvce-editor/constants": "^3.7.0", - "execa": "^9.6.0", - "ws": "^8.18.3" + "@lvce-editor/constants": "^5.14.0", + "execa": "^9.6.1", + "ws": "^8.21.0" }, "bin": { "search-process": "bin/searchProcess.js" @@ -495,24 +487,17 @@ "node": ">=24" }, "optionalDependencies": { - "@lvce-editor/ripgrep": "^4.0.0" + "@lvce-editor/ripgrep": "^5.1.0" } }, - "node_modules/@lvce-editor/search-process/node_modules/@lvce-editor/constants": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/constants/-/constants-3.7.0.tgz", - "integrity": "sha512-NTxt0cZlacI63ZryyoMFh1Nw717jyWpTIqnoaK7ssNBDjAWuEmIdNTcJq2ZyAtGkcJReuq1XHzbjAE5o44O0ow==", - "license": "MIT", - "optional": true - }, "node_modules/@lvce-editor/server": { - "version": "0.83.1", - "resolved": "https://registry.npmjs.org/@lvce-editor/server/-/server-0.83.1.tgz", - "integrity": "sha512-wZzSWs1HrpwbbJazVF5FK7vDKp8xynskVNQEOSmSvoqbNUvU+fDlzLcpiHVlhcO9RIpNj/5zrHmA1zrLvRZc0Q==", + "version": "0.84.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/server/-/server-0.84.0.tgz", + "integrity": "sha512-P1P8EfQNmwHwqeQTm2+LbUtX3L+m8wXQpBk14fhkea8rraRLga1hamxjwlo8dGPe7188dBJn+r6u4Ja3FBhGDg==", "license": "MIT", "dependencies": { - "@lvce-editor/shared-process": "0.83.1", - "@lvce-editor/static-server": "0.83.1" + "@lvce-editor/shared-process": "0.84.0", + "@lvce-editor/static-server": "0.84.0" }, "bin": { "server": "bin/server.js" @@ -522,19 +507,19 @@ } }, "node_modules/@lvce-editor/shared-process": { - "version": "0.83.1", - "resolved": "https://registry.npmjs.org/@lvce-editor/shared-process/-/shared-process-0.83.1.tgz", - "integrity": "sha512-XQu/tcdqqrYOpY16Sw0kVohakCs6s7ZC9/iQtMoTFLB3Fi/vcThjSICYwXlEPuuw2GjR5xSzcwZY+5GhLV54jA==", + "version": "0.84.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/shared-process/-/shared-process-0.84.0.tgz", + "integrity": "sha512-yA1dZ5y/eLpfCVUiNpcdJf1w+TZ2NlmeFI/K5+aepCiBNro1u+uDW8TPQM2/fvJSM+9V3/z3DMl5fQ2pe/4RZg==", "license": "MIT", "dependencies": { "@lvce-editor/assert": "1.5.1", "@lvce-editor/auth-process": "1.6.0", - "@lvce-editor/extension-host-helper-process": "0.83.1", + "@lvce-editor/extension-host-helper-process": "0.84.0", "@lvce-editor/ipc": "16.0.0", "@lvce-editor/json-rpc": "8.0.0", "@lvce-editor/jsonc-parser": "1.5.0", "@lvce-editor/pretty-error": "2.0.0", - "@lvce-editor/rpc-registry": "9.25.0", + "@lvce-editor/rpc-registry": "9.27.0", "@lvce-editor/verror": "1.7.0", "is-object": "^1.0.2", "xdg-basedir": "^5.1.0" @@ -550,7 +535,7 @@ "@lvce-editor/preload": "1.5.0", "@lvce-editor/preview-process": "11.0.0", "@lvce-editor/pty-host": "8.1.0", - "@lvce-editor/search-process": "13.1.0", + "@lvce-editor/search-process": "15.0.0", "@lvce-editor/typescript-compile-process": "5.1.0", "open": "^11.0.0", "tail": "^2.2.6", @@ -559,9 +544,9 @@ } }, "node_modules/@lvce-editor/static-server": { - "version": "0.83.1", - "resolved": "https://registry.npmjs.org/@lvce-editor/static-server/-/static-server-0.83.1.tgz", - "integrity": "sha512-MOfwrBIKnQdnl0Q9mgCk6o9BXa1vXGwi5kNxlYhy62yqCnzhQpbkotHeoeLbrlplpDMIZ0mcEy7+5++bVrgCFA==", + "version": "0.84.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/static-server/-/static-server-0.84.0.tgz", + "integrity": "sha512-zPk2kpELEWouL1zxETF8bgVgZJ018A+BsmYt6jw2TLebA+V+0bY2kRuV+XbgHt27IQA0HbPRqfe6BcxXO6eteg==", "license": "MIT", "engines": { "node": ">=24" @@ -788,25 +773,182 @@ "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", "license": "MIT" }, - "node_modules/@types/node": { - "version": "25.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", - "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "node_modules/@vscode/ripgrep": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.18.0.tgz", + "integrity": "sha512-ns5lWe44tSfbTMbVUsyB+I1819PVSw4AdpgK0RNkzfWfwy6+3IUNSxwSrfTno1/oWaS/hERNz+XLWVyga2aJBQ==", "license": "MIT", "optional": true, - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } + "optionalDependencies": { + "@vscode/ripgrep-darwin-arm64": "1.18.0", + "@vscode/ripgrep-darwin-x64": "1.18.0", + "@vscode/ripgrep-linux-arm": "1.18.0", + "@vscode/ripgrep-linux-arm64": "1.18.0", + "@vscode/ripgrep-linux-ia32": "1.18.0", + "@vscode/ripgrep-linux-ppc64": "1.18.0", + "@vscode/ripgrep-linux-riscv64": "1.18.0", + "@vscode/ripgrep-linux-s390x": "1.18.0", + "@vscode/ripgrep-linux-x64": "1.18.0", + "@vscode/ripgrep-win32-arm64": "1.18.0", + "@vscode/ripgrep-win32-ia32": "1.18.0", + "@vscode/ripgrep-win32-x64": "1.18.0" + } + }, + "node_modules/@vscode/ripgrep-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-darwin-arm64/-/ripgrep-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-r3ktHSvbFycQNF6sl7sNDPocpsI7J+mEzh1IaZFkY0spm3k2Z9t8hPAeOK7+p0l6p6/swkQC14XWX01low+94Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "node_modules/@vscode/ripgrep-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-darwin-x64/-/ripgrep-darwin-x64-1.18.0.tgz", + "integrity": "sha512-25b4gWbL138dGuQU244ebCKKc0q05ULBMoFSz9oAEUHNeqK/lOJViDS7DRvbDazzAzSEdan391Znks/R5mkaTQ==", + "cpu": [ + "x64" + ], "license": "MIT", "optional": true, - "dependencies": { - "@types/node": "*" - } + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-arm/-/ripgrep-linux-arm-1.18.0.tgz", + "integrity": "sha512-GDAvufNDHu8zqLEmXstalQF0Wh6wQvdsBi/Vg3Yi3CK4a8XoFXqqXVEHEZ9xQz3t0NfoSEc9JbvK9DDS6FxyxQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-arm64/-/ripgrep-linux-arm64-1.18.0.tgz", + "integrity": "sha512-lQ/5zTG++U0E3IhVgS4EPTTn/U4okncaRMM5GOFfOYZywS4nuD31GhkHbNYlDk5CuDC68+hYJ0/eQeyCKJDA+g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-ia32/-/ripgrep-linux-ia32-1.18.0.tgz", + "integrity": "sha512-YWLkSUtFd4Jh5EepIhA9RJSfv3uMAVMo+2rBIGHPBnvgLrZciIs2cDKei1/p6Wc/aCzUoHyMAg2R6tw4ZCBKGg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ppc64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-ppc64/-/ripgrep-linux-ppc64-1.18.0.tgz", + "integrity": "sha512-quXVY8fwQ8O/lvU1yrSqSl3jlUzysRSb+AfUfCL/tRtphxsKlFvPAejryZ6vg4Bgvn8XL74xb4qMCDmWgYrT5w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-riscv64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-riscv64/-/ripgrep-linux-riscv64-1.18.0.tgz", + "integrity": "sha512-f5kBQBrWfQt8Q7OhSORuNDei5dkYagBj3y4jImSUXGMy8B/Ke7SltSRcUtjPv166FAFfHCAmWuZp3+cWnX2/Vw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-s390x": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-s390x/-/ripgrep-linux-s390x-1.18.0.tgz", + "integrity": "sha512-rTOcJFGGcl2c07RUOWUo4U1ndnemKhY6A9hnMB18uk7jSgJc0d/QLBGWMWpumdtoJtpizn/wIv5mXIisJukusQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-x64/-/ripgrep-linux-x64-1.18.0.tgz", + "integrity": "sha512-mQ3bVrUpnD2vs7QT0vX90Lt0cnUq467uFtEktIdsJJmW296RoSULRGqWgzG1AKxyBpNDD6l4ZO4qKf6SgyC23Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-win32-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-win32-arm64/-/ripgrep-win32-arm64-1.18.0.tgz", + "integrity": "sha512-vfTIjq1OHnzUjxZcHVQAMbnggp8dpGf+0QKFOZHwWPqFwXxQC8eCWM+5NUdoJ6yrElCeMzoUTXoK/LdZaniB+Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-win32-ia32/-/ripgrep-win32-ia32-1.18.0.tgz", + "integrity": "sha512-//rfAE+BOw5AC2EMmepmiE36jUuevtQYNQqqlw1s3m9FlRxjxEut97RkRPHAu9BG4mSojatZx+kXZXNdyI9caQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-win32-x64/-/ripgrep-win32-x64-1.18.0.tgz", + "integrity": "sha512-KNPvtElldqILHdnAetujPaowkNbpqJy3ssIGGN6F6Kve9Qi+nNLI2DN01O83JjCEVQbCzl8Ov3QZ9Eov3BR8Dg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@zkochan/rimraf": { "version": "3.0.2", @@ -998,16 +1140,6 @@ "node": ">=8" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": "*" - } - }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -1125,53 +1257,6 @@ "node": ">= 8" } }, - "node_modules/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "license": "MIT", - "optional": true, - "dependencies": { - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "license": "(MIT OR CC0-1.0)", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "optional": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/decompress-response": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-10.0.0.tgz", @@ -1312,43 +1397,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "license": "BSD-2-Clause", - "optional": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", - "optional": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", @@ -1383,16 +1431,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "optional": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/figures": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", @@ -1432,9 +1470,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", - "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "license": "MIT", "optional": true, "dependencies": { @@ -1961,13 +1999,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true - }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -2170,13 +2201,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT", - "optional": true - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2329,21 +2353,6 @@ "node": ">=18" } }, - "node_modules/rename-overwrite/node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", - "license": "MIT", - "optional": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/resolve-alpn": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", @@ -2572,61 +2581,6 @@ "streamx": "^2.12.5" } }, - "node_modules/temp-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", - "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/tempy": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.2.0.tgz", - "integrity": "sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "is-stream": "^3.0.0", - "temp-dir": "^3.0.0", - "type-fest": "^2.12.2", - "unique-string": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "license": "MIT", - "optional": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "license": "(MIT OR CC0-1.0)", - "optional": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/text-decoder": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", @@ -2764,13 +2718,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "license": "MIT", - "optional": true - }, "node_modules/unicorn-magic": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", @@ -2783,22 +2730,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "crypto-random-string": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -2920,17 +2851,6 @@ "node": ">=8" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "optional": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/yoctocolors": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", diff --git a/packages/server/package.json b/packages/server/package.json index f71c74e..adb8021 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,12 +1,15 @@ { - "name": "@lvce-editor/pull-request-github-server", + "name": "@lvce-editor/explorer-view-server", "version": "0.0.0-dev", "main": "index.js", "type": "module", + "scripts": { + "dev": "node ./node_modules/@lvce-editor/server/bin/server.js --test-path=../e2e" + }, "keywords": [], "author": "", "license": "MIT", "dependencies": { - "@lvce-editor/server": "0.83.1" + "@lvce-editor/server": "0.84.0" } } diff --git a/packages/server/package.json.lerna_backup b/packages/server/package.json.lerna_backup deleted file mode 100644 index bdf7068..0000000 --- a/packages/server/package.json.lerna_backup +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@lvce-editor/explorer-view-server", - "version": "0.0.0-dev", - "main": "index.js", - "type": "module", - "scripts": { - "dev": "node ./node_modules/@lvce-editor/server/bin/server.js --test-path=../e2e" - }, - "keywords": [], - "author": "", - "license": "MIT", - "dependencies": { - "@lvce-editor/server": "0.83.1" - } -} From 1ebd3d4bc87e54827f074c73b2f929b4bc7bf216 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 14:53:41 +0200 Subject: [PATCH 11/17] add fns --- package.json | 2 +- packages/build/src/build-static.ts | 2 +- packages/build/src/build.ts | 3 +- packages/build/src/bundleJs.ts | 4 +- packages/build/src/measureMemory.ts | 2 +- packages/explorer-view/extension.json | 14 +++ packages/explorer-view/package-lock.json | 23 ++-- packages/explorer-view/package.json | 3 + .../GetPullRequestVirtualDom.ts | 113 ++++++++++++++++++ .../GitHubPullRequest/GitHubPullRequest.ts | 58 +++++++++ .../explorer-view/src/parts/Listen/Listen.ts | 15 ++- .../parts/PullRequestUrl/PullRequestUrl.ts | 30 +++++ .../parts/PullRequestView/PullRequestView.ts | 83 +++++++++++++ .../PullRequestViewState.ts | 28 +++++ .../src/pullRequestWorkerMain.ts | 2 +- .../test/GetPullRequestVirtualDom.test.ts | 44 +++++++ .../test/GitHubPullRequest.test.ts | 74 ++++++++++++ .../explorer-view/test/PullRequestUrl.test.ts | 22 ++++ 18 files changed, 500 insertions(+), 22 deletions(-) create mode 100644 packages/explorer-view/extension.json create mode 100644 packages/explorer-view/src/parts/GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts create mode 100644 packages/explorer-view/src/parts/GitHubPullRequest/GitHubPullRequest.ts create mode 100644 packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts create mode 100644 packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts create mode 100644 packages/explorer-view/src/parts/PullRequestViewState/PullRequestViewState.ts create mode 100644 packages/explorer-view/test/GetPullRequestVirtualDom.test.ts create mode 100644 packages/explorer-view/test/GitHubPullRequest.test.ts create mode 100644 packages/explorer-view/test/PullRequestUrl.test.ts diff --git a/package.json b/package.json index 57fd4f9..e40001e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "node packages/build/src/build.ts", "build:static": "node packages/build/src/build-static.ts", - "build:watch": "./packages/build/node_modules/.bin/esbuild --format=esm --bundle --external:node:buffer --external:electron --external:ws --external:node:worker_threads --watch packages/explorer-view/src/explorerViewWorkerMain.ts --outfile=.tmp/dist/dist/explorerViewWorkerMain.js", + "build:watch": "./packages/build/node_modules/.bin/esbuild --format=esm --bundle --external:node:buffer --external:electron --external:ws --external:node:worker_threads --watch packages/explorer-view/src/pullRequestWorkerMain.ts --outfile=.tmp/dist/dist/pullRequestWorkerMain.js", "dev": "node packages/build/src/dev.ts", "e2e": "cd packages/e2e && npm run e2e", "format": "prettier --write .", diff --git a/packages/build/src/build-static.ts b/packages/build/src/build-static.ts index b681e5b..5df5e48 100644 --- a/packages/build/src/build-static.ts +++ b/packages/build/src/build-static.ts @@ -24,7 +24,7 @@ export const getRemoteUrl = (path: string): string => { } const content = await readFile(rendererWorkerPath, 'utf8') -const workerPath = join(root, '.tmp/dist/dist/explorerViewWorkerMain.js') +const workerPath = join(root, '.tmp/dist/dist/pullRequestWorkerMain.js') const remoteUrl = getRemoteUrl(workerPath) const occurrence = `// const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\` diff --git a/packages/build/src/build.ts b/packages/build/src/build.ts index ddce738..9c3bc40 100644 --- a/packages/build/src/build.ts +++ b/packages/build/src/build.ts @@ -66,9 +66,10 @@ delete packageJson.xo delete packageJson.directories delete packageJson.nodemonConfig packageJson.version = version -packageJson.main = 'dist/explorerViewWorkerMain.js' +packageJson.main = 'dist/pullRequestWorkerMain.js' await writeJson(join(dist, 'package.json'), packageJson) +await cp(join(root, 'packages', 'explorer-view', 'extension.json'), join(dist, 'extension.json')) await cp(join(root, 'README.md'), join(dist, 'README.md')) await cp(join(root, 'LICENSE'), join(dist, 'LICENSE')) diff --git a/packages/build/src/bundleJs.ts b/packages/build/src/bundleJs.ts index 67bcbc5..1f23eda 100644 --- a/packages/build/src/bundleJs.ts +++ b/packages/build/src/bundleJs.ts @@ -6,13 +6,13 @@ import { rollup, type RollupOptions } from 'rollup' import { root } from './root.ts' const options: RollupOptions = { - input: join(root, 'packages/explorer-view/src/explorerViewWorkerMain.ts'), + input: join(root, 'packages/explorer-view/src/pullRequestWorkerMain.ts'), preserveEntrySignatures: 'strict', treeshake: { propertyReadSideEffects: false, }, output: { - file: join(root, '.tmp/dist/dist/explorerViewWorkerMain.js'), + file: join(root, '.tmp/dist/dist/pullRequestWorkerMain.js'), format: 'es', freeze: false, generatedCode: { diff --git a/packages/build/src/measureMemory.ts b/packages/build/src/measureMemory.ts index db99ef7..4ef21de 100644 --- a/packages/build/src/measureMemory.ts +++ b/packages/build/src/measureMemory.ts @@ -8,7 +8,7 @@ const instantiations = 9000 const instantiationsPath = join(root, 'packages', 'explorer-view') -const workerPath = join(root, '.tmp/dist/dist/explorerViewWorkerMain.js') +const workerPath = join(root, '.tmp/dist/dist/pullRequestWorkerMain.js') const playwrightPath = import.meta.resolve('../../e2e/node_modules/playwright/index.mjs') diff --git a/packages/explorer-view/extension.json b/packages/explorer-view/extension.json new file mode 100644 index 0000000..f4e74e4 --- /dev/null +++ b/packages/explorer-view/extension.json @@ -0,0 +1,14 @@ +{ + "id": "github.pull-requests", + "browser": "dist/pullRequestWorkerMain.js", + "isolated": true, + "activation": ["onView:github.pullRequests"], + "views": [ + { + "id": "github.pullRequests", + "title": "Pull Requests", + "icon": "symbol-github", + "kind": "virtualDom" + } + ] +} diff --git a/packages/explorer-view/package-lock.json b/packages/explorer-view/package-lock.json index a444e51..d229b59 100644 --- a/packages/explorer-view/package-lock.json +++ b/packages/explorer-view/package-lock.json @@ -8,6 +8,9 @@ "name": "@lvce-editor/pull-request-view", "version": "0.0.0-dev", "license": "MIT", + "dependencies": { + "@lvce-editor/api": "^8.24.0" + }, "devDependencies": { "@jest/globals": "^30.4.1", "@lvce-editor/assert": "^1.5.1", @@ -989,25 +992,32 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lvce-editor/api": { + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/api/-/api-8.24.0.tgz", + "integrity": "sha512-5BeaB0zJcKtVYJv/Zy9JtDcao9kGEshixAtovfZPsm0+ig/tvfEz+MgBuRS/c8UPw5aM5StpJptPB9rCpKy9GQ==", + "license": "MIT", + "dependencies": { + "@lvce-editor/rpc": "^6.4.0", + "@lvce-editor/rpc-registry": "^9.24.0" + } + }, "node_modules/@lvce-editor/assert": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@lvce-editor/assert/-/assert-1.5.1.tgz", "integrity": "sha512-euS3PuVVjZy06bPFbgTz1yjQ0mY5BgWeYEDb9eQL2ncqYeap0ADy1D57nddlps1VkhHxj1g2ifXkLeIKLkQYJg==", - "dev": true, "license": "MIT" }, "node_modules/@lvce-editor/command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@lvce-editor/command/-/command-2.0.0.tgz", "integrity": "sha512-NZokXOACzuRoIpsHVHx+VhNQwM/QcQ4bl3wc8DgDM/+AxAVT2EU8S9cVQQedtJj94N35zmAB2To6Egm8aifOlw==", - "dev": true, "license": "MIT" }, "node_modules/@lvce-editor/constants": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/@lvce-editor/constants/-/constants-5.14.0.tgz", "integrity": "sha512-eJvcdatVxKHYVtVhMOIULPo53uMNl6YCNztj65ejI4zVrP0qUspM2ymhpglyRoDnyZ+XtUVlMduCmSSq0fT6eQ==", - "dev": true, "license": "MIT" }, "node_modules/@lvce-editor/i18n": { @@ -1021,7 +1031,6 @@ "version": "15.0.0", "resolved": "https://registry.npmjs.org/@lvce-editor/ipc/-/ipc-15.0.0.tgz", "integrity": "sha512-PY8HVhuShfGaTgTSgrsgwgv7Po3WPkgh9AlilgYull4yFPKYZphlGogMSudxq+IsdhKYjD7hdncUEoox+idXiQ==", - "dev": true, "license": "MIT", "dependencies": { "@lvce-editor/assert": "^1.5.1", @@ -1036,7 +1045,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@lvce-editor/json-rpc/-/json-rpc-8.0.0.tgz", "integrity": "sha512-mjeSYYd0qJ0Jz3vpEucBnikdbIFsdmewDX/EkVLHw7obYh0WUXr9f3u528nVAHskrUpb8/IsZY4ynJ0Uaar9bA==", - "dev": true, "license": "MIT" }, "node_modules/@lvce-editor/list": { @@ -1053,7 +1061,6 @@ "version": "6.4.0", "resolved": "https://registry.npmjs.org/@lvce-editor/rpc/-/rpc-6.4.0.tgz", "integrity": "sha512-AhIyFrPz9/9usLNSLNdMtHxSmrfYw4TfJXRMV19px/eYOv+Y20pEq3O31HtKejZaUVRUbPhhJ0EOa0z9YsGAcA==", - "dev": true, "license": "MIT", "dependencies": { "@lvce-editor/assert": "^1.5.1", @@ -1066,7 +1073,6 @@ "version": "9.27.0", "resolved": "https://registry.npmjs.org/@lvce-editor/rpc-registry/-/rpc-registry-9.27.0.tgz", "integrity": "sha512-rMqWoslwQb1H55QTwCgSbFVdc68YqQpK78ZjXmPxs+iQ9RFe+7qVl6mvfyiuFiRNe9avvln42vbt9WhaqWJiug==", - "dev": true, "license": "MIT", "dependencies": { "@lvce-editor/assert": "^1.5.1", @@ -1078,7 +1084,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@lvce-editor/verror/-/verror-1.7.0.tgz", "integrity": "sha512-+LGuAEIC2L7pbvkyAQVWM2Go0dAy+UWEui28g07zNtZsCBhm+gusBK8PNwLJLV5Jay+TyUYuwLIbJdjLLzqEBg==", - "dev": true, "license": "MIT" }, "node_modules/@lvce-editor/viewlet-registry": { @@ -1105,7 +1110,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@lvce-editor/web-socket-server/-/web-socket-server-2.1.0.tgz", "integrity": "sha512-Yldf6nJ4seaFaysYTkkLkOhuJQxkdyX/u01vk1X0dXi21882wMtQbDmYZoAg9rVGWbdBFDIdAJ99pFCAM8eUQA==", - "dev": true, "license": "MIT", "dependencies": { "ws": "^8.18.2" @@ -4659,7 +4663,6 @@ "version": "8.21.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/packages/explorer-view/package.json b/packages/explorer-view/package.json index 24b976e..64a5ebd 100644 --- a/packages/explorer-view/package.json +++ b/packages/explorer-view/package.json @@ -57,5 +57,8 @@ "@lvce-editor/virtual-dom-worker": "^10.0.0", "jest": "^30.4.2", "ts-jest": "^29.4.11" + }, + "dependencies": { + "@lvce-editor/api": "^8.24.0" } } diff --git a/packages/explorer-view/src/parts/GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts b/packages/explorer-view/src/parts/GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts new file mode 100644 index 0000000..7b3653d --- /dev/null +++ b/packages/explorer-view/src/parts/GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts @@ -0,0 +1,113 @@ +import type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker' +import { text, VirtualDomElements } from '@lvce-editor/virtual-dom-worker' +import type { PullRequestData } from '../GitHubPullRequest/GitHubPullRequest.ts' +import type { PullRequestViewState } from '../PullRequestViewState/PullRequestViewState.ts' +import * as PullRequestViewStatus from '../PullRequestViewState/PullRequestViewState.ts' + +const renderField = (label: string, value: string): readonly VirtualDomNode[] => { + return [ + { + childCount: 2, + className: 'PullRequestField', + type: VirtualDomElements.Div, + }, + { + childCount: 1, + className: 'PullRequestFieldLabel', + type: VirtualDomElements.Div, + }, + text(label), + { + childCount: 1, + className: 'PullRequestFieldValue', + type: VirtualDomElements.Div, + }, + text(value || '-'), + ] +} + +const renderPullRequest = (pullRequest: PullRequestData): readonly VirtualDomNode[] => { + return [ + { + childCount: 4, + className: 'PullRequestDetails', + type: VirtualDomElements.Div, + }, + ...renderField('Title', pullRequest.title), + ...renderField('Head', pullRequest.headBranch), + ...renderField('Base', pullRequest.baseBranch), + ...renderField('Description', pullRequest.description || 'No description'), + ] +} + +const renderStatus = (state: PullRequestViewState): readonly VirtualDomNode[] => { + if (state.status === PullRequestViewStatus.Loading) { + return [ + { + childCount: 1, + className: 'PullRequestMessage', + type: VirtualDomElements.Div, + }, + text('Loading pull request...'), + ] + } + if (state.status === PullRequestViewStatus.Error) { + return [ + { + childCount: 1, + className: 'PullRequestMessage PullRequestMessageError', + type: VirtualDomElements.Div, + }, + text(state.error), + ] + } + if (state.status === PullRequestViewStatus.Ready && state.pullRequest) { + return renderPullRequest(state.pullRequest) + } + return [ + { + childCount: 1, + className: 'PullRequestMessage', + type: VirtualDomElements.Div, + }, + text('Enter a GitHub pull request URL.'), + ] +} + +export const getPullRequestVirtualDom = (state: PullRequestViewState): readonly VirtualDomNode[] => { + const statusDom = renderStatus(state) + return [ + { + childCount: 2, + className: 'PullRequestView', + type: VirtualDomElements.Div, + }, + { + childCount: 2, + className: 'PullRequestForm', + name: 'pullRequestForm', + onSubmit: 'handleSubmit', + type: VirtualDomElements.Form, + }, + { + childCount: 0, + className: 'PullRequestInput', + name: 'pullRequestUrl', + onBlur: 'handleBlur', + onFocus: 'handleFocus', + onInput: 'handleInput', + placeholder: 'https://github.com/owner/repo/pull/123', + type: VirtualDomElements.Input, + value: state.url, + }, + { + childCount: 1, + className: 'PullRequestButton', + name: 'loadPullRequest', + onClick: 'handleClick', + type: VirtualDomElements.Button, + }, + text('Load'), + ...statusDom, + ] +} diff --git a/packages/explorer-view/src/parts/GitHubPullRequest/GitHubPullRequest.ts b/packages/explorer-view/src/parts/GitHubPullRequest/GitHubPullRequest.ts new file mode 100644 index 0000000..4552802 --- /dev/null +++ b/packages/explorer-view/src/parts/GitHubPullRequest/GitHubPullRequest.ts @@ -0,0 +1,58 @@ +import { parsePullRequestUrl } from '../PullRequestUrl/PullRequestUrl.ts' + +export interface PullRequestData { + readonly baseBranch: string + readonly description: string + readonly headBranch: string + readonly title: string +} + +interface GitHubPullResponse { + readonly base?: { + readonly ref?: unknown + } + readonly body?: unknown + readonly head?: { + readonly ref?: unknown + } + readonly message?: unknown + readonly title?: unknown +} + +const assertString = (value: unknown): string => { + if (typeof value === 'string') { + return value + } + return '' +} + +export const toPullRequestData = (response: GitHubPullResponse): PullRequestData => { + return { + baseBranch: assertString(response.base?.ref), + description: assertString(response.body), + headBranch: assertString(response.head?.ref), + title: assertString(response.title), + } +} + +const getErrorMessage = (response: GitHubPullResponse, status: number): string => { + if (typeof response.message === 'string' && response.message) { + return response.message + } + return `GitHub request failed with status ${status}` +} + +export const fetchPullRequest = async (url: string, fetchFn: typeof fetch = fetch): Promise => { + const location = parsePullRequestUrl(url) + const apiUrl = `https://api.github.com/repos/${location.owner}/${location.repo}/pulls/${location.number}` + const response = await fetchFn(apiUrl, { + headers: { + Accept: 'application/vnd.github+json', + }, + }) + const json = (await response.json()) as GitHubPullResponse + if (!response.ok) { + throw new Error(getErrorMessage(json, response.status)) + } + return toPullRequestData(json) +} diff --git a/packages/explorer-view/src/parts/Listen/Listen.ts b/packages/explorer-view/src/parts/Listen/Listen.ts index 8b93f30..68b5d44 100644 --- a/packages/explorer-view/src/parts/Listen/Listen.ts +++ b/packages/explorer-view/src/parts/Listen/Listen.ts @@ -1,8 +1,13 @@ -import * as CommandMap from '../CommandMap/CommandMap.ts' -import { registerCommands } from '../ExplorerStates/ExplorerStates.ts' -import { initializeRendererWorker } from '../InitializeRendererWorker/initializeRendereWorker.ts' +import { activate as activateExtensionApi, registerView } from '@lvce-editor/api' +import * as PullRequestView from '../PullRequestView/PullRequestView.ts' export const listen = async (): Promise => { - registerCommands(CommandMap.commandMap) - await Promise.all([initializeRendererWorker()]) + activateExtensionApi() + registerView({ + create: PullRequestView.create, + icon: 'symbol-github', + id: 'github.pullRequests', + kind: 'virtualDom', + title: 'Pull Requests', + } as any) } diff --git a/packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts b/packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts new file mode 100644 index 0000000..4e748bc --- /dev/null +++ b/packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts @@ -0,0 +1,30 @@ +export interface PullRequestLocation { + readonly number: number + readonly owner: string + readonly repo: string +} + +export const parsePullRequestUrl = (value: string): PullRequestLocation => { + let url: URL + try { + url = new URL(value) + } catch { + throw new Error('Enter a valid GitHub pull request URL') + } + if (url.protocol !== 'https:' || url.hostname !== 'github.com') { + throw new Error('Only https://github.com pull request URLs are supported') + } + const parts = url.pathname.split('/').filter(Boolean) + if (parts.length < 4 || parts[2] !== 'pull') { + throw new Error('Enter a GitHub pull request URL like https://github.com/owner/repo/pull/123') + } + const number = Number.parseInt(parts[3], 10) + if (!Number.isInteger(number) || number <= 0 || `${number}` !== parts[3]) { + throw new Error('Pull request number must be a positive integer') + } + return { + number, + owner: parts[0], + repo: parts[1], + } +} diff --git a/packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts b/packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts new file mode 100644 index 0000000..e023dfd --- /dev/null +++ b/packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts @@ -0,0 +1,83 @@ +import type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker' +import { fetchPullRequest } from '../GitHubPullRequest/GitHubPullRequest.ts' +import { getPullRequestVirtualDom } from '../GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts' +import type { PullRequestViewSavedState, PullRequestViewState } from '../PullRequestViewState/PullRequestViewState.ts' +import * as PullRequestViewStatus from '../PullRequestViewState/PullRequestViewState.ts' + +interface ViewContext { + readonly state?: unknown +} + +interface ViewEvent { + readonly name?: string + readonly type: string + readonly value?: unknown +} + +interface VirtualDomViewInstance { + readonly handleEvent: (event: ViewEvent) => Promise + readonly render: () => readonly VirtualDomNode[] + readonly saveState: () => PullRequestViewSavedState +} + +const isSavedState = (value: unknown): value is PullRequestViewSavedState => { + return Boolean(value && typeof value === 'object') +} + +const getSavedState = (context: ViewContext | undefined): PullRequestViewSavedState | undefined => { + if (!isSavedState(context?.state)) { + return undefined + } + return context.state +} + +const loadPullRequest = async (state: PullRequestViewState): Promise => { + try { + const pullRequest = await fetchPullRequest(state.url) + return { + ...state, + error: '', + pullRequest, + status: PullRequestViewStatus.Ready, + } + } catch (error) { + return { + ...state, + error: error instanceof Error ? error.message : `${error}`, + pullRequest: undefined, + status: PullRequestViewStatus.Error, + } + } +} + +export const create = (context?: ViewContext): VirtualDomViewInstance => { + let state = PullRequestViewStatus.createDefaultState(getSavedState(context)) + return { + async handleEvent(event: ViewEvent): Promise { + if (event.type === 'input' && event.name === 'pullRequestUrl') { + state = { + ...state, + url: typeof event.value === 'string' ? event.value : '', + } + return + } + if ((event.type === 'click' && event.name === 'loadPullRequest') || event.type === 'submit') { + state = { + ...state, + error: '', + pullRequest: undefined, + status: PullRequestViewStatus.Loading, + } + state = await loadPullRequest(state) + } + }, + render() { + return getPullRequestVirtualDom(state) + }, + saveState(): PullRequestViewSavedState { + return { + url: state.url, + } + }, + } +} diff --git a/packages/explorer-view/src/parts/PullRequestViewState/PullRequestViewState.ts b/packages/explorer-view/src/parts/PullRequestViewState/PullRequestViewState.ts new file mode 100644 index 0000000..f1bb12a --- /dev/null +++ b/packages/explorer-view/src/parts/PullRequestViewState/PullRequestViewState.ts @@ -0,0 +1,28 @@ +import type { PullRequestData } from '../GitHubPullRequest/GitHubPullRequest.ts' + +export const Empty = 'empty' +export const Error = 'error' +export const Loading = 'loading' +export const Ready = 'ready' + +export type PullRequestViewStatus = typeof Empty | typeof Error | typeof Loading | typeof Ready + +export interface PullRequestViewSavedState { + readonly url?: string +} + +export interface PullRequestViewState { + readonly error: string + readonly pullRequest: PullRequestData | undefined + readonly status: PullRequestViewStatus + readonly url: string +} + +export const createDefaultState = (savedState: PullRequestViewSavedState | undefined): PullRequestViewState => { + return { + error: '', + pullRequest: undefined, + status: Empty, + url: savedState?.url || '', + } +} diff --git a/packages/explorer-view/src/pullRequestWorkerMain.ts b/packages/explorer-view/src/pullRequestWorkerMain.ts index abfaa99..1ac9fe8 100644 --- a/packages/explorer-view/src/pullRequestWorkerMain.ts +++ b/packages/explorer-view/src/pullRequestWorkerMain.ts @@ -1,3 +1,3 @@ import * as Main from './parts/Main/Main.ts' -Main.main() +export const activate = Main.main diff --git a/packages/explorer-view/test/GetPullRequestVirtualDom.test.ts b/packages/explorer-view/test/GetPullRequestVirtualDom.test.ts new file mode 100644 index 0000000..62bddea --- /dev/null +++ b/packages/explorer-view/test/GetPullRequestVirtualDom.test.ts @@ -0,0 +1,44 @@ +import { expect, test } from '@jest/globals' +import { getPullRequestVirtualDom } from '../src/parts/GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts' +import * as PullRequestViewStatus from '../src/parts/PullRequestViewState/PullRequestViewState.ts' + +test('getPullRequestVirtualDom renders empty state', () => { + const dom = getPullRequestVirtualDom({ + error: '', + pullRequest: undefined, + status: PullRequestViewStatus.Empty, + url: '', + }) + + expect(dom.some((node) => node.text === 'Enter a GitHub pull request URL.')).toBe(true) +}) + +test('getPullRequestVirtualDom renders success state', () => { + const dom = getPullRequestVirtualDom({ + error: '', + pullRequest: { + baseBranch: 'main', + description: 'description', + headBranch: 'feature', + title: 'Add feature', + }, + status: PullRequestViewStatus.Ready, + url: 'https://github.com/owner/repo/pull/1', + }) + + expect(dom.some((node) => node.text === 'Add feature')).toBe(true) + expect(dom.some((node) => node.text === 'feature')).toBe(true) + expect(dom.some((node) => node.text === 'main')).toBe(true) + expect(dom.some((node) => node.text === 'description')).toBe(true) +}) + +test('getPullRequestVirtualDom renders error state', () => { + const dom = getPullRequestVirtualDom({ + error: 'Not Found', + pullRequest: undefined, + status: PullRequestViewStatus.Error, + url: 'https://github.com/owner/repo/pull/1', + }) + + expect(dom.some((node) => node.text === 'Not Found')).toBe(true) +}) diff --git a/packages/explorer-view/test/GitHubPullRequest.test.ts b/packages/explorer-view/test/GitHubPullRequest.test.ts new file mode 100644 index 0000000..87d7065 --- /dev/null +++ b/packages/explorer-view/test/GitHubPullRequest.test.ts @@ -0,0 +1,74 @@ +import { expect, test } from '@jest/globals' +import { fetchPullRequest, toPullRequestData } from '../src/parts/GitHubPullRequest/GitHubPullRequest.ts' + +test('toPullRequestData maps github response', () => { + expect( + toPullRequestData({ + base: { + ref: 'main', + }, + body: 'description', + head: { + ref: 'feature', + }, + title: 'Add feature', + }), + ).toEqual({ + baseBranch: 'main', + description: 'description', + headBranch: 'feature', + title: 'Add feature', + }) +}) + +test('fetchPullRequest fetches public github pull request', async () => { + const calls: unknown[] = [] + const fetchFn = async (url: URL | RequestInfo, options?: RequestInit): Promise => { + calls.push([`${url}`, options]) + return { + json: async () => ({ + base: { + ref: 'main', + }, + body: 'description', + head: { + ref: 'feature', + }, + title: 'Add feature', + }), + ok: true, + status: 200, + } as Response + } + + await expect(fetchPullRequest('https://github.com/owner/repo/pull/7', fetchFn)).resolves.toEqual({ + baseBranch: 'main', + description: 'description', + headBranch: 'feature', + title: 'Add feature', + }) + expect(calls).toEqual([ + [ + 'https://api.github.com/repos/owner/repo/pulls/7', + { + headers: { + Accept: 'application/vnd.github+json', + }, + }, + ], + ]) +}) + +test('fetchPullRequest reports github error message', async () => { + const fetchFn = async (): Promise => { + return { + json: async () => ({ + message: 'Not Found', + }), + ok: false, + status: 404, + } as Response + } + + await expect(fetchPullRequest('https://github.com/owner/repo/pull/7', fetchFn)).rejects.toThrow('Not Found') +}) diff --git a/packages/explorer-view/test/PullRequestUrl.test.ts b/packages/explorer-view/test/PullRequestUrl.test.ts new file mode 100644 index 0000000..e794e02 --- /dev/null +++ b/packages/explorer-view/test/PullRequestUrl.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from '@jest/globals' +import { parsePullRequestUrl } from '../src/parts/PullRequestUrl/PullRequestUrl.ts' + +test('parsePullRequestUrl parses github pull request url', () => { + expect(parsePullRequestUrl('https://github.com/lvce-editor/lvce-editor/pull/123')).toEqual({ + number: 123, + owner: 'lvce-editor', + repo: 'lvce-editor', + }) +}) + +test('parsePullRequestUrl rejects non github urls', () => { + expect(() => parsePullRequestUrl('https://example.com/lvce-editor/lvce-editor/pull/123')).toThrow( + 'Only https://github.com pull request URLs are supported', + ) +}) + +test('parsePullRequestUrl rejects invalid pull request number', () => { + expect(() => parsePullRequestUrl('https://github.com/lvce-editor/lvce-editor/pull/abc')).toThrow( + 'Pull request number must be a positive integer', + ) +}) From 2895fbb59eb5d1228243aa305acb55c250306bb9 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 15:00:08 +0200 Subject: [PATCH 12/17] fix --- .../test/PullRequestView.test.ts | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 packages/explorer-view/test/PullRequestView.test.ts diff --git a/packages/explorer-view/test/PullRequestView.test.ts b/packages/explorer-view/test/PullRequestView.test.ts new file mode 100644 index 0000000..be112ff --- /dev/null +++ b/packages/explorer-view/test/PullRequestView.test.ts @@ -0,0 +1,78 @@ +import { afterEach, expect, jest, test } from '@jest/globals' +import { create } from '../src/parts/PullRequestView/PullRequestView.ts' + +const originalFetch = globalThis.fetch + +afterEach(() => { + globalThis.fetch = originalFetch +}) + +test('create renders saved url', () => { + const view = create({ + state: { + url: 'https://github.com/owner/repo/pull/1', + }, + }) + + const dom = view.render() + expect(dom.some((node) => node.value === 'https://github.com/owner/repo/pull/1')).toBe(true) + expect(view.saveState()).toEqual({ + url: 'https://github.com/owner/repo/pull/1', + }) +}) + +test('handleEvent updates url from input', async () => { + const view = create() + await view.handleEvent({ + name: 'pullRequestUrl', + type: 'input', + value: 'https://github.com/owner/repo/pull/2', + }) + + expect(view.saveState()).toEqual({ + url: 'https://github.com/owner/repo/pull/2', + }) +}) + +test('handleEvent loads pull request on button click', async () => { + globalThis.fetch = jest.fn(async () => { + return { + json: async () => ({ + base: { + ref: 'main', + }, + body: 'description', + head: { + ref: 'feature', + }, + title: 'Add feature', + }), + ok: true, + status: 200, + } as Response + }) as typeof fetch + + const view = create() + await view.handleEvent({ + name: 'pullRequestUrl', + type: 'input', + value: 'https://github.com/owner/repo/pull/2', + }) + await view.handleEvent({ + name: 'loadPullRequest', + type: 'click', + }) + + const dom = view.render() + expect(dom.some((node) => node.text === 'Add feature')).toBe(true) +}) + +test('handleEvent renders error on invalid submit', async () => { + const view = create() + await view.handleEvent({ + type: 'submit', + }) + + const dom = view.render() + expect(dom.some((node) => node.text === 'Enter a valid GitHub pull request URL')).toBe(true) +}) From cc196b8c065303a37a26c1a20b0532ed0d34077d Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 15:04:42 +0200 Subject: [PATCH 13/17] lint --- .../explorer-view/src/parts/Listen/Listen.ts | 2 +- .../parts/PullRequestUrl/PullRequestUrl.ts | 4 ++-- .../parts/PullRequestView/PullRequestView.ts | 8 +++---- .../test/GitHubPullRequest.test.ts | 24 +++++++++---------- .../test/PullRequestView.test.ts | 8 +++---- packages/server/src/index.ts | 1 + 6 files changed, 23 insertions(+), 24 deletions(-) create mode 100644 packages/server/src/index.ts diff --git a/packages/explorer-view/src/parts/Listen/Listen.ts b/packages/explorer-view/src/parts/Listen/Listen.ts index 68b5d44..641b2cc 100644 --- a/packages/explorer-view/src/parts/Listen/Listen.ts +++ b/packages/explorer-view/src/parts/Listen/Listen.ts @@ -2,7 +2,7 @@ import { activate as activateExtensionApi, registerView } from '@lvce-editor/api import * as PullRequestView from '../PullRequestView/PullRequestView.ts' export const listen = async (): Promise => { - activateExtensionApi() + void activateExtensionApi() registerView({ create: PullRequestView.create, icon: 'symbol-github', diff --git a/packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts b/packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts index 4e748bc..737063b 100644 --- a/packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts +++ b/packages/explorer-view/src/parts/PullRequestUrl/PullRequestUrl.ts @@ -18,8 +18,8 @@ export const parsePullRequestUrl = (value: string): PullRequestLocation => { if (parts.length < 4 || parts[2] !== 'pull') { throw new Error('Enter a GitHub pull request URL like https://github.com/owner/repo/pull/123') } - const number = Number.parseInt(parts[3], 10) - if (!Number.isInteger(number) || number <= 0 || `${number}` !== parts[3]) { + const number = Number(parts[3]) + if (!Number.isSafeInteger(number) || number <= 0 || String(number) !== parts[3]) { throw new Error('Pull request number must be a positive integer') } return { diff --git a/packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts b/packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts index e023dfd..233b3f7 100644 --- a/packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts +++ b/packages/explorer-view/src/parts/PullRequestView/PullRequestView.ts @@ -1,7 +1,7 @@ import type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker' -import { fetchPullRequest } from '../GitHubPullRequest/GitHubPullRequest.ts' -import { getPullRequestVirtualDom } from '../GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts' import type { PullRequestViewSavedState, PullRequestViewState } from '../PullRequestViewState/PullRequestViewState.ts' +import { getPullRequestVirtualDom } from '../GetPullRequestVirtualDom/GetPullRequestVirtualDom.ts' +import { fetchPullRequest } from '../GitHubPullRequest/GitHubPullRequest.ts' import * as PullRequestViewStatus from '../PullRequestViewState/PullRequestViewState.ts' interface ViewContext { @@ -43,7 +43,7 @@ const loadPullRequest = async (state: PullRequestViewState): Promise { state = await loadPullRequest(state) } }, - render() { + render(): readonly VirtualDomNode[] { return getPullRequestVirtualDom(state) }, saveState(): PullRequestViewSavedState { diff --git a/packages/explorer-view/test/GitHubPullRequest.test.ts b/packages/explorer-view/test/GitHubPullRequest.test.ts index 87d7065..6d7fda5 100644 --- a/packages/explorer-view/test/GitHubPullRequest.test.ts +++ b/packages/explorer-view/test/GitHubPullRequest.test.ts @@ -1,6 +1,16 @@ import { expect, test } from '@jest/globals' import { fetchPullRequest, toPullRequestData } from '../src/parts/GitHubPullRequest/GitHubPullRequest.ts' +const createNotFoundFetch = async (): Promise => { + return { + json: async () => ({ + message: 'Not Found', + }), + ok: false, + status: 404, + } as Response +} + test('toPullRequestData maps github response', () => { expect( toPullRequestData({ @@ -24,7 +34,7 @@ test('toPullRequestData maps github response', () => { test('fetchPullRequest fetches public github pull request', async () => { const calls: unknown[] = [] const fetchFn = async (url: URL | RequestInfo, options?: RequestInit): Promise => { - calls.push([`${url}`, options]) + calls.push([String(url), options]) return { json: async () => ({ base: { @@ -60,15 +70,5 @@ test('fetchPullRequest fetches public github pull request', async () => { }) test('fetchPullRequest reports github error message', async () => { - const fetchFn = async (): Promise => { - return { - json: async () => ({ - message: 'Not Found', - }), - ok: false, - status: 404, - } as Response - } - - await expect(fetchPullRequest('https://github.com/owner/repo/pull/7', fetchFn)).rejects.toThrow('Not Found') + await expect(fetchPullRequest('https://github.com/owner/repo/pull/7', createNotFoundFetch)).rejects.toThrow('Not Found') }) diff --git a/packages/explorer-view/test/PullRequestView.test.ts b/packages/explorer-view/test/PullRequestView.test.ts index be112ff..f3161fa 100644 --- a/packages/explorer-view/test/PullRequestView.test.ts +++ b/packages/explorer-view/test/PullRequestView.test.ts @@ -1,10 +1,8 @@ import { afterEach, expect, jest, test } from '@jest/globals' import { create } from '../src/parts/PullRequestView/PullRequestView.ts' -const originalFetch = globalThis.fetch - afterEach(() => { - globalThis.fetch = originalFetch + jest.restoreAllMocks() }) test('create renders saved url', () => { @@ -35,7 +33,7 @@ test('handleEvent updates url from input', async () => { }) test('handleEvent loads pull request on button click', async () => { - globalThis.fetch = jest.fn(async () => { + jest.spyOn(globalThis, 'fetch').mockImplementation(async () => { return { json: async () => ({ base: { @@ -50,7 +48,7 @@ test('handleEvent loads pull request on button click', async () => { ok: true, status: 200, } as Response - }) as typeof fetch + }) const view = create() await view.handleEvent({ diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts new file mode 100644 index 0000000..336ce12 --- /dev/null +++ b/packages/server/src/index.ts @@ -0,0 +1 @@ +export {} From 6b26a6c6dc6e1b530222bc5f360eb5f23235fa78 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 15:04:59 +0200 Subject: [PATCH 14/17] fix --- packages/explorer-view/test/GitHubPullRequest.test.ts | 3 ++- packages/server/tsconfig.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/explorer-view/test/GitHubPullRequest.test.ts b/packages/explorer-view/test/GitHubPullRequest.test.ts index 6d7fda5..ef518e5 100644 --- a/packages/explorer-view/test/GitHubPullRequest.test.ts +++ b/packages/explorer-view/test/GitHubPullRequest.test.ts @@ -34,7 +34,8 @@ test('toPullRequestData maps github response', () => { test('fetchPullRequest fetches public github pull request', async () => { const calls: unknown[] = [] const fetchFn = async (url: URL | RequestInfo, options?: RequestInit): Promise => { - calls.push([String(url), options]) + const requestUrl = typeof url === 'string' ? url : url instanceof URL ? url.href : url.url + calls.push([requestUrl, options]) return { json: async () => ({ base: { diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 571bd1d..d952721 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -3,7 +3,7 @@ "lib": ["esnext"], "checkJs": true, "target": "esnext", - "types": ["node"], + "types": [], "module": "NodeNext", "moduleResolution": "NodeNext", "skipLibCheck": true, From 8cefec8eb3b7a9f55e2ee093b2a9d7ae713c5354 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 15:06:41 +0200 Subject: [PATCH 15/17] fix pull request view checks --- packages/explorer-view/test/GitHubPullRequest.test.ts | 9 ++++++++- packages/explorer-view/test/PullRequestUrl.test.ts | 4 +--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/explorer-view/test/GitHubPullRequest.test.ts b/packages/explorer-view/test/GitHubPullRequest.test.ts index ef518e5..1b7cf47 100644 --- a/packages/explorer-view/test/GitHubPullRequest.test.ts +++ b/packages/explorer-view/test/GitHubPullRequest.test.ts @@ -34,7 +34,14 @@ test('toPullRequestData maps github response', () => { test('fetchPullRequest fetches public github pull request', async () => { const calls: unknown[] = [] const fetchFn = async (url: URL | RequestInfo, options?: RequestInit): Promise => { - const requestUrl = typeof url === 'string' ? url : url instanceof URL ? url.href : url.url + let requestUrl: string + if (typeof url === 'string') { + requestUrl = url + } else if (url instanceof URL) { + requestUrl = url.href + } else { + requestUrl = url.url + } calls.push([requestUrl, options]) return { json: async () => ({ diff --git a/packages/explorer-view/test/PullRequestUrl.test.ts b/packages/explorer-view/test/PullRequestUrl.test.ts index e794e02..8c1e859 100644 --- a/packages/explorer-view/test/PullRequestUrl.test.ts +++ b/packages/explorer-view/test/PullRequestUrl.test.ts @@ -16,7 +16,5 @@ test('parsePullRequestUrl rejects non github urls', () => { }) test('parsePullRequestUrl rejects invalid pull request number', () => { - expect(() => parsePullRequestUrl('https://github.com/lvce-editor/lvce-editor/pull/abc')).toThrow( - 'Pull request number must be a positive integer', - ) + expect(() => parsePullRequestUrl('https://github.com/lvce-editor/lvce-editor/pull/abc')).toThrow('Pull request number must be a positive integer') }) From 59bf0eb9aae4ae005f3874d33841823149619f00 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 16:05:40 +0200 Subject: [PATCH 16/17] fix static build worker patch --- packages/build/src/build-static.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/build/src/build-static.ts b/packages/build/src/build-static.ts index 5df5e48..e0d576f 100644 --- a/packages/build/src/build-static.ts +++ b/packages/build/src/build-static.ts @@ -30,10 +30,9 @@ const remoteUrl = getRemoteUrl(workerPath) const occurrence = `// const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\` const explorerWorkerUrl = \`${remoteUrl}\`` const replacement = `const explorerWorkerUrl = \`\${assetDir}/packages/explorer-worker/dist/explorerViewWorkerMain.js\`` -if (!content.includes(occurrence)) { - throw new Error('occurrence not found') +if (content.includes(occurrence)) { + const newContent = content.replace(occurrence, replacement) + await writeFile(rendererWorkerPath, newContent) } -const newContent = content.replace(occurrence, replacement) -await writeFile(rendererWorkerPath, newContent) await cp(join(root, 'dist'), join(root, '.tmp', 'static'), { recursive: true }) From 8d78139363bac8d0e7a8482aa97695d236360994 Mon Sep 17 00:00:00 2001 From: Le Vivilet Date: Thu, 18 Jun 2026 16:31:13 +0200 Subject: [PATCH 17/17] fix --- packages/explorer-view/package-lock.json | 12 ++++++------ packages/explorer-view/package.json | 2 +- packages/explorer-view/src/pullRequestWorkerMain.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/explorer-view/package-lock.json b/packages/explorer-view/package-lock.json index d229b59..9500a99 100644 --- a/packages/explorer-view/package-lock.json +++ b/packages/explorer-view/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0-dev", "license": "MIT", "dependencies": { - "@lvce-editor/api": "^8.24.0" + "@lvce-editor/api": "^8.26.0" }, "devDependencies": { "@jest/globals": "^30.4.1", @@ -993,13 +993,14 @@ } }, "node_modules/@lvce-editor/api": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/@lvce-editor/api/-/api-8.24.0.tgz", - "integrity": "sha512-5BeaB0zJcKtVYJv/Zy9JtDcao9kGEshixAtovfZPsm0+ig/tvfEz+MgBuRS/c8UPw5aM5StpJptPB9rCpKy9GQ==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@lvce-editor/api/-/api-8.26.0.tgz", + "integrity": "sha512-IdG6ZL5p2en+wnWAUuyh4eanMPU2yzc0p7tG1a7XIT73A3TMScxzz3ZI310TlZAOEhqtRfPNFCn+qIid3JSR2g==", "license": "MIT", "dependencies": { "@lvce-editor/rpc": "^6.4.0", - "@lvce-editor/rpc-registry": "^9.24.0" + "@lvce-editor/rpc-registry": "^9.24.0", + "@lvce-editor/virtual-dom-worker": "^10.0.0" } }, "node_modules/@lvce-editor/assert": { @@ -1100,7 +1101,6 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/@lvce-editor/virtual-dom-worker/-/virtual-dom-worker-10.0.0.tgz", "integrity": "sha512-qVUH7rIt/k/iVAZy8pGXK1deX87ILlYf1cTD8zIO7A8WELgTnkwQGE2uAYeZPKrbk1wk1Ud7wM0yAdqsCzDQyA==", - "dev": true, "license": "MIT", "dependencies": { "@lvce-editor/constants": "^5.14.0" diff --git a/packages/explorer-view/package.json b/packages/explorer-view/package.json index 64a5ebd..b6be924 100644 --- a/packages/explorer-view/package.json +++ b/packages/explorer-view/package.json @@ -59,6 +59,6 @@ "ts-jest": "^29.4.11" }, "dependencies": { - "@lvce-editor/api": "^8.24.0" + "@lvce-editor/api": "^8.26.0" } } diff --git a/packages/explorer-view/src/pullRequestWorkerMain.ts b/packages/explorer-view/src/pullRequestWorkerMain.ts index 1ac9fe8..a072fc3 100644 --- a/packages/explorer-view/src/pullRequestWorkerMain.ts +++ b/packages/explorer-view/src/pullRequestWorkerMain.ts @@ -1,3 +1,3 @@ import * as Main from './parts/Main/Main.ts' -export const activate = Main.main +await Main.main()