mirror of
https://github.com/foambubble/foam.git
synced 2026-01-08 05:34:09 -05:00
Change sanitized characters to support Windows paths (#1529)
Fixed #1526
This commit is contained in:
@@ -1,6 +1,28 @@
|
||||
import { asAbsolutePaths } from './path';
|
||||
import { asAbsolutePaths, fromFsPath } from './path';
|
||||
|
||||
describe('path utils', () => {
|
||||
describe('fromFsPath', () => {
|
||||
it('should normalize backslashes in relative paths', () => {
|
||||
const [path] = fromFsPath('areas\\dailies\\2024\\file.md');
|
||||
expect(path).toBe('areas/dailies/2024/file.md');
|
||||
});
|
||||
|
||||
it('should handle mixed separators in relative paths', () => {
|
||||
const [path] = fromFsPath('areas/dailies\\2024/file.md');
|
||||
expect(path).toBe('areas/dailies/2024/file.md');
|
||||
});
|
||||
|
||||
it('should preserve forward slashes in relative paths', () => {
|
||||
const [path] = fromFsPath('areas/dailies/2024/file.md');
|
||||
expect(path).toBe('areas/dailies/2024/file.md');
|
||||
});
|
||||
|
||||
it('should normalize backslashes in Windows absolute paths', () => {
|
||||
const [path] = fromFsPath('C:\\workspace\\file.md');
|
||||
expect(path).toBe('/C:/workspace/file.md');
|
||||
});
|
||||
});
|
||||
|
||||
describe('asAbsolutePaths', () => {
|
||||
it('returns the path if already absolute', () => {
|
||||
const paths = asAbsolutePaths('/path/to/test', [
|
||||
|
||||
@@ -16,13 +16,16 @@ export function fromFsPath(path: string): [string, string] {
|
||||
let authority: string;
|
||||
if (isUNCShare(path)) {
|
||||
[path, authority] = parseUNCShare(path);
|
||||
path = path.replace(/\\/g, '/');
|
||||
} else if (hasDrive(path)) {
|
||||
path = '/' + path[0].toUpperCase() + path.substr(1).replace(/\\/g, '/');
|
||||
path = '/' + path[0].toUpperCase() + path.substr(1);
|
||||
} else if (path[0] === '/' && hasDrive(path, 1)) {
|
||||
// POSIX representation of a Windows path: just normalize drive letter case
|
||||
path = '/' + path[1].toUpperCase() + path.substr(2);
|
||||
}
|
||||
|
||||
// Always normalize backslashes to forward slashes (filesystem → POSIX)
|
||||
path = path.replace(/\\/g, '/');
|
||||
|
||||
return [path, authority];
|
||||
}
|
||||
|
||||
|
||||
@@ -493,17 +493,17 @@ foam_template:
|
||||
'foam-vscode.create-note'
|
||||
);
|
||||
|
||||
// Title with many invalid characters (excluding / which is preserved for directories): \#%&{}<>?*$!'":@+`|=
|
||||
// Title with many invalid characters
|
||||
const resolver = new Resolver(new Map(), new Date());
|
||||
resolver.define('FOAM_TITLE', 'Test\\#%&{}<>?*$!\'"Title:@+`|=');
|
||||
resolver.define('FOAM_TITLE', 'Test#%&{}<>?*$!\'"Title@+`|=');
|
||||
|
||||
const result = await engine.processTemplate(trigger, template, resolver);
|
||||
|
||||
// All invalid characters should become dashes: Test + 14 invalid chars + Title + : + @+`|= (6 more total)
|
||||
expect(result.filepath.path).toBe('Test--------------Title------.md');
|
||||
// All invalid characters should become dashes
|
||||
expect(result.filepath.path).toBe('Test-------------Title-----.md');
|
||||
|
||||
// Content should remain unchanged
|
||||
expect(result.content).toContain('# Test\\#%&{}<>?*$!\'"Title:@+`|=');
|
||||
expect(result.content).toContain('# Test#%&{}<>?*$!\'"Title@+`|=');
|
||||
});
|
||||
|
||||
it('should not affect FOAM_TITLE when not used in filepath', async () => {
|
||||
@@ -569,7 +569,7 @@ Date and title combination.`,
|
||||
const result = await engine.processTemplate(trigger, template, resolver);
|
||||
|
||||
// Entire resolved filepath should be sanitized
|
||||
expect(result.filepath.path).toBe('2024/03/Note-With-Invalid-Chars.md');
|
||||
expect(result.filepath.path).toBe('2024/03/Note:With-Invalid-Chars.md');
|
||||
|
||||
// Content should use original FOAM_TITLE
|
||||
expect(result.content).toContain('# Note:With|Invalid*Chars');
|
||||
@@ -601,5 +601,78 @@ foam_template:
|
||||
expect(result.filepath.path).toBe('notes/ValidTitle123.md');
|
||||
expect(result.content).toContain('# ValidTitle123');
|
||||
});
|
||||
|
||||
it('should preserve backslashes as directory separators (Windows-style paths)', async () => {
|
||||
const { engine } = await setupFoamEngine();
|
||||
|
||||
// Simulate a resolved filepath with Windows-style backslash separators
|
||||
const template: Template = {
|
||||
type: 'markdown',
|
||||
content: `# MyNote`,
|
||||
metadata: new Map([
|
||||
['filepath', 'areas\\dailies\\2024\\MyNote.md'], // Already resolved, has backslashes
|
||||
]),
|
||||
};
|
||||
|
||||
const trigger = TriggerFactory.createCommandTrigger(
|
||||
'foam-vscode.create-note'
|
||||
);
|
||||
|
||||
const resolver = new Resolver(new Map(), new Date());
|
||||
|
||||
const result = await engine.processTemplate(trigger, template, resolver);
|
||||
|
||||
// Backslashes should be normalized to forward slashes
|
||||
expect(result.filepath.path).toBe('areas/dailies/2024/MyNote.md');
|
||||
expect(result.content).toContain('# MyNote');
|
||||
});
|
||||
|
||||
it('should normalize mixed forward and backslashes', async () => {
|
||||
const { engine } = await setupFoamEngine();
|
||||
|
||||
// Simulate a resolved filepath with mixed separators
|
||||
const template: Template = {
|
||||
type: 'markdown',
|
||||
content: `# MyNote`,
|
||||
metadata: new Map([
|
||||
['filepath', 'areas/dailies\\2024/MyNote.md'], // Mixed separators
|
||||
]),
|
||||
};
|
||||
|
||||
const trigger = TriggerFactory.createCommandTrigger(
|
||||
'foam-vscode.create-note'
|
||||
);
|
||||
|
||||
const resolver = new Resolver(new Map(), new Date());
|
||||
|
||||
const result = await engine.processTemplate(trigger, template, resolver);
|
||||
|
||||
// Both separators should be normalized to forward slashes
|
||||
expect(result.filepath.path).toBe('areas/dailies/2024/MyNote.md');
|
||||
expect(result.content).toContain('# MyNote');
|
||||
});
|
||||
|
||||
it('should sanitize invalid characters while normalizing backslash separators', async () => {
|
||||
const { engine } = await setupFoamEngine();
|
||||
|
||||
// Simulate a resolved filepath with backslash separator and invalid chars
|
||||
const template: Template = {
|
||||
type: 'markdown',
|
||||
content: `# Note:With*Invalid`,
|
||||
metadata: new Map([['filepath', 'areas\\Note:With*Invalid.md']]), // Backslash + invalid chars
|
||||
};
|
||||
|
||||
const trigger = TriggerFactory.createCommandTrigger(
|
||||
'foam-vscode.create-note'
|
||||
);
|
||||
|
||||
const resolver = new Resolver(new Map(), new Date());
|
||||
|
||||
const result = await engine.processTemplate(trigger, template, resolver);
|
||||
|
||||
// Backslash normalized to forward slash, invalid chars sanitized
|
||||
expect(result.filepath.path).toBe('areas/Note:With-Invalid.md');
|
||||
expect(result.content).toContain('# Note:With*Invalid');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,14 +14,13 @@ import { URI } from '../core/model/uri';
|
||||
|
||||
/**
|
||||
* Characters that are invalid in file names
|
||||
* Based on UNALLOWED_CHARS from variable-resolver.ts but excluding forward slash
|
||||
* which is needed for directory separators in filepaths
|
||||
* Based on UNALLOWED_CHARS from variable-resolver.ts but excluding filepaths
|
||||
* related chars
|
||||
*/
|
||||
const FILEPATH_UNALLOWED_CHARS = '\\#%&{}<>?*$!\'":@+`|=';
|
||||
const FILEPATH_UNALLOWED_CHARS = '#%&{}<>?*$!\'"@+`|=';
|
||||
|
||||
/**
|
||||
* Sanitizes a filepath by replacing invalid characters with dashes
|
||||
* Note: Forward slashes (/) are preserved for directory separators
|
||||
* @param filepath The filepath to sanitize
|
||||
* @returns The sanitized filepath
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user