Skip to content

Commit

Permalink
Make create() extensible
Browse files Browse the repository at this point in the history
* Extensible: Create FileSystemRepresentation
* Refactoring: Move most jobs to subclasses of FileSystemRepresentation
  • Loading branch information
KSXGitHub committed May 25, 2018
1 parent 8e9855a commit 14984c6
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/typescript/fs-tree-utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import traverse from './lib/traverse'
import read from './lib/read'
import create from './lib/create'
export * from './lib/types'
export * from './lib/classes'
export {traverse, read, create}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as path from 'path'
import * as fsx from 'fs-extra'
import {WriteTreeObject, WriteTree} from '../../types'
import create from '../../create'

export abstract class FileSystemRepresentation {
abstract async write (target: string): Promise<void>
}

export namespace FileSystemRepresentation {
export class File extends FileSystemRepresentation {
private readonly content: File.Content

constructor (content: File.Content) {
super()
this.content = content
}

async write (filename: string) {
await fsx.writeFile(filename, this.content)
}
}

export namespace File {
export type Content = string | Buffer
}

export class Directory extends FileSystemRepresentation {
readonly content: Directory.Content

constructor (content: Directory.Content) {
super()
this.content = content
}

async write (dirname: string) {
if (fsx.existsSync(dirname)) {
const stats = await fsx.stat(dirname)
if (!stats.isDirectory()) {
throw new Error(`Entity ${dirname} exists but is not directory`)
}
} else {
await fsx.mkdir(dirname)
}

await Promise.all(
Object
.entries(this.content)
.map(([key, val]): [string, WriteTree] => [path.join(dirname, key), val])
.map(([newContainer, newTree]) => create(newTree, newContainer))
)
}
}

export namespace Directory {
export type Content = WriteTreeObject
}

export class Symlink extends FileSystemRepresentation {
private readonly linkTarget: string
private readonly type?: Symlink.Options.Type

constructor (linkTarget: string, options: Symlink.Options = {}) {
super()
this.linkTarget = linkTarget
Object.assign(this, options)
}

async write (linkName: string) {
await fsx.symlink(linkName, this.linkTarget, this.type)
}
}

export namespace Symlink {
export interface Options {
readonly type?: Options.Type
}

export namespace Options {
export type Type = 'dir' | 'file' | 'junction'
}
}
}

export default FileSystemRepresentation
2 changes: 2 additions & 0 deletions packages/typescript/fs-tree-utils/lib/classes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import FileSystemRepresentation from './fs-representation'
export {FileSystemRepresentation}
31 changes: 12 additions & 19 deletions packages/typescript/fs-tree-utils/lib/create.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
import * as path from 'path'
import * as fsx from 'fs-extra'
import {Tree} from './types'
import {WriteTree} from './types'
import FileSystemRepresentation from './classes/fs-representation'
const {File, Directory} = FileSystemRepresentation

/**
* Create a directory tree
* @param tree Tree structure that needs to create
* @param container Where to place the tree
*/
export async function create (tree: Tree, container: string = '') {
export async function create (tree: WriteTree, container: string = ''): Promise<void> {
if (typeof tree === 'string') {
await fsx.writeFile(container, tree)
return
return create(new File(tree), container)
}

if (fsx.existsSync(container)) {
const stats = await fsx.stat(container)
if (!stats.isDirectory()) {
throw new Error(`Entity ${container} exists but is not directory`)
}
} else {
await fsx.mkdir(container)
if (typeof tree === 'function') {
return tree(container)
}

await Promise.all(
Object
.entries(tree)
.map(([key, val]): [string, Tree] => [path.join(container, key), val])
.map(([newContainer, newTree]) => create(newTree, newContainer))
)
if (tree instanceof FileSystemRepresentation) {
return create(x => tree.write(x), container)
}

return create(new Directory(tree), container)
}

export namespace create {
Expand Down
8 changes: 8 additions & 0 deletions packages/typescript/fs-tree-utils/lib/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import FileSystemRepresentation from '../classes/fs-representation'

export type FileContent = string
export type TreeObject = {[name: string]: TreeObject | FileContent}
export type TreeNode = FileContent | TreeObject
export type Tree = TreeNode

export type WriteFileContent = FileContent
export type WriteFunction = (name: string) => Promise<void> | void
export type WriteTreeObject = {readonly [name: string]: WriteTreeObject | WriteFileContent}
export type WriteTreeNode = WriteFileContent | WriteFunction | WriteTreeObject | FileSystemRepresentation
export type WriteTree = WriteTreeNode

0 comments on commit 14984c6

Please sign in to comment.