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
JavaScript
/*
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