Skip to content

Commit

Permalink
feat: add Observable functions
Browse files Browse the repository at this point in the history
pathAcessible(), dirExists(), fileExists()
  • Loading branch information
waitingsong committed Dec 29, 2018
1 parent 6ee8cab commit c9364db
Show file tree
Hide file tree
Showing 2 changed files with 240 additions and 0 deletions.
58 changes: 58 additions & 0 deletions src/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import {
resolve as pathResolve,
sep,
} from 'path'
import { defer, from as ofrom, of, Observable } from 'rxjs'
import {
concatMap, last, map, mapTo, mergeMap, scan,
} from 'rxjs/operators'
import { promisify } from 'util'


Expand All @@ -47,18 +51,40 @@ export {
}
export { tmpdir } from 'os'

export function pathAcessible(path: string): Observable<string> {
return defer(() => isPathAcessible(path)).pipe(
map(exists => exists ? normalize(path) : ''),
)
}
// support relative file ('./foo')
export function isPathAcessible(path: string): Promise<boolean> {
return path
? new Promise(resolve => access(path, err => resolve(err ? false : true)))
: Promise.resolve(false)
}

/** Check folder path exists, return path if exists, blank if not exists */
export function dirExists(path: string): Observable<string> {
if (! path) {
return of('')
}
const dir = normalize(path)
return defer(() => isDirExists(dir)).pipe(
map(exists => exists ? dir : ''),
)
}
export function isDirExists(path: string): Promise<boolean> {
return path ? isDirFileExists(path, 'DIR') : Promise.resolve(false)
}


/** Check file exists, return path if exists, blank if not exists */
export function fileExists(path: string): Observable<string> {
const file = normalize(path)
return defer(() => isFileExists(file)).pipe(
map(exists => exists ? file : ''),
)
}
export function isFileExists(path: string): Promise<boolean> {
return path ? isDirFileExists(path, 'FILE') : Promise.resolve(false)
}
Expand All @@ -74,6 +100,38 @@ function isDirFileExists(path: string, type: 'DIR' | 'FILE'): Promise<boolean> {
: Promise.resolve(false)
}

export function createDirObb(path: string): Observable<string> {
/* istanbul ignore else */
if (! path) {
throw new Error('value of path param invalid')
}

const target = normalize(path) // ! required for '.../.myca' under win32
const paths$ = ofrom(target.split(sep)).pipe(
scan((acc: string, curr: string) => {
return acc ? join(acc, curr) : curr
}, ''),
)
const create$ = paths$.pipe(
concatMap(_createDirObb),
last(),
)

const ret$ = dirExists(path).pipe(
concatMap(p => p ? of(p) : create$),
)

return ret$
}
function _createDirObb(path: string, index?: number): Observable<string> {
return pathAcessible(path).pipe(
mergeMap(str => {
return str
? of(str)
: defer(() => mkdirAsync(path, 0o755)).pipe(mapTo(path))
}),
)
}

/** create directories recursively */
export async function createDir(path: string): Promise<string> {
Expand Down
182 changes: 182 additions & 0 deletions test/10_shared_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@
import * as assert from 'power-assert'
import rewire = require('rewire')
import * as rmdir from 'rimraf'
import { from as ofrom, of } from 'rxjs'
import { mergeMap, tap } from 'rxjs/operators'

import {
basename,
createDir,
createDirObb,
createFile,
dirExists,
isDirExists,
isFileExists,
isPathAcessible,
join,
normalize,
pathAcessible,
readFileAsync,
tmpdir,
} from '../src/shared/index'
Expand Down Expand Up @@ -250,7 +255,58 @@ describe(filename, () => {
})


describe(filename + ' :pathAcessible()', () => {
after(done => {
rmdir(tmpDir, err => {
err && console.error(err)
done()
})
})

const fnName = 'pathAcessible'

it(`Should ${fnName}() works`, done => {
const dir = tmpdir()
return of(dir).pipe(
mergeMap(pathAcessible),
).subscribe(
(path => {
assert(path === dir, `sytem temp path should accessible: "${dir}"`)
done()
}),
(err: Error) => {
assert(false, err.message)
done()
},
)
})

it(`Should ${fnName}() works with invalid value`, async () => {
const dir = join(tmpDir, Math.random().toString())

const ret = await pathAcessible('').toPromise()
assert(ret === '', 'should return false with blank path:' + ret)

if (await pathAcessible(dir).toPromise()) {
return assert(false, `path should not accessible: "${dir}"`)
}

if (await pathAcessible(dir).toPromise()) {
return assert(false, `path should not accessible: "${dir}"`)
}

await createDir(dir)
if (! await pathAcessible(dir).toPromise()) {
return assert(false, `path should accessible: "${dir}"`)
}
})

})

describe(filename + ' :isPathAcessible()', () => {
before(async () => {
await createDir(tmpDir)
})
after(done => {
rmdir(tmpDir, err => {
err && console.error(err)
Expand Down Expand Up @@ -286,4 +342,130 @@ describe(filename + ' :isPathAcessible()', () => {
return assert(false, `path should accessible: "${dir}"`)
}
})

})


describe(filename + ' :dirExists()', () => {
before(async () => {
await createDir(tmpDir)
})
after(done => {
rmdir(tmpDir, err => {
err && console.error(err)
done()
})
})

const fnName = 'dirExists'

it(`Should ${fnName}() works`, done => {
return of(tmpDir).pipe(
mergeMap(dirExists),
).subscribe(
(path => {
assert(path && path === tmpDir, `path should exists: "${tmpDir}"`)
done()
}),
(err: Error) => {
assert(false, err.message)
done()
},
)
})

it(`Should ${fnName}() works with invalid path`, done => {
const random = Math.random()
const randomPath = `${tmpDir}/${pathPrefix}-${random}`

return of(randomPath).pipe(
mergeMap(dirExists),
).subscribe(
(path => {
assert(path === '', `path should NOT exists: "${randomPath}"`)
done()
}),
(err: Error) => {
assert(false, err.message)
done()
},
)
})

it(`Should ${fnName}() works with blank path`, done => {
return of('').pipe(
mergeMap(dirExists),
).subscribe(
(path => {
assert(path === '', 'empty path should NOT exists')
done()
}),
(err: Error) => {
assert(false, err.message)
done()
},
)
})

})


describe(filename + ' :createDirObb()', () => {
before(async () => {
await createDir(tmpDir)
})
after(done => {
rmdir(tmpDir, err => {
err && console.error(err)
done()
})
})

const fnName = 'createDirObb'

it(`Should ${fnName}() works`, done => {
const paths = [
`${tmpDir}/${pathPrefix}-${Math.random()}`,
`${tmpDir}/${pathPrefix}-${Math.random()}/.test/0ab`,
]

return ofrom(paths).pipe(
mergeMap(path => {
return createDirObb(path).pipe(
tap(retPath => {
assert(retPath === normalize(path))
}),
)
}),
mergeMap(dirExists),
).subscribe(
(path => {
assert(path.length)
rmdir(path, err => err && console.error(err))
}),
(err: Error) => {
assert(false, err.message)
done()
},
done,
)
})


it(`Should ${fnName}() works with blank param`, done => {
return of('').pipe(
mergeMap(createDirObb),
mergeMap(dirExists),
).subscribe(
(path => {
assert(false, 'should throw error, but NOT with' + path)
done()
}),
(err: Error) => {
assert(true, err.message)
done()
},
)
})

})

0 comments on commit c9364db

Please sign in to comment.