Skip to content

Commit

Permalink
refactor: remove all sync calls, anything is now async
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex-D committed May 21, 2023
1 parent 1a757b9 commit befabdf
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 74 deletions.
7 changes: 4 additions & 3 deletions src/functions/getFirstExistingParentPath.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import isDirectoryExisting from '@/src/functions/isDirectoryExisting'
import Dependencies from '@/src/types/dependencies'

/**
Expand All @@ -6,13 +7,13 @@ import Dependencies from '@/src/types/dependencies'
* @param directoryPath - The file/folder path from where we want to know disk space
* @param dependencies - Dependencies container
*/
function getFirstExistingParentPath(directoryPath: string, dependencies: Dependencies): string {
async function getFirstExistingParentPath(directoryPath: string, dependencies: Dependencies): Promise<string> {
let parentDirectoryPath = directoryPath
let parentDirectoryFound = dependencies.fsExistsSync(parentDirectoryPath)
let parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies)

while (!parentDirectoryFound) {
parentDirectoryPath = dependencies.pathNormalize(parentDirectoryPath + '/..')
parentDirectoryFound = dependencies.fsExistsSync(parentDirectoryPath)
parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies)
}

return parentDirectoryPath
Expand Down
15 changes: 8 additions & 7 deletions src/functions/hasPowerShell3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@ import Dependencies from '@/src/types/dependencies'
*
* @param dependencies - Dependencies Injection Container
*/
function hasPowerShell3(dependencies: Dependencies): Promise<boolean> {
async function hasPowerShell3(dependencies: Dependencies): Promise<boolean> {
const major = parseInt(dependencies.release.split('.')[0], 10)

if (major <= 6) {
return Promise.resolve(false)
return false
}

return new Promise<boolean>(function (resolve) {
dependencies.cpExecFile('where', ['powershell'], { windowsHide: true }, function (error) {
resolve(!error)
})
})
try {
await dependencies.cpExecFile('where', ['powershell'], { windowsHide: true })
return true
} catch (error) {
return false
}
}

export default hasPowerShell3
18 changes: 18 additions & 0 deletions src/functions/isDirectoryExisting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Dependencies from '@/src/types/dependencies'

/**
* Tells if directory exists
*
* @param directoryPath - The file/folder path
* @param dependencies - Dependencies container
*/
async function isDirectoryExisting(directoryPath: string, dependencies: Dependencies): Promise<boolean> {
try {
await dependencies.fsAccess(directoryPath)
return Promise.resolve(true)
} catch (error) {
return Promise.resolve(false)
}
}

export default isDirectoryExisting
60 changes: 27 additions & 33 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { execFile } from 'child_process'
import { existsSync } from 'fs'
import { release } from 'os'
import { normalize, sep } from 'path'
import { platform } from 'process'
import { execFile } from 'node:child_process'
import { access } from 'node:fs/promises'
import { release } from 'node:os'
import { normalize, sep } from 'node:path'
import { platform } from 'node:process'
import { promisify } from 'node:util'

import InvalidPathError from '@/src/errors/invalidPathError'
import NoMatchError from '@/src/errors/noMatchError'
Expand All @@ -20,10 +21,10 @@ import DiskSpace from '@/src/types/diskSpace'
function checkDiskSpace(directoryPath: string, dependencies: Dependencies = {
platform,
release: release(),
fsExistsSync: existsSync,
fsAccess: access,
pathNormalize: normalize,
pathSep: sep,
cpExecFile: execFile,
cpExecFile: promisify(execFile),
}): Promise<DiskSpace> {
// Note: This function contains other functions in order
// to wrap them in a common context and make unit tests easier
Expand Down Expand Up @@ -69,35 +70,28 @@ function checkDiskSpace(directoryPath: string, dependencies: Dependencies = {
* @param mapping - Map between column index and normalized column name
* @param coefficient - The size coefficient to get bytes instead of kB
*/
function check(
async function check(
cmd: string[],
filter: (driveData: string[]) => boolean,
mapping: Record<string, number>,
coefficient = 1,
): Promise<DiskSpace> {
return new Promise((resolve, reject) => {
const [
file,
...args
] = cmd

/* istanbul ignore if */
if (file === undefined) {
return Promise.reject(new Error('cmd must contain at least one item'))
}

dependencies.cpExecFile(file, args, { windowsHide: true }, (error, stdout) => {
if (error) {
reject(error)
}

try {
resolve(mapOutput(stdout, filter, mapping, coefficient))
} catch (error2) {
reject(error2)
}
})
})
const [
file,
...args
] = cmd

/* istanbul ignore if */
if (file === undefined) {
return Promise.reject(new Error('cmd must contain at least one item'))
}

try {
const { stdout } = await dependencies.cpExecFile(file, args, { windowsHide: true })
return mapOutput(stdout, filter, mapping, coefficient)
} catch (error) {
return Promise.reject(error)
}
}

/**
Expand Down Expand Up @@ -142,12 +136,12 @@ function checkDiskSpace(directoryPath: string, dependencies: Dependencies = {
*
* @param directoryPath - The file/folder path from where we want to know disk space
*/
function checkUnix(directoryPath: string): Promise<DiskSpace> {
async function checkUnix(directoryPath: string): Promise<DiskSpace> {
if (!dependencies.pathNormalize(directoryPath).startsWith(dependencies.pathSep)) {
return Promise.reject(new InvalidPathError(`The following path is invalid (should start by ${dependencies.pathSep}): ${directoryPath}`))
}

const pathToCheck = getFirstExistingParentPath(directoryPath, dependencies)
const pathToCheck = await getFirstExistingParentPath(directoryPath, dependencies)

return check(
[
Expand Down
21 changes: 8 additions & 13 deletions src/types/dependencies.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
import { ChildProcess, ExecException } from 'child_process'
import { existsSync } from 'fs'
import { normalize, sep } from 'path'

type ExecFileException = ExecException & NodeJS.ErrnoException
import { access } from 'node:fs/promises'
import { normalize, sep } from 'node:path'

type Dependencies = {
platform: NodeJS.Platform
release: string
fsExistsSync: typeof existsSync
fsAccess: typeof access
pathNormalize: typeof normalize
pathSep: typeof sep
cpExecFile: (
file: string,
args: ReadonlyArray<string> | undefined | null,
options: {
windowsHide: true
},
callback: (
error: ExecFileException | null,
stdout: string,
stderr: string
) => void
) => ChildProcess
}
) => Promise<{
stdout: string
stderr: string
}>
}

export default Dependencies
24 changes: 12 additions & 12 deletions test/__helpers__/mockDependencies.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ChildProcess } from 'child_process'
import { EventEmitter } from 'events'
import { normalize } from 'path'
import { normalize } from 'node:path'
import { promisify } from 'node:util'

import Dependencies from '@/src/types/dependencies'

Expand All @@ -11,19 +10,20 @@ function mockDependencies(overrides?: Partial<Dependencies>, options?: {
const dependencies: Dependencies = {
platform: 'linux',
release: '11.5.0',
fsExistsSync: () => true,
fsAccess: () => Promise.resolve(),
pathNormalize: normalize,
pathSep: '/',
cpExecFile: (cmd, args, opts, callback) => {
process.nextTick(() => {
if (options?.cpExecFileError !== undefined) {
callback(options.cpExecFileError, '', '')
}
cpExecFile: async () => {
await promisify(process.nextTick)

callback(null, options?.cpExecFileOutput ?? '', '')
})
if (options?.cpExecFileError !== undefined) {
return Promise.reject(options.cpExecFileError)
}

return new EventEmitter() as ChildProcess
return {
stdout: options?.cpExecFileOutput ?? '',
stderr: '',
}
},
...overrides,
}
Expand Down
12 changes: 6 additions & 6 deletions test/functions/getFirstExistingParentPath.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ import getFirstExistingParentPath from '@/src/functions/getFirstExistingParentPa
import mockDependencies from '@/test/__helpers__/mockDependencies'


test('unix: get first existing parent path', t => {
test('unix: get first existing parent path', async t => {
const parentPath = '/home/Alex'
const dependencies = mockDependencies({
fsExistsSync: (directoryPath: PathLike) => directoryPath === parentPath,
fsAccess: async (directoryPath: PathLike) => directoryPath === parentPath ? Promise.resolve() : Promise.reject(new Error('File does not exists')),
})

t.is(getFirstExistingParentPath('/home/Alex/games/Some/Game', dependencies), parentPath)
t.is(await getFirstExistingParentPath('/home/Alex/games/Some/Game', dependencies), parentPath)
})

test('unix: get first parent can be the path itself', t => {
test('unix: get first parent can be the path itself', async t => {
const parentPath = '/home/Alex'
const dependencies = mockDependencies({
fsExistsSync: (directoryPath: PathLike) => directoryPath === parentPath,
fsAccess: async (directoryPath: PathLike) => directoryPath === parentPath ? Promise.resolve() : Promise.reject(new Error('File does not exists')),
})

t.is(getFirstExistingParentPath(parentPath, dependencies), parentPath)
t.is(await getFirstExistingParentPath(parentPath, dependencies), parentPath)
})

0 comments on commit befabdf

Please sign in to comment.