You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
132 KiB

3 years ago
'use strict';
var obsidian = require('obsidian');
3 years ago
/******************************************************************************
3 years ago
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
/** @deprecated */
function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
var DeleteFilesModal = /** @class */ (function (_super) {
__extends(DeleteFilesModal, _super);
function DeleteFilesModal(app, filesToDelete) {
var _this = _super.call(this, app) || this;
_this.filesToDelete = filesToDelete;
return _this;
}
DeleteFilesModal.prototype.onOpen = function () {
var _this = this;
var _a = this, contentEl = _a.contentEl, titleEl = _a.titleEl;
titleEl.setText('Move ' + this.filesToDelete.length + ' files to system trash?');
contentEl
.createEl("button", { text: "Cancel" })
.addEventListener("click", function () { return _this.close(); });
contentEl
.setAttr("margin", "auto");
contentEl
.createEl("button", {
cls: "mod-cta",
text: "Confirm"
})
.addEventListener("click", function () { return __awaiter(_this, void 0, void 0, function () {
var _i, _a, file;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_i = 0, _a = this.filesToDelete;
_b.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
file = _a[_i];
return [4 /*yield*/, this.app.vault.trash(file, true)];
case 2:
_b.sent();
_b.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
case 4:
this.close();
return [2 /*return*/];
}
});
}); });
};
DeleteFilesModal.prototype.onClose = function () {
var contentEl = this.contentEl;
contentEl.empty();
};
return DeleteFilesModal;
}(obsidian.Modal));
var SettingsTab = /** @class */ (function (_super) {
__extends(SettingsTab, _super);
function SettingsTab(app, plugin, defaultSettings) {
var _this = _super.call(this, app, plugin) || this;
_this.defaultSettings = defaultSettings;
_this.plugin = plugin;
return _this;
}
3 years ago
// Add trailing slash to catch files named like the directory. See https://github.com/Vinzent03/find-unlinked-files/issues/24
3 years ago
SettingsTab.prototype.formatPath = function (path, addDirectorySlash) {
if (path.length == 0)
return path;
path = obsidian.normalizePath(path);
if (addDirectorySlash)
return path + "/";
else
return path;
};
SettingsTab.prototype.display = function () {
var _this = this;
var containerEl = this.containerEl;
containerEl.empty();
containerEl.createEl("h2", { text: this.plugin.manifest.name });
2 years ago
containerEl.createEl("h4", { text: "Settings for finding orphaned files" });
new obsidian.Setting(containerEl)
.setName("Open output file")
.addToggle(function (cb) {
return cb.setValue(_this.plugin.settings.openOutputFile)
.onChange(function (value) {
_this.plugin.settings.openOutputFile = value;
_this.plugin.saveSettings();
});
});
3 years ago
new obsidian.Setting(containerEl)
.setName('Output file name')
.setDesc('Set name of output file (without file extension). Make sure no file exists with this name because it will be overwritten! If the name is empty, the default name is set.')
.addText(function (cb) { return cb.onChange(function (value) {
if (value.length == 0) {
_this.plugin.settings.outputFileName = _this.defaultSettings.outputFileName;
}
else {
_this.plugin.settings.outputFileName = value;
}
_this.plugin.saveSettings();
}).setValue(_this.plugin.settings.outputFileName); });
new obsidian.Setting(containerEl)
.setName('Disable working links')
.setDesc('Indent lines to disable the link and to clean up the graph view')
.addToggle(function (cb) { return cb.onChange(function (value) {
_this.plugin.settings.disableWorkingLinks = value;
_this.plugin.saveSettings();
}).setValue(_this.plugin.settings.disableWorkingLinks); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude files in the given directories")
.setDesc("Enable to exclude files in the given directories. Disable to only include files in the given directories")
3 years ago
.addToggle(function (cb) {
return cb.setValue(_this.plugin.settings.ignoreDirectories)
.onChange(function (value) {
_this.plugin.settings.ignoreDirectories = value;
_this.plugin.saveSettings();
});
});
new obsidian.Setting(containerEl)
.setName("Directories")
.setDesc("Add each directory path in a new line")
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/Subdirectory")
.setValue(_this.plugin.settings.directoriesToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, true); });
_this.plugin.settings.directoriesToIgnore = paths;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude files")
3 years ago
.setDesc("Add each file path in a new line (with file extension!)")
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/file.md")
.setValue(_this.plugin.settings.filesToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, false); });
_this.plugin.settings.filesToIgnore = paths;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude links")
.setDesc("Exclude files, which contain the given file as link. Add each file path in a new line (with file extension!). Set it to `*` to exclude files with links.")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/file.md")
.setValue(_this.plugin.settings.linksToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, false); });
_this.plugin.settings.linksToIgnore = paths;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude files with the given filetypes")
.setDesc("Enable to exclude files with the given filetypes. Disable to only include files with the given filetypes")
3 years ago
.addToggle(function (cb) {
return cb.setValue(_this.plugin.settings.ignoreFileTypes)
.onChange(function (value) {
_this.plugin.settings.ignoreFileTypes = value;
_this.plugin.saveSettings();
});
});
new obsidian.Setting(containerEl)
.setName("File types")
.setDesc("Effect depends on toggle above")
.addTextArea(function (cb) { return cb
.setPlaceholder("docx,txt")
.setValue(_this.plugin.settings.fileTypesToIgnore.join(","))
.onChange(function (value) {
var extensions = value.trim().split(",");
_this.plugin.settings.fileTypesToIgnore = extensions;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude tags")
.setDesc("Exclude files, which contain the given tag. Add each tag separated by comma (without `#`)")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("todo,unfinished")
.setValue(_this.plugin.settings.tagsToIgnore.join(","))
.onChange(function (value) {
var tags = value.trim().split(",");
_this.plugin.settings.tagsToIgnore = tags;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
.setName("Filetypes to delete per command. See README.")
.setDesc("Add each filetype separated by comma. Set to `*` to delete all files.")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("jpg,png")
.setValue(_this.plugin.settings.fileTypesToDelete.join(","))
.onChange(function (value) {
var extensions = value.trim().split(",");
_this.plugin.settings.fileTypesToDelete = extensions;
_this.plugin.saveSettings();
}); });
2 years ago
/// Settings for find brokenLinks
containerEl.createEl("h4", { text: "Settings for finding broken links" });
3 years ago
new obsidian.Setting(containerEl)
.setName('Output file name')
.setDesc('Set name of output file (without file extension). Make sure no file exists with this name because it will be overwritten! If the name is empty, the default name is set.')
.addText(function (cb) { return cb.onChange(function (value) {
if (value.length == 0) {
_this.plugin.settings.unresolvedLinksOutputFileName = _this.defaultSettings.unresolvedLinksOutputFileName;
}
else {
_this.plugin.settings.unresolvedLinksOutputFileName = value;
}
_this.plugin.saveSettings();
}).setValue(_this.plugin.settings.unresolvedLinksOutputFileName); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude directories")
.setDesc("Exclude links in files in the specified directory. Add each directory path in a new line")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/Subdirectory")
.setValue(_this.plugin.settings.unresolvedLinksDirectoriesToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, true); });
_this.plugin.settings.unresolvedLinksDirectoriesToIgnore = paths;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude files")
.setDesc("Exclude links in the specified file. Add each file path in a new line (with file extension!)")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/file.md")
.setValue(_this.plugin.settings.unresolvedLinksFilesToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, false); });
_this.plugin.settings.unresolvedLinksFilesToIgnore = paths;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude links")
.setDesc("Exclude files, which contain the given file as link. Add each file path in a new line (with file extension!). Set it to `*` to exclude files with links.")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/file.md")
.setValue(_this.plugin.settings.unresolvedLinksLinksToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, false); });
_this.plugin.settings.unresolvedLinksLinksToIgnore = paths;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude filetypes")
.setDesc("Exclude links with the specified filetype. Add each filetype separated by comma")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("docx,txt")
.setValue(_this.plugin.settings.unresolvedLinksFileTypesToIgnore.join(","))
.onChange(function (value) {
var extensions = value.trim().split(",");
_this.plugin.settings.unresolvedLinksFileTypesToIgnore = extensions;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude tags")
.setDesc("Exclude links in files, which contain the given tag. Add each tag separated by comma (without `#`)")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("todo,unfinished")
.setValue(_this.plugin.settings.unresolvedLinksTagsToIgnore.join(","))
.onChange(function (value) {
var tags = value.trim().split(",");
_this.plugin.settings.unresolvedLinksTagsToIgnore = tags;
_this.plugin.saveSettings();
}); });
2 years ago
containerEl.createEl("h4", { text: "Settings for finding files without tags" });
3 years ago
new obsidian.Setting(containerEl)
.setName('Output file name')
.setDesc('Set name of output file (without file extension). Make sure no file exists with this name because it will be overwritten! If the name is empty, the default name is set.')
.addText(function (cb) { return cb.onChange(function (value) {
if (value.length == 0) {
_this.plugin.settings.withoutTagsOutputFileName = _this.defaultSettings.withoutTagsOutputFileName;
}
else {
_this.plugin.settings.withoutTagsOutputFileName = value;
}
_this.plugin.saveSettings();
}).setValue(_this.plugin.settings.withoutTagsOutputFileName); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude files")
.setDesc("Exclude the specific files. Add each file path in a new line (with file extension!)")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/file.md")
.setValue(_this.plugin.settings.withoutTagsFilesToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, false); });
_this.plugin.settings.withoutTagsFilesToIgnore = paths;
_this.plugin.saveSettings();
}); });
new obsidian.Setting(containerEl)
2 years ago
.setName("Exclude directories")
.setDesc("Exclude files in the specified directories. Add each directory path in a new line")
3 years ago
.addTextArea(function (cb) { return cb
.setPlaceholder("Directory/Subdirectory")
.setValue(_this.plugin.settings.withoutTagsDirectoriesToIgnore.join("\n"))
.onChange(function (value) {
var paths = value.trim().split("\n").map(function (value) { return _this.formatPath(value, true); });
_this.plugin.settings.withoutTagsDirectoriesToIgnore = paths;
_this.plugin.saveSettings();
}); });
};
return SettingsTab;
}(obsidian.PluginSettingTab));
var Utils = /** @class */ (function () {
/**
2 years ago
* Checks for the given settings. Is used for `Find orphaned files` and `Find broken links`
3 years ago
* @param app
* @param filePath
* @param tagsToIgnore
* @param linksToIgnore
* @param directoriesToIgnore
* @param filesToIgnore
* @param ignoreDirectories
*/
function Utils(app, filePath, tagsToIgnore, linksToIgnore, directoriesToIgnore, filesToIgnore, ignoreDirectories, dir) {
3 years ago
if (ignoreDirectories === void 0) { ignoreDirectories = true; }
this.app = app;
this.filePath = filePath;
this.tagsToIgnore = tagsToIgnore;
this.linksToIgnore = linksToIgnore;
this.directoriesToIgnore = directoriesToIgnore;
this.filesToIgnore = filesToIgnore;
this.ignoreDirectories = ignoreDirectories;
this.dir = dir;
3 years ago
this.fileCache = app.metadataCache.getCache(filePath);
}
Utils.prototype.hasTagsToIgnore = function () {
var _this = this;
var tags = obsidian.getAllTags(this.fileCache);
return (tags === null || tags === void 0 ? void 0 : tags.find(function (tag) { return _this.tagsToIgnore.contains(tag.substring(1)); })) !== undefined;
};
Utils.prototype.hasLinksToIgnore = function () {
var _this = this;
var _a, _b;
if ((((_a = this.fileCache) === null || _a === void 0 ? void 0 : _a.embeds) != null || ((_b = this.fileCache) === null || _b === void 0 ? void 0 : _b.links) != null) && this.linksToIgnore[0] == "*") {
return true;
}
return obsidian.iterateCacheRefs(this.fileCache, function (cb) {
var _a;
var link = (_a = _this.app.metadataCache.getFirstLinkpathDest(cb.link, _this.filePath)) === null || _a === void 0 ? void 0 : _a.path;
return _this.linksToIgnore.contains(link);
});
};
Utils.prototype.checkDirectory = function () {
var _this = this;
if (this.dir) {
if (!this.filePath.startsWith(this.dir)) {
return true;
}
}
var contains = this.directoriesToIgnore.find(function (value) { return value.length != 0 && _this.filePath.startsWith(value); }) !== undefined;
3 years ago
if (this.ignoreDirectories) {
return contains;
}
else {
return !contains;
}
};
Utils.prototype.isFileToIgnore = function () {
return this.filesToIgnore.contains(this.filePath);
};
Utils.prototype.isValid = function () {
return !this.hasTagsToIgnore() && !this.hasLinksToIgnore() && !this.checkDirectory() && !this.isFileToIgnore();
};
/**
* Writes the text to the file and opens the file in a new pane if it is not opened yet
* @param app
* @param outputFileName name of the output file
* @param text data to be written to the file
*/
2 years ago
Utils.writeAndOpenFile = function (app, outputFileName, text, openFile) {
3 years ago
return __awaiter(this, void 0, void 0, function () {
var fileIsAlreadyOpened, newPane, file;
3 years ago
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, app.vault.adapter.write(outputFileName, text)];
case 1:
_a.sent();
2 years ago
if (!openFile)
return [2 /*return*/];
3 years ago
fileIsAlreadyOpened = false;
app.workspace.iterateAllLeaves(function (leaf) {
if (leaf.getDisplayText() != "" && outputFileName.startsWith(leaf.getDisplayText())) {
fileIsAlreadyOpened = true;
}
});
if (!!fileIsAlreadyOpened) return [3 /*break*/, 5];
newPane = app.workspace.getLeavesOfType("empty").length == 0;
if (!newPane) return [3 /*break*/, 2];
app.workspace.openLinkText(outputFileName, "/", true);
return [3 /*break*/, 5];
case 2:
file = app.vault.getAbstractFileByPath(outputFileName);
if (!(file instanceof obsidian.TFile)) return [3 /*break*/, 4];
return [4 /*yield*/, app.workspace.getLeavesOfType("empty")[0].openFile(file)];
case 3:
_a.sent();
return [3 /*break*/, 5];
case 4:
app.workspace.openLinkText(outputFileName, "/", true);
_a.label = 5;
case 5: return [2 /*return*/];
3 years ago
}
});
});
};
return Utils;
}());
var DEFAULT_SETTINGS = {
2 years ago
outputFileName: "orphaned files output",
3 years ago
disableWorkingLinks: false,
directoriesToIgnore: [],
filesToIgnore: [],
fileTypesToIgnore: [],
linksToIgnore: [],
tagsToIgnore: [],
fileTypesToDelete: [],
ignoreFileTypes: true,
ignoreDirectories: true,
2 years ago
unresolvedLinksOutputFileName: "broken links output",
3 years ago
unresolvedLinksDirectoriesToIgnore: [],
unresolvedLinksFilesToIgnore: [],
unresolvedLinksFileTypesToIgnore: [],
unresolvedLinksLinksToIgnore: [],
unresolvedLinksTagsToIgnore: [],
withoutTagsDirectoriesToIgnore: [],
withoutTagsFilesToIgnore: [],
2 years ago
withoutTagsOutputFileName: "files without tags",
openOutputFile: true,
3 years ago
};
2 years ago
var FindOrphanedFilesPlugin = /** @class */ (function (_super) {
__extends(FindOrphanedFilesPlugin, _super);
function FindOrphanedFilesPlugin() {
3 years ago
return _super !== null && _super.apply(this, arguments) || this;
}
2 years ago
FindOrphanedFilesPlugin.prototype.onload = function () {
3 years ago
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log('loading ' + this.manifest.name + " plugin");
return [4 /*yield*/, this.loadSettings()];
case 1:
_a.sent();
this.addCommand({
id: 'find-unlinked-files',
2 years ago
name: 'Find orphaned files',
callback: function () { return _this.findOrphanedFiles(); },
3 years ago
});
this.addCommand({
id: 'find-unresolved-link',
2 years ago
name: 'Find broken links',
callback: function () { return _this.findBrokenLinks(); },
3 years ago
});
this.addCommand({
id: "delete-unlinked-files",
2 years ago
name: "Delete orphaned files with certain extension. See README",
callback: function () { return _this.deleteOrphanedFiles(); }
3 years ago
});
this.addCommand({
id: "find-files-without-tags",
name: "Find files without tags",
callback: function () { return _this.findFilesWithoutTags(); }
});
this.addSettingTab(new SettingsTab(this.app, this, DEFAULT_SETTINGS));
this.app.workspace.on("file-menu", function (menu, file, source, leaf) {
if (file instanceof obsidian.TFolder) {
menu.addItem(function (cb) {
cb.setIcon("search");
2 years ago
cb.setTitle("Find orphaned files");
3 years ago
// Add trailing slash to catch files named like the directory. See https://github.com/Vinzent03/find-unlinked-files/issues/24
2 years ago
cb.onClick(function (e) { _this.findOrphanedFiles(file.path + "/"); });
});
}
});
3 years ago
return [2 /*return*/];
}
});
});
};
2 years ago
FindOrphanedFilesPlugin.prototype.findOrphanedFiles = function (dir) {
3 years ago
var _this = this;
var outFileName = this.settings.outputFileName + ".md";
var outFile;
var files = this.app.vault.getFiles();
var markdownFiles = this.app.vault.getMarkdownFiles();
var links = [];
markdownFiles.forEach(function (markFile) {
if (markFile.path == outFileName) {
outFile = markFile;
return;
}
obsidian.iterateCacheRefs(_this.app.metadataCache.getFileCache(markFile), function (cb) {
var txt = _this.app.metadataCache.getFirstLinkpathDest(obsidian.getLinkpath(cb.link), markFile.path);
if (txt != null)
links.push(txt.path);
});
});
var notLinkedFiles = files.filter(function (file) { return _this.isValid(file, links, dir); });
3 years ago
notLinkedFiles.remove(outFile);
var text = "";
var prefix;
if (this.settings.disableWorkingLinks)
prefix = " ";
else
prefix = "";
notLinkedFiles.forEach(function (file) {
3 years ago
text += prefix + "- [[" + _this.app.metadataCache.fileToLinktext(file, "/", false) + "]]\n";
3 years ago
});
2 years ago
Utils.writeAndOpenFile(this.app, outFileName, text, this.settings.openOutputFile);
3 years ago
};
2 years ago
FindOrphanedFilesPlugin.prototype.deleteOrphanedFiles = function () {
3 years ago
var _a, _b;
return __awaiter(this, void 0, void 0, function () {
var links, filesToDelete;
var _this = this;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, this.app.vault.adapter.exists(this.settings.outputFileName + ".md")];
case 1:
if (!(_c.sent())) {
2 years ago
new obsidian.Notice("Can't find file - Please run the `Find orphaned files' command before");
3 years ago
return [2 /*return*/];
}
links = (_b = (_a = this.app.metadataCache.getCache(this.settings.outputFileName + ".md")) === null || _a === void 0 ? void 0 : _a.links) !== null && _b !== void 0 ? _b : [];
filesToDelete = [];
console.log(this.settings.fileTypesToDelete);
3 years ago
links.forEach(function (link) {
var file = _this.app.metadataCache.getFirstLinkpathDest(link.link, "/");
if (!file)
return;
if (_this.settings.fileTypesToDelete[0] == "*" || _this.settings.fileTypesToDelete.contains(file.extension)) {
3 years ago
filesToDelete.push(file);
}
});
if (filesToDelete.length > 0)
new DeleteFilesModal(this.app, filesToDelete).open();
return [2 /*return*/];
}
});
});
};
2 years ago
FindOrphanedFilesPlugin.prototype.findBrokenLinks = function () {
3 years ago
var outFileName = this.settings.unresolvedLinksOutputFileName + ".md";
var links = [];
2 years ago
var brokenLinks = this.app.metadataCache.unresolvedLinks;
for (var filePath in brokenLinks) {
3 years ago
if (filePath == this.settings.unresolvedLinksOutputFileName + ".md")
continue;
var fileType = filePath.substring(filePath.lastIndexOf(".") + 1);
var utils = new Utils(this.app, filePath, this.settings.unresolvedLinksTagsToIgnore, this.settings.unresolvedLinksLinksToIgnore, this.settings.unresolvedLinksDirectoriesToIgnore, this.settings.unresolvedLinksFilesToIgnore);
if (!utils.isValid())
continue;
var _loop_1 = function (link) {
var linkFileType = link.substring(link.lastIndexOf(".") + 1);
console.log(linkFileType);
if (this_1.settings.unresolvedLinksFileTypesToIgnore.contains(linkFileType))
return "continue";
var formattedFilePath = filePath;
if (fileType == "md") {
formattedFilePath = filePath.substring(0, filePath.lastIndexOf(".md"));
}
2 years ago
var brokenLink = { files: [formattedFilePath], link: link };
if (links.contains(brokenLink))
3 years ago
return "continue";
var duplication = links.find(function (e) { return e.link == link; });
if (duplication) {
duplication.files.push(formattedFilePath);
}
else {
2 years ago
links.push(brokenLink);
3 years ago
}
};
var this_1 = this;
2 years ago
for (var link in brokenLinks[filePath]) {
3 years ago
_loop_1(link);
}
}
Utils.writeAndOpenFile(this.app, outFileName, __spreadArrays([
"Don't forget that creating the file from here may create the file in the wrong directory!"
2 years ago
], links.map(function (e) { return "- [[" + e.link + "]] in [[" + e.files.join("]], [[") + "]]"; })).join("\n"), this.settings.openOutputFile);
3 years ago
};
2 years ago
FindOrphanedFilesPlugin.prototype.findFilesWithoutTags = function () {
3 years ago
var _this = this;
var outFileName = this.settings.withoutTagsOutputFileName + ".md";
var outFile;
var files = this.app.vault.getMarkdownFiles();
var withoutFiles = files.filter(function (file) {
var _a;
if (new Utils(_this.app, file.path, [], [], _this.settings.withoutTagsDirectoriesToIgnore, _this.settings.withoutTagsFilesToIgnore, true).isValid()) {
return ((_a = obsidian.getAllTags(_this.app.metadataCache.getFileCache(file)).length) !== null && _a !== void 0 ? _a : 0) <= 0;
}
else {
return false;
}
});
withoutFiles.remove(outFile);
var prefix;
if (this.settings.disableWorkingLinks)
prefix = " ";
else
prefix = "";
var text = withoutFiles.map(function (file) { return prefix + "- [[" + file.path + "]]"; }).join("\n");
2 years ago
Utils.writeAndOpenFile(this.app, outFileName, text, this.settings.openOutputFile);
3 years ago
};
/**
2 years ago
* Checks if the given file in an orphaned file
3 years ago
*
* @param file file to check
* @param links all links in the vault
*/
2 years ago
FindOrphanedFilesPlugin.prototype.isValid = function (file, links, dir) {
3 years ago
if (links.contains(file.path))
return false;
//filetypes to ignore by default
if (file.extension == "css")
return false;
if (this.settings.fileTypesToIgnore[0] !== "") {
var containsFileType = this.settings.fileTypesToIgnore.contains(file.extension);
if (this.settings.ignoreFileTypes) {
if (containsFileType)
return;
}
else {
if (!containsFileType)
return;
}
}
var utils = new Utils(this.app, file.path, this.settings.tagsToIgnore, this.settings.linksToIgnore, this.settings.directoriesToIgnore, this.settings.filesToIgnore, this.settings.ignoreDirectories, dir);
3 years ago
if (!utils.isValid())
return false;
return true;
};
2 years ago
FindOrphanedFilesPlugin.prototype.onunload = function () {
3 years ago
console.log('unloading ' + this.manifest.name + " plugin");
};
2 years ago
FindOrphanedFilesPlugin.prototype.loadSettings = function () {
3 years ago
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
_a = this;
_c = (_b = Object).assign;
_d = [DEFAULT_SETTINGS];
return [4 /*yield*/, this.loadData()];
case 1:
_a.settings = _c.apply(_b, _d.concat([_e.sent()]));
return [2 /*return*/];
}
});
});
};
2 years ago
FindOrphanedFilesPlugin.prototype.saveSettings = function () {
3 years ago
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.saveData(this.settings)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
2 years ago
return FindOrphanedFilesPlugin;
3 years ago
}(obsidian.Plugin));
2 years ago
module.exports = FindOrphanedFilesPlugin;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInNyYy9kZWxldGVGaWxlc01vZGFsLnRzIiwic3JjL3NldHRpbmdzVGFiLnRzIiwic3JjL3V0aWxzLnRzIiwic3JjL21haW4udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi5cclxuXHJcblBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGFuZC9vciBkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUgZm9yIGFueVxyXG5wdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQuXHJcblxyXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiIEFORCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIXHJcblJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWVxyXG5BTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsXHJcbklORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTVxyXG5MT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUlxyXG5PVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SXHJcblBFUkZPUk1BTkNFIE9GIFRISVMgU09GVFdBUkUuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGIsIHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBpZiAodHlwZW9mIGIgIT09IFwiZnVuY3Rpb25cIiAmJiBiICE9PSBudWxsKVxyXG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDbGFzcyBleHRlbmRzIHZhbHVlIFwiICsgU3RyaW5nKGIpICsgXCIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbFwiKTtcclxuICAgIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbiAgICBmdW5jdGlvbiBfXygpIHsgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7IH1cclxuICAgIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTtcclxufVxyXG5cclxuZXhwb3J0IHZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gX19hc3NpZ24uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVzdChzLCBlKSB7XHJcbiAgICB2YXIgdCA9IHt9O1xyXG4gICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApICYmIGUuaW5kZXhPZihwKSA8IDApXHJcbiAgICAgICAgdFtwXSA9IHNbcF07XHJcbiAgICBpZiAocyAhPSBudWxsICYmIHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzID09PSBcImZ1bmN0aW9uXCIpXHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIHAgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHMpOyBpIDwgcC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMCAmJiBPYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlLmNhbGwocywgcFtpXSkpXHJcbiAgICAgICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgICAgICB9XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUgPT09IFwiZnVuY3Rpb25cIikgciA9IFJlZmxlY3QuZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpO1xyXG4gICAgZWxzZSBmb3IgKHZhciBpID0gZGVjb3JhdG9ycy5