2017-11-03 02:09:34 +02:00
const fs = require ( 'fs-extra' ) ;
2020-10-09 19:35:46 +02:00
const shim = require ( 'lib/shim' ) . default ;
2017-11-03 02:09:34 +02:00
const { GeolocationNode } = require ( 'lib/geolocation-node.js' ) ;
const { FileApiDriverLocal } = require ( 'lib/file-api-driver-local.js' ) ;
2020-10-09 19:35:46 +02:00
const { setLocale , defaultLocale , closestSupportedLocale } = require ( 'lib/locale' ) ;
2020-10-21 01:23:55 +02:00
const FsDriverNode = require ( 'lib/fs-driver-node' ) . default ;
2018-05-25 09:51:54 +02:00
const mimeUtils = require ( 'lib/mime-utils.js' ) . mime ;
2018-06-10 02:19:24 +02:00
const Note = require ( 'lib/models/Note.js' ) ;
const Resource = require ( 'lib/models/Resource.js' ) ;
2018-05-01 20:05:14 +02:00
const urlValidator = require ( 'valid-url' ) ;
2020-10-09 19:35:46 +02:00
const { _ } = require ( 'lib/locale' ) ;
2020-02-27 02:14:40 +02:00
const http = require ( 'http' ) ;
const https = require ( 'https' ) ;
2020-03-10 01:24:57 +02:00
const toRelative = require ( 'relative' ) ;
2020-10-09 19:35:46 +02:00
const timers = require ( 'timers' ) ;
2017-07-24 20:01:40 +02:00
2017-07-10 20:09:58 +02:00
function shimInit ( ) {
2019-07-29 15:43:53 +02:00
shim . fsDriver = ( ) => {
throw new Error ( 'Not implemented' ) ;
} ;
2017-07-24 20:01:40 +02:00
shim . FileApiDriverLocal = FileApiDriverLocal ;
2017-07-10 20:09:58 +02:00
shim . Geolocation = GeolocationNode ;
2017-07-24 20:01:40 +02:00
shim . FormData = require ( 'form-data' ) ;
2017-12-12 01:52:42 +02:00
shim . sjclModule = require ( 'lib/vendor/sjcl.js' ) ;
2017-10-15 13:13:09 +02:00
2018-01-21 19:01:37 +02:00
shim . fsDriver = ( ) => {
if ( ! shim . fsDriver _ ) shim . fsDriver _ = new FsDriverNode ( ) ;
return shim . fsDriver _ ;
2019-07-29 15:43:53 +02:00
} ;
2018-01-21 19:01:37 +02:00
2020-05-21 10:14:33 +02:00
shim . randomBytes = async count => {
2017-12-12 19:51:07 +02:00
const buffer = require ( 'crypto' ) . randomBytes ( count ) ;
return Array . from ( buffer ) ;
2019-07-29 15:43:53 +02:00
} ;
2017-12-12 19:51:07 +02:00
2019-07-29 15:43:53 +02:00
shim . detectAndSetLocale = function ( Setting ) {
2017-11-04 14:23:46 +02:00
let locale = process . env . LANG ;
if ( ! locale ) locale = defaultLocale ( ) ;
locale = locale . split ( '.' ) ;
locale = locale [ 0 ] ;
locale = closestSupportedLocale ( locale ) ;
Setting . setValue ( 'locale' , locale ) ;
setLocale ( locale ) ;
return locale ;
2019-07-29 15:43:53 +02:00
} ;
2017-11-04 14:23:46 +02:00
2018-05-10 11:45:44 +02:00
shim . writeImageToFile = async function ( nativeImage , mime , targetPath ) {
2019-07-29 15:43:53 +02:00
if ( shim . isElectron ( ) ) {
// For Electron
2018-05-25 09:51:54 +02:00
let buffer = null ;
2018-05-10 11:45:44 +02:00
2018-05-25 09:51:54 +02:00
mime = mime . toLowerCase ( ) ;
2018-05-10 11:45:44 +02:00
2018-05-25 09:51:54 +02:00
if ( mime === 'image/png' ) {
buffer = nativeImage . toPNG ( ) ;
} else if ( mime === 'image/jpg' || mime === 'image/jpeg' ) {
buffer = nativeImage . toJPEG ( 90 ) ;
}
2018-05-10 11:45:44 +02:00
2019-09-19 23:51:18 +02:00
if ( ! buffer ) throw new Error ( ` Cannot resize image because mime type " ${ mime } " is not supported: ${ targetPath } ` ) ;
2018-05-10 11:45:44 +02:00
2018-05-25 09:51:54 +02:00
await shim . fsDriver ( ) . writeFile ( targetPath , buffer , 'buffer' ) ;
} else {
throw new Error ( 'Node support not implemented' ) ;
}
2019-07-29 15:43:53 +02:00
} ;
2018-05-10 11:45:44 +02:00
2020-03-31 23:40:38 +02:00
shim . showMessageBox = ( message , options = null ) => {
if ( shim . isElectron ( ) ) {
2020-10-09 19:35:46 +02:00
const bridge = require ( 'electron' ) . remote . require ( './bridge' ) . default ;
2020-03-31 23:40:38 +02:00
return bridge ( ) . showMessageBox ( message , options ) ;
} else {
throw new Error ( 'Not implemented' ) ;
}
} ;
const handleResizeImage _ = async function ( filePath , targetPath , mime , resizeLargeImages ) {
2019-05-12 12:38:33 +02:00
const maxDim = Resource . IMAGE _MAX _DIMENSION ;
2019-07-29 15:43:53 +02:00
if ( shim . isElectron ( ) ) {
// For Electron
2018-04-22 21:10:43 +02:00
const nativeImage = require ( 'electron' ) . nativeImage ;
let image = nativeImage . createFromPath ( filePath ) ;
2019-09-19 23:51:18 +02:00
if ( image . isEmpty ( ) ) throw new Error ( ` Image is invalid or does not exist: ${ filePath } ` ) ;
2018-04-22 21:10:43 +02:00
const size = image . getSize ( ) ;
2020-03-31 23:40:38 +02:00
let mustResize = size . width > maxDim || size . height > maxDim ;
if ( mustResize && resizeLargeImages === 'ask' ) {
const answer = shim . showMessageBox ( _ ( 'You are about to attach a large image (%dx%d pixels). Would you like to resize it down to %d pixels before attaching it?' , size . width , size . height , maxDim ) , {
buttons : [ _ ( 'Yes' ) , _ ( 'No' ) , _ ( 'Cancel' ) ] ,
} ) ;
if ( answer === 2 ) return false ;
mustResize = answer === 0 ;
}
if ( ! mustResize ) {
2018-04-22 21:10:43 +02:00
shim . fsDriver ( ) . copy ( filePath , targetPath ) ;
2020-03-31 23:40:38 +02:00
return true ;
2018-04-22 21:10:43 +02:00
}
const options = { } ;
if ( size . width > size . height ) {
options . width = maxDim ;
} else {
options . height = maxDim ;
}
image = image . resize ( options ) ;
2018-05-10 11:45:44 +02:00
await shim . writeImageToFile ( image , mime , targetPath ) ;
2019-07-29 15:43:53 +02:00
} else {
// For the CLI tool
2018-04-22 21:10:43 +02:00
const sharp = require ( 'sharp' ) ;
2019-05-12 12:38:33 +02:00
const image = sharp ( filePath ) ;
const md = await image . metadata ( ) ;
if ( md . width <= maxDim && md . height <= maxDim ) {
shim . fsDriver ( ) . copy ( filePath , targetPath ) ;
2020-03-31 23:40:38 +02:00
return true ;
2019-05-12 12:38:33 +02:00
}
2018-04-22 21:10:43 +02:00
return new Promise ( ( resolve , reject ) => {
2019-07-29 15:43:53 +02:00
image
. resize ( Resource . IMAGE _MAX _DIMENSION , Resource . IMAGE _MAX _DIMENSION , {
fit : 'inside' ,
withoutEnlargement : true ,
} )
. toFile ( targetPath , ( err , info ) => {
if ( err ) {
reject ( err ) ;
} else {
resolve ( info ) ;
}
} ) ;
2017-11-11 00:18:00 +02:00
} ) ;
2018-04-22 21:10:43 +02:00
}
2020-03-31 23:40:38 +02:00
return true ;
2019-07-29 15:43:53 +02:00
} ;
2017-11-11 00:18:00 +02:00
2020-03-31 23:40:38 +02:00
shim . createResourceFromPath = async function ( filePath , defaultProps = null , options = null ) {
options = Object . assign ( {
2020-05-30 14:25:05 +02:00
resizeLargeImages : 'always' , // 'always', 'ask' or 'never'
2020-07-24 02:45:15 +02:00
userSideValidation : false ,
2020-03-31 23:40:38 +02:00
} , options ) ;
2018-05-23 15:25:59 +02:00
const readChunk = require ( 'read-chunk' ) ;
const imageType = require ( 'image-type' ) ;
2020-10-09 19:35:46 +02:00
const uuid = require ( 'lib/uuid' ) . default ;
2020-10-21 01:23:55 +02:00
const { basename , fileExtension , safeFileExtension } = require ( 'lib/path-utils' ) ;
2017-11-11 00:18:00 +02:00
if ( ! ( await fs . pathExists ( filePath ) ) ) throw new Error ( _ ( 'Cannot access %s' , filePath ) ) ;
2019-02-03 20:58:44 +02:00
defaultProps = defaultProps ? defaultProps : { } ;
const resourceId = defaultProps . id ? defaultProps . id : uuid . create ( ) ;
2020-07-24 02:45:15 +02:00
const resource = Resource . new ( ) ;
2019-02-03 20:58:44 +02:00
resource . id = resourceId ;
2019-10-08 21:36:33 +02:00
resource . mime = mimeUtils . fromFilename ( filePath ) ;
2017-12-02 01:15:49 +02:00
resource . title = basename ( filePath ) ;
2018-05-23 15:25:59 +02:00
let fileExt = safeFileExtension ( fileExtension ( filePath ) ) ;
if ( ! resource . mime ) {
const buffer = await readChunk ( filePath , 0 , 64 ) ;
const detectedType = imageType ( buffer ) ;
if ( detectedType ) {
fileExt = detectedType . ext ;
resource . mime = detectedType . mime ;
} else {
resource . mime = 'application/octet-stream' ;
}
}
resource . file _extension = fileExt ;
2017-11-11 00:18:00 +02:00
2020-03-14 01:46:14 +02:00
const targetPath = Resource . fullPath ( resource ) ;
2017-11-11 00:18:00 +02:00
2020-05-30 14:25:05 +02:00
if ( options . resizeLargeImages !== 'never' && [ 'image/jpeg' , 'image/jpg' , 'image/png' ] . includes ( resource . mime ) ) {
2020-03-31 23:40:38 +02:00
const ok = await handleResizeImage _ ( filePath , targetPath , resource . mime , options . resizeLargeImages ) ;
if ( ! ok ) return null ;
2017-11-11 00:18:00 +02:00
} else {
await fs . copy ( filePath , targetPath , { overwrite : true } ) ;
}
2020-07-24 02:45:15 +02:00
// While a whole object can be passed as defaultProps, we only just
// support the title and ID (used above). Any other prop should be
// derived from the provided file.
if ( 'title' in defaultProps ) resource . title = defaultProps . title ;
2019-02-03 20:58:44 +02:00
2019-05-12 02:15:52 +02:00
const itDoes = await shim . fsDriver ( ) . waitTillExists ( targetPath ) ;
2019-09-19 23:51:18 +02:00
if ( ! itDoes ) throw new Error ( ` Resource file was not created: ${ targetPath } ` ) ;
2019-05-12 02:15:52 +02:00
2019-05-11 18:55:40 +02:00
const fileStat = await shim . fsDriver ( ) . stat ( targetPath ) ;
resource . size = fileStat . size ;
2020-07-24 02:45:15 +02:00
const saveOptions = { isNew : true } ;
if ( options . userSideValidation ) saveOptions . userSideValidation = true ;
return Resource . save ( resource , saveOptions ) ;
2019-07-29 15:43:53 +02:00
} ;
2018-05-23 13:14:38 +02:00
2020-05-02 17:41:07 +02:00
shim . attachFileToNoteBody = async function ( noteBody , filePath , position = null , options = null ) {
2020-03-31 23:40:38 +02:00
options = Object . assign ( { } , {
createFileURL : false ,
} , options ) ;
2019-07-29 12:16:47 +02:00
const { basename } = require ( 'path' ) ;
2020-10-09 19:35:46 +02:00
const { escapeTitleText } = require ( 'lib/markdownUtils' ) . default ;
2019-07-29 12:16:47 +02:00
const { toFileProtocolPath } = require ( 'lib/path-utils' ) ;
2020-03-31 23:40:38 +02:00
let resource = null ;
if ( ! options . createFileURL ) {
resource = await shim . createResourceFromPath ( filePath , null , options ) ;
2020-04-03 00:01:14 +02:00
if ( ! resource ) return null ;
2019-07-29 12:16:47 +02:00
}
2018-05-23 13:14:38 +02:00
2018-02-25 19:01:16 +02:00
const newBody = [ ] ;
2018-05-10 11:45:44 +02:00
if ( position === null ) {
2020-05-02 17:41:07 +02:00
position = noteBody ? noteBody . length : 0 ;
2018-05-10 11:45:44 +02:00
}
2020-05-02 17:41:07 +02:00
if ( noteBody && position ) newBody . push ( noteBody . substr ( 0 , position ) ) ;
2019-07-29 12:16:47 +02:00
2020-03-31 23:40:38 +02:00
if ( ! options . createFileURL ) {
2019-07-29 12:16:47 +02:00
newBody . push ( Resource . markdownTag ( resource ) ) ;
} else {
2020-06-07 13:55:40 +02:00
const filename = escapeTitleText ( basename ( filePath ) ) ; // to get same filename as standard drag and drop
2020-03-14 01:46:14 +02:00
const fileURL = ` [ ${ filename } ]( ${ toFileProtocolPath ( filePath ) } ) ` ;
2019-07-29 12:16:47 +02:00
newBody . push ( fileURL ) ;
}
2020-05-02 17:41:07 +02:00
if ( noteBody ) newBody . push ( noteBody . substr ( position ) ) ;
return newBody . join ( '\n\n' ) ;
} ;
shim . attachFileToNote = async function ( note , filePath , position = null , options = null ) {
const newBody = await shim . attachFileToNoteBody ( note . body , filePath , position , options ) ;
if ( ! newBody ) return null ;
2018-02-25 19:01:16 +02:00
2017-11-11 00:18:00 +02:00
const newNote = Object . assign ( { } , note , {
2020-05-02 17:41:07 +02:00
body : newBody ,
2017-11-11 00:18:00 +02:00
} ) ;
return await Note . save ( newNote ) ;
2019-07-29 15:43:53 +02:00
} ;
2017-11-11 00:18:00 +02:00
2018-05-25 09:51:54 +02:00
shim . imageFromDataUrl = async function ( imageDataUrl , filePath , options = null ) {
if ( options === null ) options = { } ;
if ( shim . isElectron ( ) ) {
const nativeImage = require ( 'electron' ) . nativeImage ;
let image = nativeImage . createFromDataURL ( imageDataUrl ) ;
2020-02-14 01:59:23 +02:00
if ( image . isEmpty ( ) ) throw new Error ( 'Could not convert data URL to image - perhaps the format is not supported (eg. image/gif)' ) ; // Would throw for example if the image format is no supported (eg. image/gif)
2018-09-23 19:03:11 +02:00
if ( options . cropRect ) {
// Crop rectangle values need to be rounded or the crop() call will fail
const c = options . cropRect ;
if ( 'x' in c ) c . x = Math . round ( c . x ) ;
if ( 'y' in c ) c . y = Math . round ( c . y ) ;
if ( 'width' in c ) c . width = Math . round ( c . width ) ;
if ( 'height' in c ) c . height = Math . round ( c . height ) ;
image = image . crop ( c ) ;
}
2018-05-25 09:51:54 +02:00
const mime = mimeUtils . fromDataUrl ( imageDataUrl ) ;
await shim . writeImageToFile ( image , mime , filePath ) ;
} else {
2018-09-27 10:14:05 +02:00
if ( options . cropRect ) throw new Error ( 'Crop rect not supported in Node' ) ;
const imageDataURI = require ( 'image-data-uri' ) ;
const result = imageDataURI . decode ( imageDataUrl ) ;
2019-07-29 15:43:53 +02:00
await shim . fsDriver ( ) . writeFile ( filePath , result . dataBuffer , 'buffer' ) ;
2018-05-25 09:51:54 +02:00
}
2019-07-29 15:43:53 +02:00
} ;
2018-05-25 09:51:54 +02:00
2017-10-15 13:13:09 +02:00
const nodeFetch = require ( 'node-fetch' ) ;
2018-09-27 20:35:10 +02:00
// Not used??
2020-05-21 10:14:33 +02:00
shim . readLocalFileBase64 = path => {
2017-11-05 18:51:03 +02:00
const data = fs . readFileSync ( path ) ;
return new Buffer ( data ) . toString ( 'base64' ) ;
2019-07-29 15:43:53 +02:00
} ;
2017-11-05 18:51:03 +02:00
2017-10-22 14:45:56 +02:00
shim . fetch = async function ( url , options = null ) {
2018-05-01 20:05:14 +02:00
const validatedUrl = urlValidator . isUri ( url ) ;
2019-09-19 23:51:18 +02:00
if ( ! validatedUrl ) throw new Error ( ` Not a valid URL: ${ url } ` ) ;
2018-05-01 20:05:14 +02:00
2017-11-13 00:52:54 +02:00
return shim . fetchWithRetry ( ( ) => {
2019-07-29 15:43:53 +02:00
return nodeFetch ( url , options ) ;
2017-11-13 00:52:54 +02:00
} , options ) ;
2019-07-29 15:43:53 +02:00
} ;
2017-07-10 20:09:58 +02:00
shim . fetchBlob = async function ( url , options ) {
if ( ! options || ! options . path ) throw new Error ( 'fetchBlob: target file path is missing' ) ;
if ( ! options . method ) options . method = 'GET' ;
2019-10-09 21:35:13 +02:00
// if (!('maxRetry' in options)) options.maxRetry = 5;
2017-07-10 20:09:58 +02:00
const urlParse = require ( 'url' ) . parse ;
url = urlParse ( url . trim ( ) ) ;
2018-03-24 21:35:10 +02:00
const method = options . method ? options . method : 'GET' ;
2017-07-10 20:09:58 +02:00
const http = url . protocol . toLowerCase ( ) == 'http:' ? require ( 'follow-redirects' ) . http : require ( 'follow-redirects' ) . https ;
const headers = options . headers ? options . headers : { } ;
const filePath = options . path ;
function makeResponse ( response ) {
return {
ok : response . statusCode < 400 ,
path : filePath ,
2019-07-29 15:43:53 +02:00
text : ( ) => {
return response . statusMessage ;
} ,
json : ( ) => {
2019-09-19 23:51:18 +02:00
return { message : ` ${ response . statusCode } : ${ response . statusMessage } ` } ;
2019-07-29 15:43:53 +02:00
} ,
2017-07-10 20:09:58 +02:00
status : response . statusCode ,
headers : response . headers ,
} ;
}
const requestOptions = {
protocol : url . protocol ,
2018-05-20 13:20:15 +02:00
host : url . hostname ,
2017-07-10 20:09:58 +02:00
port : url . port ,
method : method ,
2019-09-19 23:51:18 +02:00
path : url . pathname + ( url . query ? ` ? ${ url . query } ` : '' ) ,
2017-07-10 20:09:58 +02:00
headers : headers ,
} ;
2017-10-22 14:45:56 +02:00
const doFetchOperation = async ( ) => {
return new Promise ( ( resolve , reject ) => {
2018-05-20 13:20:15 +02:00
let file = null ;
2020-05-21 10:14:33 +02:00
const cleanUpOnError = error => {
2018-05-20 13:20:15 +02:00
// We ignore any unlink error as we only want to report on the main error
2019-07-29 15:43:53 +02:00
fs . unlink ( filePath )
. catch ( ( ) => { } )
. then ( ( ) => {
if ( file ) {
file . close ( ( ) => {
file = null ;
reject ( error ) ;
} ) ;
} else {
2018-05-20 13:20:15 +02:00
reject ( error ) ;
2019-07-29 15:43:53 +02:00
}
} ) ;
} ;
2018-05-20 13:20:15 +02:00
2017-10-22 14:45:56 +02:00
try {
// Note: relative paths aren't supported
2018-05-20 13:20:15 +02:00
file = fs . createWriteStream ( filePath ) ;
file . on ( 'error' , function ( error ) {
cleanUpOnError ( error ) ;
} ) ;
2017-07-10 20:09:58 +02:00
2018-03-24 21:35:10 +02:00
const request = http . request ( requestOptions , function ( response ) {
2017-10-22 14:45:56 +02:00
response . pipe ( file ) ;
2017-07-10 20:09:58 +02:00
2017-10-22 14:45:56 +02:00
file . on ( 'finish' , function ( ) {
file . close ( ( ) => {
resolve ( makeResponse ( response ) ) ;
} ) ;
2017-07-10 20:09:58 +02:00
} ) ;
2019-07-29 15:43:53 +02:00
} ) ;
2017-07-10 20:09:58 +02:00
2017-10-22 14:45:56 +02:00
request . on ( 'error' , function ( error ) {
2018-05-20 13:20:15 +02:00
cleanUpOnError ( error ) ;
2017-10-22 14:45:56 +02:00
} ) ;
2018-03-24 21:35:10 +02:00
request . end ( ) ;
2018-05-20 13:20:15 +02:00
} catch ( error ) {
cleanUpOnError ( error ) ;
2017-10-22 14:45:56 +02:00
}
} ) ;
} ;
2017-11-13 00:52:54 +02:00
return shim . fetchWithRetry ( doFetchOperation , options ) ;
2019-07-29 15:43:53 +02:00
} ;
2017-12-18 22:46:22 +02:00
shim . uploadBlob = async function ( url , options ) {
2019-07-29 15:43:53 +02:00
if ( ! options || ! options . path ) throw new Error ( 'uploadBlob: source file path is missing' ) ;
2017-12-18 22:46:22 +02:00
const content = await fs . readFile ( options . path ) ;
options = Object . assign ( { } , options , {
body : content ,
} ) ;
return shim . fetch ( url , options ) ;
2019-07-29 15:43:53 +02:00
} ;
2017-12-18 22:46:22 +02:00
2018-02-15 20:33:08 +02:00
shim . stringByteLength = function ( string ) {
return Buffer . byteLength ( string , 'utf-8' ) ;
2019-07-29 15:43:53 +02:00
} ;
2018-02-15 20:33:08 +02:00
2018-03-24 21:35:10 +02:00
shim . Buffer = Buffer ;
2020-05-21 10:14:33 +02:00
shim . openUrl = url => {
2020-10-09 19:35:46 +02:00
const bridge = require ( 'electron' ) . remote . require ( './bridge' ) . default ;
2019-12-13 02:40:58 +02:00
// Returns true if it opens the file successfully; returns false if it could
// not find the file.
return bridge ( ) . openExternal ( url ) ;
} ;
2020-02-27 02:14:40 +02:00
shim . httpAgent _ = null ;
2020-05-21 10:14:33 +02:00
shim . httpAgent = url => {
2020-02-27 02:14:40 +02:00
if ( shim . isLinux ( ) && ! shim . httpAgent ) {
2020-03-14 01:46:14 +02:00
const AgentSettings = {
2020-02-27 02:14:40 +02:00
keepAlive : true ,
maxSockets : 1 ,
keepAliveMsecs : 5000 ,
} ;
if ( url . startsWith ( 'https' ) ) {
shim . httpAgent _ = new https . Agent ( AgentSettings ) ;
} else {
shim . httpAgent _ = new http . Agent ( AgentSettings ) ;
}
}
return shim . httpAgent _ ;
} ;
2019-12-13 02:40:58 +02:00
shim . openOrCreateFile = ( filepath , defaultContents ) => {
// If the file doesn't exist, create it
if ( ! fs . existsSync ( filepath ) ) {
fs . writeFile ( filepath , defaultContents , 'utf-8' , ( error ) => {
if ( error ) {
console . error ( ` error: ${ error } ` ) ;
}
} ) ;
}
// Open the file
return shim . openUrl ( ` file:// ${ filepath } ` ) ;
2019-07-29 15:43:53 +02:00
} ;
2018-06-25 19:14:57 +02:00
2019-07-29 15:43:53 +02:00
shim . waitForFrame = ( ) => { } ;
2020-01-24 22:56:44 +02:00
shim . appVersion = ( ) => {
if ( shim . isElectron ( ) ) {
const p = require ( '../packageInfo.js' ) ;
return p . version ;
}
const p = require ( '../package.json' ) ;
return p . version ;
} ;
2020-03-10 01:24:57 +02:00
shim . pathRelativeToCwd = ( path ) => {
return toRelative ( process . cwd ( ) , path ) ;
} ;
2020-06-03 18:07:50 +02:00
2020-10-09 19:35:46 +02:00
shim . setTimeout = ( fn , interval ) => {
return timers . setTimeout ( fn , interval ) ;
} ;
shim . setInterval = ( fn , interval ) => {
return timers . setInterval ( fn , interval ) ;
} ;
shim . clearTimeout = ( id ) => {
return timers . clearTimeout ( id ) ;
} ;
shim . clearInterval = ( id ) => {
return timers . clearInterval ( id ) ;
} ;
2017-07-10 20:09:58 +02:00
}
2018-11-14 00:37:39 +02:00
module . exports = { shimInit } ;