Comparing version 0.1.9 to 0.2.0
241
index.js
@@ -1,9 +0,238 @@ | ||
const Hotfile = require('./models/Hotfile') | ||
const Hotfolder = require('./models/Hotfolder') | ||
const Hot = require('./models/Hot') | ||
const fs = require('fs') | ||
const p = require('path') | ||
const crypto = require('crypto') | ||
exports = module.exports = (path) => new Hotfolder(path) | ||
class HotfileError extends Error {} | ||
class Hotfile { | ||
constructor(path){ | ||
if(p.extname(path) == "" && !this.existsSync(path)) this.mkdirSync(path) | ||
const stat = fs.statSync(path) | ||
this.isFile = stat.isFile() | ||
this.path = path | ||
this.basename = p.basename(path) | ||
this.size = stat.size | ||
stat.isDirectory() ? this.children = [] : this.ext = p.extname(path) | ||
} | ||
/* COMPUTED PROPERTIES */ | ||
get name(){ | ||
return this.ext ? this.basename.replace(this.ext, '') : this.basename | ||
} | ||
get foldername(){ | ||
return this.basename | ||
} | ||
get lowername(){ | ||
return this.name.toLowerCase() | ||
} | ||
get lowerbasename(){ | ||
return this.basename.toLowerCase() | ||
} | ||
get parentPath(){ | ||
return p.dirname(this.path) | ||
} | ||
id(){ | ||
return this.md5Id(this.path) | ||
} | ||
/* GENERAL FUNCTIONS */ | ||
md5Id(string){ | ||
return crypto.createHash('md5').update(string).digest('hex'); | ||
} | ||
static mkdirSync(path, options = { recursive: true }){ | ||
if(!p.extname(path) == "") | ||
throw(new Error(`mkdirSync expects a folder path, but ${path} provided`)) | ||
let flag = true | ||
try{ | ||
fs.mkdirSync(path, options) | ||
}catch(e){ | ||
flag = false | ||
} | ||
return flag | ||
} | ||
static existsSync(path){ | ||
let flag = true | ||
try{ | ||
fs.accessSync(path, fs.constants.F_OK) | ||
}catch(e){ | ||
flag = false | ||
} | ||
return flag | ||
} | ||
mkdirSync(path, options = { recursive: true }){ | ||
if(!p.extname(path) == "") | ||
throw(new Error(`mkdirSync expects a folder path, but ${path} provided`)) | ||
let flag = true | ||
try{ | ||
fs.mkdirSync(path, options) | ||
}catch(e){ | ||
flag = false | ||
} | ||
return flag | ||
} | ||
existsSync(path){ | ||
let flag = true | ||
try{ | ||
fs.accessSync(path, fs.constants.F_OK) | ||
}catch(e){ | ||
flag = false | ||
} | ||
return flag | ||
} | ||
async exists(path){ | ||
try { | ||
await fs.promises.access(path, fs.constants.F_OK) | ||
return true | ||
} catch (err) { | ||
if(err.message.includes('no such file or directory')) return false | ||
} | ||
} | ||
async mkdir(path, options = {}){ | ||
if(!p.extname(path) == "") | ||
throw(new Error(`mkdir expects a folder path, but ${path} provided`)) | ||
const { recursive, force } = options | ||
if(!force && await this.exists(path)) return false | ||
try { | ||
await fs.promises.mkdir(path, { recursive }) | ||
return true | ||
} catch (err) { | ||
console.log(err) | ||
return false | ||
} | ||
} | ||
async rename(from, to){ | ||
try { | ||
await fs.promises.rename(from, to) | ||
this.path = to | ||
} catch (err) { | ||
throw(err) | ||
} | ||
} | ||
async delete(){ | ||
try { | ||
await fs.promises.unlink(this.path) | ||
} catch (err) { | ||
console.error('there was an error:', err.message) | ||
} | ||
} | ||
/* FILE FUNCTIONS */ | ||
setNameTo(name){ | ||
if(!name) throw(new Error(`setNameTo expects a string, ${name} provided`)) | ||
this.basename = name + this.ext | ||
return this | ||
} | ||
appendToBasename(text = null){ | ||
if(text == null) throw(new Error(`setLangTo expects a string, ${text} provided`)) | ||
const basename = this.name.concat(text) | ||
this.basename = this.basename.replace(this.name, basename) | ||
return this | ||
} | ||
setExtTo(ext = null){ | ||
if(ext == null) throw(new Error(`setExtTo expects a string, ${ext} provided`)) | ||
const _ext = '.' + ext.replace(/\.*/g,'') | ||
this.basename = this.basename.replace(this.ext, _ext) | ||
this.ext = _ext | ||
return this | ||
} | ||
setBasenameTo(name = null){ | ||
if(!name) throw(new Error(`setBasenameTo expects a string, ${name} provided`)) | ||
this.basename = name | ||
this.ext = p.extname(name) | ||
return this | ||
} | ||
async moveTo(instance = null, options = {}){ | ||
const { force } = options | ||
if(instance && !(instance instanceof Hotfile)) | ||
throw(new Error(`moveTo: expects Hotfile instace or null, ${instance} provided`)) | ||
let destDir = this.parent | ||
if(instance) destDir = instance.isFile ? instance.parent : instance.path | ||
const to = p.join(destDir, this.basename) | ||
if(force || !await this.exists(to)) await this.rename(this.path, to) | ||
return new Hotfile(to) | ||
} | ||
/* FOLDER FUNCTIONS */ | ||
createFolderSync(name, options = { recursive: true }){ | ||
const path = p.join(this.path, name) | ||
this.mkdirSync(path, options) | ||
if(!options.force && this.existsSync(path)) return new Hotfile(path) | ||
const folder = new Hotfile(path) | ||
this.children.push(folder) | ||
return folder | ||
} | ||
async createFolder(name, options = { recursive: true }){ | ||
const path = p.join(this.path, name) | ||
await this.mkdir(path, options) | ||
if(!options.force && await this.exists(path)) return new Hotfile(path) | ||
const folder = new Hotfile(path) | ||
this.children.push(folder) | ||
return folder | ||
} | ||
async loadChildren(options = {}){ | ||
const { depth } = options | ||
this.children = await this.loaddir(this.path, depth, options) | ||
return this | ||
} | ||
async loaddir(path, depth = 0, options = {}){ | ||
const { id, cb, files, exclude, include, $include, $exclude } = options | ||
let items = await fs.promises.readdir(path) | ||
/* FILTERS */ | ||
if(exclude) items = items.filter(o => !exclude.includes(o)) | ||
if(include) items = items.filter(o => include.includes(o)) | ||
if($exclude) items = items.filter(o => !$exclude.find(regex => (regex).test(o))) | ||
if($include) items = items.filter(o => $include.find(regex => (regex).test(o))) | ||
items = items.map(o => new Hotfile(p.join(path, o))) | ||
for(let i = 0; i < items.length; i++){ | ||
/* options */ | ||
if(cb) await cb(items[i]) | ||
if(id) items[i].id = this.md5Id(items[i].path) | ||
if(files && items[i].isFile) { | ||
if(!this.files) this.files = [] | ||
this.files.push(items[i]) | ||
} | ||
if(!items[i].isFile && depth > 0){ | ||
items[i].children = await this.loaddir(items[i].path, depth - 1, options) | ||
} | ||
} | ||
return items | ||
} | ||
} | ||
exports = module.exports = (path = null) => { | ||
if(!path) throw(new HotfileError(`hotfile requires a directory path, ${path} provided`)) | ||
return new Hotfile(path) | ||
} | ||
exports.Hotfile = Hotfile | ||
exports.Hotfolder = Hotfolder | ||
exports.Hot = Hot | ||
exports.HotfileError = HotfileError |
{ | ||
"name": "hotfile", | ||
"version": "0.1.9", | ||
"description": "", | ||
"version": "0.2.0", | ||
"description": "Hotfile makes working with folders and files in node-js easy and clear.", | ||
"main": "index.js", | ||
@@ -13,5 +13,5 @@ "scripts": { | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC", | ||
"keywords": ["folder", "files", "dirtree", "readdir"], | ||
"author": "David M.Chen", | ||
"license": "MIT", | ||
"bugs": { | ||
@@ -18,0 +18,0 @@ "url": "https://github.com/chen7david/hotfile/issues" |
249
README.md
# Hotfile | ||
Hotfile makes working with folders and files in node-js easy and clear. | ||
## Getting Started | ||
1. <code>$ npm i hotfile</code> | ||
```js | ||
const SOME_FOLDER_PATH = 'some-folder-path' | ||
const aHotFolder = require('hotfile')(SOME_FOLDER_PATH) | ||
const someAsyncFunction = async () => { | ||
await aHotFolder.loadChildren() | ||
console.log(aHotFolder) | ||
} | ||
someAsyncFunction() | ||
``` | ||
```cmd | ||
##### console.log(aHotFolder) | ||
{ | ||
"isFile": false, | ||
"path": "home", | ||
"basename": "home", | ||
"size": 224, | ||
"children": [ | ||
{ | ||
"isFile": false, | ||
"path": "home/1", | ||
"basename": "1", | ||
"size": 192, | ||
"children": [] | ||
}, | ||
... | ||
{ | ||
"isFile": true, | ||
"path": "home/an video file.mp4", | ||
"basename": "an video file.mp4", | ||
"size": 60, | ||
"ext": ".mp4" | ||
} | ||
] | ||
} | ||
``` | ||
## Documentation | ||
### Diagram A | ||
Below is a tree diagram of the folders and files that we will be using in this documentation. This diagram will hereinafter be referred to as "Diagram A" | ||
```cmd | ||
/Users/YOUR_USER_NAME/Desktop/YOUR_PROJECT_NAME/home | ||
├── 1 | ||
| ├── 2 | ||
| | └── 3 | ||
| | └── 4 | ||
| | └── 5 | ||
| | ├── a subtitle file.en.srt | ||
| | ├── an audio file.mp3 | ||
| | └── a video file.mp4 | ||
| ├── a subtitle file.en copy.srt | ||
| ├── an audio file.mp3 | ||
| └── a video file.mp4 | ||
├── a | ||
| ├── a subtitle file.en.srt | ||
| ├── an audio file.mp3 | ||
| ├── an video file.mp4 | ||
| └── b | ||
| └── c | ||
| └── d | ||
| └── e | ||
| ├── a subtitle file.en.srt | ||
| ├── an audio file.mp3 | ||
| └── a video file.mp4 | ||
├── a subtitle file.en.srt | ||
├── an audio file.mp3 | ||
└── a video file.mp4 | ||
directory: 10 file: 15 | ||
``` | ||
### Usage | ||
#### instantiation | ||
#### Instantiation | ||
#### Example 1 | ||
```js | ||
const { Hotfolder, Hotfile, Hot } = require('hotfile') | ||
// const myfolder = require('hotfile')('./myfolder') | ||
const dirpath = './myfolder' | ||
const filepath = './myfile.txt' | ||
const myfolder = new Hotfolder(dirpath) | ||
const myfile = new Hotfile(filepath) | ||
const SOME_FOLDER_PATH = 'home' | ||
const SOME_FILE_PATH = 'home/a/a subtitle file.en.srt' | ||
const aHotFolder = require('hotfile')(SOME_FOLDER_PATH) | ||
const aHotFile = require('hotfile')(SOME_FILE_PATH) | ||
``` | ||
#### 0. place your code in an asycn function | ||
#### Example 2 | ||
If you would like to access the Hotfile and or HotfileError class | ||
```js | ||
const someAsyncFucn = async () => { | ||
// NOTE: all the code below shuold be placed in an asycn function | ||
const SOME_FOLDER_PATH = 'home' | ||
const SOME_FILE_PATH = 'home/a/a subtitle file.en.srt' | ||
const { Hotfile, HotfileError } = require('hotfile') | ||
const aHotFolder = Hotfile(SOME_FOLDER_PATH) | ||
const aHotFile = Hotfile(SOME_FILE_PATH) | ||
``` | ||
### Options | ||
When you want to load the subfolders of a hotfile folder instance can specify certain parameters by passing an options object to the loadChildren function like so: <code>instance.loadChildren(/* options */)</code> | ||
```js | ||
const options = { | ||
id: true, // generates md5 hashes of an item's path and adds that to the item as its id property | ||
depth: 3, // how deep down the directory tree it loads items, this is 0 by default. | ||
files: true, // constructs an array of files present in the loaded folders and attaches it to the instance that called the load method. | ||
cb: async (item) => { /* code in here runs for each loaded file and folder */ }, | ||
exclude: ['strings'], // files and folders matching any of the strings in this array will not be loaded | ||
include: ['strings'], // files and folders matching any of the strings in this array will be loaded | ||
$exclude: ['regex'], // files and folders matching any of the regular expressions in this array will not be loaded | ||
$include: ['regex'] // files and folders matching any of the regular expressions in this array will be loaded | ||
} | ||
aHotFolder.loadChildren(options) | ||
``` | ||
#### 1. Create sub-folders | ||
Note: filters can not be mixed, as such only one of the four filters (include, exclude, $include, $exclude) may be included in an object. | ||
#### Example 1 | ||
In this example we add md5 ids to each loaded item, load just 1 subfolder deep, collect the files in an array, filter out <code>.SD_Store</code> files, and run an async call back function which renames and moves all files to another Hotfile folder instance. | ||
```js | ||
const someAsyncFunction = async () => { | ||
const sub1folder = await myfolder.createFolder('subfolder-01') | ||
const sub2folder = await myfolder.createFolder('subfolder-02') | ||
await aHotFolder.loadChildren({ | ||
id: true, | ||
depth: 1, | ||
files: true, | ||
exclude: ['.DS_Store'], | ||
cb: async (item) => { | ||
const name = item.md5Id(new Date().toISOString()) | ||
const ext = 'mp4' | ||
await item.setNameTo(name).setExtTo(ext).moveTo(anotherHotFolder) | ||
} | ||
}) | ||
} | ||
someAsyncFunction() | ||
``` | ||
#### Example 2 | ||
In this example we load 5 levels deep and delete all files and folders. | ||
```js | ||
const someAsyncFunction = async () => { | ||
await aHotFolder.loadChildren({ | ||
depth: 5, | ||
files: true, | ||
cb: async (item) => { | ||
await item.delete() | ||
} | ||
}) | ||
} | ||
someAsyncFunction() | ||
``` | ||
#### 2. Create file in folder | ||
### Instance Methods | ||
#### Example 1: Creating a Subfolder | ||
You can create subfolders in Hotfile folder instances by using the createFolder or createFolderSync method. Both of these return an instance of the newly created subfolder. | ||
```js | ||
const file = await subfolder.create('summer.js') | ||
instance.createFolderSync(string) -> instance | ||
instance.createFolder(string) -> instance | ||
``` | ||
In the following example we create 4 nested folders A,B,C, and D. | ||
```js | ||
const aHotFolderA = require('hotfile')(SOME_FOLDER_PATH) | ||
const foldername = 'some-name-not-a-path' | ||
const aHotfolderB = aHotFolderA.createFolderSync(foldername) | ||
const aHotfolderC = aHotfolderB.createFolderSync(foldername) | ||
const aHotfolderD = aHotfolderC.createFolderSync(foldername) | ||
``` | ||
#### 3. Move file to another folder | ||
#### Example 2: Moving a Hotfile | ||
Hotfile file instances can be move from one Hotfile folder instance to another. | ||
```js | ||
await file.setNameTo('water').setBasenameTo('nemo.mp4').moveTo(sub2folder) | ||
async instance.moveTo(instanec) -> instance | ||
``` | ||
#### 4. Load subfolders with their files | ||
Hotfile file instances can be move from one Hotfile folder instance to another. | ||
```js | ||
await myfolder.laodChildren() | ||
const aHotFolderA = require('hotfile')(SOME_FOLDER_PATH_A) | ||
const aHotFolderB = require('hotfile')(SOME_FOLDER_PATH_A) | ||
const aHotFile = require('hotfile')(SOME_FILE_PATH) | ||
await aHotfile.moveTo(aHotFolderA) | ||
await aHotfile.moveTo(aHotFolderB) | ||
``` | ||
#### 5. Load subfolders, their files and for callback for each child | ||
#### Example 3: Renaming a File | ||
Hotfile file instances can be renamed. | ||
```js | ||
const cb = async (item) => { | ||
if(item.isFile){ | ||
// later files here | ||
}else { | ||
// later folders here | ||
} | ||
} | ||
await myfolder.laodChildren({cb}) | ||
instance.setNameTo(string) -> self | ||
``` | ||
#### 6. Ignore children that are included | ||
With Hotfiles renaming a file is made easy and clear with the setNameTo method. | ||
Note: the moveTo() method should be called for the rename to take place on the file system. Do not pass it any parameters when you call it. | ||
```js | ||
await myfolder.laodChildren({ | ||
cb, | ||
exclude: ['node_modules', 'exact_name_of_unwated_file', 'DS_Store'] | ||
}) | ||
const aHotFile = require('hotfile')(SOME_FILE_PATH) | ||
const result = await aHotfile.setNameTo('a cool new name').moveTo() | ||
``` | ||
#### 7. Exclude all hidden files | ||
#### Example 4: Changing File Extension | ||
Hotfile file instances their extensions can be changed. | ||
```js | ||
await myfolder.laodChildren({ | ||
cb, | ||
deny: [ /(^|\/)\.[^\/\.]/g, /.*\.mp4/g] | ||
}) | ||
instance.setExtTo(string) -> self | ||
``` | ||
With Hotfiles changeing file extensions is made easy and clear with the setExtTo method. | ||
Note: the moveTo() method should be called for the rename to take place on the file system. Do not pass it any parameters when you call it. | ||
``` | ||
```js | ||
const aHotFile = require('hotfile')(SOME_FILE_PATH) | ||
const ext = '.mp4' // including the period is optional. It will work either way. | ||
const result = await aHotfile.setExtTo('mp4').moveTo() | ||
``` | ||
#### Example 5: Deleting a Hotlile | ||
Hotfile file instances can be deleted from anywhere. | ||
```js | ||
async instance.delete() -> boolean | ||
``` | ||
Hotfile file instances can be move from one Hotfile folder instance to another. | ||
```js | ||
const aHotFile = require('hotfile')(SOME_FILE_PATH) | ||
const result = await aHotfile.delete() | ||
``` | ||
47
test.js
@@ -1,20 +0,31 @@ | ||
global.z = (v) => console.log(v) | ||
const { Hotfolder, Hotfile, Hot } = require('./index') | ||
// const myfolder = require('hotfile')('./myfolder') | ||
const dirpath = './myfolder/sub01/sub02' | ||
const filepath = './myfile.txt' | ||
// if(!Hot.exists(dirpath)) Hot.mkdir(dirpath) | ||
const myfolder = new Hotfolder(dirpath) | ||
// const myfile = new Hotfile(filepath) | ||
global.v = (v) => console.log(v) | ||
const app = new (require('koa')) | ||
const rootdir = 'home' | ||
const folder = require('./index')(rootdir) | ||
const someAsyncFucn = async () => { | ||
// create sub-folders | ||
// const subfolder = await myfolder.createFolder('subfolder-05') | ||
// const subfolder2 = await subfolder.createFolder('subfolder-04') | ||
// const file = await subfolder.create('summer.js') | ||
// await file.setNameTo('water').moveTo(subfolder) | ||
await myfolder.loadChildren() | ||
console.log(myfolder) | ||
} | ||
const SOME_FOLDER_PATH = 'home' | ||
const ANOTHER_FOLDER_PATH = 'home2' | ||
const SOME_FILE_PATH = 'home/a/a subtitle file.en.srt' | ||
const aHotFolder = require('./index')(SOME_FOLDER_PATH) | ||
// const aHotFile = require('./index')(SOME_FILE_PATH) | ||
const anotherHotFolder = require('./index')(ANOTHER_FOLDER_PATH) | ||
someAsyncFucn() | ||
app.use(async (ctx) => { | ||
// await anotherHotFolder.loadChildren({ | ||
// id:true, | ||
// depth: 5, | ||
// files: true, | ||
// cb: async (item) => { | ||
// await item.delete() | ||
// } | ||
// }) | ||
console.log(aHotFolder.md5Id(new Date().toISOString())) | ||
const foldername = 'some-name-not-a-path' | ||
const aHotFolderB = aHotFolder.createFolderSync(foldername) | ||
ctx.body = aHotFolder | ||
}) | ||
app.listen(3000) | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
15582
1
239
1
4
224
1