1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00
joplin/packages/lib/path-utils.ts

199 lines
5.9 KiB
TypeScript
Raw Normal View History

2019-10-09 21:35:13 +02:00
/* eslint no-useless-escape: 0*/
2020-11-05 18:58:23 +02:00
const { _ } = require('./locale');
export function dirname(path: string) {
2017-06-23 23:32:24 +02:00
if (!path) throw new Error('Path is empty');
const s = path.split(/\/|\\/);
2017-06-23 23:32:24 +02:00
s.pop();
return s.join('/');
}
export function basename(path: string) {
if (!path) throw new Error('Path is empty');
const s = path.split(/\/|\\/);
return s[s.length - 1];
}
export function filename(path: string, includeDir: boolean = false) {
2017-06-25 01:19:11 +02:00
if (!path) throw new Error('Path is empty');
2020-10-24 01:14:30 +02:00
const output = includeDir ? path : basename(path);
2017-06-25 01:19:11 +02:00
if (output.indexOf('.') < 0) return output;
Plugins: Added support for content scripts - For now, supports Markdown-it plugins - Also fixed slow rendering of notes in some cases - Simplified how Markdown-It plugins are created and cleaned MdToHtml code commit 89576de2896c99134f25f2a2db25008514cb1315 Merge: c75aa21f 5292fc14 Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 21 00:23:00 2020 +0100 Merge branch 'release-1.3' into plugin_content_scripts commit c75aa21ffdc42764d71dc9deadba7a7ef4233995 Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 21 00:19:52 2020 +0100 Fixed tests commit 075187729d11a16d385b651cbf1ebb89f14935e0 Author: Laurent Cozic <laurent@cozic.net> Date: Wed Oct 21 00:11:53 2020 +0100 Fixed tests commit 14696b8c651e7afdaf71269bcdbadf0d58d3ef8a Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 20 23:27:58 2020 +0100 Fixed slow rendering of note commit 61c09f5bf856481f91b00cfe87ff05596c63d4bc Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 20 22:35:21 2020 +0100 Clean up commit 9f7ea7d865a990b3a21cc8c59093390d9db61653 Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 20 20:05:31 2020 +0100 Updated doc commit 98bf3bde8d6663f2f91ff965304b4aac00bdd98b Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 20 19:56:34 2020 +0100 Finished converting plugins commit fe90d92e01427bd2b38200393713ea28763507a9 Author: Laurent Cozic <laurent@cozic.net> Date: Tue Oct 20 17:52:02 2020 +0100 Simplified how Markdown-It plugins are created commit 47c7b864cbb864d5df79849f27625aecf312df4b Author: Laurent Cozic <laurent@cozic.net> Date: Mon Oct 19 16:40:11 2020 +0100 Clean up rules commit d927a238bb635a4be45f9216d776f7d07cb0a584 Author: Laurent Cozic <laurent@cozic.net> Date: Mon Oct 19 14:29:40 2020 +0100 Fixed tests commit 388a56c5dde4c382e3ee0035791137150adaba1b Author: Laurent Cozic <laurent@cozic.net> Date: Mon Oct 19 14:00:47 2020 +0100 Add support for content scripts
2020-10-21 01:23:55 +02:00
const splitted = output.split('.');
splitted.pop();
return splitted.join('.');
2017-06-25 01:19:11 +02:00
}
export function fileExtension(path: string) {
2017-07-10 20:17:03 +02:00
if (!path) throw new Error('Path is empty');
const output = path.split('.');
2017-07-10 20:17:03 +02:00
if (output.length <= 1) return '';
return output[output.length - 1];
}
export function isHidden(path: string) {
const b = basename(path);
2019-09-19 23:51:18 +02:00
if (!b.length) throw new Error(`Path empty or not a valid path: ${path}`);
return b[0] === '.';
}
export function safeFileExtension(e: string, maxLength: number = null) {
// In theory the file extension can have any length but in practice Joplin
// expects a fixed length, so we limit it to 20 which should cover most cases.
// Note that it means that a file extension longer than 20 will break
// external editing (since the extension would be truncated).
// https://discourse.joplinapp.org/t/troubles-with-webarchive-files-on-ios/10447
if (maxLength === null) maxLength = 20;
if (!e || !e.replace) return '';
return e.replace(/[^a-zA-Z0-9]/g, '').substr(0, maxLength);
}
export function safeFilename(e: string, maxLength: number = null, allowSpaces: boolean = false) {
if (maxLength === null) maxLength = 32;
if (!e || !e.replace) return '';
2019-07-29 15:43:53 +02:00
const regex = allowSpaces ? /[^a-zA-Z0-9\-_\(\)\. ]/g : /[^a-zA-Z0-9\-_\(\)\.]/g;
const output = e.replace(regex, '_');
return output.substr(0, maxLength);
}
let friendlySafeFilename_blackListChars = '/\n\r<>:\'"\\|?*#';
for (let i = 0; i < 32; i++) {
friendlySafeFilename_blackListChars += String.fromCharCode(i);
}
2019-07-29 15:43:53 +02:00
const friendlySafeFilename_blackListNames = ['.', '..', 'CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'];
// The goal of this function is to provide a safe filename, that should work in
// any filesystem, but that's still user friendly, in particular because it
// supports any charset - Chinese, Russian, etc.
//
// "Safe" however doesn't mean it can be safely inserted in any content (HTML,
// Markdown, etc.) - it still needs to be encoded by the calling code according
// to the context.
export function friendlySafeFilename(e: string, maxLength: number = null, preserveExtension: boolean = false) {
// Although Windows supports paths up to 255 characters, but that includes the filename and its
// parent directory path. Also there's generally no good reason for dir or file names
// to be so long, so keep it at 50, which should prevent various errors.
if (maxLength === null) maxLength = 50;
if (!e || !e.replace) return _('Untitled');
2019-07-29 15:43:53 +02:00
let fileExt = '';
if (preserveExtension) {
const baseExt = fileExtension(e);
fileExt = baseExt ? `.${safeFileExtension(baseExt)}` : '';
e = filename(e);
}
let output = '';
for (let i = 0; i < e.length; i++) {
const c = e[i];
if (friendlySafeFilename_blackListChars.indexOf(c) >= 0) {
output += '_';
} else {
output += c;
}
}
if (output.length <= 4) {
if (friendlySafeFilename_blackListNames.indexOf(output.toUpperCase()) >= 0) {
output = '___';
}
}
while (output.length) {
const c = output[output.length - 1];
if (c === ' ' || c === '.') {
output = output.substr(0, output.length - 1);
} else {
break;
}
}
while (output.length) {
const c = output[0];
if (c === ' ') {
output = output.substr(1, output.length - 1);
} else {
break;
}
}
if (!output) return _('Untitled') + fileExt;
return output.substr(0, maxLength) + fileExt;
}
export function toFileProtocolPath(filePathEncode: string, os: string = null) {
if (os === null) os = process.platform;
2019-07-29 15:43:53 +02:00
if (os === 'win32') {
filePathEncode = filePathEncode.replace(/\\/g, '/'); // replace backslash in windows pathname with slash e.g. c:\temp to c:/temp
2019-09-19 23:51:18 +02:00
filePathEncode = `/${filePathEncode}`; // put slash in front of path to comply with windows fileURL syntax
}
filePathEncode = encodeURI(filePathEncode);
filePathEncode = filePathEncode.replace(/\+/g, '%2B'); // escape '+' with unicode
2019-09-19 23:51:18 +02:00
return `file://${filePathEncode.replace(/\'/g, '%27')}`; // escape '(single quote) with unicode, to prevent crashing the html view
}
export function toSystemSlashes(path: string, os: string = null) {
2018-05-14 19:46:04 +02:00
if (os === null) os = process.platform;
2019-07-29 15:43:53 +02:00
if (os === 'win32') return path.replace(/\//g, '\\');
return path.replace(/\\/g, '/');
}
export function rtrimSlashes(path: string) {
return path.replace(/[\/\\]+$/, '');
2018-01-25 21:01:14 +02:00
}
export function ltrimSlashes(path: string) {
2018-01-25 21:01:14 +02:00
return path.replace(/^\/+/, '');
}
export function trimSlashes(path: string): string {
return ltrimSlashes(rtrimSlashes(path));
}
export function quotePath(path: string) {
if (!path) return '';
if (path.indexOf('"') < 0 && path.indexOf(' ') < 0) return path;
path = path.replace(/"/, '\\"');
2019-09-19 23:51:18 +02:00
return `"${path}"`;
}
export function unquotePath(path: string) {
if (!path.length) return '';
if (path.length && path[0] === '"') {
path = path.substr(1, path.length - 2);
}
path = path.replace(/\\"/, '"');
return path;
}
export function extractExecutablePath(cmd: string) {
if (!cmd.length) return '';
const quoteType = ['"', '\''].indexOf(cmd[0]) >= 0 ? cmd[0] : '';
let output = '';
for (let i = 0; i < cmd.length; i++) {
const c = cmd[i];
if (quoteType) {
if (i > 0 && c === quoteType) {
output += c;
break;
}
} else {
if (c === ' ') break;
}
output += c;
}
return output;
}