UNPKG

obsidian-dev-utils

Version:

This is the collection of useful functions that you can use for your Obsidian plugin development

833 lines (820 loc) 104 kB
/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ (function initCjs() { const globalThisRecord = globalThis; globalThisRecord['__name'] ??= name; const originalRequire = require; if (originalRequire && !originalRequire.__isPatched) { // eslint-disable-next-line no-global-assign, no-implicit-globals -- We need to patch the `require()` function. require = Object.assign( (id) => requirePatched(id), originalRequire, { __isPatched: true } ); } const newFuncs = { __extractDefault() { return extractDefault; }, process() { const browserProcess = { browser: true, cwd() { return '/'; }, env: {}, platform: 'android' }; return browserProcess; } }; for (const key of Object.keys(newFuncs)) { globalThisRecord[key] ??= newFuncs[key]?.(); } function name(obj) { return obj; } function extractDefault(module) { return module && module.__esModule && 'default' in module ? module.default : module; } const OBSIDIAN_BUILT_IN_MODULE_NAMES = [ 'obsidian', '@codemirror/autocomplete', '@codemirror/collab', '@codemirror/commands', '@codemirror/language', '@codemirror/lint', '@codemirror/search', '@codemirror/state', '@codemirror/text', '@codemirror/view', '@lezer/common', '@lezer/lr', '@lezer/highlight']; const DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES = [ '@codemirror/closebrackets', '@codemirror/comment', '@codemirror/fold', '@codemirror/gutter', '@codemirror/highlight', '@codemirror/history', '@codemirror/matchbrackets', '@codemirror/panel', '@codemirror/rangeset', '@codemirror/rectangular-selection', '@codemirror/stream-parser', '@codemirror/tooltip']; function requirePatched(id) { if (OBSIDIAN_BUILT_IN_MODULE_NAMES.includes(id) || DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES.includes(id)) { return originalRequire?.(id); } // eslint-disable-next-line @typescript-eslint/no-deprecated, @typescript-eslint/no-unnecessary-condition -- We need access to app here which might not be available yet. if (globalThis?.app?.isMobile) { if (id === 'process' || id === 'node:process') { console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Fake process object is returned instead.`); return globalThis.process; } } else { const module = originalRequire?.(id); if (module) { return extractDefault(module); } } console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Empty object is returned instead.`); return {}; } })(); "use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var RenameDeleteHandler_exports = {}; __export(RenameDeleteHandler_exports, { EmptyAttachmentFolderBehavior: () => EmptyAttachmentFolderBehavior, registerRenameDeleteHandlers: () => registerRenameDeleteHandlers }); module.exports = __toCommonJS(RenameDeleteHandler_exports); var import_i18next = require('i18next'); var import_obsidian = require('obsidian'); var import_implementations = require('obsidian-typings/implementations'); var import_AbortController = require('../AbortController.cjs'); var import_Array = require('../Array.cjs'); var import_Debug = require('../Debug.cjs'); var import_ObjectUtils = require('../ObjectUtils.cjs'); var import_Path = require('../Path.cjs'); var import_App = require('./App.cjs'); var import_AttachmentPath = require('./AttachmentPath.cjs'); var import_FileSystem = require('./FileSystem.cjs'); var import_Link = require('./Link.cjs'); var import_MetadataCache = require('./MetadataCache.cjs'); var import_MonkeyAround = require('./MonkeyAround.cjs'); var import_Queue = require('./Queue.cjs'); var import_Vault = require('./Vault.cjs'); var import_VaultEx = require('./VaultEx.cjs'); var EmptyAttachmentFolderBehavior = /* @__PURE__ */ ((EmptyAttachmentFolderBehavior2) => { EmptyAttachmentFolderBehavior2["Delete"] = "Delete"; EmptyAttachmentFolderBehavior2["DeleteWithEmptyParents"] = "DeleteWithEmptyParents"; EmptyAttachmentFolderBehavior2["Keep"] = "Keep"; return EmptyAttachmentFolderBehavior2; })(EmptyAttachmentFolderBehavior || {}); class DeleteHandler { constructor(app, file, abortSignal, settingsManager, deletedMetadataCacheMap) { this.app = app; this.file = file; this.abortSignal = abortSignal; this.settingsManager = settingsManager; this.deletedMetadataCacheMap = deletedMetadataCacheMap; } async handle() { this.abortSignal.throwIfAborted(); (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleDelete")(`Handle Delete ${this.file.path}`); if (!(0, import_FileSystem.isNote)(this.app, this.file)) { return; } const settings = this.settingsManager.getSettings(); if (!settings.shouldHandleDeletions) { return; } if (settings.isPathIgnored?.(this.file.path)) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleDelete")(`Skipping delete handler of ${this.file.path} as the path is ignored.`); return; } const cache = this.deletedMetadataCacheMap.get(this.file.path); this.deletedMetadataCacheMap.delete(this.file.path); const parentFolderPaths = /* @__PURE__ */ new Set(); if (cache) { const links = (0, import_MetadataCache.getAllLinks)(cache); for (const link of links) { const attachmentFile = (0, import_Link.extractLinkFile)(this.app, link, this.file.path); if (!attachmentFile) { continue; } if (this.settingsManager.isNoteEx(attachmentFile.path)) { continue; } parentFolderPaths.add(attachmentFile.parent?.path ?? ""); await (0, import_VaultEx.deleteSafe)(this.app, attachmentFile, this.file.path, false, settings.emptyAttachmentFolderBehavior !== "Keep" /* Keep */); } } await cleanupParentFolders(this.app, this.settingsManager.getSettings(), Array.from(parentFolderPaths)); this.abortSignal.throwIfAborted(); const attachmentFolderPath = await (0, import_AttachmentPath.getAttachmentFolderPath)(this.app, this.file.path, import_AttachmentPath.AttachmentPathContext.DeleteNote); const attachmentFolder = (0, import_FileSystem.getFolderOrNull)(this.app, attachmentFolderPath); if (!attachmentFolder) { return; } if (!await (0, import_AttachmentPath.hasOwnAttachmentFolder)(this.app, this.file.path, import_AttachmentPath.AttachmentPathContext.DeleteNote)) { return; } this.abortSignal.throwIfAborted(); await (0, import_VaultEx.deleteSafe)(this.app, attachmentFolder, this.file.path, false, settings.emptyAttachmentFolderBehavior !== "Keep" /* Keep */); this.abortSignal.throwIfAborted(); } } class HandledRenames { map = /* @__PURE__ */ new Map(); add(oldPath, newPath) { this.map.set(this.keyToString(oldPath, newPath), { newPath, oldPath }); } delete(oldPath, newPath) { this.map.delete(this.keyToString(oldPath, newPath)); } has(oldPath, newPath) { return this.map.has(this.keyToString(oldPath, newPath)); } keys() { return this.map.values(); } keyToString(oldPath, newPath) { return `${oldPath} -> ${newPath}`; } } class MetadataDeletedHandler { constructor(app, file, prevCache, settingsManager, deletedMetadataCacheMap) { this.app = app; this.file = file; this.prevCache = prevCache; this.settingsManager = settingsManager; this.deletedMetadataCacheMap = deletedMetadataCacheMap; } handle() { const settings = this.settingsManager.getSettings(); if (!settings.shouldHandleDeletions) { return; } if (settings.isPathIgnored?.(this.file.path)) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleMetadataDeleted")(`Skipping metadata delete handler of ${this.file.path} as the path is ignored.`); return; } if ((0, import_FileSystem.isMarkdownFile)(this.app, this.file) && this.prevCache) { this.deletedMetadataCacheMap.set(this.file.path, this.prevCache); } } } class Registry { constructor(plugin, settingsBuilder, settingsManager) { this.plugin = plugin; this.settingsBuilder = settingsBuilder; this.settingsManager = settingsManager; this.app = plugin.app; this.pluginId = plugin.manifest.id; this.abortSignal = plugin.abortSignal ?? (0, import_AbortController.abortSignalNever)(); } abortSignal; app; deletedMetadataCacheMap = /* @__PURE__ */ new Map(); handledRenames = new HandledRenames(); interruptedRenamesMap = /* @__PURE__ */ new Map(); pluginId; register() { const renameDeleteHandlersMap = this.settingsManager.renameDeleteHandlersMap; renameDeleteHandlersMap.set(this.pluginId, this.settingsBuilder); this.logRegisteredHandlers(); this.plugin.register(() => { renameDeleteHandlersMap.delete(this.pluginId); this.logRegisteredHandlers(); }); this.plugin.registerEvent(this.app.vault.on("delete", this.handleDelete.bind(this))); this.plugin.registerEvent(this.app.vault.on("rename", this.handleRename.bind(this))); this.plugin.registerEvent(this.app.metadataCache.on("deleted", this.handleMetadataDeleted.bind(this))); (0, import_MonkeyAround.registerPatch)(this.plugin, this.app.fileManager, { runAsyncLinkUpdate: (next) => { return Object.assign((linkUpdatesHandler) => this.runAsyncLinkUpdate(next, linkUpdatesHandler), { renameDeleteHandlerPatched: true }); } }); } handleDelete(file) { if (!this.shouldInvokeHandler()) { return; } (0, import_Queue.addToQueue)({ app: this.app, operationFn: (abortSignal) => new DeleteHandler(this.app, file, abortSignal, this.settingsManager, this.deletedMetadataCacheMap).handle(), operationName: (0, import_i18next.t)(($) => $.obsidianDevUtils.renameDeleteHandler.handleDelete, { filePath: file.path }) }); } handleMetadataDeleted(file, prevCache) { if (!this.shouldInvokeHandler()) { return; } new MetadataDeletedHandler(this.app, file, prevCache, this.settingsManager, this.deletedMetadataCacheMap).handle(); } handleRename(file, oldPath) { if (!this.shouldInvokeHandler()) { return; } if (!(0, import_FileSystem.isFile)(file)) { return; } const newPath = file.path; (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleRename")(`Handle Rename ${oldPath} -> ${newPath}`); if (this.handledRenames.has(oldPath, newPath)) { this.handledRenames.delete(oldPath, newPath); return; } const settings = this.settingsManager.getSettings(); if (!settings.shouldHandleRenames) { return; } if (settings.isPathIgnored?.(oldPath)) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleRename")(`Skipping rename handler of old path ${oldPath} as the path is ignored.`); return; } if (settings.isPathIgnored?.(newPath)) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleRename")(`Skipping rename handler of new path ${newPath} as the path is ignored.`); return; } const oldCache = this.app.metadataCache.getCache(oldPath) ?? this.app.metadataCache.getCache(newPath); const oldPathBacklinksMap = (0, import_MetadataCache.getBacklinksForFileOrPath)(this.app, oldPath).data; (0, import_Queue.addToQueue)({ abortSignal: this.abortSignal, app: this.app, operationFn: (abortSignal) => new RenameHandler({ abortSignal, app: this.app, handledRenames: this.handledRenames, interruptedRenamesMap: this.interruptedRenamesMap, newPath, oldCache, oldPath, oldPathBacklinksMap, settingsManager: this.settingsManager }).handle(), operationName: (0, import_i18next.t)(($) => $.obsidianDevUtils.renameDeleteHandler.handleRename, { newPath, oldPath }) }); } logRegisteredHandlers() { const renameDeleteHandlersMap = this.settingsManager.renameDeleteHandlersMap; (0, import_Debug.getLibDebugger)("RenameDeleteHandler:logRegisteredHandlers")( `Plugins with registered rename/delete handlers: ${JSON.stringify(Array.from(renameDeleteHandlersMap.keys()))}` ); } async runAsyncLinkUpdate(next, linkUpdatesHandler) { if (next.renameDeleteHandlerPatched) { await next.call(this.app.fileManager, linkUpdatesHandler); return; } await next.call(this.app.fileManager, (linkUpdates) => this.wrapLinkUpdatesHandler(linkUpdates, linkUpdatesHandler)); } shouldInvokeHandler() { const pluginId = this.plugin.manifest.id; const renameDeleteHandlersMap = this.settingsManager.renameDeleteHandlersMap; const mainPluginId = Array.from(renameDeleteHandlersMap.keys())[0]; return mainPluginId === pluginId; } async wrapLinkUpdatesHandler(linkUpdates, linkUpdatesHandler) { let isRenameCalled = false; const eventRef = this.app.vault.on("rename", () => { isRenameCalled = true; }); try { await linkUpdatesHandler(linkUpdates); } finally { this.app.vault.offref(eventRef); } const settings = this.settingsManager.getSettings(); if (!isRenameCalled || !settings.shouldHandleRenames) { return; } (0, import_Array.filterInPlace)( linkUpdates, (linkUpdate) => { if (settings.isPathIgnored?.(linkUpdate.sourceFile.path)) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:runAsyncLinkUpdate")( `Roll back to default link update of source file ${linkUpdate.sourceFile.path} as the path is ignored.` ); return true; } if (settings.isPathIgnored?.(linkUpdate.resolvedFile.path)) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:runAsyncLinkUpdate")( `Roll back to default link update of resolved file ${linkUpdate.resolvedFile.path} as the path is ignored.` ); return true; } if (!this.app.internalPlugins.getEnabledPluginById(import_implementations.InternalPluginName.Canvas)) { return false; } if (this.app.plugins.getPlugin("backlink-cache")) { return false; } if (linkUpdate.sourceFile.extension === import_FileSystem.CANVAS_FILE_EXTENSION) { return true; } if (linkUpdate.resolvedFile.extension === import_FileSystem.CANVAS_FILE_EXTENSION) { return true; } return false; } ); } } class RenameHandler { abortSignal; app; handledRenames; interruptedCombinedBacklinksMap; interruptedRenamesMap; newPath; oldCache; oldPath; oldPathBacklinksMap; oldPathLinks; settingsManager; constructor(options) { this.app = options.app; this.oldPath = options.oldPath; this.newPath = options.newPath; this.oldPathBacklinksMap = options.oldPathBacklinksMap; this.oldCache = options.oldCache; this.abortSignal = options.abortSignal; this.settingsManager = options.settingsManager; this.interruptedRenamesMap = options.interruptedRenamesMap; this.oldPathLinks = this.oldCache ? (0, import_MetadataCache.getAllLinks)(this.oldCache) : []; this.handledRenames = options.handledRenames; this.interruptedCombinedBacklinksMap = options.interruptedCombinedBacklinksMap ?? /* @__PURE__ */ new Map(); } async handle() { if (this.oldPath === this.newPath) { return; } this.abortSignal.throwIfAborted(); await this.continueInterruptedRenames(); this.abortSignal.throwIfAborted(); await this.refreshLinks(); this.abortSignal.throwIfAborted(); if (await this.handleCaseCollision()) { return; } this.abortSignal.throwIfAborted(); const renamedFilePaths = (0, import_App.getObsidianDevUtilsState)(this.app, "renamedFilePaths", /* @__PURE__ */ new Set()).value; const renamedLinks = (0, import_App.getObsidianDevUtilsState)(this.app, "renamedLinkPaths", /* @__PURE__ */ new Set()).value; try { const renameMap = new RenameMap({ abortSignal: this.abortSignal, app: this.app, newPath: this.newPath, oldCache: this.oldCache, oldPath: this.oldPath, settingsManager: this.settingsManager }); await renameMap.fill(); this.abortSignal.throwIfAborted(); const combinedBacklinksMap = /* @__PURE__ */ new Map(); renameMap.initOriginalLinksMap(combinedBacklinksMap); renameMap.initBacklinksMap(this.oldPathBacklinksMap, combinedBacklinksMap, this.oldPath); for (const attachmentOldPath of renameMap.keys()) { if (attachmentOldPath === this.oldPath) { continue; } const attachmentOldPathBacklinksMap = (await (0, import_MetadataCache.getBacklinksForFileSafe)(this.app, attachmentOldPath)).data; this.abortSignal.throwIfAborted(); renameMap.initBacklinksMap(attachmentOldPathBacklinksMap, combinedBacklinksMap, attachmentOldPath); } const parentFolderPaths = /* @__PURE__ */ new Set(); for (const [oldAttachmentPath, newAttachmentPath] of renameMap.entries()) { if (oldAttachmentPath !== this.oldPath) { const fixedNewAttachmentPath = await this.renameHandled(oldAttachmentPath, newAttachmentPath); this.abortSignal.throwIfAborted(); renameMap.set(oldAttachmentPath, fixedNewAttachmentPath); } if (!this.settingsManager.isNoteEx(oldAttachmentPath)) { parentFolderPaths.add((0, import_Path.dirname)(oldAttachmentPath)); } } await cleanupParentFolders(this.app, this.settingsManager.getSettings(), Array.from(parentFolderPaths)); this.abortSignal.throwIfAborted(); const settings = this.settingsManager.getSettings(); for (const [newBacklinkPath, linkJsonToPathMap] of Array.from(combinedBacklinksMap.entries()).concat( Array.from(this.interruptedCombinedBacklinksMap.entries()) )) { let linkIndex = 0; await (0, import_Link.editLinks)(this.app, newBacklinkPath, (link) => { linkIndex++; const oldAttachmentPath = linkJsonToPathMap.get((0, import_ObjectUtils.toJson)(link)); if (!oldAttachmentPath) { return; } const newAttachmentPath = renameMap.get(oldAttachmentPath) ?? oldAttachmentPath; renamedFilePaths.add(newBacklinkPath); renamedLinks.add(`${newBacklinkPath}//${String(linkIndex)}`); return (0, import_Link.updateLink)((0, import_ObjectUtils.normalizeOptionalProperties)({ app: this.app, link, newSourcePathOrFile: newBacklinkPath, newTargetPathOrFile: newAttachmentPath, oldTargetPathOrFile: oldAttachmentPath, shouldUpdateFileNameAlias: settings.shouldUpdateFileNameAliases })); }, { shouldFailOnMissingFile: false }); this.abortSignal.throwIfAborted(); } if ((0, import_FileSystem.isNote)(this.app, this.newPath)) { await (0, import_Link.updateLinksInFile)((0, import_ObjectUtils.normalizeOptionalProperties)({ app: this.app, newSourcePathOrFile: this.newPath, oldSourcePathOrFile: this.oldPath, shouldFailOnMissingFile: false, shouldUpdateFileNameAlias: settings.shouldUpdateFileNameAliases })); this.abortSignal.throwIfAborted(); } if (!(0, import_FileSystem.getFileOrNull)(this.app, this.newPath)) { let interruptedRenames = this.interruptedRenamesMap.get(this.newPath); if (!interruptedRenames) { interruptedRenames = []; this.interruptedRenamesMap.set(this.newPath, interruptedRenames); } interruptedRenames.push({ combinedBacklinksMap, oldPath: this.oldPath }); } } finally { const orphanKeys = Array.from(this.handledRenames.keys()); (0, import_Queue.addToQueue)({ abortSignal: this.abortSignal, app: this.app, operationFn: () => { for (const orphanKey of orphanKeys) { this.handledRenames.delete(orphanKey.oldPath, orphanKey.newPath); } if (renamedLinks.size === 0) { return; } new import_obsidian.Notice((0, import_i18next.t)(($) => $.obsidianDevUtils.renameDeleteHandler.updatedLinks, { filesCount: renamedFilePaths.size, linksCount: renamedLinks.size })); renamedFilePaths.clear(); renamedLinks.clear(); }, operationName: (0, import_i18next.t)(($) => $.obsidianDevUtils.renameDeleteHandler.handleOrphanedRenames) }); } } async continueInterruptedRenames() { const interruptedRenames = this.interruptedRenamesMap.get(this.oldPath); if (interruptedRenames) { this.interruptedRenamesMap.delete(this.oldPath); for (const interruptedRename of interruptedRenames) { await new RenameHandler({ abortSignal: this.abortSignal, app: this.app, handledRenames: this.handledRenames, interruptedCombinedBacklinksMap: interruptedRename.combinedBacklinksMap, interruptedRenamesMap: this.interruptedRenamesMap, newPath: this.newPath, oldCache: this.oldCache, oldPath: interruptedRename.oldPath, oldPathBacklinksMap: this.oldPathBacklinksMap, settingsManager: this.settingsManager }).handle(); } } } async handleCaseCollision() { if (!this.app.vault.adapter.insensitive || this.oldPath.toLowerCase() !== this.newPath.toLowerCase()) { return false; } const tempPath = (0, import_Path.join)((0, import_Path.dirname)(this.newPath), `__temp__${(0, import_Path.basename)(this.newPath)}`); await this.renameHandled(this.newPath, tempPath); await new RenameHandler({ abortSignal: this.abortSignal, app: this.app, handledRenames: this.handledRenames, interruptedRenamesMap: this.interruptedRenamesMap, newPath: tempPath, oldCache: this.oldCache, oldPath: this.oldPath, oldPathBacklinksMap: this.oldPathBacklinksMap, settingsManager: this.settingsManager }).handle(); await this.app.fileManager.renameFile((0, import_FileSystem.getFile)(this.app, tempPath), this.newPath); return true; } async refreshLinks() { const cache = this.app.metadataCache.getCache(this.oldPath) ?? this.app.metadataCache.getCache(this.newPath); const oldPathLinksRefreshed = cache ? (0, import_MetadataCache.getAllLinks)(cache) : []; const fakeOldFile = (0, import_FileSystem.getFile)(this.app, this.oldPath, true); let oldPathBacklinksMapRefreshed = /* @__PURE__ */ new Map(); await (0, import_MetadataCache.tempRegisterFilesAndRun)(this.app, [fakeOldFile], async () => { oldPathBacklinksMapRefreshed = (await (0, import_MetadataCache.getBacklinksForFileSafe)(this.app, fakeOldFile)).data; }); for (const link of oldPathLinksRefreshed) { if (this.oldPathLinks.includes(link)) { continue; } this.oldPathLinks.push(link); } for (const [backlinkPath, refreshedLinks] of oldPathBacklinksMapRefreshed.entries()) { let oldLinks = this.oldPathBacklinksMap.get(backlinkPath); if (!oldLinks) { oldLinks = []; this.oldPathBacklinksMap.set(backlinkPath, oldLinks); } for (const link of refreshedLinks) { if (oldLinks.includes(link)) { continue; } oldLinks.push(link); } } } async renameHandled(oldPath, newPath) { newPath = (0, import_Vault.getSafeRenamePath)(this.app, oldPath, newPath); if (oldPath === newPath) { return newPath; } this.handledRenames.add(oldPath, newPath); newPath = await (0, import_Vault.renameSafe)(this.app, oldPath, newPath); return newPath; } } class RenameMap { abortSignal; app; map = /* @__PURE__ */ new Map(); newPath; oldCache; oldPath; oldPathLinks; settingsManager; constructor(options) { this.abortSignal = options.abortSignal; this.app = options.app; this.settingsManager = options.settingsManager; this.oldCache = options.oldCache; this.oldPath = options.oldPath; this.newPath = options.newPath; this.oldPathLinks = this.oldCache ? (0, import_MetadataCache.getAllLinks)(this.oldCache) : []; } entries() { return this.map.entries(); } async fill() { this.abortSignal.throwIfAborted(); this.map.set(this.oldPath, this.newPath); if (!(0, import_FileSystem.isNote)(this.app, this.oldPath)) { return; } const settings = this.settingsManager.getSettings(); const oldFile = (0, import_FileSystem.getFile)(this.app, this.oldPath, true); let oldAttachmentFolderPath = ""; await (0, import_MetadataCache.tempRegisterFilesAndRunAsync)(this.app, [oldFile], async () => { const shouldFakeOldPathCache = this.oldCache && oldFile.deleted; if (shouldFakeOldPathCache) { (0, import_MetadataCache.registerFileCacheForNonExistingFile)(this.app, oldFile, this.oldCache); } try { oldAttachmentFolderPath = await (0, import_AttachmentPath.getAttachmentFolderPath)(this.app, this.oldPath, import_AttachmentPath.AttachmentPathContext.RenameNote); } finally { if (shouldFakeOldPathCache) { (0, import_MetadataCache.unregisterFileCacheForNonExistingFile)(this.app, oldFile); } } }); const newAttachmentFolderPath = settings.shouldRenameAttachmentFolder ? await (0, import_AttachmentPath.getAttachmentFolderPath)(this.app, this.newPath, import_AttachmentPath.AttachmentPathContext.RenameNote) : oldAttachmentFolderPath; const isOldAttachmentFolderAtRoot = oldAttachmentFolderPath === "/"; const oldAttachmentFolder = (0, import_FileSystem.getFolderOrNull)(this.app, oldAttachmentFolderPath); if (!oldAttachmentFolder) { return; } if (oldAttachmentFolderPath === newAttachmentFolderPath && !settings.shouldRenameAttachmentFiles) { return; } const oldAttachmentFiles = []; if (await (0, import_AttachmentPath.hasOwnAttachmentFolder)(this.app, this.oldPath, import_AttachmentPath.AttachmentPathContext.RenameNote)) { import_obsidian.Vault.recurseChildren(oldAttachmentFolder, (oldAttachmentFile) => { this.abortSignal.throwIfAborted(); if ((0, import_FileSystem.isFile)(oldAttachmentFile)) { oldAttachmentFiles.push(oldAttachmentFile); } }); } else { for (const oldPathLink of this.oldPathLinks) { this.abortSignal.throwIfAborted(); const oldAttachmentFile = (0, import_Link.extractLinkFile)(this.app, oldPathLink, this.oldPath); if (!oldAttachmentFile) { continue; } if (isOldAttachmentFolderAtRoot || oldAttachmentFile.path.startsWith(oldAttachmentFolderPath)) { const oldAttachmentBacklinks = await (0, import_MetadataCache.getBacklinksForFileSafe)(this.app, oldAttachmentFile); this.abortSignal.throwIfAborted(); const keys = new Set(oldAttachmentBacklinks.keys()); keys.delete(this.oldPath); keys.delete(this.newPath); if (keys.size === 0) { oldAttachmentFiles.push(oldAttachmentFile); } } } } for (const oldAttachmentFile of oldAttachmentFiles) { this.abortSignal.throwIfAborted(); if (this.settingsManager.isNoteEx(oldAttachmentFile.path)) { continue; } let newAttachmentFilePath; if (settings.shouldRenameAttachmentFiles) { newAttachmentFilePath = await (0, import_AttachmentPath.getAttachmentFilePath)({ app: this.app, context: import_AttachmentPath.AttachmentPathContext.RenameNote, notePathOrFile: this.newPath, oldAttachmentPathOrFile: oldAttachmentFile, oldNotePathOrFile: this.oldPath, shouldSkipDuplicateCheck: true }); this.abortSignal.throwIfAborted(); } else { const relativePath = isOldAttachmentFolderAtRoot ? oldAttachmentFile.path : (0, import_Path.relative)(oldAttachmentFolderPath, oldAttachmentFile.path); const newFolder = (0, import_Path.join)(newAttachmentFolderPath, (0, import_Path.dirname)(relativePath)); newAttachmentFilePath = (0, import_Path.join)(newFolder, oldAttachmentFile.name); } if (oldAttachmentFile.path === newAttachmentFilePath) { continue; } if (settings.shouldDeleteConflictingAttachments) { const newAttachmentFile = (0, import_FileSystem.getFileOrNull)(this.app, newAttachmentFilePath); if (newAttachmentFile) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:fillRenameMap")(`Removing conflicting attachment ${newAttachmentFile.path}.`); await this.app.fileManager.trashFile(newAttachmentFile); this.abortSignal.throwIfAborted(); } } else { const dir = (0, import_Path.dirname)(newAttachmentFilePath); const ext = (0, import_Path.extname)(newAttachmentFilePath); const baseName = (0, import_Path.basename)(newAttachmentFilePath, ext); newAttachmentFilePath = this.app.vault.getAvailablePath((0, import_Path.join)(dir, baseName), ext.slice(1)); } this.map.set(oldAttachmentFile.path, newAttachmentFilePath); } } get(oldPath) { return this.map.get(oldPath); } initBacklinksMap(singleBacklinksMap, combinedBacklinksMap, path) { for (const [backlinkPath, links] of singleBacklinksMap.entries()) { const newBacklinkPath = this.map.get(backlinkPath) ?? backlinkPath; const linkJsonToPathMap = combinedBacklinksMap.get(newBacklinkPath) ?? /* @__PURE__ */ new Map(); combinedBacklinksMap.set(newBacklinkPath, linkJsonToPathMap); for (const link of links) { linkJsonToPathMap.set((0, import_ObjectUtils.toJson)(link), path); } } } initOriginalLinksMap(combinedBacklinksMap) { for (const oldPathLink of this.oldPathLinks) { const oldAttachmentFile = (0, import_Link.extractLinkFile)(this.app, oldPathLink, this.oldPath); if (!oldAttachmentFile) { continue; } const backlinksMap = /* @__PURE__ */ new Map(); backlinksMap.set(this.newPath, [oldPathLink]); this.initBacklinksMap(backlinksMap, combinedBacklinksMap, oldAttachmentFile.path); } } keys() { return this.map.keys(); } set(oldPath, newPath) { this.map.set(oldPath, newPath); } } class SettingsManager { constructor(app) { this.app = app; this.renameDeleteHandlersMap = (0, import_App.getObsidianDevUtilsState)(app, "renameDeleteHandlersMap", /* @__PURE__ */ new Map()).value; } renameDeleteHandlersMap; getSettings() { const settingsBuilders = Array.from(this.renameDeleteHandlersMap.values()).reverse(); const settings = {}; settings.isNote = (path) => (0, import_FileSystem.isNote)(this.app, path); settings.isPathIgnored = () => false; for (const settingsBuilder of settingsBuilders) { const newSettings = settingsBuilder(); settings.shouldDeleteConflictingAttachments ||= newSettings.shouldDeleteConflictingAttachments ?? false; if (newSettings.emptyAttachmentFolderBehavior) { settings.emptyAttachmentFolderBehavior ??= newSettings.emptyAttachmentFolderBehavior; } settings.shouldHandleDeletions ||= newSettings.shouldHandleDeletions ?? false; settings.shouldHandleRenames ||= newSettings.shouldHandleRenames ?? false; settings.shouldRenameAttachmentFiles ||= newSettings.shouldRenameAttachmentFiles ?? false; settings.shouldRenameAttachmentFolder ||= newSettings.shouldRenameAttachmentFolder ?? false; settings.shouldUpdateFileNameAliases ||= newSettings.shouldUpdateFileNameAliases ?? false; const isPathIgnored = settings.isPathIgnored; settings.isPathIgnored = (path) => isPathIgnored(path) || (newSettings.isPathIgnored?.(path) ?? false); const currentIsNote = settings.isNote; settings.isNote = (path) => currentIsNote(path) && (newSettings.isNote?.(path) ?? true); } settings.emptyAttachmentFolderBehavior ??= "Keep" /* Keep */; return settings; } isNoteEx(path) { const settings = this.getSettings(); return settings.isNote?.(path) ?? false; } } function registerRenameDeleteHandlers(plugin, settingsBuilder) { new Registry(plugin, settingsBuilder, new SettingsManager(plugin.app)).register(); } async function cleanupParentFolders(app, settings, parentFolderPaths) { if (settings.emptyAttachmentFolderBehavior === "Keep" /* Keep */) { return; } for (const parentFolderPath of parentFolderPaths) { switch (settings.emptyAttachmentFolderBehavior) { case "Delete" /* Delete */: await (0, import_VaultEx.deleteEmptyFolder)(app, parentFolderPath); break; case "DeleteWithEmptyParents" /* DeleteWithEmptyParents */: await (0, import_VaultEx.deleteEmptyFolderHierarchy)(app, parentFolderPath); break; default: break; } } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { EmptyAttachmentFolderBehavior, registerRenameDeleteHandlers }); //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL1JlbmFtZURlbGV0ZUhhbmRsZXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQHBhY2thZ2VEb2N1bWVudGF0aW9uXG4gKlxuICogQ29udGFpbnMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIGhhbmRsaW5nIHJlbmFtZSBhbmQgZGVsZXRlIGV2ZW50cyBpbiBPYnNpZGlhbi5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIEFwcCxcbiAgQ2FjaGVkTWV0YWRhdGEsXG4gIEZpbGVNYW5hZ2VyLFxuICBQbHVnaW4sXG4gIFJlZmVyZW5jZSxcbiAgVEFic3RyYWN0RmlsZSxcbiAgVEZpbGVcbn0gZnJvbSAnb2JzaWRpYW4nO1xuaW1wb3J0IHR5cGUge1xuICBMaW5rVXBkYXRlLFxuICBMaW5rVXBkYXRlc0hhbmRsZXJcbn0gZnJvbSAnb2JzaWRpYW4tdHlwaW5ncyc7XG5cbmltcG9ydCB7IHQgfSBmcm9tICdpMThuZXh0JztcbmltcG9ydCB7XG4gIE5vdGljZSxcbiAgVmF1bHRcbn0gZnJvbSAnb2JzaWRpYW4nO1xuaW1wb3J0IHsgSW50ZXJuYWxQbHVnaW5OYW1lIH0gZnJvbSAnb2JzaWRpYW4tdHlwaW5ncy9pbXBsZW1lbnRhdGlvbnMnO1xuXG5pbXBvcnQgdHlwZSB7XG4gIFVwZGF0ZUxpbmtPcHRpb25zLFxuICBVcGRhdGVMaW5rc0luRmlsZU9wdGlvbnNcbn0gZnJvbSAnLi9MaW5rLnRzJztcblxuaW1wb3J0IHsgYWJvcnRTaWduYWxOZXZlciB9IGZyb20gJy4uL0Fib3J0Q29udHJvbGxlci50cyc7XG5pbXBvcnQgeyBmaWx0ZXJJblBsYWNlIH0gZnJvbSAnLi4vQXJyYXkudHMnO1xuaW1wb3J0IHsgZ2V0TGliRGVidWdnZXIgfSBmcm9tICcuLi9EZWJ1Zy50cyc7XG5pbXBvcnQge1xuICBub3JtYWxpemVPcHRpb25hbFByb3BlcnRpZXMsXG4gIHRvSnNvblxufSBmcm9tICcuLi9PYmplY3RVdGlscy50cyc7XG5pbXBvcnQge1xuICBiYXNlbmFtZSxcbiAgZGlybmFtZSxcbiAgZXh0bmFtZSxcbiAgam9pbixcbiAgcmVsYXRpdmVcbn0gZnJvbSAnLi4vUGF0aC50cyc7XG5pbXBvcnQgeyBnZXRPYnNpZGlhbkRldlV0aWxzU3RhdGUgfSBmcm9tICcuL0FwcC50cyc7XG5pbXBvcnQge1xuICBBdHRhY2htZW50UGF0aENvbnRleHQsXG4gIGdldEF0dGFjaG1lbnRGaWxlUGF0aCxcbiAgZ2V0QXR0YWNobWVudEZvbGRlclBhdGgsXG4gIGhhc093bkF0dGFjaG1lbnRGb2xkZXJcbn0gZnJvbSAnLi9BdHRhY2htZW50UGF0aC50cyc7XG5pbXBvcnQge1xuICBDQU5WQVNfRklMRV9FWFRFTlNJT04sXG4gIGdldEZpbGUsXG4gIGdldEZpbGVPck51bGwsXG4gIGdldEZvbGRlck9yTnVsbCxcbiAgaXNGaWxlLFxuICBpc01hcmtkb3duRmlsZSxcbiAgaXNOb3RlXG59IGZyb20gJy4vRmlsZVN5c3RlbS50cyc7XG5pbXBvcnQge1xuICBlZGl0TGlua3MsXG4gIGV4dHJhY3RMaW5rRmlsZSxcbiAgdXBkYXRlTGluayxcbiAgdXBkYXRlTGlua3NJbkZpbGVcbn0gZnJvbSAnLi9MaW5rLnRzJztcbmltcG9ydCB7XG4gIGdldEFsbExpbmtzLFxuICBnZXRCYWNrbGlua3NGb3JGaWxlT3JQYXRoLFxuICBnZXRCYWNrbGlua3NGb3JGaWxlU2FmZSxcbiAgcmVnaXN0ZXJGaWxlQ2FjaGVGb3JOb25FeGlzdGluZ0ZpbGUsXG4gIHRlbXBSZWdpc3RlckZpbGVzQW5kUnVuLFxuICB0ZW1wUmVnaXN0ZXJGaWxlc0FuZFJ1bkFzeW5jLFxuICB1bnJlZ2lzdGVyRmlsZUNhY2hlRm9yTm9uRXhpc3RpbmdGaWxlXG59IGZyb20gJy4vTWV0YWRhdGFDYWNoZS50cyc7XG5pbXBvcnQgeyByZWdpc3RlclBhdGNoIH0gZnJvbSAnLi9Nb25rZXlBcm91bmQudHMnO1xuaW1wb3J0IHsgYWRkVG9RdWV1ZSB9IGZyb20gJy4vUXVldWUudHMnO1xuaW1wb3J0IHtcbiAgZ2V0U2FmZVJlbmFtZVBhdGgsXG4gIHJlbmFtZVNhZmVcbn0gZnJvbSAnLi9WYXVsdC50cyc7XG5pbXBvcnQge1xuICBkZWxldGVFbXB0eUZvbGRlcixcbiAgZGVsZXRlRW1wdHlGb2xkZXJIaWVyYXJjaHksXG4gIGRlbGV0ZVNhZmVcbn0gZnJvbSAnLi9WYXVsdEV4LnRzJztcblxuLyoqXG4gKiBBIGJlaGF2aW9yIG9mIHRoZSByZW5hbWUvZGVsZXRlIGhhbmRsZXIgd2hlbiBkZWxldGluZyBlbXB0eSBhdHRhY2htZW50IGZvbGRlcnMuXG4gKi9cbmV4cG9ydCBlbnVtIEVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yIHtcbiAgLyoqXG4gICAqIERlbGV0ZSB0aGUgZW1wdHkgYXR0YWNobWVudCBmb2xkZXIuXG4gICAqL1xuICBEZWxldGUgPSAnRGVsZXRlJyxcblxuICAvKipcbiAgICogRGVsZXRlIHRoZSBlbXB0eSBhdHRhY2htZW50IGZvbGRlciBhbmQgYWxsIGl0cyBlbXB0eSBwYXJlbnRzLlxuICAgKi9cbiAgRGVsZXRlV2l0aEVtcHR5UGFyZW50cyA9ICdEZWxldGVXaXRoRW1wdHlQYXJlbnRzJyxcblxuICAvKipcbiAgICogS2VlcCB0aGUgZW1wdHkgYXR0YWNobWVudCBmb2xkZXIuXG4gICAqL1xuICBLZWVwID0gJ0tlZXAnXG59XG5cbi8qKlxuICogU2V0dGluZ3MgZm9yIHRoZSByZW5hbWUvZGVsZXRlIGhhbmRsZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVuYW1lRGVsZXRlSGFuZGxlclNldHRpbmdzIHtcbiAgLyoqXG4gICAqIEEgYmVoYXZpb3Igb2YgdGhlIHJlbmFtZS9kZWxldGUgaGFuZGxlciB3aGVuIGRlbGV0aW5nIGVtcHR5IGF0dGFjaG1lbnQgZm9sZGVycy5cbiAgICovXG4gIGVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yOiBFbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvcjtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgcGF0aCBpcyBhIG5vdGUuXG4gICAqL1xuICBpc05vdGUocGF0aDogc3RyaW5nKTogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBpZ25vcmUgdGhlIHBhdGguXG4gICAqL1xuICBpc1BhdGhJZ25vcmVkKHBhdGg6IHN0cmluZyk6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZGVsZXRlIGNvbmZsaWN0aW5nIGF0dGFjaG1lbnRzLlxuICAgKi9cbiAgc2hvdWxkRGVsZXRlQ29uZmxpY3RpbmdBdHRhY2htZW50czogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBoYW5kbGUgZGVsZXRpb25zLlxuICAgKi9cbiAgc2hvdWxkSGFuZGxlRGVsZXRpb25zOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGhhbmRsZSByZW5hbWVzLlxuICAgKi9cbiAgc2hvdWxkSGFuZGxlUmVuYW1lczogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byByZW5hbWUgYXR0YWNobWVudCBmaWxlcyB3aGVuIGEgbm90ZSBpcyByZW5hbWVkLlxuICAgKi9cbiAgc2hvdWxkUmVuYW1lQXR0YWNobWVudEZpbGVzOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHJlbmFtZSBhdHRhY2htZW50IGZvbGRlciB3aGVuIGEgbm90ZSBpcyByZW5hbWVkLlxuICAgKi9cbiAgc2hvdWxkUmVuYW1lQXR0YWNobWVudEZvbGRlcjogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byB1cGRhdGUgZmlsZSBuYW1lIGFsaWFzZXMgd2hlbiBhIG5vdGUgaXMgcmVuYW1lZC5cbiAgICovXG4gIHNob3VsZFVwZGF0ZUZpbGVOYW1lQWxpYXNlczogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIEFib3J0YWJsZVBsdWdpbiBleHRlbmRzIFBsdWdpbiB7XG4gIGFib3J0U2lnbmFsPzogQWJvcnRTaWduYWw7XG59XG5cbmludGVyZmFjZSBIYW5kbGVkUmVuYW1lS2V5IHtcbiAgbmV3UGF0aDogc3RyaW5nO1xuICBvbGRQYXRoOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBJbnRlcnJ1cHRlZFJlbmFtZSB7XG4gIGNvbWJpbmVkQmFja2xpbmtzTWFwOiBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBzdHJpbmc+PjtcbiAgb2xkUGF0aDogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgUmVuYW1lSGFuZGxlck9wdGlvbnMge1xuICBhYm9ydFNpZ25hbDogQWJvcnRTaWduYWw7XG4gIGFwcDogQXBwO1xuICBoYW5kbGVkUmVuYW1lczogSGFuZGxlZFJlbmFtZXM7XG4gIGludGVycnVwdGVkQ29tYmluZWRCYWNrbGlua3NNYXA/OiBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBzdHJpbmc+PjtcbiAgaW50ZXJydXB0ZWRSZW5hbWVzTWFwOiBNYXA8c3RyaW5nLCBJbnRlcnJ1cHRlZFJlbmFtZVtdPjtcbiAgbmV3UGF0aDogc3RyaW5nO1xuICBvbGRDYWNoZTogQ2FjaGVkTWV0YWRhdGEgfCBudWxsO1xuICBvbGRQYXRoOiBzdHJpbmc7XG4gIG9sZFBhdGhCYWNrbGlua3NNYXA6IE1hcDxzdHJpbmcsIFJlZmVyZW5jZVtdPjtcbiAgc2V0dGluZ3NNYW5hZ2VyOiBTZXR0aW5nc01hbmFnZXI7XG59XG5cbmludGVyZmFjZSBSZW5hbWVNYXBPcHRpb25zIHtcbiAgYWJvcnRTaWduYWw6IEFib3J0U2lnbmFsO1xuICBhcHA6IEFwcDtcbiAgbmV3UGF0aDogc3RyaW5nO1xuICBvbGRDYWNoZTogQ2FjaGVkTWV0YWRhdGEgfCBudWxsO1xuICBvbGRQYXRoOiBzdHJpbmc7XG4gIHNldHRpbmdzTWFuYWdlcjogU2V0dGluZ3NNYW5hZ2VyO1xufVxuXG50eXBlIFJ1bkFzeW5jTGlua1VwZGF0ZUZuID0geyByZW5hbWVEZWxldGVIYW5kbGVyUGF0Y2hlZD86IGJvb2xlYW4gfSAmIEZpbGVNYW5hZ2VyWydydW5Bc3luY0xpbmtVcGRhdGUnXTtcblxuY2xhc3MgRGVsZXRlSGFuZGxlciB7XG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFwcDogQXBwLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZmlsZTogVEFic3RyYWN0RmlsZSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFib3J0U2lnbmFsOiBBYm9ydFNpZ25hbCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNldHRpbmdzTWFuYWdlcjogU2V0dGluZ3NNYW5hZ2VyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZGVsZXRlZE1ldGFkYXRhQ2FjaGVNYXA6IE1hcDxzdHJpbmcsIENhY2hlZE1ldGFkYXRhPlxuICApIHtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBoYW5kbGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5hYm9ydFNpZ25hbC50aHJvd0lmQWJvcnRlZCgpO1xuICAgIGdldExpYkRlYnVnZ2VyKCdSZW5hbWVEZWxldGVIYW5kbGVyOmhhbmRsZURlbGV0ZScpKGBIYW5kbGUgRGVsZXRlICR7dGhpcy5maWxlLnBhdGh9YCk7XG4gICAgaWYgKCFpc05vdGUodGhpcy5hcHAsIHRoaXMuZmlsZSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzZXR0aW5ncyA9IHRoaXMuc2V0dGluZ3NNYW5hZ2VyLmdldFNldHRpbmdzKCk7XG4gICAgaWYgKCFzZXR0aW5ncy5zaG91bGRIYW5kbGVEZWxldGlvbnMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc2V0dGluZ3MuaXNQYXRoSWdub3JlZD8uKHRoaXMuZmlsZS5wYXRoKSkge1xuICAgICAgZ2V0TGliRGVidWdnZXIoJ1JlbmFtZURlbGV0ZUhhbmRsZXI6aGFuZGxlRGVsZXRlJykoYFNraXBwaW5nIGRlbGV0ZSBoYW5kbGVyIG9mICR7dGhpcy5maWxlLnBhdGh9IGFzIHRoZSBwYXRoIGlzIGlnbm9yZWQuYCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY2FjaGUgPSB0aGlzLmRlbGV0ZWRNZXRhZGF0YUNhY2hlTWFwLmdldCh0aGlzLmZpbGUucGF0aCk7XG4gICAgdGhpcy5kZWxldGVkTWV0YWRhdGFDYWNoZU1hcC5kZWxldGUodGhpcy5maWxlLnBhdGgpO1xuICAgIGNvbnN0IHBhcmVudEZvbGRlclBhdGhzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgaWYgKGNhY2hlKSB7XG4gICAgICBjb25zdCBsaW5rcyA9IGdldEFsbExpbmtzKGNhY2hlKTtcblxuICAgICAgZm9yIChjb25zdCBsaW5rIG9mIGxpbmtzKSB7XG4gICAgICAgIGNvbnN0IGF0dGFjaG1lbnRGaWxlID0gZXh0cmFjdExpbmtGaWxlKHRoaXMuYXBwLCBsaW5rLCB0aGlzLmZpbGUucGF0aCk7XG4gICAgICAgIGlmICghYXR0YWNobWVudEZpbGUpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnNldHRpbmdzTWFuYWdlci5pc05vdGVFeChhdHRhY2htZW50RmlsZS5wYXRoKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgcGFyZW50Rm9sZGVyUGF0aHMuYWRkKGF0dGFjaG1lbnRGaWxlLnBhcmVudD8ucGF0aCA/PyAnJyk7XG4gICAgICAgIGF3YWl0IGRlbGV0ZVNhZmUodGhpcy5hcHAsIGF0dGFjaG1lbnRGaWxlLCB0aGlzLmZpbGUucGF0aCwgZmFsc2UsIHNldHRpbmdzLmVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yICE9PSBFbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvci5LZWVwKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBhd2FpdCBjbGVhbnVwUGFyZW50Rm9sZGVycyh0aGlzLmFwcCwgdGhpcy5zZXR0aW5nc01hbmFnZXIuZ2V0U2V0dGluZ3MoKSwgQXJyYXkuZnJvbShwYXJlbnRGb2xkZXJQYXRocykpO1xuICAgIHRoaXMuYWJvcnRTaWduYWwudGhyb3dJZkFib3J0ZWQoKTtcblxuICAgIGNvbnN0IGF0dGFjaG1lbnRGb2xkZXJQYXRoID0gYXdhaXQgZ2V0QXR0YWNobWVudEZvbGRlclBhdGgodGhpcy5hcHAsIHRoaXMuZmlsZS5wYXRoLCBBdHRhY2htZW50UGF0aENvbnRleHQuRGVsZXRlTm90ZSk7XG4gICAgY29uc3QgYXR0YWNobWVudEZvbGRlciA9IGdldEZvbGRlck9yTnVsbCh0aGlzLmFwcCwgYXR0YWNobWVudEZvbGRlclBhdGgpO1xuXG4gICAgaWYgKCFhdHRhY2htZW50Rm9sZGVyKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCEoYXdhaXQgaGFzT3duQXR0YWNobWVudEZvbGRlcih0aGlzLmFwcCwgdGhpcy5maWxlLnBhdGgsIEF0dGFjaG1lbnRQYXRoQ29udGV4dC5EZWxldGVOb3RlKSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmFib3J0U2lnbmFsLnRocm93SWZBYm9ydGVkKCk7XG5cbiAgICBhd2FpdCBkZWxldGVTYWZlKHRoaXMuYXBwLCBhdHRhY2htZW50Rm9sZGVyLCB0aGlzLmZpbGUucGF0aCwgZmFsc2UsIHNldHRpbmdzLmVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yICE9PSBFbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvci5LZWVwKTtcbiAgICB0aGlzLmFib3J0U2lnbmFsLnRocm93SWZBYm9ydGVkKCk7XG4gIH1cbn1cblxuY2xhc3MgSGFuZGxlZFJlbmFtZXMge1xuICBwcml2YXRlIHJlYWRvbmx5IG1hcCA9IG5ldyBNYXA8c3RyaW5nLCBIYW5kbGVkUmVuYW1lS2V5PigpO1xuXG4gIHB1YmxpYyBhZGQob2xkUGF0aDogc3RyaW5nLCBuZXdQYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLm1hcC5zZXQodGhpcy5rZXlUb1N0cmluZyhvbGRQYXRoLCBuZXdQYXRoKSwgeyBuZXdQYXRoLCBvbGRQYXRoIH0pO1xuICB9XG5cbiAgcHVibGljIGRlbGV0ZShvbGRQYXRoOiBzdHJpbmcsIG5ld1BhdGg6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMubWFwLmRlbGV0ZSh0aGlzLmtleVRvU3RyaW5nKG9sZFBhdGgsIG5ld1BhdGgpKTtcbiAgfVxuXG4gIHB1YmxpYyBoYXMob2xkUGF0aDogc3RyaW5nLCBuZXdQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5tYXAuaGFzKHRoaXMua2V5VG9TdHJpbmcob2xkUGF0aCwgbmV3UGF0aCkpO1xuICB9XG5cbiAgcHVibGljIGtleXMoKTogSXRlcmFibGVJdGVyYXRvcjxIYW5kbGVkUmVuYW1lS2V5PiB7XG4gICAgcmV0dXJuIHRoaXMubWFwLnZhbHVlcygpO1xuICB9XG5cbiAgcHJpdmF0ZSBrZXlUb1N0cmluZyhvbGRQYXRoOiBzdHJpbmcsIG5ld1BhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke29sZFBhdGh9IC0+ICR7bmV3UGF0aH1gO1xuICB9XG59XG5cbmNsYXNzIE1ldGFkYXRhRGVsZXRlZEhhbmRsZXIge1xuICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBhcHA6IEFwcCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGZpbGU6IFRBYnN0cmFjdEZpbGUsXG4gICAgcHJpdmF0ZSByZWFkb25seSBwcmV2Q2FjaGU6IENhY2hlZE1ldGFkYXRhIHwgbnVsbCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNldHRpbmdzTWFuYWdlcjogU2V0dGluZ3NNYW5hZ2VyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZGVsZXRlZE1ldGFkYXRhQ2FjaGVNYXA6IE1hcDxzdHJpbmcsIENhY2hlZE1ldGFkYXRhPlxuICApIHtcbiAgfVxuXG4gIHB1YmxpYyBoYW5kbGUoKTogdm9pZCB7XG4gICAgY29uc3Qgc2V0dGluZ3MgPSB0aGlzLnNldHRpbmdzTWFuYWdlci5nZXRTZXR0aW5ncygpO1xuXG4gICAgaWYgKCFzZXR0aW5ncy5zaG91bGRIYW5kbGVEZWxldGlvbnMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc2V0dGluZ3MuaXNQYXRoSWdub3JlZD8uKHRoaXMuZmlsZS5wYXRoKSkge1xuICAgICAgZ2V0TGliRGVidWdnZXIoJ1JlbmFtZURlbGV0ZUhhbmRsZXI6aGFuZGxlTWV0YWRhdGFEZWxldGVkJykoYFNraXBwaW5nIG1ldGFkYXRhIGRlbGV0ZSBoYW5kbGVyIG9mICR7dGhpcy5maWxlLnBhdGh9IGFzIHRoZSBwYXRoIGlzIGlnbm9yZWQuYCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTWFya2Rvd25GaWxlKHRoaXMuYXBwLCB0aGlzLmZpbGUpICYmIHRoaXMucHJldkNhY2hlKSB7XG4gICAgICB0aGlzLmRlbGV0ZWRNZXRhZGF0YUNhY2hlTWFwLnNldCh0aGlzLmZpbGUucGF0aCwgdGhpcy5wcmV2Q2FjaGUpO1xuICAgIH1cbiAgfVxufVxuXG5jbGFzcyBSZWdpc3RyeSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYWJvcnRTaWduYWw6IEFib3J0U2lnbmFsO1xuICBwcml2YXRlIHJlYWRvbmx5IGFwcDogQXBwO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlbGV0ZWRNZXRhZGF0YUNhY2hlTWFwID0gbmV3IE1hcDxzdHJpbmcsIENhY2hlZE1ldGFkYXRhPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGhhbmRsZWRSZW5hbWVzID0gbmV3IEhhbmRsZWRSZW5hbWVzKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgaW50ZXJydXB0ZWRSZW5hbWVzTWFwID0gbmV3IE1hcDxzdHJpbmcsIEludGVycnVwdGVkUmVuYW1lW10+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgcGx1Z2luSWQ6IHN0cmluZztcblxuICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBwbHVnaW46IEFib3J0YWJsZVBsdWdpbixcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNldHRpbmdzQnVpbGRlcjogKCkgPT4gUGFydGlhbDxSZW5hbWVEZWxldGVIYW5kbGVyU2V0dGluZ3M+LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc2V0dGluZ3NNYW5hZ2VyOiBTZXR0aW5nc01hbmFnZXJcbiAgKSB7XG4gICAgdGhpcy5hcHAgPSBwbHVnaW4uYXBwO1xuICAgIHRoaXMucGx1Z2luSWQgPSBwbHVnaW4ubWFuaWZlc3QuaWQ7XG4gICAgdGhpcy5hYm9ydFNpZ25hbCA9IHBsdWdpbi5hYm9ydFNpZ25hbCA/PyBhYm9ydFNpZ25hbE5ldmVyKCk7XG4gIH1cblxuICBwdWJsaWMgcmVnaXN0ZXIoKTogdm9pZCB7XG4gICAgY29uc3QgcmVuYW1lRGVsZXRlSGFuZGxlcnNNYXAgPSB0aGlzLnNldHRpbmdzTWFuYWdlci5yZW5hbWVEZWxldGVIYW5kbGVyc01hcDtcblxuICAgIHJlbmFtZURlbGV0ZUhhbmRsZXJzTWFwLnNldCh0aGlzLnBsdWdpbklkLCB0aGlzLnNldHRpbmdzQnVpbGRlcik7XG4gICAgdGhpcy5sb2dSZWdpc3RlcmVkSGFuZGxlcnMoKTtcblxuICAgIHRoaXMucGx1Z2luLnJlZ2lzdGVyKCgpID0+IHtcbiAgICAgIHJlbmFtZURlbGV0ZUhhbmRsZXJzTWFwLmRlbGV0ZSh0aGlzLnBsdWdpbklkKTtcbiAgICAgIHRoaXMubG9nUmVnaXN0ZXJlZEhhbmRsZXJzKCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnBsdWdpbi5yZWdpc3RlckV2ZW50KHRoaXMuYXBwLnZhdWx0Lm9uKCdkZWxldGUnLCB0aGlzLmhhbmRsZURlbGV0ZS5iaW5kKHRoaXMpKSk7XG4gICAgdGhpcy5wbHVnaW4ucmVnaXN0ZXJFdmVudCh0aGlzLmFwcC52YXVsdC5vbigncmVuYW1lJywgdGhpcy5oYW5kbGVSZW5hbWUuYmluZCh0aGlzKSkpO1xuICAgIHRoaXMucGx1Z2luLnJlZ2lzdGVyRXZlbnQodGhpcy5hcHAubWV0YWRhdGFDYWNoZS5vbignZGVsZXRlZCcsIHRoaXMuaGFuZGxlTWV0YWRhdGFEZWxldGVkLmJpbmQodGhpcykpKTtcblxuICAgIHJlZ2lzdGVyUGF0Y2godGhpcy5wbHVnaW4sIHRoaXMuYXBwLmZpbGVNYW5hZ2VyLCB7XG4gICAgICBydW5Bc3luY0xpbmtVcGRhdGU6IChuZXh0OiBSdW5Bc3luY0xpbmtVcGRhdGVGbik6IFJ1bkFzeW5jTGlua1VwZGF0ZUZuID0+IHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oKGxpbmtVcGRhdGVzSGFuZGxlcikgPT4gdGhpcy5ydW5Bc3luY0xpbmtVcGRhdGUobmV4dCwgbGlua1VwZGF0ZXNIYW5kbGVyKSwgeyByZW5hbWVEZWxldGVIYW5kbGVyUGF0Y2hlZDogdHJ1ZSB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlRGVsZXRlKGZpbGU6IFRBYnN0cmFjdEZpbGUpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuc2hvdWxkSW52b2tlSGFuZGxlcigpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGFkZFRvUXVldWUoe1xuICAgICAgYXBwOiB0aGlzLmFwcCxcbiAgICAgIG9wZXJhdGlvbkZuOiAoYWJvcnRTaWduYWwpID0+IG5ldyBEZWxldGVIYW5kbGVyKHRoaXMuYXBwLCBmaWxlLCBhYm9ydFNpZ25hbCwgdGhpcy5zZXR0aW5nc01hbmFnZXIsIHRoaXMuZGVsZXRlZE1ldGFkYXRhQ2FjaGVNYXApLmhhbmRsZSgpLFxuICAgICAgb3BlcmF0aW9uTmFtZTogdCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnJlbmFtZURlbGV0ZUhhbmRsZXIuaGFuZGxlRGVsZXRlLCB7IGZpbGVQYXRoOiBmaWxlLnBhdGggfSlcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlTWV0YWRhdGFEZWxldGVkKGZpbGU6IFRBYnN0cmFjdEZpbGUsIHByZXZDYWNoZTogQ2FjaGVkTWV0YWRhdGEgfCBudWxsKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnNob3VsZEludm9rZUhhbmRsZXIoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBuZXcgTWV0YWRhdGFEZWxldGVkSGFuZGxlcih0aGlzLmFwcCwgZmlsZSwgcHJldkNhY2hlLCB0aGlzLnNldHRpbmdzTWFuYWdlciwgdGhpcy5kZWxldGVkTWV0YWRhdGFDYWNoZU1hcCkuaGFuZGxlKCk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZVJlbmFtZShmaWxlOiBUQWJzdHJhY3RGaWxlLCBvbGRQYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuc2hvdWxkSW52b2tlSGFuZGxlcigpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFpc0ZpbGUoZmlsZSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBuZXdQYXRoID0gZmlsZS5wYXRoO1xuXG4gICAgZ2V0TGliRGVidWdnZXIoJ1JlbmFtZURlbGV0ZUhhbmRsZXI6aGFuZGxlUmVuYW1lJykoYEhhbmRsZSBSZW5hbWUgJHtvbGRQYXRofSAtPiAke25ld1BhdGh9YCk7XG4gICAgaWYgKHRoaXMuaGFuZGxlZFJlbmFtZXMuaGFzKG9sZFBhdGgsIG5ld1BhdGgpKSB7XG4gICAgICB0aGlzLmhhbmRsZWRSZW5hbWVzLmRlbGV0ZShvbGRQYXRoLCBuZXdQYXRoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzZXR0aW5ncyA9IHRoaXMuc2V0dGluZ3NNYW5hZ2VyLmdldFNldHRpbmdzKCk7XG4gICAgaWYgKCFzZXR0aW5ncy5zaG91bGRIYW5kbGVSZW5hbWVzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNldHRpbmdzLmlzUGF0aElnbm9yZWQ/LihvbGRQYXRoKSkge1xuICAgICAgZ2V0TGliRGVidWdnZXIoJ1JlbmFtZURlbGV0ZUhhbmRsZXI6aGFuZGxlUmVuYW1lJykoYFNraXBwaW5nIHJlbmFtZSBoYW5kbGVyIG9mIG9sZCBwYXRoICR7b2xkUGF0aH0gYXMgdGhlIHBhdGggaXMgaWdub3JlZC5gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc2V0dGluZ3MuaXNQYXRoSWdub3JlZD8uKG5ld1BhdGgpKSB7XG4gICAgICBnZXRMaWJEZWJ1Z2dlcignUmVuYW1lRGVsZXRlSGFuZGxlcjpoYW5kbGVSZW5hbWUnKShgU2tpcHBpbmcgcmVuYW1lIGhhbmRsZXIgb2YgbmV3IHBhdGggJ