2019-10-09 21:35:13 +02:00
/* eslint no-useless-escape: 0*/
2019-07-30 09:35:42 +02:00
2018-11-20 02:42:21 +02:00
const { _ } = require ( 'lib/locale' ) ;
2020-10-21 01:23:55 +02:00
export function dirname ( path :string ) {
2017-06-23 23:32:24 +02:00
if ( ! path ) throw new Error ( 'Path is empty' ) ;
2020-03-14 01:46:14 +02:00
const s = path . split ( /\/|\\/ ) ;
2017-06-23 23:32:24 +02:00
s . pop ( ) ;
return s . join ( '/' ) ;
}
2020-10-21 01:23:55 +02:00
export function basename ( path :string ) {
2017-06-23 20:51:02 +02:00
if ( ! path ) throw new Error ( 'Path is empty' ) ;
2020-03-14 01:46:14 +02:00
const s = path . split ( /\/|\\/ ) ;
2017-06-23 20:51:02 +02:00
return s [ s . length - 1 ] ;
}
2020-10-21 01:23:55 +02:00
export function filename ( path :string , includeDir :boolean = false ) {
2017-06-25 01:19:11 +02:00
if ( ! path ) throw new Error ( 'Path is empty' ) ;
2018-11-20 02:42:21 +02:00
let output = includeDir ? path : basename ( path ) ;
2017-06-25 01:19:11 +02:00
if ( output . indexOf ( '.' ) < 0 ) return output ;
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
}
2020-10-21 01:23:55 +02:00
export function fileExtension ( path :string ) {
2017-07-10 20:17:03 +02:00
if ( ! path ) throw new Error ( 'Path is empty' ) ;
2020-03-14 01:46:14 +02:00
const output = path . split ( '.' ) ;
2017-07-10 20:17:03 +02:00
if ( output . length <= 1 ) return '' ;
return output [ output . length - 1 ] ;
}
2020-10-21 01:23:55 +02:00
export function isHidden ( path :string ) {
2020-03-14 01:46:14 +02:00
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 } ` ) ;
2017-06-23 20:51:02 +02:00
return b [ 0 ] === '.' ;
}
2020-10-21 01:23:55 +02:00
export function safeFileExtension ( e :string , maxLength :number = null ) {
2020-09-17 11:17:45 +02:00
// 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 ;
2017-12-02 01:15:49 +02:00
if ( ! e || ! e . replace ) return '' ;
2019-06-12 10:45:31 +02:00
return e . replace ( /[^a-zA-Z0-9]/g , '' ) . substr ( 0 , maxLength ) ;
2017-12-02 01:15:49 +02:00
}
2020-10-21 01:23:55 +02:00
export function safeFilename ( e :string , maxLength :number = null , allowSpaces :boolean = false ) {
2018-09-04 12:59:09 +02:00
if ( maxLength === null ) maxLength = 32 ;
2018-05-23 15:25:59 +02:00
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 ;
2020-03-14 01:46:14 +02:00
const output = e . replace ( regex , '_' ) ;
2018-05-23 15:25:59 +02:00
return output . substr ( 0 , maxLength ) ;
}
2020-09-22 13:06:19 +02:00
let friendlySafeFilename_blackListChars = '/<>:\'"\\|?*#' ;
2018-11-20 02:42:21 +02:00
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' ] ;
2018-11-20 02:42:21 +02:00
2020-10-21 01:23:55 +02:00
export function friendlySafeFilename ( e :string , maxLength :number = null ) {
2020-09-07 23:12:51 +02:00
// 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 ;
2018-11-20 02:42:21 +02:00
if ( ! e || ! e . replace ) return _ ( 'Untitled' ) ;
2019-07-29 15:43:53 +02:00
2018-11-20 02:42:21 +02:00
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 ;
}
}
2018-11-21 02:36:23 +02:00
while ( output . length ) {
const c = output [ 0 ] ;
if ( c === ' ' ) {
output = output . substr ( 1 , output . length - 1 ) ;
} else {
break ;
}
}
2019-07-29 15:43:53 +02:00
if ( ! output ) return _ ( 'Untitled' ) ;
2018-11-20 02:42:21 +02:00
return output . substr ( 0 , maxLength ) ;
}
2020-10-21 01:23:55 +02:00
export function toFileProtocolPath ( filePathEncode :string , os :string = null ) {
2019-07-29 12:16:47 +02:00
if ( os === null ) os = process . platform ;
2019-07-29 15:43:53 +02:00
2019-07-29 12:16:47 +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
2019-07-29 12:16:47 +02:00
}
filePathEncode = encodeURI ( filePathEncode ) ;
filePathEncode = filePathEncode . replace ( /\+/g , '%2B' ) ; // escape '+' with unicode
filePathEncode = filePathEncode . replace ( /%20/g , '+' ) ; // switch space (%20) with '+'. To comply with syntax used by joplin, see urldecode_(str) in MdToHtml.js
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
2019-04-20 22:12:19 +02:00
}
2020-10-21 01:23:55 +02:00
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 , '/' ) ;
2017-12-08 23:51:59 +02:00
}
2020-10-21 01:23:55 +02:00
export function rtrimSlashes ( path :string ) {
2018-05-08 12:29:25 +02:00
return path . replace ( /[\/\\]+$/ , '' ) ;
2018-01-25 21:01:14 +02:00
}
2020-10-21 01:23:55 +02:00
export function ltrimSlashes ( path :string ) {
2018-01-25 21:01:14 +02:00
return path . replace ( /^\/+/ , '' ) ;
}
2020-10-21 01:23:55 +02:00
export function quotePath ( path :string ) {
2019-01-30 21:19:06 +02:00
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 } " ` ;
2019-01-30 21:19:06 +02:00
}
2020-10-21 01:23:55 +02:00
export function unquotePath ( path :string ) {
2019-01-30 21:19:06 +02:00
if ( ! path . length ) return '' ;
if ( path . length && path [ 0 ] === '"' ) {
path = path . substr ( 1 , path . length - 2 ) ;
}
path = path . replace ( /\\"/ , '"' ) ;
return path ;
}
2020-10-21 01:23:55 +02:00
export function extractExecutablePath ( cmd :string ) {
2019-01-30 21:19:06 +02:00
if ( ! cmd . length ) return '' ;
2019-07-30 09:35:42 +02:00
const quoteType = [ '"' , '\'' ] . indexOf ( cmd [ 0 ] ) >= 0 ? cmd [ 0 ] : '' ;
2019-01-30 21:19:06 +02:00
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 ;
}