@magic/fs 0.0.31 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,9 +72,9 @@ rmDir
72
72
  ### export overloads:
73
73
 
74
74
  ```javascript
75
- rmdir, rmDir
76
- readfile, readFile
77
- readdir, readDir
75
+ // rmdir, rmDir
76
+ // readfile, readFile
77
+ // readdir, readDir
78
78
  ```
79
79
 
80
80
  ### Additional functions:
@@ -312,7 +312,12 @@ update dependencies
312
312
  - add tests for [...threedot_dirs]
313
313
  - update dependencies
314
314
 
315
- ##### 0.0.32 - unreleased
315
+ ##### 0.0.32
316
+
317
+ - add jsdoc types
318
+ - update dependencies
319
+
320
+ ##### 0.0.33 - unreleased
316
321
 
317
322
  ...
318
323
 
package/package.json CHANGED
@@ -1,20 +1,23 @@
1
1
  {
2
2
  "name": "@magic/fs",
3
- "version": "0.0.31",
3
+ "version": "0.0.32",
4
4
  "author": "Wizards & Witches",
5
5
  "description": "nodejs fs promises + goodies",
6
6
  "license": "AGPL-3.0",
7
7
  "homepage": "https://magic.github.io/fs",
8
8
  "main": "src/index.mjs",
9
+ "types": "types/index.d.ts",
9
10
  "module": "src/index.mjs",
10
11
  "type": "module",
11
12
  "scripts": {
12
13
  "start": "npm test",
14
+ "build": "tsc && npm run format",
15
+ "prepublishOnly": "npm run test && npm run build",
13
16
  "test": "t --exclude docs example config.js",
14
17
  "format": "f -w --exclude docs",
15
18
  "format:check": "f",
16
19
  "calls": "calls",
17
- "build": "NODE_ENV=production magic build",
20
+ "build:docs": "NODE_ENV=production magic build",
18
21
  "prod": "NODE_ENV=production magic build serve",
19
22
  "clean": "magic clean",
20
23
  "serve": "magic serve",
@@ -38,18 +41,21 @@
38
41
  "@magic-modules/pre": "0.0.12",
39
42
  "@magic-themes/docs": "0.0.15",
40
43
  "@magic/core": "0.0.156",
41
- "@magic/format": "0.0.66",
42
- "@magic/test": "0.2.20"
44
+ "@magic/format": "0.0.68",
45
+ "@magic/test": "0.2.22",
46
+ "@types/node": "24.7.2",
47
+ "typescript": "5.9.3"
43
48
  },
44
49
  "dependencies": {
45
- "@magic/deep": "0.1.16",
46
- "@magic/error": "0.0.17",
47
- "@magic/log": "0.1.18",
48
- "@magic/mime-types": "0.0.18",
49
- "@magic/types": "0.1.23"
50
+ "@magic/deep": "0.1.18",
51
+ "@magic/error": "0.0.20",
52
+ "@magic/log": "0.1.20",
53
+ "@magic/mime-types": "0.0.21",
54
+ "@magic/types": "0.1.29"
50
55
  },
51
56
  "files": [
52
- "src"
57
+ "src",
58
+ "types"
53
59
  ],
54
60
  "contributors": [
55
61
  {
@@ -1,10 +1,11 @@
1
- import { fs } from './fs.mjs'
1
+ import { fs } from './fs.js'
2
2
 
3
3
  import error from '@magic/error'
4
4
  import is from '@magic/types'
5
5
 
6
6
  const libName = '@magic/fs.exists'
7
7
 
8
+ /** @type {(f: import('node:fs').PathLike) => Promise<boolean>} */
8
9
  export const exists = async f => {
9
10
  if (is.empty(f)) {
10
11
  throw error(`${libName} expects argument to be non-empty`, 'E_ARG_EMPTY')
@@ -18,10 +19,11 @@ export const exists = async f => {
18
19
  await fs.stat(f)
19
20
  return true
20
21
  } catch (e) {
21
- if (e.code === 'ENOENT') {
22
+ const err = /** @type {Error & { code: string }} */ (e)
23
+ if (err.code === 'ENOENT') {
22
24
  return false
23
25
  }
24
26
 
25
- throw error(e.message, e.code || e.name)
27
+ throw error(err.message, err.code || err.name)
26
28
  }
27
29
  }
@@ -1,11 +1,11 @@
1
- import fso from 'fs'
2
- import util from 'util'
1
+ import fso from 'node:fs'
2
+ import util from 'node:util'
3
3
 
4
4
  const readDir = fso.promises.readdir
5
5
  const readFile = fso.promises.readFile
6
6
  const rmdir = fso.promises.rmdir
7
7
 
8
- export const fs = {
8
+ export const fs = /** @type {const} */ ({
9
9
  ...fso,
10
10
  ...fso.promises,
11
11
  exists: util.promisify(fso.exists),
@@ -16,4 +16,4 @@ export const fs = {
16
16
  rmdir,
17
17
  rmDir: rmdir,
18
18
  watch: fso.watch,
19
- }
19
+ })
@@ -1,11 +1,16 @@
1
- import { getFileType } from './getFileType.mjs'
2
- import { contentTypes } from './contentTypes.mjs'
3
-
1
+ import mimes from '@magic/mime-types'
4
2
  import is from '@magic/types'
5
3
  import error from '@magic/error'
6
4
 
5
+ import { getFileType } from './getFileType.js'
6
+
7
7
  const libName = '@magic/fs.getContentType'
8
8
 
9
+ /**
10
+ *
11
+ * @param {string} uri
12
+ * @returns {string}
13
+ */
9
14
  export const getContentType = uri => {
10
15
  if (is.empty(uri)) {
11
16
  throw error(`${libName}: need uri to be a non-empty string`, 'E_ARG_EMPTY')
@@ -17,8 +22,11 @@ export const getContentType = uri => {
17
22
 
18
23
  const fileType = getFileType(uri)
19
24
  let contentType = 'text/plain'
20
- if (contentTypes[fileType]) {
21
- contentType = contentTypes[fileType]
25
+
26
+ const mimeTypes = /** @type {Record<string, string>} */ (mimes)
27
+
28
+ if (fileType in mimeTypes) {
29
+ contentType = mimeTypes[fileType]
22
30
  }
23
31
 
24
32
  return contentType
@@ -0,0 +1,144 @@
1
+ import path from 'node:path'
2
+
3
+ import is from '@magic/types'
4
+ import deep from '@magic/deep'
5
+ import error from '@magic/error'
6
+
7
+ import { fs } from './fs.js'
8
+
9
+ import { getFilePath } from './getFilePath.js'
10
+
11
+ const libName = '@magic/fs.getDirectories'
12
+
13
+ /**
14
+ * @typedef {object} Options
15
+ * @property {string} [root]
16
+ * @property {number} [maxDepth]
17
+ * @property {number} [minDepth]
18
+ * @property {boolean | number} [depth]
19
+ * @property {boolean} [noRoot]
20
+ */
21
+
22
+ /**
23
+ * @param {string | string[]} dir
24
+ * @param {number | false | Options} [options]
25
+ * if options is a number, its the max depth of recursion.
26
+ * if it is false, maxDepth is set to 1
27
+ * @returns {Promise<string[]>}
28
+ */
29
+ export const getDirectories = async (dir, options = {}) => {
30
+ if (is.number(options)) {
31
+ options = {
32
+ maxDepth: options,
33
+ }
34
+ } else if (options === false) {
35
+ options = {
36
+ maxDepth: 1,
37
+ }
38
+ }
39
+
40
+ let { minDepth, maxDepth = false, depth = false, root, noRoot = false } = options
41
+
42
+ if (!is.number(maxDepth)) {
43
+ maxDepth = is.number(depth) ? depth : 200_000
44
+ }
45
+
46
+ if (!is.number(minDepth)) {
47
+ minDepth = 0
48
+ }
49
+
50
+ if (!is.array(dir) && !is.string(dir)) {
51
+ throw error(`${libName}: need an array or a string as first argument`, 'E_ARG_TYPE')
52
+ }
53
+
54
+ if (is.empty(dir)) {
55
+ throw error(`${libName}: first argument can not be empty`, 'E_ARG_EMPTY')
56
+ }
57
+
58
+ if (is.empty(root) && is.string(dir)) {
59
+ root = dir
60
+ }
61
+
62
+ try {
63
+ if (is.array(dir)) {
64
+ const dirs = await Promise.all(dir.map(async f => await getDirectories(f, options)))
65
+
66
+ return deep.flatten(...dirs).filter(a => a)
67
+ }
68
+
69
+ const currentDepth = dir
70
+ .replace(root || process.cwd(), '')
71
+ .split(path.sep)
72
+ .filter(a => a).length
73
+
74
+ if (currentDepth > maxDepth) {
75
+ return []
76
+ }
77
+
78
+ const dirContent = await fs.readdir(dir)
79
+
80
+ /** @type {string[]} */
81
+ const dirs = []
82
+
83
+ await Promise.all(
84
+ dirContent.map(async file => {
85
+ if (!is.string(file)) {
86
+ throw error(`${libName}: path was not a string: ${file}`, 'E_ARG_TYPE')
87
+ }
88
+
89
+ let filePath = await getFilePath(getDirectories, dir, file, { maxDepth, minDepth, root })
90
+
91
+ if (filePath) {
92
+ if (!is.array(filePath)) {
93
+ filePath = [filePath]
94
+ }
95
+
96
+ await Promise.all(
97
+ filePath.map(async file => {
98
+ try {
99
+ const stat = await fs.stat(file)
100
+ if (stat.isDirectory()) {
101
+ if (is.array(filePath)) {
102
+ dirs.push(...filePath)
103
+ } else if (is.string(filePath)) {
104
+ dirs.push(filePath)
105
+ }
106
+ }
107
+ } catch (statErr) {
108
+ // File might have been deleted between readdir and stat
109
+ // Just skip it
110
+ }
111
+ }),
112
+ )
113
+ }
114
+ }),
115
+ )
116
+
117
+ let finalDirs = deep.flatten(dirs).filter(a => a)
118
+ if (!noRoot) {
119
+ finalDirs = [dir, ...finalDirs]
120
+ }
121
+
122
+ const finalized = finalDirs
123
+ .filter(a => is.string(a))
124
+ .filter(dir => {
125
+ const currentDepth = dir
126
+ .replace(root || process.cwd(), '')
127
+ .split(path.sep)
128
+ .filter(a => a).length
129
+
130
+ return currentDepth >= minDepth
131
+ })
132
+
133
+ const unique = Array.from(new Set(finalized))
134
+
135
+ return unique
136
+ } catch (e) {
137
+ const err = /** @type {import('@magic/error').CustomError} */ (e)
138
+ if (err.code === 'ENOENT') {
139
+ return []
140
+ }
141
+
142
+ throw e
143
+ }
144
+ }
@@ -1,12 +1,27 @@
1
- import path from 'path'
1
+ import path from 'node:path'
2
2
 
3
3
  import is from '@magic/types'
4
4
  import error from '@magic/error'
5
5
 
6
- import { fs } from './fs.mjs'
6
+ import { fs } from './fs.js'
7
7
 
8
8
  const libName = '@magic/fs.getFilePath'
9
9
 
10
+ /**
11
+ * @typedef {typeof import('./getFiles.js').getFiles} GetFiles
12
+ * @typedef {import('./getFiles.js').Options} GetFilesOptions
13
+ * @typedef {typeof import('./getDirectories.js').getDirectories} GetDirectories
14
+ *
15
+ */
16
+
17
+ /**
18
+ *
19
+ * @param {GetFiles | GetDirectories} fn
20
+ * @param {string} dir
21
+ * @param {string} file
22
+ * @param {GetFilesOptions} args
23
+ * @returns {Promise<string | string[] | undefined>}
24
+ */
10
25
  export const getFilePath = async (fn, dir, file, args = {}) => {
11
26
  if (is.empty(fn)) {
12
27
  throw error(`${libName}: fn: first argument can not be empty`, 'E_ARG_1_EMPTY')
@@ -32,7 +47,7 @@ export const getFilePath = async (fn, dir, file, args = {}) => {
32
47
  const filePath = path.join(dir, file)
33
48
 
34
49
  const stat = await fs.stat(filePath)
35
- if (stat.isDirectory(filePath)) {
50
+ if (stat.isDirectory()) {
36
51
  return await fn(filePath, args)
37
52
  } else if (stat.isFile()) {
38
53
  return filePath
@@ -1,4 +1,9 @@
1
- import path from 'path'
1
+ import path from 'node:path'
2
2
 
3
+ /**
4
+ *
5
+ * @param {string} name
6
+ * @returns {string}
7
+ */
3
8
  export const getFileType = name =>
4
9
  !name || !name.includes('.') ? 'txt' : path.extname(name).substring(1)
@@ -0,0 +1,134 @@
1
+ import path from 'node:path'
2
+
3
+ // import deep from '@magic/deep'
4
+ import is from '@magic/types'
5
+ import error from '@magic/error'
6
+
7
+ import { getFilePath } from './getFilePath.js'
8
+ import { fs } from './fs.js'
9
+
10
+ const libName = '@magic/fs.getFiles'
11
+
12
+ /**
13
+ * @typedef {object} Options
14
+ * @property {number} [minDepth]
15
+ * @property {number} [maxDepth]
16
+ * @property {number | false} [depth]
17
+ * @property {string} [extension]
18
+ * @property {string} [ext]
19
+ * @property {string} [root]
20
+ */
21
+
22
+ /**
23
+ * @param {string} dir
24
+ * First argument: directory to scan
25
+ * @param {number | Options} [options]
26
+ * If number, sets maxDepth directly.
27
+ * @returns {Promise<string[]>}
28
+ */
29
+
30
+ export const getFiles = async (dir, options = {}) => {
31
+ if (is.number(options)) {
32
+ options = {
33
+ maxDepth: options,
34
+ }
35
+ }
36
+
37
+ let {
38
+ minDepth = 0,
39
+ maxDepth = false,
40
+ depth = false,
41
+ extension = false,
42
+ ext = false,
43
+ root = process.cwd(),
44
+ } = options
45
+
46
+ if (ext && !extension) {
47
+ extension = ext
48
+ }
49
+
50
+ if (!is.number(maxDepth)) {
51
+ maxDepth = is.number(depth) ? depth : 200_000
52
+ }
53
+
54
+ if (!is.number(minDepth)) {
55
+ minDepth = 0
56
+ }
57
+
58
+ if (is.empty(dir)) {
59
+ throw error(`${libName}: dir: first argument can not be empty.`, 'E_ARG_EMPTY')
60
+ }
61
+
62
+ if (!is.string(dir)) {
63
+ throw error(`${libName}: dir: first argument must be a string.`, 'E_ARG_TYPE')
64
+ }
65
+
66
+ if (is.empty(root)) {
67
+ root = dir
68
+ }
69
+
70
+ const currentDepth =
71
+ dir
72
+ .replace(root, '')
73
+ .split(path.sep)
74
+ .filter(a => a).length - 1
75
+
76
+ if (currentDepth > maxDepth) {
77
+ return []
78
+ }
79
+
80
+ try {
81
+ const dirContent = await fs.readdir(dir)
82
+ const files = await Promise.all(
83
+ dirContent.map(file => getFilePath(getFiles, dir, file, { maxDepth, minDepth, root })),
84
+ )
85
+
86
+ const flatFiles = files
87
+ .flat(20000)
88
+ .filter(a => !is.undef(a))
89
+ /*
90
+ * if an extension parameter has been passed,
91
+ * remove the file if it does not end with extension
92
+ */
93
+ .filter(a => !extension || a.endsWith(extension))
94
+
95
+ /*
96
+ * filter nonfiles - use async stat
97
+ */
98
+ const fileStats = await Promise.all(
99
+ flatFiles.map(async f => {
100
+ try {
101
+ const stat = await fs.stat(f)
102
+ return { path: f, isFile: stat.isFile() }
103
+ } catch {
104
+ return { path: f, isFile: false }
105
+ }
106
+ }),
107
+ )
108
+
109
+ return (
110
+ fileStats
111
+ .filter(({ isFile }) => isFile)
112
+ .map(({ path }) => path)
113
+ /*
114
+ * filter files if depth is smaller than minDepth
115
+ */
116
+ .filter(file => {
117
+ const currentDepth =
118
+ file
119
+ .replace(root ?? '', '')
120
+ .split(path.sep)
121
+ .filter(a => a).length - 1
122
+
123
+ return currentDepth >= minDepth
124
+ })
125
+ )
126
+ } catch (e) {
127
+ const err = /** @type {Error & { code?: string }} */ (e)
128
+ if (err.code === 'ENOENT') {
129
+ return []
130
+ }
131
+
132
+ throw error(err.message, err.code)
133
+ }
134
+ }
package/src/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import { fs as fso } from './fs.js'
2
+
3
+ import { mkdirp } from './mkdirp.js'
4
+ import { rmrf } from './rmrf.js'
5
+ import { getFileType } from './getFileType.js'
6
+ import { getDirectories } from './getDirectories.js'
7
+ import { getFiles } from './getFiles.js'
8
+ import { exists } from './exists.js'
9
+ import { getContentType } from './getContentType.js'
10
+ import { getFilePath } from './getFilePath.js'
11
+
12
+ export const fs = /** @type {const} */ ({
13
+ ...fso,
14
+ mkdirp,
15
+ rmrf,
16
+ getFileType,
17
+ getDirectories,
18
+ getFiles,
19
+ exists,
20
+ getContentType,
21
+ getFilePath,
22
+ })
23
+
24
+ export default fs
@@ -3,10 +3,15 @@ import path from 'path'
3
3
  import error from '@magic/error'
4
4
  import is from '@magic/types'
5
5
 
6
- import { fs } from './fs.mjs'
6
+ import { fs } from './fs.js'
7
7
 
8
8
  const libName = '@magic/fs.mkdirp'
9
9
 
10
+ /**
11
+ *
12
+ * @param {string} p
13
+ * @returns {Promise<boolean | void>}
14
+ */
10
15
  export const mkdirp = async p => {
11
16
  if (is.empty(p)) {
12
17
  throw error(`${libName} expects a non-empty path string as argument.`, 'E_ARG_EMPTY')
@@ -29,10 +34,11 @@ export const mkdirp = async p => {
29
34
  await fs.mkdir(p)
30
35
  return true
31
36
  } catch (e) {
32
- if (e.code === 'EEXIST') {
37
+ const err = /** @type {Error & { code?: string}} */ (e)
38
+ if (err.code === 'EEXIST') {
33
39
  return true
34
40
  }
35
41
 
36
- throw error(e.message, e.code)
42
+ throw error(err)
37
43
  }
38
44
  }
@@ -3,12 +3,25 @@ import path from 'path'
3
3
  import is from '@magic/types'
4
4
  import error from '@magic/error'
5
5
 
6
- import { fs } from './fs.mjs'
6
+ import { fs } from './fs.js'
7
7
 
8
8
  const cwd = process.cwd()
9
9
 
10
10
  const libName = '@magic/fs.rmrf'
11
11
 
12
+ /**
13
+ * @typedef {object} Options
14
+ * @property {boolean} [dryRun]
15
+ */
16
+
17
+ /**
18
+ * Recursively removes a file or directory.
19
+ *
20
+ * @throws {Error} If the argument is invalid, outside cwd, or fs operations fail.
21
+ * @param {string} dir
22
+ * @param {Options} [opts]
23
+ * @returns {Promise<boolean | undefined>}
24
+ */
12
25
  export const rmrf = async (dir, opts = {}) => {
13
26
  if (is.empty(dir)) {
14
27
  throw error(`${libName}: expecting a non-empty argument.`, 'E_DIR_EMPTY')
@@ -45,10 +58,12 @@ export const rmrf = async (dir, opts = {}) => {
45
58
  return true
46
59
  }
47
60
  } catch (e) {
48
- if (e.code === 'ENOENT') {
61
+ const err = /** @type {Error & { code?: string}} */ (e)
62
+
63
+ if (err.code === 'ENOENT') {
49
64
  return true
50
65
  }
51
66
 
52
- throw error(e)
67
+ throw error(err)
53
68
  }
54
69
  }
@@ -0,0 +1,2 @@
1
+ /** @type {(f: import('node:fs').PathLike) => Promise<boolean>} */
2
+ export const exists: (f: import('node:fs').PathLike) => Promise<boolean>
package/types/fs.d.ts ADDED
@@ -0,0 +1,109 @@
1
+ export const fs: {
2
+ readonly exists: typeof fso.exists.__promisify__
3
+ readonly readdir: typeof fso.promises.readdir
4
+ readonly readDir: typeof fso.promises.readdir
5
+ readonly readFile: typeof fso.promises.readFile
6
+ readonly readfile: typeof fso.promises.readFile
7
+ readonly rmdir: typeof fso.promises.rmdir
8
+ readonly rmDir: typeof fso.promises.rmdir
9
+ readonly watch: typeof fso.watch
10
+ readonly access: typeof fso.promises.access
11
+ readonly copyFile: typeof fso.promises.copyFile
12
+ readonly open: typeof fso.promises.open
13
+ readonly rename: typeof fso.promises.rename
14
+ readonly truncate: typeof fso.promises.truncate
15
+ readonly rm: typeof fso.promises.rm
16
+ readonly mkdir: typeof fso.promises.mkdir
17
+ readonly readlink: typeof fso.promises.readlink
18
+ readonly symlink: typeof fso.promises.symlink
19
+ readonly lstat: typeof fso.promises.lstat
20
+ readonly stat: typeof fso.promises.stat
21
+ readonly statfs: typeof fso.promises.statfs
22
+ readonly link: typeof fso.promises.link
23
+ readonly unlink: typeof fso.promises.unlink
24
+ readonly chmod: typeof fso.promises.chmod
25
+ readonly lchmod: typeof fso.promises.lchmod
26
+ readonly lchown: typeof fso.promises.lchown
27
+ readonly lutimes: typeof fso.promises.lutimes
28
+ readonly chown: typeof fso.promises.chown
29
+ readonly utimes: typeof fso.promises.utimes
30
+ readonly realpath: typeof fso.promises.realpath
31
+ readonly mkdtemp: typeof fso.promises.mkdtemp
32
+ readonly mkdtempDisposable: typeof fso.promises.mkdtempDisposable
33
+ readonly writeFile: typeof fso.promises.writeFile
34
+ readonly appendFile: typeof fso.promises.appendFile
35
+ readonly opendir: typeof fso.promises.opendir
36
+ readonly cp: typeof fso.promises.cp
37
+ readonly glob: typeof fso.promises.glob
38
+ readonly constants: typeof fso.constants
39
+ readonly renameSync: typeof fso.renameSync
40
+ readonly truncateSync: typeof fso.truncateSync
41
+ readonly ftruncate: typeof fso.ftruncate
42
+ readonly ftruncateSync: typeof fso.ftruncateSync
43
+ readonly chownSync: typeof fso.chownSync
44
+ readonly fchown: typeof fso.fchown
45
+ readonly fchownSync: typeof fso.fchownSync
46
+ readonly lchownSync: typeof fso.lchownSync
47
+ readonly lutimesSync: typeof fso.lutimesSync
48
+ readonly chmodSync: typeof fso.chmodSync
49
+ readonly fchmod: typeof fso.fchmod
50
+ readonly fchmodSync: typeof fso.fchmodSync
51
+ readonly lchmodSync: typeof fso.lchmodSync
52
+ readonly fstat: typeof fso.fstat
53
+ readonly fstatSync: typeof fso.fstatSync
54
+ readonly statfsSync: typeof fso.statfsSync
55
+ readonly linkSync: typeof fso.linkSync
56
+ readonly symlinkSync: typeof fso.symlinkSync
57
+ readonly readlinkSync: typeof fso.readlinkSync
58
+ readonly realpathSync: typeof fso.realpathSync
59
+ readonly unlinkSync: typeof fso.unlinkSync
60
+ readonly rmdirSync: typeof fso.rmdirSync
61
+ readonly rmSync: typeof fso.rmSync
62
+ readonly mkdirSync: typeof fso.mkdirSync
63
+ readonly mkdtempSync: typeof fso.mkdtempSync
64
+ readonly mkdtempDisposableSync: typeof fso.mkdtempDisposableSync
65
+ readonly readdirSync: typeof fso.readdirSync
66
+ readonly close: typeof fso.close
67
+ readonly closeSync: typeof fso.closeSync
68
+ readonly openSync: typeof fso.openSync
69
+ readonly utimesSync: typeof fso.utimesSync
70
+ readonly futimes: typeof fso.futimes
71
+ readonly futimesSync: typeof fso.futimesSync
72
+ readonly fsync: typeof fso.fsync
73
+ readonly fsyncSync: typeof fso.fsyncSync
74
+ readonly write: typeof fso.write
75
+ readonly writeSync: typeof fso.writeSync
76
+ readonly read: typeof fso.read
77
+ readonly readSync: typeof fso.readSync
78
+ readonly readFileSync: typeof fso.readFileSync
79
+ readonly writeFileSync: typeof fso.writeFileSync
80
+ readonly appendFileSync: typeof fso.appendFileSync
81
+ readonly watchFile: typeof fso.watchFile
82
+ readonly unwatchFile: typeof fso.unwatchFile
83
+ readonly existsSync: typeof fso.existsSync
84
+ readonly accessSync: typeof fso.accessSync
85
+ readonly createReadStream: typeof fso.createReadStream
86
+ readonly createWriteStream: typeof fso.createWriteStream
87
+ readonly fdatasync: typeof fso.fdatasync
88
+ readonly fdatasyncSync: typeof fso.fdatasyncSync
89
+ readonly copyFileSync: typeof fso.copyFileSync
90
+ readonly writev: typeof fso.writev
91
+ readonly writevSync: typeof fso.writevSync
92
+ readonly readv: typeof fso.readv
93
+ readonly readvSync: typeof fso.readvSync
94
+ readonly openAsBlob: typeof fso.openAsBlob
95
+ readonly opendirSync: typeof fso.opendirSync
96
+ readonly cpSync: typeof fso.cpSync
97
+ readonly globSync: typeof fso.globSync
98
+ readonly promises: typeof fso.promises
99
+ readonly Stats: typeof fso.Stats
100
+ readonly StatsFs: typeof fso.StatsFs
101
+ readonly Dirent: typeof fso.Dirent
102
+ readonly Dir: typeof fso.Dir
103
+ readonly ReadStream: typeof fso.ReadStream
104
+ readonly Utf8Stream: typeof fso.Utf8Stream
105
+ readonly WriteStream: typeof fso.WriteStream
106
+ readonly statSync: fso.StatSyncFn
107
+ readonly lstatSync: fso.StatSyncFn
108
+ }
109
+ import fso from 'node:fs'
@@ -0,0 +1 @@
1
+ export function getContentType(uri: string): string
@@ -0,0 +1,11 @@
1
+ export function getDirectories(
2
+ dir: string | string[],
3
+ options?: number | false | Options,
4
+ ): Promise<string[]>
5
+ export type Options = {
6
+ root?: string | undefined
7
+ maxDepth?: number | undefined
8
+ minDepth?: number | undefined
9
+ depth?: number | boolean | undefined
10
+ noRoot?: boolean | undefined
11
+ }
@@ -0,0 +1,9 @@
1
+ export function getFilePath(
2
+ fn: GetFiles | GetDirectories,
3
+ dir: string,
4
+ file: string,
5
+ args?: GetFilesOptions,
6
+ ): Promise<string | string[] | undefined>
7
+ export type GetFiles = typeof import('./getFiles.js').getFiles
8
+ export type GetFilesOptions = import('./getFiles.js').Options
9
+ export type GetDirectories = typeof import('./getDirectories.js').getDirectories
@@ -0,0 +1 @@
1
+ export function getFileType(name: string): string
@@ -0,0 +1,9 @@
1
+ export function getFiles(dir: string, options?: number | Options): Promise<string[]>
2
+ export type Options = {
3
+ minDepth?: number | undefined
4
+ maxDepth?: number | undefined
5
+ depth?: number | false | undefined
6
+ extension?: string | undefined
7
+ ext?: string | undefined
8
+ root?: string | undefined
9
+ }
@@ -0,0 +1,124 @@
1
+ export const fs: {
2
+ readonly mkdirp: (p: string) => Promise<boolean | void>
3
+ readonly rmrf: (dir: string, opts?: Options) => Promise<boolean | undefined>
4
+ readonly getFileType: (name: string) => string
5
+ readonly getDirectories: (
6
+ dir: string | string[],
7
+ options?: number | false | Options,
8
+ ) => Promise<string[]>
9
+ readonly getFiles: (dir: string, options?: number | Options) => Promise<string[]>
10
+ readonly exists: (f: import('fs').PathLike) => Promise<boolean>
11
+ readonly getContentType: (uri: string) => string
12
+ readonly getFilePath: (
13
+ fn: GetFiles | GetDirectories,
14
+ dir: string,
15
+ file: string,
16
+ args?: GetFilesOptions,
17
+ ) => Promise<string | string[] | undefined>
18
+ readonly readdir: typeof import('fs/promises').readdir
19
+ readonly readDir: typeof import('fs/promises').readdir
20
+ readonly readFile: typeof import('fs/promises').readFile
21
+ readonly readfile: typeof import('fs/promises').readFile
22
+ readonly rmdir: typeof import('fs/promises').rmdir
23
+ readonly rmDir: typeof import('fs/promises').rmdir
24
+ readonly watch: typeof import('fs').watch
25
+ readonly access: typeof import('fs/promises').access
26
+ readonly copyFile: typeof import('fs/promises').copyFile
27
+ readonly open: typeof import('fs/promises').open
28
+ readonly rename: typeof import('fs/promises').rename
29
+ readonly truncate: typeof import('fs/promises').truncate
30
+ readonly rm: typeof import('fs/promises').rm
31
+ readonly mkdir: typeof import('fs/promises').mkdir
32
+ readonly readlink: typeof import('fs/promises').readlink
33
+ readonly symlink: typeof import('fs/promises').symlink
34
+ readonly lstat: typeof import('fs/promises').lstat
35
+ readonly stat: typeof import('fs/promises').stat
36
+ readonly statfs: typeof import('fs/promises').statfs
37
+ readonly link: typeof import('fs/promises').link
38
+ readonly unlink: typeof import('fs/promises').unlink
39
+ readonly chmod: typeof import('fs/promises').chmod
40
+ readonly lchmod: typeof import('fs/promises').lchmod
41
+ readonly lchown: typeof import('fs/promises').lchown
42
+ readonly lutimes: typeof import('fs/promises').lutimes
43
+ readonly chown: typeof import('fs/promises').chown
44
+ readonly utimes: typeof import('fs/promises').utimes
45
+ readonly realpath: typeof import('fs/promises').realpath
46
+ readonly mkdtemp: typeof import('fs/promises').mkdtemp
47
+ readonly mkdtempDisposable: typeof import('fs/promises').mkdtempDisposable
48
+ readonly writeFile: typeof import('fs/promises').writeFile
49
+ readonly appendFile: typeof import('fs/promises').appendFile
50
+ readonly opendir: typeof import('fs/promises').opendir
51
+ readonly cp: typeof import('fs/promises').cp
52
+ readonly glob: typeof import('fs/promises').glob
53
+ readonly constants: typeof import('fs').constants
54
+ readonly renameSync: typeof import('fs').renameSync
55
+ readonly truncateSync: typeof import('fs').truncateSync
56
+ readonly ftruncate: typeof import('fs').ftruncate
57
+ readonly ftruncateSync: typeof import('fs').ftruncateSync
58
+ readonly chownSync: typeof import('fs').chownSync
59
+ readonly fchown: typeof import('fs').fchown
60
+ readonly fchownSync: typeof import('fs').fchownSync
61
+ readonly lchownSync: typeof import('fs').lchownSync
62
+ readonly lutimesSync: typeof import('fs').lutimesSync
63
+ readonly chmodSync: typeof import('fs').chmodSync
64
+ readonly fchmod: typeof import('fs').fchmod
65
+ readonly fchmodSync: typeof import('fs').fchmodSync
66
+ readonly lchmodSync: typeof import('fs').lchmodSync
67
+ readonly fstat: typeof import('fs').fstat
68
+ readonly fstatSync: typeof import('fs').fstatSync
69
+ readonly statfsSync: typeof import('fs').statfsSync
70
+ readonly linkSync: typeof import('fs').linkSync
71
+ readonly symlinkSync: typeof import('fs').symlinkSync
72
+ readonly readlinkSync: typeof import('fs').readlinkSync
73
+ readonly realpathSync: typeof import('fs').realpathSync
74
+ readonly unlinkSync: typeof import('fs').unlinkSync
75
+ readonly rmdirSync: typeof import('fs').rmdirSync
76
+ readonly rmSync: typeof import('fs').rmSync
77
+ readonly mkdirSync: typeof import('fs').mkdirSync
78
+ readonly mkdtempSync: typeof import('fs').mkdtempSync
79
+ readonly mkdtempDisposableSync: typeof import('fs').mkdtempDisposableSync
80
+ readonly readdirSync: typeof import('fs').readdirSync
81
+ readonly close: typeof import('fs').close
82
+ readonly closeSync: typeof import('fs').closeSync
83
+ readonly openSync: typeof import('fs').openSync
84
+ readonly utimesSync: typeof import('fs').utimesSync
85
+ readonly futimes: typeof import('fs').futimes
86
+ readonly futimesSync: typeof import('fs').futimesSync
87
+ readonly fsync: typeof import('fs').fsync
88
+ readonly fsyncSync: typeof import('fs').fsyncSync
89
+ readonly write: typeof import('fs').write
90
+ readonly writeSync: typeof import('fs').writeSync
91
+ readonly read: typeof import('fs').read
92
+ readonly readSync: typeof import('fs').readSync
93
+ readonly readFileSync: typeof import('fs').readFileSync
94
+ readonly writeFileSync: typeof import('fs').writeFileSync
95
+ readonly appendFileSync: typeof import('fs').appendFileSync
96
+ readonly watchFile: typeof import('fs').watchFile
97
+ readonly unwatchFile: typeof import('fs').unwatchFile
98
+ readonly existsSync: typeof import('fs').existsSync
99
+ readonly accessSync: typeof import('fs').accessSync
100
+ readonly createReadStream: typeof import('fs').createReadStream
101
+ readonly createWriteStream: typeof import('fs').createWriteStream
102
+ readonly fdatasync: typeof import('fs').fdatasync
103
+ readonly fdatasyncSync: typeof import('fs').fdatasyncSync
104
+ readonly copyFileSync: typeof import('fs').copyFileSync
105
+ readonly writev: typeof import('fs').writev
106
+ readonly writevSync: typeof import('fs').writevSync
107
+ readonly readv: typeof import('fs').readv
108
+ readonly readvSync: typeof import('fs').readvSync
109
+ readonly openAsBlob: typeof import('fs').openAsBlob
110
+ readonly opendirSync: typeof import('fs').opendirSync
111
+ readonly cpSync: typeof import('fs').cpSync
112
+ readonly globSync: typeof import('fs').globSync
113
+ readonly promises: typeof import('node:fs/promises')
114
+ readonly Stats: typeof import('fs').Stats
115
+ readonly StatsFs: typeof import('fs').StatsFs
116
+ readonly Dirent: typeof import('fs').Dirent
117
+ readonly Dir: typeof import('fs').Dir
118
+ readonly ReadStream: typeof import('fs').ReadStream
119
+ readonly Utf8Stream: typeof import('fs').Utf8Stream
120
+ readonly WriteStream: typeof import('fs').WriteStream
121
+ readonly statSync: import('fs').StatSyncFn
122
+ readonly lstatSync: import('fs').StatSyncFn
123
+ }
124
+ export default fs
@@ -0,0 +1 @@
1
+ export function mkdirp(p: string): Promise<boolean | void>
@@ -0,0 +1,4 @@
1
+ export function rmrf(dir: string, opts?: Options): Promise<boolean | undefined>
2
+ export type Options = {
3
+ dryRun?: boolean | undefined
4
+ }
@@ -1,3 +0,0 @@
1
- import mimeTypes from '@magic/mime-types'
2
-
3
- export const contentTypes = mimeTypes
@@ -1,137 +0,0 @@
1
- import path from 'path'
2
-
3
- import is from '@magic/types'
4
- import deep from '@magic/deep'
5
- import error from '@magic/error'
6
- import log from '@magic/log'
7
-
8
- import { fs } from './fs.mjs'
9
-
10
- import { getFilePath } from './getFilePath.mjs'
11
-
12
- const libName = '@magic/fs.getDirectories'
13
-
14
- export const getDirectories = async (dir, args = {}) => {
15
- if (is.number(args)) {
16
- args = {
17
- maxDepth: args,
18
- }
19
- } else if (args === false) {
20
- args = {
21
- maxDepth: 1,
22
- }
23
- }
24
-
25
- let { minDepth, maxDepth = false, depth = false, root, noRoot = false } = args
26
-
27
- if (is.number(depth) && !is.number(maxDepth)) {
28
- maxDepth = depth
29
- }
30
-
31
- if (!is.number(maxDepth)) {
32
- maxDepth = 200_000
33
- }
34
- if (!is.number(minDepth)) {
35
- minDepth = 0
36
- }
37
-
38
- if (!is.array(dir) && !is.string(dir)) {
39
- throw error(`${libName}: need an array or a string as first argument`, 'E_ARG_TYPE')
40
- }
41
-
42
- if (is.empty(dir)) {
43
- throw error(`${libName}: first argument can not be empty`, 'E_ARG_EMPTY')
44
- }
45
-
46
- if (is.empty(root)) {
47
- if (is.string(dir)) {
48
- root = dir
49
- } else {
50
- root = process.cwd()
51
- }
52
- }
53
-
54
- try {
55
- if (is.array(dir)) {
56
- const dirs = await Promise.all(
57
- dir.map(async f => await getDirectories(f, { maxDepth, minDepth, root, noRoot })),
58
- )
59
-
60
- return deep.flatten(...dirs).filter(a => a)
61
- }
62
-
63
- const currentDepth = dir
64
- .replace(root, '')
65
- .split(path.sep)
66
- .filter(a => a).length
67
-
68
- if (currentDepth > maxDepth) {
69
- return []
70
- }
71
-
72
- const dirContent = await fs.readdir(dir)
73
-
74
- const dirs = await Promise.all(
75
- dirContent.map(async file => {
76
- if (!is.string(file)) {
77
- throw error(`${libName}: path was not a string: ${file}`, 'E_ARG_TYPE')
78
- }
79
-
80
- let filePath = await getFilePath(getDirectories, dir, file, { maxDepth, minDepth, root })
81
-
82
- if (filePath) {
83
- if (!is.array(filePath)) {
84
- filePath = [filePath]
85
- }
86
-
87
- const files = await Promise.all(
88
- filePath.map(async file => {
89
- if (!is.string(file)) {
90
- throw error(`${libName}: path was not a string: ${file}`, 'E_ARG_TYPE')
91
- }
92
-
93
- const stat = await fs.stat(file)
94
- if (stat.isDirectory()) {
95
- return filePath
96
- }
97
- }),
98
- )
99
-
100
- return files
101
- }
102
-
103
- return
104
- }),
105
- )
106
-
107
- let finalDirs = deep.flatten(dirs).filter(a => a)
108
- if (!noRoot) {
109
- finalDirs = [dir, ...finalDirs]
110
- }
111
-
112
- const finalized = finalDirs
113
- .filter(a => a)
114
- .filter(dir => {
115
- if (is.number(minDepth)) {
116
- const currentDepth = dir
117
- .replace(root, '')
118
- .split(path.sep)
119
- .filter(a => a).length
120
-
121
- return currentDepth >= minDepth
122
- }
123
-
124
- return false
125
- })
126
-
127
- const unique = Array.from(new Set(finalized))
128
-
129
- return unique
130
- } catch (e) {
131
- if (e.code === 'ENOENT') {
132
- return []
133
- }
134
-
135
- throw e
136
- }
137
- }
package/src/getFiles.mjs DELETED
@@ -1,107 +0,0 @@
1
- import path from 'path'
2
-
3
- import deep from '@magic/deep'
4
- import is from '@magic/types'
5
- import error from '@magic/error'
6
-
7
- import { getFilePath } from './getFilePath.mjs'
8
- import { fs } from './fs.mjs'
9
-
10
- const libName = '@magic/fs.getFiles'
11
-
12
- export const getFiles = async (dir, args = {}) => {
13
- if (is.number(args)) {
14
- args = {
15
- maxDepth: args,
16
- }
17
- }
18
-
19
- let { minDepth = 0, maxDepth = false, depth = false, extension = false, ext = false, root } = args
20
-
21
- if (ext && !extension) {
22
- extension = ext
23
- }
24
-
25
- if (is.number(depth) && !is.number(maxDepth)) {
26
- maxDepth = depth
27
- }
28
-
29
- if (!is.number(maxDepth)) {
30
- maxDepth = 200_000
31
- }
32
- if (!is.number(minDepth)) {
33
- minDepth = 0
34
- }
35
-
36
- if (is.empty(dir)) {
37
- throw error(`${libName}: dir: first argument can not be empty.`, 'E_ARG_EMPTY')
38
- }
39
-
40
- if (!is.string(dir)) {
41
- throw error(`${libName}: dir: first argument must be a string.`, 'E_ARG_TYPE')
42
- }
43
-
44
- if (is.empty(root)) {
45
- root = dir
46
- }
47
-
48
- const currentDepth = dir
49
- .replace(root, '')
50
- .split(path.sep)
51
- .filter(a => a).length
52
-
53
- if (currentDepth > maxDepth) {
54
- return []
55
- }
56
-
57
- try {
58
- const dirContent = await fs.readdir(dir)
59
- const files = await Promise.all(
60
- dirContent.map(file => getFilePath(getFiles, dir, file, { maxDepth, minDepth, root })),
61
- )
62
-
63
- return await Promise.all(
64
- deep
65
- .flatten(files)
66
- .filter(a => a)
67
- /*
68
- * if an extension parameter has been passed,
69
- * remove the file if it does not end with extension
70
- */
71
- .filter(a => !extension || a.endsWith(extension))
72
- /*
73
- * filter nonfiles
74
- */
75
- .filter(async f => {
76
- const stat = await fs.stat(f)
77
- return stat.isFile()
78
- })
79
- /*
80
- * filter files if depth is smaller than minDepth
81
- */
82
- .filter(file => {
83
- if (!file) {
84
- return false
85
- }
86
-
87
- if (is.number(minDepth)) {
88
- const currentDepth =
89
- file
90
- .replace(root, '')
91
- .split(path.sep)
92
- .filter(a => a).length - 1
93
-
94
- return currentDepth >= minDepth
95
- }
96
-
97
- return true
98
- }),
99
- )
100
- } catch (e) {
101
- if (e.code === 'ENOENT') {
102
- return []
103
- }
104
-
105
- throw error(e.message, e.code)
106
- }
107
- }
package/src/index.mjs DELETED
@@ -1,24 +0,0 @@
1
- import { fs as fso } from './fs.mjs'
2
-
3
- import { mkdirp } from './mkdirp.mjs'
4
- import { rmrf } from './rmrf.mjs'
5
- import { getFileType } from './getFileType.mjs'
6
- import { getDirectories } from './getDirectories.mjs'
7
- import { getFiles } from './getFiles.mjs'
8
- import { exists } from './exists.mjs'
9
- import { getContentType } from './getContentType.mjs'
10
- import { getFilePath } from './getFilePath.mjs'
11
-
12
- export const fs = {
13
- ...fso,
14
- mkdirp,
15
- rmrf,
16
- getFileType,
17
- getDirectories,
18
- getFiles,
19
- exists,
20
- getContentType,
21
- getFilePath,
22
- }
23
-
24
- export default fs