2024-06-13 21:01:37 +03:00
/ *
THIS IS A GENERATED / BUNDLED FILE BY ESBUILD
if you want to view the source visit the plugins github repository ( https : //github.com/Vinzent03/obsidian-advanced-uri)
* /
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 ) ;
// src/main.ts
var main _exports = { } ;
_ _export ( main _exports , {
default : ( ) => FindOrphanedFilesPlugin
} ) ;
module . exports = _ _toCommonJS ( main _exports ) ;
var import _obsidian4 = require ( "obsidian" ) ;
// src/deleteFilesModal.ts
var import _obsidian = require ( "obsidian" ) ;
var DeleteFilesModal = class extends import _obsidian . Modal {
constructor ( app , filesToDelete ) {
super ( app ) ;
this . filesToDelete = filesToDelete ;
}
onOpen ( ) {
let { contentEl , titleEl } = this ;
titleEl . setText (
"Move " + this . filesToDelete . length + " files to system trash?"
) ;
contentEl . createEl ( "button" , { text : "Cancel" } ) . addEventListener ( "click" , ( ) => this . close ( ) ) ;
contentEl . setAttr ( "margin" , "auto" ) ;
contentEl . createEl ( "button" , {
cls : "mod-cta" ,
text : "Confirm"
} ) . addEventListener ( "click" , async ( ) => {
for ( const file of this . filesToDelete ) {
await this . app . vault . trash ( file , true ) ;
}
this . close ( ) ;
} ) ;
}
onClose ( ) {
let { contentEl } = this ;
contentEl . empty ( ) ;
}
} ;
// src/settingsTab.ts
var import _obsidian2 = require ( "obsidian" ) ;
var SettingsTab = class extends import _obsidian2 . PluginSettingTab {
constructor ( app , plugin , defaultSettings ) {
super ( app , plugin ) ;
this . defaultSettings = defaultSettings ;
this . plugin = plugin ;
}
// Add trailing slash to catch files named like the directory. See https://github.com/Vinzent03/find-unlinked-files/issues/24
formatPath ( path , addDirectorySlash ) {
if ( path . length == 0 )
return path ;
path = ( 0 , import _obsidian2 . normalizePath ) ( path ) ;
if ( addDirectorySlash )
return path + "/" ;
else
return path ;
}
display ( ) {
let { containerEl } = this ;
containerEl . empty ( ) ;
containerEl . createEl ( "h2" , { text : this . plugin . manifest . name } ) ;
containerEl . createEl ( "h4" , {
text : "Settings for finding orphaned files"
} ) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Open output file" ) . addToggle (
( cb ) => cb . setValue ( this . plugin . settings . openOutputFile ) . onChange ( ( value ) => {
this . plugin . settings . openOutputFile = value ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . 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 (
( cb ) => cb . onChange ( ( 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 import _obsidian2 . Setting ( containerEl ) . setName ( "Disable working links" ) . setDesc (
"Indent lines to disable the link and to clean up the graph view"
) . addToggle (
( cb ) => cb . onChange ( ( value ) => {
this . plugin . settings . disableWorkingLinks = value ;
this . plugin . saveSettings ( ) ;
} ) . setValue ( this . plugin . settings . disableWorkingLinks )
) ;
new import _obsidian2 . Setting ( containerEl ) . 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"
) . addToggle (
( cb ) => cb . setValue ( this . plugin . settings . ignoreDirectories ) . onChange ( ( value ) => {
this . plugin . settings . ignoreDirectories = value ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Directories" ) . setDesc ( "Add each directory path in a new line" ) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/Subdirectory" ) . setValue (
this . plugin . settings . directoriesToIgnore . join ( "\n" )
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , true ) ) ;
this . plugin . settings . directoriesToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude files" ) . setDesc ( "Add each file path in a new line (with file extension!)" ) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/file.md" ) . setValue ( this . plugin . settings . filesToIgnore . join ( "\n" ) ) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , false ) ) ;
this . plugin . settings . filesToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . 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."
) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/file.md" ) . setValue ( this . plugin . settings . linksToIgnore . join ( "\n" ) ) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , false ) ) ;
this . plugin . settings . linksToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . 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"
) . addToggle (
( cb ) => cb . setValue ( this . plugin . settings . ignoreFileTypes ) . onChange ( ( value ) => {
this . plugin . settings . ignoreFileTypes = value ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "File types" ) . setDesc ( "Effect depends on toggle above" ) . addTextArea (
( cb ) => cb . setPlaceholder ( "docx,txt" ) . setValue ( this . plugin . settings . fileTypesToIgnore . join ( "," ) ) . onChange ( ( value ) => {
let extensions = value . trim ( ) . split ( "," ) ;
this . plugin . settings . fileTypesToIgnore = extensions ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude tags" ) . setDesc (
"Exclude files, which contain the given tag. Add each tag separated by comma (without `#`)"
) . addTextArea (
( cb ) => cb . setPlaceholder ( "todo,unfinished" ) . setValue ( this . plugin . settings . tagsToIgnore . join ( "," ) ) . onChange ( ( value ) => {
let tags = value . trim ( ) . split ( "," ) ;
this . plugin . settings . tagsToIgnore = tags ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Filetypes to delete per command. See README." ) . setDesc (
"Add each filetype separated by comma. Set to `*` to delete all files."
) . addTextArea (
( cb ) => cb . setPlaceholder ( "jpg,png" ) . setValue ( this . plugin . settings . fileTypesToDelete . join ( "," ) ) . onChange ( ( value ) => {
let extensions = value . trim ( ) . split ( "," ) ;
this . plugin . settings . fileTypesToDelete = extensions ;
this . plugin . saveSettings ( ) ;
} )
) ;
containerEl . createEl ( "h4" , {
text : "Settings for finding broken links"
} ) ;
new import _obsidian2 . 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 (
( cb ) => cb . onChange ( ( 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 import _obsidian2 . Setting ( containerEl ) . 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"
) . addToggle (
( cb ) => cb . setValue (
this . plugin . settings . unresolvedLinksIgnoreDirectories
) . onChange ( ( value ) => {
this . plugin . settings . unresolvedLinksIgnoreDirectories = value ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Directories" ) . setDesc ( "Add each directory path in a new line" ) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/Subdirectory" ) . setValue (
this . plugin . settings . unresolvedLinksDirectoriesToIgnore . join (
"\n"
)
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , true ) ) ;
this . plugin . settings . unresolvedLinksDirectoriesToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude files" ) . setDesc (
"Exclude links in the specified file. Add each file path in a new line (with file extension!)"
) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/file.md" ) . setValue (
this . plugin . settings . unresolvedLinksFilesToIgnore . join (
"\n"
)
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , false ) ) ;
this . plugin . settings . unresolvedLinksFilesToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . 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."
) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/file.md" ) . setValue (
this . plugin . settings . unresolvedLinksLinksToIgnore . join (
"\n"
)
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , false ) ) ;
this . plugin . settings . unresolvedLinksLinksToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude filetypes" ) . setDesc (
"Exclude links with the specified filetype. Add each filetype separated by comma"
) . addTextArea (
( cb ) => cb . setPlaceholder ( "docx,txt" ) . setValue (
this . plugin . settings . unresolvedLinksFileTypesToIgnore . join (
","
)
) . onChange ( ( value ) => {
let extensions = value . trim ( ) . split ( "," ) ;
this . plugin . settings . unresolvedLinksFileTypesToIgnore = extensions ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude tags" ) . setDesc (
" Exclude links in files , which contain the given tag . Add each tag separated by comma ( without ` # ` ) "
) . addTextArea (
( cb ) => cb . setPlaceholder ( "todo,unfinished" ) . setValue (
this . plugin . settings . unresolvedLinksTagsToIgnore . join (
","
)
) . onChange ( ( value ) => {
let tags = value . trim ( ) . split ( "," ) ;
this . plugin . settings . unresolvedLinksTagsToIgnore = tags ;
this . plugin . saveSettings ( ) ;
} )
) ;
containerEl . createEl ( "h4" , {
text : "Settings for finding files without tags"
} ) ;
new import _obsidian2 . 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 (
( cb ) => cb . onChange ( ( 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 import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude files" ) . setDesc (
"Exclude the specific files. Add each file path in a new line (with file extension!)"
) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/file.md" ) . setValue (
this . plugin . settings . withoutTagsFilesToIgnore . join ( "\n" )
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , false ) ) ;
this . plugin . settings . withoutTagsFilesToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude directories" ) . setDesc (
"Exclude files in the specified directories. Add each directory path in a new line"
) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/Subdirectory" ) . setValue (
this . plugin . settings . withoutTagsDirectoriesToIgnore . join (
"\n"
)
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , true ) ) ;
this . plugin . settings . withoutTagsDirectoriesToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
containerEl . createEl ( "h4" , {
text : "Settings for finding empty files"
} ) ;
new import _obsidian2 . 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 (
( cb ) => cb . onChange ( ( value ) => {
if ( value . length == 0 ) {
this . plugin . settings . emptyFilesOutputFileName = this . defaultSettings . emptyFilesOutputFileName ;
} else {
this . plugin . settings . emptyFilesOutputFileName = value ;
}
this . plugin . saveSettings ( ) ;
} ) . setValue ( this . plugin . settings . emptyFilesOutputFileName )
) ;
new import _obsidian2 . Setting ( containerEl ) . 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"
) . addToggle (
( cb ) => cb . setValue ( this . plugin . settings . emptyFilesIgnoreDirectories ) . onChange ( ( value ) => {
this . plugin . settings . emptyFilesIgnoreDirectories = value ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Directories" ) . setDesc ( "Add each directory path in a new line" ) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/Subdirectory" ) . setValue (
this . plugin . settings . emptyFilesDirectories . join ( "\n" )
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , true ) ) ;
this . plugin . settings . emptyFilesDirectories = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Exclude files" ) . setDesc ( "Add each file path in a new line (with file extension!)" ) . addTextArea (
( cb ) => cb . setPlaceholder ( "Directory/file.md" ) . setValue (
this . plugin . settings . emptyFilesFilesToIgnore . join ( "\n" )
) . onChange ( ( value ) => {
let paths = value . trim ( ) . split ( "\n" ) . map ( ( value2 ) => this . formatPath ( value2 , false ) ) ;
this . plugin . settings . emptyFilesFilesToIgnore = paths ;
this . plugin . saveSettings ( ) ;
} )
) ;
new import _obsidian2 . Setting ( containerEl ) . setName ( "Donate" ) . setDesc (
"If you like this Plugin, consider donating to support continued development."
) . addButton ( ( bt ) => {
bt . buttonEl . outerHTML = "<a href='https://ko-fi.com/F1F195IQ5' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi3.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>" ;
} ) ;
}
} ;
// src/utils.ts
var import _obsidian3 = require ( "obsidian" ) ;
var Utils = class {
/ * *
* Checks for the given settings . Is used for ` Find orphaned files ` and ` Find broken links `
* @ param app
* @ param filePath
* @ param tagsToIgnore
* @ param linksToIgnore
* @ param directoriesToIgnore
* @ param filesToIgnore
* @ param ignoreDirectories
* /
constructor ( app , filePath , tagsToIgnore , linksToIgnore , directoriesToIgnore , filesToIgnore , ignoreDirectories = true , dir ) {
this . app = app ;
this . filePath = filePath ;
this . tagsToIgnore = tagsToIgnore ;
this . linksToIgnore = linksToIgnore ;
this . directoriesToIgnore = directoriesToIgnore ;
this . filesToIgnore = filesToIgnore ;
this . ignoreDirectories = ignoreDirectories ;
this . dir = dir ;
this . fileCache = app . metadataCache . getCache ( filePath ) ;
}
hasTagsToIgnore ( ) {
const tags = ( 0 , import _obsidian3 . getAllTags ) ( this . fileCache ) ;
return ( tags == null ? void 0 : tags . find (
( tag ) => this . tagsToIgnore . contains ( tag . substring ( 1 ) )
) ) !== void 0 ;
}
hasLinksToIgnore ( ) {
var _a , _b ;
if ( ( ( ( _a = this . fileCache ) == null ? void 0 : _a . embeds ) != null || ( ( _b = this . fileCache ) == null ? void 0 : _b . links ) != null ) && this . linksToIgnore [ 0 ] == "*" ) {
return true ;
}
return ( 0 , import _obsidian3 . iterateCacheRefs ) ( this . fileCache , ( cb ) => {
var _a2 ;
const link = ( _a2 = this . app . metadataCache . getFirstLinkpathDest (
cb . link ,
this . filePath
) ) == null ? void 0 : _a2 . path ;
return this . linksToIgnore . contains ( link ) ;
} ) ;
}
checkDirectory ( ) {
if ( this . dir ) {
if ( ! this . filePath . startsWith ( this . dir ) ) {
return true ;
}
}
const contains = this . directoriesToIgnore . find (
( value ) => value . length != 0 && this . filePath . startsWith ( value )
) !== void 0 ;
if ( this . ignoreDirectories ) {
return contains ;
} else {
return ! contains ;
}
}
isFileToIgnore ( ) {
return this . filesToIgnore . contains ( this . filePath ) ;
}
shouldIgnoreFile ( ) {
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
* /
static async writeAndOpenFile ( app , outputFileName , text , openFile ) {
await app . vault . adapter . write ( outputFileName , text ) ;
if ( ! openFile )
return ;
let fileIsAlreadyOpened = false ;
app . workspace . iterateAllLeaves ( ( leaf ) => {
if ( leaf . getDisplayText ( ) != "" && outputFileName . startsWith ( leaf . getDisplayText ( ) ) ) {
fileIsAlreadyOpened = true ;
}
} ) ;
if ( ! fileIsAlreadyOpened ) {
const newPane = app . workspace . getLeavesOfType ( "empty" ) . length == 0 ;
if ( newPane ) {
app . workspace . openLinkText ( outputFileName , "/" , true ) ;
} else {
const file = app . vault . getAbstractFileByPath ( outputFileName ) ;
if ( file instanceof import _obsidian3 . TFile ) {
await app . workspace . getLeavesOfType ( "empty" ) [ 0 ] . openFile ( file ) ;
} else {
app . workspace . openLinkText ( outputFileName , "/" , true ) ;
}
}
}
}
} ;
// src/main.ts
var DEFAULT _SETTINGS = {
outputFileName : "orphaned files output" ,
disableWorkingLinks : false ,
directoriesToIgnore : [ ] ,
filesToIgnore : [ ] ,
fileTypesToIgnore : [ ] ,
linksToIgnore : [ ] ,
tagsToIgnore : [ ] ,
fileTypesToDelete : [ ] ,
ignoreFileTypes : true ,
ignoreDirectories : true ,
unresolvedLinksIgnoreDirectories : true ,
unresolvedLinksOutputFileName : "broken links output" ,
unresolvedLinksDirectoriesToIgnore : [ ] ,
unresolvedLinksFilesToIgnore : [ ] ,
unresolvedLinksFileTypesToIgnore : [ ] ,
unresolvedLinksLinksToIgnore : [ ] ,
unresolvedLinksTagsToIgnore : [ ] ,
withoutTagsDirectoriesToIgnore : [ ] ,
withoutTagsFilesToIgnore : [ ] ,
withoutTagsOutputFileName : "files without tags" ,
emptyFilesOutputFileName : "empty files" ,
emptyFilesDirectories : [ ] ,
emptyFilesFilesToIgnore : [ ] ,
emptyFilesIgnoreDirectories : true ,
openOutputFile : true
} ;
var FindOrphanedFilesPlugin = class extends import _obsidian4 . Plugin {
constructor ( ) {
super ( ... arguments ) ;
this . findExtensionRegex = /(\.[^.]+)$/ ;
}
async onload ( ) {
console . log ( "loading " + this . manifest . name + " plugin" ) ;
await this . loadSettings ( ) ;
this . addCommand ( {
id : "find-unlinked-files" ,
name : "Find orphaned files" ,
callback : ( ) => this . findOrphanedFiles ( )
} ) ;
this . addCommand ( {
id : "find-unresolved-link" ,
name : "Find broken links" ,
callback : ( ) => this . findBrokenLinks ( )
} ) ;
this . addCommand ( {
id : "delete-unlinked-files" ,
name : "Delete orphaned files with certain extension. See README" ,
callback : ( ) => this . deleteOrphanedFiles ( )
} ) ;
this . addCommand ( {
id : "create-files-of-broken-links" ,
name : "Create files of broken links" ,
callback : ( ) => this . createFilesOfBrokenLinks ( )
} ) ;
this . addCommand ( {
id : "find-files-without-tags" ,
name : "Find files without tags" ,
callback : ( ) => this . findFilesWithoutTags ( )
} ) ;
this . addCommand ( {
id : "find-empty-files" ,
name : "Find empty files" ,
callback : ( ) => this . findEmptyFiles ( )
} ) ;
this . addCommand ( {
id : "delete-empty-files" ,
name : "Delete empty files" ,
callback : ( ) => this . deleteEmptyFiles ( )
} ) ;
this . addSettingTab ( new SettingsTab ( this . app , this , DEFAULT _SETTINGS ) ) ;
this . app . workspace . on ( "file-menu" , ( menu , file , _ , _ _ ) => {
if ( file instanceof import _obsidian4 . TFolder ) {
menu . addItem ( ( cb ) => {
cb . setIcon ( "search" ) ;
cb . setTitle ( "Find orphaned files" ) ;
cb . onClick ( ( _2 ) => {
this . findOrphanedFiles ( file . path + "/" ) ;
} ) ;
} ) ;
}
} ) ;
}
async createFilesOfBrokenLinks ( ) {
var _a , _b ;
if ( ! await this . app . vault . adapter . exists (
this . settings . unresolvedLinksOutputFileName + ".md"
) ) {
new import _obsidian4 . Notice (
"Can't find file - Please run the `Find broken files' command before"
) ;
return ;
}
const links = ( _a = this . app . metadataCache . getCache (
this . settings . unresolvedLinksOutputFileName + ".md"
) ) == null ? void 0 : _a . links ;
if ( ! links ) {
new import _obsidian4 . Notice ( "No broken links found" ) ;
return ;
}
const filesToCreate = [ ] ;
for ( const link of links ) {
const file = this . app . metadataCache . getFirstLinkpathDest (
link . link ,
"/"
) ;
if ( file )
continue ;
const foundType = ( _b = this . findExtensionRegex . exec ( link . link ) ) == null ? void 0 : _b [ 0 ] ;
if ( ( foundType != null ? foundType : ".md" ) == ".md" ) {
if ( foundType ) {
filesToCreate . push ( link . link ) ;
} else {
filesToCreate . push ( link . link + ".md" ) ;
}
}
}
if ( filesToCreate ) {
for ( const file of filesToCreate ) {
await this . app . vault . create ( file , "" ) ;
}
}
}
async findEmptyFiles ( ) {
var _a ;
const files = this . app . vault . getFiles ( ) ;
const emptyFiles = [ ] ;
for ( const file of files ) {
if ( new Utils (
this . app ,
file . path ,
[ ] ,
[ ] ,
this . settings . emptyFilesDirectories ,
this . settings . emptyFilesFilesToIgnore ,
this . settings . emptyFilesIgnoreDirectories
) . shouldIgnoreFile ( ) ) {
continue ;
}
const content = await this . app . vault . read ( file ) ;
const trimmedContent = content . trim ( ) ;
if ( ! trimmedContent ) {
emptyFiles . push ( file ) ;
}
const cache = this . app . metadataCache . getFileCache ( file ) ;
const frontmatter = cache == null ? void 0 : cache . frontmatter ;
if ( frontmatter ) {
const lines = content . trimRight ( ) . split ( "\n" ) . length ;
if ( ( ( _a = cache . frontmatterPosition ) != null ? _a : frontmatter . position ) . end . line == lines - 1 ) {
emptyFiles . push ( file ) ;
}
}
}
let prefix ;
if ( this . settings . disableWorkingLinks )
prefix = " " ;
else
prefix = "" ;
const text = emptyFiles . map ( ( file ) => ` ${ prefix } - [[ ${ file . path } ]] ` ) . join ( "\n" ) ;
Utils . writeAndOpenFile (
this . app ,
this . settings . emptyFilesOutputFileName + ".md" ,
text ,
this . settings . openOutputFile
) ;
}
async findOrphanedFiles ( dir ) {
const startTime = Date . now ( ) ;
const outFileName = this . settings . outputFileName + ".md" ;
let outFile = null ;
const allFiles = this . app . vault . getFiles ( ) ;
const markdownFiles = this . app . vault . getMarkdownFiles ( ) ;
const canvasFiles = allFiles . filter (
( file ) => file . extension === "canvas"
) ;
const links = /* @__PURE__ */ new Set ( ) ;
const findLinkInTextRegex = /\[\[(.*?)\]\]|\[.*?\]\((.*?)\)/g ;
const canvasParsingPromises = canvasFiles . map (
async ( canvasFile ) => {
2024-08-16 21:46:33 +03:00
var _a ;
2024-06-13 21:01:37 +03:00
const canvasFileContent = JSON . parse (
2024-08-16 21:46:33 +03:00
await this . app . vault . cachedRead ( canvasFile ) || "{}"
2024-06-13 21:01:37 +03:00
) ;
2024-08-16 21:46:33 +03:00
( _a = canvasFileContent . nodes ) == null ? void 0 : _a . forEach ( ( node ) => {
var _a2 ;
2024-06-13 21:01:37 +03:00
let linkTexts = [ ] ;
if ( node . type === "file" ) {
linkTexts . push ( node . file ) ;
} else if ( node . type === "text" ) {
let match ;
while ( ( match = findLinkInTextRegex . exec ( node . text ) ) !== null ) {
2024-08-16 21:46:33 +03:00
linkTexts . push ( ( _a2 = match [ 1 ] ) != null ? _a2 : match [ 2 ] ) ;
2024-06-13 21:01:37 +03:00
}
} else {
return ;
}
linkTexts . forEach ( ( linkText ) => {
const targetFile = this . app . metadataCache . getFirstLinkpathDest (
linkText . split ( "|" ) [ 0 ] . split ( "#" ) [ 0 ] ,
canvasFile . path
) ;
if ( targetFile != null )
links . add ( targetFile . path ) ;
} ) ;
} ) ;
}
) ;
markdownFiles . forEach ( ( mdFile ) => {
var _a , _b , _c ;
if ( outFile === null && mdFile . path == outFileName ) {
outFile = mdFile ;
return ;
}
const cache = this . app . metadataCache . getFileCache ( mdFile ) ;
for ( const ref of [
... ( _a = cache . embeds ) != null ? _a : [ ] ,
... ( _b = cache . links ) != null ? _b : [ ] ,
... ( _c = cache . frontmatterLinks ) != null ? _c : [ ]
] ) {
const txt = this . app . metadataCache . getFirstLinkpathDest (
( 0 , import _obsidian4 . getLinkpath ) ( ref . link ) ,
mdFile . path
) ;
if ( txt != null )
links . add ( txt . path ) ;
}
} ) ;
await Promise . all ( canvasParsingPromises ) ;
const notLinkedFiles = allFiles . filter (
( file ) => this . isFileAnOrphan ( file , links , dir )
) ;
notLinkedFiles . remove ( outFile ) ;
let text = "" ;
let prefix ;
if ( this . settings . disableWorkingLinks )
prefix = " " ;
else
prefix = "" ;
notLinkedFiles . sort ( ( a , b ) => b . stat . size - a . stat . size ) ;
notLinkedFiles . forEach ( ( file ) => {
text += prefix + "- [[" + this . app . metadataCache . fileToLinktext ( file , "/" , false ) + "]]\n" ;
} ) ;
Utils . writeAndOpenFile (
this . app ,
outFileName ,
text ,
this . settings . openOutputFile
) ;
const endTime = Date . now ( ) ;
const diff = endTime - startTime ;
if ( diff > 1e3 ) {
new import _obsidian4 . Notice (
` Found ${ notLinkedFiles . length } orphaned files in ${ diff } ms `
) ;
}
}
async deleteOrphanedFiles ( ) {
var _a , _b ;
if ( ! await this . app . vault . adapter . exists (
this . settings . outputFileName + ".md"
) ) {
new import _obsidian4 . Notice (
"Can't find file - Please run the `Find orphaned files' command before"
) ;
return ;
}
const links = ( _b = ( _a = this . app . metadataCache . getCache (
this . settings . outputFileName + ".md"
) ) == null ? void 0 : _a . links ) != null ? _b : [ ] ;
const filesToDelete = [ ] ;
links . forEach ( ( link ) => {
const file = this . app . metadataCache . getFirstLinkpathDest (
link . link ,
"/"
) ;
if ( ! file )
return ;
if ( this . settings . fileTypesToDelete [ 0 ] == "*" || this . settings . fileTypesToDelete . contains ( file . extension ) ) {
filesToDelete . push ( file ) ;
}
} ) ;
if ( filesToDelete . length > 0 )
new DeleteFilesModal ( this . app , filesToDelete ) . open ( ) ;
}
async deleteEmptyFiles ( ) {
var _a , _b ;
if ( ! await this . app . vault . adapter . exists (
this . settings . emptyFilesOutputFileName + ".md"
) ) {
new import _obsidian4 . Notice (
"Can't find file - Please run the `Find orphaned files' command before"
) ;
return ;
}
const links = ( _b = ( _a = this . app . metadataCache . getCache (
this . settings . emptyFilesOutputFileName + ".md"
) ) == null ? void 0 : _a . links ) != null ? _b : [ ] ;
const filesToDelete = [ ] ;
for ( const link of links ) {
const file = this . app . metadataCache . getFirstLinkpathDest (
link . link ,
"/"
) ;
if ( ! file )
return ;
filesToDelete . push ( file ) ;
}
if ( filesToDelete . length > 0 )
new DeleteFilesModal ( this . app , filesToDelete ) . open ( ) ;
}
findBrokenLinks ( ) {
const outFileName = this . settings . unresolvedLinksOutputFileName + ".md" ;
const links = [ ] ;
const brokenLinks = this . app . metadataCache . unresolvedLinks ;
for ( const sourceFilepath in brokenLinks ) {
if ( sourceFilepath == this . settings . unresolvedLinksOutputFileName + ".md" )
continue ;
const fileType = sourceFilepath . substring (
sourceFilepath . lastIndexOf ( "." ) + 1
) ;
const utils = new Utils (
this . app ,
sourceFilepath ,
this . settings . unresolvedLinksTagsToIgnore ,
this . settings . unresolvedLinksLinksToIgnore ,
this . settings . unresolvedLinksDirectoriesToIgnore ,
this . settings . unresolvedLinksFilesToIgnore ,
this . settings . unresolvedLinksIgnoreDirectories
) ;
if ( utils . shouldIgnoreFile ( ) )
continue ;
for ( const link in brokenLinks [ sourceFilepath ] ) {
const linkFileType = link . substring ( link . lastIndexOf ( "." ) + 1 ) ;
if ( this . settings . unresolvedLinksFileTypesToIgnore . contains (
linkFileType
) )
continue ;
let formattedFilePath = sourceFilepath ;
if ( fileType == "md" ) {
formattedFilePath = sourceFilepath . substring (
0 ,
sourceFilepath . lastIndexOf ( ".md" )
) ;
}
const brokenLink = {
files : [ formattedFilePath ] ,
link
} ;
if ( links . contains ( brokenLink ) )
continue ;
const duplication = links . find ( ( e ) => e . link == link ) ;
if ( duplication ) {
duplication . files . push ( formattedFilePath ) ;
} else {
links . push ( brokenLink ) ;
}
}
}
Utils . writeAndOpenFile (
this . app ,
outFileName ,
[
"Don't forget that creating the file from here may create the file in the wrong directory!" ,
... links . map (
( e ) => ` - [[ ${ e . link } ]] in [[ ${ e . files . join ( "]], [[" ) } ]] `
)
] . join ( "\n" ) ,
this . settings . openOutputFile
) ;
}
findFilesWithoutTags ( ) {
const outFileName = this . settings . withoutTagsOutputFileName + ".md" ;
let outFile ;
const files = this . app . vault . getMarkdownFiles ( ) ;
let withoutFiles = files . filter ( ( file ) => {
var _a ;
const utils = new Utils (
this . app ,
file . path ,
[ ] ,
[ ] ,
this . settings . withoutTagsDirectoriesToIgnore ,
this . settings . withoutTagsFilesToIgnore ,
true
) ;
if ( utils . shouldIgnoreFile ( ) ) {
return false ;
}
return ( ( _a = ( 0 , import _obsidian4 . getAllTags ) ( this . app . metadataCache . getFileCache ( file ) ) . length ) != null ? _a : 0 ) <= 0 ;
} ) ;
withoutFiles . remove ( outFile ) ;
let prefix ;
if ( this . settings . disableWorkingLinks )
prefix = " " ;
else
prefix = "" ;
const text = withoutFiles . map ( ( file ) => ` ${ prefix } - [[ ${ file . path } ]] ` ) . join ( "\n" ) ;
Utils . writeAndOpenFile (
this . app ,
outFileName ,
text ,
this . settings . openOutputFile
) ;
}
/ * *
* Checks if the given file in an orphaned file
*
* @ param file file to check
* @ param links all links in the vault
* /
isFileAnOrphan ( file , links , dir ) {
if ( links . has ( file . path ) )
return false ;
if ( file . extension == "css" )
return false ;
if ( this . settings . fileTypesToIgnore [ 0 ] !== "" ) {
const containsFileType = this . settings . fileTypesToIgnore . contains (
file . extension
) ;
if ( this . settings . ignoreFileTypes ) {
if ( containsFileType )
return ;
} else {
if ( ! containsFileType )
return ;
}
}
const utils = new Utils (
this . app ,
file . path ,
this . settings . tagsToIgnore ,
this . settings . linksToIgnore ,
this . settings . directoriesToIgnore ,
this . settings . filesToIgnore ,
this . settings . ignoreDirectories ,
dir
) ;
if ( utils . shouldIgnoreFile ( ) )
return false ;
return true ;
}
onunload ( ) {
console . log ( "unloading " + this . manifest . name + " plugin" ) ;
}
async loadSettings ( ) {
this . settings = Object . assign ( DEFAULT _SETTINGS , await this . loadData ( ) ) ;
}
async saveSettings ( ) {
await this . saveData ( this . settings ) ;
}
} ;