diff --git a/README.md b/README.md index 68a02d0..88a7fe4 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,28 @@ If disabled, a timestamp will be used as the title e.g. `note-splitter-170259191 > [!NOTE] > Disabled by default. +#### Removed characters + +Depending on your operating system, Obsidian will not allow certain characters in a file name. + +When `Use first line as title` is enabled, invalid characters in the first line will be removed. + +| Character | Removed On | +| --------- | --------------------- | +| `*` | Windows | +| `"` | Windows | +| `` ` `` | Windows | +| `?` | Windows | +| `<` | Windows | +| `>` | Windows | +| `:` | Windows, macOS, Linux | +| `\` | Windows, macOS, Linux | +| `/` | Windows, macOS, Linux | +| `^` | Windows, macOS, Linux | +| `[` | Windows, macOS, Linux | +| `]` | Windows, macOS, Linux | +| `#` | Windows, macOS, Linux | + ### Append to split content This text will be appended to each section of split content. diff --git a/bun.lockb b/bun.lockb index a7b7ff6..c4cdc30 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/manifest.json b/manifest.json index 5a7f845..483f456 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "note-splitter", "name": "Note Splitter", - "version": "1.2.0", + "version": "1.2.1", "minAppVersion": "0.15.0", "description": "Split a note into individual notes based on a delimiter.", "author": "DecafDev", diff --git a/package.json b/package.json index 01b2503..660f9b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-note-splitter", - "version": "1.2.0", + "version": "1.2.1", "description": "Split notes based on a delimiter", "main": "main.js", "scripts": { diff --git a/src/main.ts b/src/main.ts index c029695..1004fa4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { MarkdownView, Notice, Plugin } from "obsidian"; +import { MarkdownView, Notice, Platform, Plugin } from "obsidian"; import NoteSplitterSettingsTab from "./obsidian/note-splitter-settings-tab"; import { splitByDelimiter } from "./splitter/split-by-delimiter"; import { NodeFileSystem, NoteSplitterSettings, Notifier } from "./types"; @@ -47,7 +47,7 @@ export default class NoteSplitterPlugin extends Plugin { read: (file) => this.app.vault.read(file), }; const notifier: Notifier = (message: string) => new Notice(message); - await splitByDelimiter(fileSystem, notifier, file, this.settings); + await splitByDelimiter(fileSystem, notifier, file, Platform.isWin, this.settings); }, }); } diff --git a/src/splitter/sanitize-file-name.ts b/src/splitter/sanitize-file-name.ts index da65d15..e3870a1 100644 --- a/src/splitter/sanitize-file-name.ts +++ b/src/splitter/sanitize-file-name.ts @@ -1,22 +1,23 @@ /** * Sanitizes a file name for use in a file system */ -export const sanitizeFileName = (name: string) => { - // Replace colon with hyphen - name = name.replace(/:/g, "-"); - // Replace back slash with space - name = name.replace(/\\/g, " "); - // Replace forward slash with space - name = name.replace(/\//g, " "); - // Replace carrot with nothing - name = name.replace(/\^/g, ""); - // Replace left bracket with nothing - name = name.replace(/\[/g, ""); - // Replace right bracket with nothing - name = name.replace(/\]/g, ""); - // Replace hash tag with nothing - name = name.replace(/#/g, ""); - // Replace pipe with nothing - name = name.replace(/\|/g, ""); - return name.trim(); +export const sanitizeFileName = (name: string, isWindows: boolean) => { + if (isWindows) { + name = name.replace(/\?/g, ""); // Remove question mark (Windows) + name = name.replace(//g, ""); // Remove greater than (Windows) + name = name.replace(/"/g, ""); // Remove double quote (Windows) + name = name.replace(/\*/g, ""); // Remove asterisk (Windows) + name = name.replace(/`/g, ""); // Remove backtick (Windows) + } + + name = name.replace(/:/g, ""); // Remove colon (Windows, macOS) + name = name.replace(/\|/g, ""); // Remove pipe (Windows) + name = name.replace(/\\/g, ""); // Remove backslash (Windows, general cross-platform safety) + name = name.replace(/\//g, ""); // Remove forward slash (Windows, Linux, macOS) + name = name.replace(/\[/g, ""); // Remove left bracket (General safety, no specific OS restriction) + name = name.replace(/\]/g, ""); // Remove right bracket (General safety, no specific OS restriction) + name = name.replace(/#/g, ""); // Remove hashtag (General safety, no specific OS restriction) + name = name.replace(/\^/g, ""); // Remove caret (General safety, no specific OS restriction) + return name.trim(); // Trim whitespace from start and end (General cleanup) }; diff --git a/src/splitter/split-by-delimiter.ts b/src/splitter/split-by-delimiter.ts index 30fa78c..ef4d551 100644 --- a/src/splitter/split-by-delimiter.ts +++ b/src/splitter/split-by-delimiter.ts @@ -1,4 +1,4 @@ -import { normalizePath, TFile } from "obsidian"; +import { normalizePath, Platform, TFile } from "obsidian"; import { removeFrontmatterBlock } from "./remove-frontmatter-block"; import { sanitizeFileName } from "./sanitize-file-name"; import { truncateFileName } from "./truncate-file-name"; @@ -8,6 +8,7 @@ export const splitByDelimiter = async ( fileSystem: NodeFileSystem, notify: Notifier, file: TFile, + isWindows: boolean, { delimiter, saveFolderPath, @@ -69,8 +70,8 @@ export const splitByDelimiter = async ( fileName = `split-note-${Date.now() + i}.md`; } - fileName = sanitizeFileName(fileName); - fileName = truncateFileName(fileName); + fileName = sanitizeFileName(fileName, isWindows); + fileName = truncateFileName(fileName, ".md"); const filePath = normalizePath(`${folderPath}/${fileName}`); diff --git a/src/splitter/truncate-file-name.ts b/src/splitter/truncate-file-name.ts index 98ee941..6535f14 100644 --- a/src/splitter/truncate-file-name.ts +++ b/src/splitter/truncate-file-name.ts @@ -1,15 +1,14 @@ /** * Truncates the string to the maximum length allowed for a file name */ -export const truncateFileName = (name: string) => { +export const truncateFileName = (name: string, extension: string) => { const MAX_LENGTH = 255; - const splitArr = name.split("."); - if (splitArr.length < 2) { - throw new Error("Invalid file name"); + //Add support for links + let length = name.length; + if (length > MAX_LENGTH) { + length = MAX_LENGTH; } - const baseName = splitArr[0]; - const extension = splitArr[1]; - return baseName.substring(0, MAX_LENGTH - extension.length - 1) + "." + splitArr[1]; + return name.substring(0, length - extension.length) + extension; }; diff --git a/test/integration/split-by-delimiter.test.ts b/test/integration/split-by-delimiter.test.ts index 9efeaf3..61f02c2 100644 --- a/test/integration/split-by-delimiter.test.ts +++ b/test/integration/split-by-delimiter.test.ts @@ -30,7 +30,7 @@ describe("splitByDelimiter", () => { path: "file1.md", } as TFile; - await splitByDelimiter(mockFileSystem, mockNotifier, file, { + await splitByDelimiter(mockFileSystem, mockNotifier, file, false, { delimiter: "", saveFolderPath: "", useContentAsTitle: false, @@ -47,7 +47,7 @@ describe("splitByDelimiter", () => { path: "file1.md", } as TFile; - await splitByDelimiter(mockFileSystem, mockNotifier, file, { + await splitByDelimiter(mockFileSystem, mockNotifier, file, false, { delimiter: "\n", saveFolderPath: "", useContentAsTitle: false, @@ -64,7 +64,7 @@ describe("splitByDelimiter", () => { path: "file2.md", } as TFile; - await splitByDelimiter(mockFileSystem, mockNotifier, file, { + await splitByDelimiter(mockFileSystem, mockNotifier, file, false, { delimiter: "\n", saveFolderPath: "", useContentAsTitle: false, @@ -81,7 +81,7 @@ describe("splitByDelimiter", () => { path: "file3.md", } as TFile; - await splitByDelimiter(mockFileSystem, mockNotifier, file, { + await splitByDelimiter(mockFileSystem, mockNotifier, file, false, { delimiter: "\n", saveFolderPath: "", useContentAsTitle: false, @@ -109,7 +109,7 @@ describe("splitByDelimiter", () => { path: "file3.md", } as TFile; - await splitByDelimiter(mockFileSystem, mockNotifier, file, { + await splitByDelimiter(mockFileSystem, mockNotifier, file, false, { delimiter: "\n", saveFolderPath: "", useContentAsTitle: false, @@ -126,7 +126,7 @@ describe("splitByDelimiter", () => { path: "file3.md", } as TFile; - await splitByDelimiter(mockFileSystem, mockNotifier, file, { + await splitByDelimiter(mockFileSystem, mockNotifier, file, false, { delimiter: "\n", saveFolderPath: "", useContentAsTitle: false, @@ -150,7 +150,7 @@ describe("splitByDelimiter", () => { path: "file3.md", } as TFile; - await splitByDelimiter(mockFileSystem, mockNotifier, file, { + await splitByDelimiter(mockFileSystem, mockNotifier, file, false, { delimiter: "\n", saveFolderPath: "", useContentAsTitle: true, diff --git a/test/unit/sanitize-file-name.test.ts b/test/unit/sanitize-file-name.test.ts index c6e837e..228b6a8 100644 --- a/test/unit/sanitize-file-name.test.ts +++ b/test/unit/sanitize-file-name.test.ts @@ -6,10 +6,10 @@ describe("sanitizeFileName", () => { const content = "file:name"; // Act - const result = sanitizeFileName(content); + const result = sanitizeFileName(content, false); // Assert - expect(result).toEqual("file-name"); + expect(result).toEqual("filename"); }); it("should replace backslash with space", () => { @@ -17,10 +17,10 @@ describe("sanitizeFileName", () => { const content = "file\\name"; // Act - const result = sanitizeFileName(content); + const result = sanitizeFileName(content, false); // Assert - expect(result).toEqual("file name"); + expect(result).toEqual("filename"); }); it("should replace forward slash with space", () => { @@ -28,10 +28,10 @@ describe("sanitizeFileName", () => { const content = "file//name"; // Act - const result = sanitizeFileName(content); + const result = sanitizeFileName(content, false); // Assert - expect(result).toEqual("file name"); + expect(result).toEqual("filename"); }); it("should remove invalid characters", () => { @@ -39,7 +39,7 @@ describe("sanitizeFileName", () => { const content = "file name #|^[]"; // Act - const result = sanitizeFileName(content); + const result = sanitizeFileName(content, false); // Assert expect(result).toEqual("file name"); diff --git a/test/unit/truncate-file-name.test.ts b/test/unit/truncate-file-name.test.ts index 1fb896a..87a32c1 100644 --- a/test/unit/truncate-file-name.test.ts +++ b/test/unit/truncate-file-name.test.ts @@ -1,26 +1,26 @@ import { truncateFileName } from "src/splitter/truncate-file-name"; describe("truncateFileName", () => { - it("should throw an error if the file name is invalid", () => { + it("should truncate the string to 255 characters", () => { // Arrange - const fileName = "file"; + const fileName = "a".repeat(260) + ".md"; // Act - const action = () => truncateFileName(fileName); + const result = truncateFileName(fileName, ".md"); // Assert - expect(action).toThrow(); + expect(result.length).toEqual(255); + expect(result.endsWith(".md")).toEqual(true); }); - it("should truncate the string to 255 characters", () => { + it("should not modify a link shorter than 255 characters", () => { // Arrange - const fileName = "a".repeat(260) + ".md"; + const fileName = "https://example.com.md"; // Act - const result = truncateFileName(fileName); + const result = truncateFileName(fileName, ".md"); // Assert - expect(result.length).toEqual(255); - expect(result.endsWith(".md")).toEqual(true); + expect(result).toEqual(fileName); }); }); diff --git a/versions.json b/versions.json index cd1f624..fea03f2 100644 --- a/versions.json +++ b/versions.json @@ -12,5 +12,6 @@ "1.0.0": "0.15.0", "1.1.0": "0.15.0", "1.1.1": "0.15.0", - "1.2.0": "0.15.0" + "1.2.0": "0.15.0", + "1.2.1": "0.15.0" }