Skip to content

Commit

Permalink
fix: folder path separators are incorrectly replaced
Browse files Browse the repository at this point in the history
Fix for #219
  • Loading branch information
sywhb authored Apr 18, 2024
2 parents efbcfd4 + 5d09b9f commit 5d6bf4f
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 27 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"no-prototype-builtins": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-extra-semi": "off",
"semi": [2, "never"]
"semi": [2, "never"],
"no-control-regex": 0
}
}
61 changes: 42 additions & 19 deletions src/__tests__/path_validation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as fs from 'fs'
import {
ILLEGAL_CHAR_REGEX,
replaceIllegalChars,
ILLEGAL_CHAR_REGEX_FILE,
replaceIllegalCharsFile,
replaceIllegalCharsFolder,
REPLACEMENT_CHAR,
} from '../util'

const expectedManualIllegalChars: string[] = [
'/',
const expectedManualIllegalCharsInFolderName: string[] = [
'\\',
'?',
'*',
Expand All @@ -19,59 +19,82 @@ const expectedManualIllegalChars: string[] = [
'\u001F',
]

// Adding forward slash too which is not allowed in file names
const expectedManualIllegalChars =
expectedManualIllegalCharsInFolderName.concat(['/'])

// ZERO WIDTH JOINER and SOFT HYPHEN
const expectedInvisibleChars: string[] = ['­', '‍']

describe('replaceIllegalChars() removes all expected characters', () => {
describe('replaceIllegalCharsFolder() does not replace forward slash', () => {
test('Forward slash is not replaced', () => {
const input = 'this/that'
const output = replaceIllegalCharsFolder(input)
expect(output).toEqual(input)
})
})

describe('replaceIllegalCharsFolder() removes all expected characters', () => {
test.each(expectedManualIllegalCharsInFolderName)(
'Illegal character "%s" is removed',
(character) => {
const input = `this${character}string`
const output = replaceIllegalCharsFolder(input)
expect(output).not.toContain(character)
},
)
})

describe('replaceIllegalCharsFile() removes all expected characters', () => {
test.each(expectedManualIllegalChars)(
'Illegal character "%s" is removed',
(character) => {
const input = `this${character}string`
const output = replaceIllegalChars(input)
const output = replaceIllegalCharsFile(input)
expect(output).not.toContain(character)
},
)
})

describe('replaceIllegalChars() function replaces illegal characters with replacement char', () => {
describe('replaceIllegalCharsFile() function replaces illegal characters with replacement char', () => {
test.each(expectedManualIllegalChars)(
"Illegal character '%s' is replaced",
(char) => {
const input = `this${char}string`
const expectedOutput = `this${REPLACEMENT_CHAR}string`
const output = replaceIllegalChars(input)
const output = replaceIllegalCharsFile(input)
expect(output).toEqual(expectedOutput)
},
)
})

describe('replaceIllegalChars() function does not modify string without illegal characters', () => {
describe('replaceIllegalCharsFile() function does not modify string without illegal characters', () => {
test.each(['this_is_a_valid_string', 'this is a valid string'])(
"String '%s' is not modified",
(input) => {
const output = replaceIllegalChars(input)
const output = replaceIllegalCharsFile(input)
expect(output).toEqual(input)
},
)
})

describe('replaceIllegalChars() function handles empty string', () => {
describe('replaceIllegalCharsFile() function handles empty string', () => {
test('Empty string is not modified', () => {
const input = ''
const output = replaceIllegalChars(input)
const output = replaceIllegalCharsFile(input)
expect(output).toEqual(input)
})
})

describe('replaceIllegalChars() function replaces all occurrences of illegal characters', () => {
describe('replaceIllegalCharsFile() function replaces all occurrences of illegal characters', () => {
test.each(expectedManualIllegalChars)(
"Illegal character '%s' is replaced",
(char) => {
const input = `${char}foo${char}bar`
const expectedOutput = `${REPLACEMENT_CHAR}foo${REPLACEMENT_CHAR}bar`
const output = replaceIllegalChars(input)
const output = replaceIllegalCharsFile(input)
expect(output).toEqual(expectedOutput)
expect(output.match(ILLEGAL_CHAR_REGEX)).toBeNull()
expect(output.match(ILLEGAL_CHAR_REGEX_FILE)).toBeNull()
},
)
})
Expand All @@ -82,7 +105,7 @@ describe('file system behavior with non-alphanumeric characters not in the illeg
(_, i) => String.fromCharCode(i + 32),
)
.filter((char) => !/^[a-zA-Z0-9]+$/.test(char))
.map(replaceIllegalChars)
.map(replaceIllegalCharsFile)

test.each(nonAlphanumericCharactersWithoutIllegal)(
"File system allows creation of file with character '%s'",
Expand All @@ -101,15 +124,15 @@ describe('file system behavior with non-alphanumeric characters not in the illeg
)
})

describe('replaceIllegalChars() function removes all occurrences of invisible characters', () => {
describe('replaceIllegalCharsFile() function removes all occurrences of invisible characters', () => {
test.each(expectedInvisibleChars)(
"Invisible character '%s' is replaced",
(char) => {
const input = `${char}foo${char}bar`
const expectedOutput = 'foobar'
const output = replaceIllegalChars(input)
const output = replaceIllegalCharsFile(input)
expect(output).toEqual(expectedOutput)
expect(output.match(ILLEGAL_CHAR_REGEX)).toBeNull()
expect(output.match(ILLEGAL_CHAR_REGEX_FILE)).toBeNull()
},
)
})
7 changes: 4 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import {
parseDateTime,
parseFrontMatterFromContent,
removeFrontMatterFromContent,
replaceIllegalChars,
replaceIllegalCharsFile,
replaceIllegalCharsFolder,
setOrUpdateHighlightColors,
} from './util'
import { OmnivoreSettingTab } from './settingsTab'
Expand Down Expand Up @@ -247,7 +248,7 @@ export default class OmnivorePlugin extends Plugin {
)

for (const item of items) {
const folderName = replaceIllegalChars(
const folderName = replaceIllegalCharsFolder(
normalizePath(render(item, folder, this.settings.folderDateFormat)),
)
const omnivoreFolder =
Expand All @@ -274,7 +275,7 @@ export default class OmnivorePlugin extends Plugin {
fileAttachment,
)
// use the custom filename
const customFilename = replaceIllegalChars(
const customFilename = replaceIllegalCharsFile(
renderFilename(item, filename, this.settings.filenameDateFormat),
)
const pageName = `${folderName}/${customFilename}.md`
Expand Down
15 changes: 12 additions & 3 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const REPLACEMENT_CHAR = '-'
// On Unix-like systems / is reserved and <>:"/\|?* as well as non-printable characters \u0000-\u001F on Windows
// credit: https://github.com/sindresorhus/filename-reserved-regex
// eslint-disable-next-line no-control-regex
export const ILLEGAL_CHAR_REGEX = /[<>:"/\\|?*\u0000-\u001F]/g
export const ILLEGAL_CHAR_REGEX_FILE = /[<>:"/\\|?*\u0000-\u001F]/g
export const ILLEGAL_CHAR_REGEX_FOLDER = /[<>:"\\|?*\u0000-\u001F]/g

export interface HighlightPoint {
left: number
Expand Down Expand Up @@ -103,8 +104,16 @@ export const unicodeSlug = (str: string, savedAt: string) => {
)
}

export const replaceIllegalChars = (str: string): string => {
return removeInvisibleChars(str.replace(ILLEGAL_CHAR_REGEX, REPLACEMENT_CHAR))
export const replaceIllegalCharsFile = (str: string): string => {
return removeInvisibleChars(
str.replace(ILLEGAL_CHAR_REGEX_FILE, REPLACEMENT_CHAR),
)
}

export const replaceIllegalCharsFolder = (str: string): string => {
return removeInvisibleChars(
str.replace(ILLEGAL_CHAR_REGEX_FOLDER, REPLACEMENT_CHAR),
)
}

export function formatDate(date: string, format: string): string {
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"isolatedModules": true,
"strictNullChecks": true,
"esModuleInterop": true,
"lib": ["ES2021","ES2021.String", "DOM"]
"lib": ["ES2021", "ES2021.String", "DOM"]
},
"include": ["src/**/*.ts"]
}

0 comments on commit 5d6bf4f

Please sign in to comment.