From b4538f7c04bbef3422b0fe025b3855bd9d46f537 Mon Sep 17 00:00:00 2001 From: linonetwo Date: Mon, 15 Dec 2025 21:56:12 +0800 Subject: [PATCH] Refactor routing utilities and improve files/ external in sub-wiki Moves routing utility functions to be exported via $tw.utils and updates type usage for better plugin integration. Adds support for excluding external attachments folders (configurable via $:/config/ExternalAttachments/WikiFolderToMove) from file watching. Updates build script to include new entry points and adjusts loader to use the correct module path. Adds and renames relevant .meta and type definition files. --- scripts/compilePlugins.mjs | 7 +++++ .../FileSystemAdaptor.ts | 6 ++--- .../WatchFileSystemAdaptor.js.meta | 3 +++ .../WatchFileSystemAdaptor.ts | 27 +++++++++++++++---- ...gtree-of.ts.meta => in-tagtree-of.js.meta} | 0 .../plugin/watchFileSystemAdaptor/loader.ts | 2 +- .../routingUtilities.js.meta | 3 +++ .../routingUtilities.ts | 27 ++++++++++++++----- .../routingUtilities.type.ts | 19 +++++++++++++ 9 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.js.meta rename src/services/wiki/plugin/watchFileSystemAdaptor/{in-tagtree-of.ts.meta => in-tagtree-of.js.meta} (100%) create mode 100644 src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.js.meta create mode 100644 src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.type.ts diff --git a/scripts/compilePlugins.mjs b/scripts/compilePlugins.mjs index d45aa1ae..814c462e 100644 --- a/scripts/compilePlugins.mjs +++ b/scripts/compilePlugins.mjs @@ -44,6 +44,10 @@ const nativeNodeModulesPlugin = { build.onResolve({ filter: /nsfw[/\\]build[/\\]Release[/\\]nsfw\.node$/ }, () => ({ external: true, })); + // External '$:/' files + build.onResolve({ filter: /^\$:\// }, () => ({ + external: true, + })); }, }; @@ -70,6 +74,9 @@ const PLUGINS = [ sourceFolder: '../src/services/wiki/plugin/watchFileSystemAdaptor', entryPoints: [ 'loader.ts', + 'in-tagtree-of.ts', + 'WatchFileSystemAdaptor.ts', + 'routingUtilities.ts', ], }, ]; diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/FileSystemAdaptor.ts b/src/services/wiki/plugin/watchFileSystemAdaptor/FileSystemAdaptor.ts index 3e597361..a7a27dbb 100644 --- a/src/services/wiki/plugin/watchFileSystemAdaptor/FileSystemAdaptor.ts +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/FileSystemAdaptor.ts @@ -7,7 +7,7 @@ import fs from 'fs'; import path from 'path'; import type { IFileInfo } from 'tiddlywiki'; import type { Tiddler, Wiki } from 'tiddlywiki'; -import { isWikiWorkspaceWithRouting, matchTiddlerToWorkspace } from './routingUtilities'; +import type { ExtendedUtilities } from './routingUtilities.type'; import { isFileLockError } from './utilities'; /** @@ -86,7 +86,7 @@ export class FileSystemAdaptor { // Filter to wiki workspaces with routing config (main or sub-wikis) const workspacesWithRouting = allWorkspaces - .filter((w: IWorkspace): w is IWikiWorkspace => isWikiWorkspaceWithRouting(w, currentWorkspace.id)) + .filter((w: IWorkspace): w is IWikiWorkspace => ($tw.utils as unknown as ExtendedUtilities).isWikiWorkspaceWithRouting(w, currentWorkspace.id)) .sort(workspaceSorter); this.wikisWithRouting = workspacesWithRouting; @@ -142,7 +142,7 @@ export class FileSystemAdaptor { } // Find matching workspace using the routing logic - const matchingWiki = matchTiddlerToWorkspace(title, tags, this.wikisWithRouting, $tw.wiki, $tw.rootWidget); + const matchingWiki = ($tw.utils as unknown as ExtendedUtilities).matchTiddlerToWorkspace(title, tags, this.wikisWithRouting, $tw.wiki, $tw.rootWidget); // Determine the target directory based on routing // Sub-wikis store tiddlers directly in their root folder (not in /tiddlers subfolder) diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.js.meta b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.js.meta new file mode 100644 index 00000000..85ad1be6 --- /dev/null +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.js.meta @@ -0,0 +1,3 @@ +title: $:/plugins/linonetwo/watch-filesystem-adaptor/WatchFileSystemAdaptor.js +type: application/javascript +module-type: library diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts index 7946c783..ba0119b0 100644 --- a/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/WatchFileSystemAdaptor.ts @@ -68,6 +68,11 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { private baseExcludedPaths: string[] = []; /** Excluded path patterns that apply to all wikis (main and sub-wikis) */ private readonly excludedPathPatterns: string[] = ['.git', 'node_modules', '.DS_Store']; + /** + * External attachments folder to exclude (read from config) + * Default is 'files', but can be configured via $:/config/ExternalAttachments/WikiFolderToMove + */ + private externalAttachmentsFolder: string = 'files'; /** * Track pending file deletions to handle git revert/checkout scenarios. * Maps absolute file path to deletion timer. @@ -124,6 +129,12 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { } if (this.workspace) { + // Load external attachments folder name from config + const externalAttachmentsFolderConfig = this.wiki.getTiddlerText('$:/config/ExternalAttachments/WikiFolderToMove', 'files'); + if (externalAttachmentsFolderConfig) { + this.externalAttachmentsFolder = externalAttachmentsFolderConfig; + } + this.ignoreSymlinks = this.workspace.ignoreSymlinks; } await this.initializeFileWatching(); @@ -452,20 +463,26 @@ export class WatchFileSystemAdaptor extends FileSystemAdaptor { } /** - * Check if a path contains any excluded pattern (like .git, node_modules) + * Check if a path contains any excluded pattern (like .git, node_modules, or external attachments folder) * This checks all parts of the path, so it will catch: * - Direct .git directories: wiki/.git/config * - Sub-wiki .git directories: wiki/tiddlers/subwiki/.git/index.lock * - Symlinked .git directories: wiki/tiddlers/link-to-subwiki/.git/config + * - External attachments folders: wiki/files/image.png * @param filePath File or directory path to check * @returns true if path should be excluded */ private shouldExcludeByPattern(filePath: string): boolean { // Check if any part of the path contains excluded patterns - return this.excludedPathPatterns.some(pattern => { - const pathParts = filePath.split(path.sep); - return pathParts.includes(pattern); - }); + const pathParts = filePath.split(path.sep); + + // Check standard excluded patterns + const hasExcludedPattern = this.excludedPathPatterns.some(pattern => pathParts.includes(pattern)); + + // Check external attachments folder + const hasExternalAttachmentsFolder = pathParts.includes(this.externalAttachmentsFolder); + + return hasExcludedPattern || hasExternalAttachmentsFolder; } /** diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/in-tagtree-of.ts.meta b/src/services/wiki/plugin/watchFileSystemAdaptor/in-tagtree-of.js.meta similarity index 100% rename from src/services/wiki/plugin/watchFileSystemAdaptor/in-tagtree-of.ts.meta rename to src/services/wiki/plugin/watchFileSystemAdaptor/in-tagtree-of.js.meta diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/loader.ts b/src/services/wiki/plugin/watchFileSystemAdaptor/loader.ts index 9a6cbf66..e688bbce 100644 --- a/src/services/wiki/plugin/watchFileSystemAdaptor/loader.ts +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/loader.ts @@ -3,6 +3,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ // Only export in Node.js environment if ($tw.node) { - const WatchFileSystemAdaptor = require('./WatchFileSystemAdaptor').WatchFileSystemAdaptor; + const WatchFileSystemAdaptor = require('$:/plugins/linonetwo/watch-filesystem-adaptor/WatchFileSystemAdaptor.js').WatchFileSystemAdaptor; exports.adaptorClass = WatchFileSystemAdaptor; } diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.js.meta b/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.js.meta new file mode 100644 index 00000000..abbe2bb9 --- /dev/null +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.js.meta @@ -0,0 +1,3 @@ +title: $:/plugins/linonetwo/watch-filesystem-adaptor/routingUtilities.js +type: application/javascript +module-type: utils diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.ts b/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.ts index 2fe4868e..dda31e94 100644 --- a/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.ts +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.ts @@ -1,9 +1,15 @@ import type { IWikiWorkspace, IWorkspace } from '@services/workspaces/interface'; +import { workspaceSorter } from '@services/workspaces/utilities'; + +/** + * Sub-wiki routing utilities for matching tiddlers/files to workspaces. + * These utilities are exposed as $tw.utils functions for use in plugins. + */ /** * Check if a workspace has routing configuration (tagNames or fileSystemPathFilter). */ -export function hasRoutingConfig(workspaceItem: IWorkspace): boolean { +function hasRoutingConfig(workspaceItem: IWorkspace): boolean { const hasTagNames = 'tagNames' in workspaceItem && Array.isArray(workspaceItem.tagNames) && workspaceItem.tagNames.length > 0; const hasFilter = 'fileSystemPathFilterEnable' in workspaceItem && workspaceItem.fileSystemPathFilterEnable && @@ -16,7 +22,7 @@ export function hasRoutingConfig(workspaceItem: IWorkspace): boolean { * Check if a workspace is a wiki workspace with routing configuration. * This filters to wiki workspaces that are either the main workspace or sub-wikis of it. */ -export function isWikiWorkspaceWithRouting( +function isWikiWorkspaceWithRouting( workspaceItem: IWorkspace, mainWorkspaceId: string, ): workspaceItem is IWikiWorkspace { @@ -48,7 +54,7 @@ export function isWikiWorkspaceWithRouting( * - Any of the tiddler's tags match any of the workspace's tagNames * - The tiddler's title IS one of the tagNames (it's a "tag tiddler") */ -export function matchesDirectTag( +function matchesDirectTag( tiddlerTitle: string, tiddlerTags: string[], workspaceTagNames: string[], @@ -67,7 +73,7 @@ export function matchesDirectTag( * Check if a tiddler matches a workspace's tag tree routing. * Uses TiddlyWiki's in-tagtree-of filter for recursive tag hierarchy matching. */ -export function matchesTagTree( +function matchesTagTree( tiddlerTitle: string, workspaceTagNames: string[], wiki: typeof $tw.wiki, @@ -90,7 +96,7 @@ export function matchesTagTree( * Check if a tiddler matches a workspace's custom filter routing. * Filters are separated by newlines; any match wins. */ -export function matchesCustomFilter( +function matchesCustomFilter( tiddlerTitle: string, filterExpression: string, wiki: typeof $tw.wiki, @@ -116,7 +122,7 @@ export function matchesCustomFilter( * 2. If includeTagTree is enabled, use in-tagtree-of filter for recursive tag matching * 3. If fileSystemPathFilterEnable is enabled, use custom filter expressions */ -export function matchTiddlerToWorkspace( +function matchTiddlerToWorkspace( tiddlerTitle: string, tiddlerTags: string[], workspacesWithRouting: IWikiWorkspace[], @@ -146,3 +152,12 @@ export function matchTiddlerToWorkspace( return undefined; } + +declare const exports: Record; +exports.hasRoutingConfig = hasRoutingConfig; +exports.isWikiWorkspaceWithRouting = isWikiWorkspaceWithRouting; +exports.workspaceSorter = workspaceSorter; +exports.matchesDirectTag = matchesDirectTag; +exports.matchesTagTree = matchesTagTree; +exports.matchesCustomFilter = matchesCustomFilter; +exports.matchTiddlerToWorkspace = matchTiddlerToWorkspace; diff --git a/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.type.ts b/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.type.ts new file mode 100644 index 00000000..85c7944f --- /dev/null +++ b/src/services/wiki/plugin/watchFileSystemAdaptor/routingUtilities.type.ts @@ -0,0 +1,19 @@ +/** + * Type definitions for extended TiddlyWiki $tw.utils with routing utilities + */ + +import type { IWikiWorkspace, IWorkspace } from '@services/workspaces/interface'; + +/** + * Extended utilities interface with routing utilities + */ +export interface ExtendedUtilities { + isWikiWorkspaceWithRouting(workspace: IWorkspace, mainWorkspaceId: string): workspace is IWikiWorkspace; + matchTiddlerToWorkspace( + tiddlerTitle: string, + tiddlerTags: string[], + workspacesWithRouting: IWikiWorkspace[], + wiki: typeof $tw.wiki, + rootWidget: typeof $tw.rootWidget, + ): IWikiWorkspace | undefined; +}