diff --git a/esbuild.config.mjs b/esbuild.config.mjs new file mode 100644 index 0000000..3c9525a --- /dev/null +++ b/esbuild.config.mjs @@ -0,0 +1,41 @@ +import esbuild from "esbuild"; +import process from "process"; +import builtins from "builtin-modules"; + +const banner = +`/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ +`; + +const prod = (process.argv[2] === 'production'); + +esbuild.build({ + banner: { + js: banner, + }, + entryPoints: ['main.ts'], + bundle: true, + external: [ + 'obsidian', + 'electron', + '@codemirror/autocomplete', + '@codemirror/collab', + '@codemirror/commands', + '@codemirror/language', + '@codemirror/lint', + '@codemirror/search', + '@codemirror/state', + '@codemirror/view', + '@lezer/common', + '@lezer/highlight', + '@lezer/lr', + ...builtins], + format: 'cjs', + target: 'es2018', + logLevel: "info", + sourcemap: prod ? false : 'inline', + treeShaking: true, + outfile: 'main.js', +}).catch(() => process.exit(1)); diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..f202da0 --- /dev/null +++ b/main.ts @@ -0,0 +1,428 @@ +import { + App, + Notice, + Plugin, + PluginSettingTab, + Setting, + TFile, + TFolder, + TAbstractFile, + Vault, + addIcon, +} from "obsidian"; + +// Define the settings interface +interface FolderListfileSettings { + listFileName: string; + excludeExtensions: string[]; + excludeListFileFromList: boolean; + includedFolders: string[]; + debug: boolean; +} + +// Default settings +const DEFAULT_SETTINGS: FolderListfileSettings = { + listFileName: "folderIndex.md", + excludeExtensions: ["css", "js", "json", "toml"], + excludeListFileFromList: true, + includedFolders: [], + debug: false, +}; + +// Custom icon for the ribbon button +const REFRESH_ICON = ` + + + + + + +`; + +export default class FolderListfilePlugin extends Plugin { + private debounceTimers: Record = {}; + settings: FolderListfileSettings; + + private log(message: string, ...args: unknown[]): void { + if (this.settings.debug) { + console.log(`[Folder-listfile] ${message}`, ...args); + } + } + + async onload() { + console.log(`Folder-listfile: loading plugin v${this.manifest.version}`); + await this.loadSettings(); + + // Add custom icon + addIcon("refresh-folder-list", REFRESH_ICON); + + // Add ribbon icon + this.addRibbonIcon( + "refresh-folder-list", + "Generate folder listfile", + async () => { + await this.createListFileForActiveFolder(); + } + ); + + // Register file events to update listfiles + this.registerEvent( + this.app.vault.on("create", (file: TAbstractFile) => { + this.log(`registerEvent - create - file: ${file.name}`); + if (file instanceof TFile && file.name === this.settings.listFileName) { + return; + } + this.handleFileChange(file); + }) + ); + + this.registerEvent( + this.app.vault.on("delete", (file: TAbstractFile) => { + this.log(`registerEvent - delete - file: ${file.name}`); + this.handleFileChange(file); + }) + ); + + this.registerEvent( + this.app.vault.on("rename", (file: TAbstractFile, oldPath: string) => { + this.log(`registerEvent - rename - file: ${file.name}`); + // Handle the file in its new location + this.handleFileChange(file); + + // Handle the old folder listfile update + const oldFolderPath = this.getFolderPathFromFilePath(oldPath); + this.log(`register event - rename - oldFolderPath: ${oldFolderPath}`); + if (oldFolderPath !== null) { + this.updateListFileForFolder(oldFolderPath); + } + }) + ); + + this.registerEvent( + this.app.vault.on("modify", (file: TAbstractFile) => { + this.log(`registerEvent - modify - file: ${file.name}`); + // Skip if this is a list file we just modified to avoid recursive updates + if (file instanceof TFile && file.name === this.settings.listFileName) { + this.log("Skipping update for list file itself"); + return; + } + + this.handleFileModification(file); + }) + ); + + // Add settings tab + this.addSettingTab(new FolderListfileSettingTab(this.app, this)); + + // on load rebuild the existing indices + console.log(`onload - includedFolders: ${this.settings.includedFolders}`); + } + + onunload() { + // Clean up when plugin is disabled + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + + async saveSettings() { + await this.saveData(this.settings); + } + + // Gets the folder path from a file path + getFolderPathFromFilePath(filePath: string): string | null { + const lastSlashIndex = filePath.lastIndexOf("/"); + if (lastSlashIndex === -1) { + return ""; // Root folder + } + return filePath.substring(0, lastSlashIndex); + } + + // Check if a folder is included in the settings + isFolderIncluded(folderPath: string): boolean { + if (this.settings.includedFolders.length === 0) { + return false; // If no folders are included, don't generate for any + } + + // Normalize the empty root path for comparison + const normalizedPath = folderPath === "" ? "/" : folderPath; + + // Check if the folder path is in the includedFolders list + return this.settings.includedFolders.some((includedFolder) => { + // Direct match + if (includedFolder === folderPath) { + return true; + } + + // If the included folder is the root folder "/" + if (includedFolder === "/" && folderPath === "") { + return true; + } + + return false; + }); + } + + // Handle file changes (creation, deletion, rename) + async handleFileChange(file: TAbstractFile) { + // If it's a file, update the listfile in its folder + if (file instanceof TFile) { + const folderPath = this.getFolderPathFromFilePath(file.path); + console.log(`handleFileChange - TFile folderPath: ${folderPath}`); + if (folderPath !== null && this.isFolderIncluded(folderPath)) { + await this.updateListFileForFolder(folderPath); + } + } + // If it's a folder, update the parent folder's listfile + else if (file instanceof TFolder) { + const folderPath = this.getFolderPathFromFilePath(file.path); + console.log(`handleFileChange - TFolder folderPath: ${folderPath}`); + if (folderPath !== null && this.isFolderIncluded(folderPath)) { + await this.updateListFileForFolder(folderPath); + } + } + } + + async handleFileModification(file: TAbstractFile) { + // Only process regular files, not folders + if (!(file instanceof TFile)) { + return; + } + + // Get the folder containing this file + const folderPath = this.getFolderPathFromFilePath(file.path); + this.log( + `handleFileModification - file: ${file.path}, folderPath: ${folderPath}` + ); + + if (folderPath !== null && this.isFolderIncluded(folderPath)) { + // Implement debouncing to prevent excessive updates + if (this.debounceTimers?.[folderPath]) { + clearTimeout(this.debounceTimers[folderPath]); + this.log(`Cleared existing debounce timer for ${folderPath}`); + } + + // Initialize debounceTimers if it doesn't exist + if (!this.debounceTimers) { + this.debounceTimers = {}; + } + + // Set a new timer + this.log(`Setting debounce timer for ${folderPath}`); + this.debounceTimers[folderPath] = setTimeout(() => { + this.log(`Debounce timer fired for ${folderPath}, updating list file`); + this.updateListFileForFolder(folderPath); + delete this.debounceTimers[folderPath]; + }, 2000); // 2-second debounce + } + } + + // Create a listfile for the active folder + async createListFileForActiveFolder() { + const activeFile = this.app.workspace.getActiveFile(); + if (!activeFile) { + new Notice("No active file. Please open a file first."); + return; + } + + const folderPath = this.getFolderPathFromFilePath(activeFile.path); + if (folderPath === null) { + new Notice("Could not determine the folder of the active file."); + return; + } + + if (!this.isFolderIncluded(folderPath)) { + new Notice( + `Folder ${folderPath || "root"} is not in the included folders list.` + ); + return; + } + + await this.updateListFileForFolder(folderPath); + new Notice(`Created listfile for folder: ${folderPath || "root"}`); + } + + // Update or create the listfile for a specific folder + async updateListFileForFolder(folderPath: string) { + try { + // Check if this folder is included in the settings + if (!this.isFolderIncluded(folderPath)) { + console.log( + `Skipping folder ${folderPath} - not in included folders list` + ); + return; + } + + // Get all files in the folder + const folder = folderPath + ? this.app.vault.getAbstractFileByPath(folderPath) + : this.app.vault.getRoot(); + + if (!folder || !(folder instanceof TFolder)) { + console.error(`Folder not found: ${folderPath}`); + return; + } + + // Get all files in the folder + const files = folder.children + .filter((file) => file instanceof TFile) + .filter((file) => { + // Skip the listfile itself if the setting is enabled + if ( + this.settings.excludeListFileFromList && + file.name === this.settings.listFileName + ) { + return false; + } + + // Skip files with excluded extensions + const extension = (file as TFile).extension.toLowerCase(); + return !this.settings.excludeExtensions.includes(extension); + }) as TFile[]; + + // Create content for the listfile + const folderName = folderPath.split("/").pop() || "Root"; + let content = `# Files in ${folderName}\n\n`; + + // Sort files by modification time in reverse order (newest first) + files.sort( + (a, b) => + (this.app.vault.getAbstractFileByPath(b.path) as TFile)?.stat.mtime - + (this.app.vault.getAbstractFileByPath(a.path) as TFile)?.stat.mtime + ); + + // Add links to each file with modification date + for (const file of files) { + const modDate = new Date(file.stat.mtime).toLocaleString(); + content += `- [[${file.basename}]] *(${modDate})*\n`; + } + + content += `\n*This list contains ${ + files.length + } files and was last updated on ${new Date().toLocaleString()}*`; + + // Create or update the listfile + this.log(`Updating listfile at: ${folderPath}`); + const listFilePath = folderPath + ? `${folderPath}/${this.settings.listFileName}` + : this.settings.listFileName; + + if (await this.app.vault.adapter.exists(listFilePath)) { + await this.app.vault.adapter.write(listFilePath, content); + } else { + await this.app.vault.create(listFilePath, content); + } + } catch (error) { + console.error("Error updating folder listfile:", error); + new Notice( + "Error updating folder listfile. Check the console for details." + ); + } + } +} + +// Settings tab for the plugin +class FolderListfileSettingTab extends PluginSettingTab { + plugin: FolderListfilePlugin; + + constructor(app: App, plugin: FolderListfilePlugin) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const { containerEl } = this; + containerEl.empty(); + + containerEl.createEl("h2", { text: "Folder Listfile Settings" }); + + new Setting(containerEl) + .setName("Listfile name") + .setDesc("The name of the file that will contain the list of links") + .addText((text) => + text + .setValue(this.plugin.settings.listFileName) + .onChange(async (value) => { + this.plugin.settings.listFileName = value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Excluded extensions") + .setDesc( + "Comma-separated list of file extensions to exclude from the list" + ) + .addText((text) => + text + .setValue(this.plugin.settings.excludeExtensions.join(", ")) + .onChange(async (value) => { + this.plugin.settings.excludeExtensions = value + .split(",") + .map((ext) => ext.trim().toLowerCase()); + await this.plugin.saveSettings(); + }) + ); + + const fragment = document.createDocumentFragment(); + const link = document.createElement("a"); + link.href = + "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#writing_a_regular_expression_pattern"; + link.text = "MDN - Regular expressions"; + fragment.append( + "Folder paths to generate indices for. One folder path per line." + ); + fragment.append(" Leave empty to disable auto-generation."); + + new Setting(containerEl) + .setName("Included folder paths") + .setDesc(fragment) + .addTextArea((textArea) => { + textArea.inputEl.setAttr("rows", 6); + textArea + .setPlaceholder("daily\nprojects/active\nnotes/reference") + .setValue(this.plugin.settings.includedFolders.join("\n")); + + textArea.inputEl.onblur = async (e: FocusEvent) => { + const paths = (e.target as HTMLInputElement).value; + this.plugin.settings.includedFolders = paths + .split("\n") + .map((item) => item.trim()) + .filter((item) => item.length > 0) + .map((item) => { + return item.endsWith("/") ? item.slice(0, -1) : item; + }); + // console.log(' -- ',this.plugin.settings.includedFolders); + await this.plugin.saveSettings(); + }; + }); + + new Setting(containerEl) + .setName("Exclude listfile from list") + .setDesc( + "Whether to exclude the list file itself from the generated list" + ) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.excludeListFileFromList) + .onChange(async (value) => { + this.plugin.settings.excludeListFileFromList = value; + await this.plugin.saveSettings(); + }) + ); + + // Add debug toggle + new Setting(containerEl) + .setName("Enable debug mode") + .setDesc( + "When enabled, detailed logs are printed to the developer console" + ) + .addToggle((toggle) => + toggle.setValue(this.plugin.settings.debug).onChange(async (value) => { + this.plugin.settings.debug = value; + await this.plugin.saveSettings(); + }) + ); + } +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..e0d9fa4 --- /dev/null +++ b/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "folder-listfile", + "name": "Folder Listfile", + "version": "1.1.0", + "minAppVersion": "0.12.0", + "description": "Create and maintain a list of wikilinks to files in specified folders", + "author": "band", + "authorUrl": "https://github.com/band", + "isDesktopOnly": true +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6ed92f1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,628 @@ +{ + "name": "obsidian-folder-listfile", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "obsidian-folder-listfile", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@types/node": "^16.11.6", + "builtin-modules": "^5.0.0", + "esbuild": "^0.25.2", + "obsidian": "latest", + "tslib": "2.4.0", + "typescript": "4.7.4" + } + }, + "node_modules/@codemirror/state": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", + "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.36.5", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.5.tgz", + "integrity": "sha512-cd+FZEUlu3GQCYnguYm3EkhJ8KJVisqqUsCOKedBoAt/d9c76JUUap6U0UrpElln5k6VyrEOYliMuDAKIeDQLg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.5.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/codemirror": { + "version": "5.60.8", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz", + "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/tern": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "16.18.126", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", + "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/builtin-modules": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", + "integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/obsidian": { + "version": "1.8.7", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.8.7.tgz", + "integrity": "sha512-h4bWwNFAGRXlMlMAzdEiIM2ppTGlrh7uGOJS6w4gClrsjc+ei/3YAtU2VdFUlCiPuTHpY4aBpFJJW75S1Tl/JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/codemirror": "5.60.8", + "moment": "2.29.4" + }, + "peerDependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "dev": true, + "license": "MIT", + "peer": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..62d58db --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "obsidian-folder-listfile", + "version": "1.0.0", + "description": "Obsidian plugin to create and maintain folder listfiles", + "main": "main.js", + "scripts": { + "dev": "node esbuild.config.mjs", + "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", + "version": "node version-bump.mjs" + }, + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@types/node": "^16.11.6", + "builtin-modules": "^5.0.0", + "esbuild": "^0.25.2", + "obsidian": "latest", + "tslib": "2.4.0", + "typescript": "4.7.4" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c44b729 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "inlineSourceMap": true, + "inlineSources": true, + "module": "ESNext", + "target": "ES6", + "allowJs": true, + "noImplicitAny": true, + "moduleResolution": "node", + "importHelpers": true, + "isolatedModules": true, + "strictNullChecks": true, + "lib": [ + "DOM", + "ES5", + "ES6", + "ES7" + ] + }, + "include": [ + "**/*.ts" + ] +} diff --git a/versions.json b/versions.json new file mode 100644 index 0000000..595dfb1 --- /dev/null +++ b/versions.json @@ -0,0 +1,3 @@ +{ + "1.0.0": "0.12.0" +}