@naturalcycles/nodejs-lib 12.90.4 → 12.91.0

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.
@@ -41,7 +41,7 @@ function csvStringToArray(str) {
41
41
  if (matches[1].length && matches[1] !== ',') {
42
42
  arr.push([]);
43
43
  }
44
- arr[arr.length - 1].push(matches[2] ? matches[2].replace(new RegExp('""', 'g'), '"') : matches[3]);
44
+ arr[arr.length - 1].push(matches[2] ? matches[2].replaceAll(new RegExp('""', 'g'), '"') : matches[3]);
45
45
  }
46
46
  return arr;
47
47
  }
@@ -34,7 +34,7 @@ class CSVWriter {
34
34
  return this.shouldQuote(s) ? this.quote(s) : s;
35
35
  }
36
36
  quote(s) {
37
- return `"${s.replace(/"/g, '""')}"`;
37
+ return `"${s.replaceAll('"', '""')}"`;
38
38
  }
39
39
  shouldQuote(s) {
40
40
  return s.includes(this.cfg.delimiter) || s.includes('"') || s.includes('\n') || s.includes('\r');
@@ -0,0 +1,36 @@
1
+ /// <reference types="node" />
2
+ import type { CopyOptions, CopyOptionsSync, MoveOptions } from 'fs-extra';
3
+ export interface JsonOptions {
4
+ spaces?: number;
5
+ }
6
+ /**
7
+ * Convenience wrapper that defaults to utf-8 string output.
8
+ */
9
+ export declare function _readFile(filePath: string): Promise<string>;
10
+ /**
11
+ * Convenience wrapper that defaults to utf-8 string output.
12
+ */
13
+ export declare function _readFileSync(filePath: string): string;
14
+ export declare function _readJsonFile<T = unknown>(filePath: string): Promise<T>;
15
+ export declare function _readJsonFileSync<T = unknown>(filePath: string): T;
16
+ export declare function _writeFile(filePath: string, data: string | Buffer): Promise<void>;
17
+ export declare function _writeFileSync(filePath: string, data: string | Buffer): void;
18
+ export declare function _outputFile(filePath: string, data: string | Buffer): Promise<void>;
19
+ export declare function _outputFileSync(filePath: string, data: string | Buffer): void;
20
+ export declare function _writeJsonFile(filePath: string, data: any, opt?: JsonOptions): Promise<void>;
21
+ export declare function _writeJsonFileSync(filePath: string, data: any, opt?: JsonOptions): void;
22
+ export declare function _outputJsonFile(filePath: string, data: any, opt?: JsonOptions): Promise<void>;
23
+ export declare function _outputJsonFileSync(filePath: string, data: any, opt?: JsonOptions): void;
24
+ export declare function _pathExists(filePath: string): Promise<boolean>;
25
+ export declare function _pathExistsSync(filePath: string): boolean;
26
+ export declare function _ensureDir(dirPath: string): Promise<void>;
27
+ export declare function _ensureDirSync(dirPath: string): void;
28
+ export declare function _ensureFileSync(filePath: string): void;
29
+ export declare function _removePath(fileOrDirPath: string): Promise<void>;
30
+ export declare function _removePathSync(fileOrDirPath: string): void;
31
+ export declare function _emptyDir(dirPath: string): Promise<void>;
32
+ export declare function _emptyDirSync(dirPath: string): void;
33
+ export declare function _copyPath(src: string, dest: string, opt?: CopyOptions): Promise<void>;
34
+ export declare function _copyPathSync(src: string, dest: string, opt?: CopyOptionsSync): void;
35
+ export declare function _movePath(src: string, dest: string, opt?: MoveOptions): Promise<void>;
36
+ export declare function _movePathSync(src: string, dest: string, opt?: MoveOptions): void;
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ /*
3
+
4
+ Why?
5
+
6
+ Convenience re-export/re-implementation of most common fs functions from
7
+ node:fs, node:fs/promises and fs-extra
8
+
9
+ Defaults to string input/output, as it's used in 80% of time. For the rest - you can use native fs.
10
+
11
+ Allows to import it easier, so you don't have to choose between the 3 import locations.
12
+ That's why function names are slightly renamed, to avoid conflict.
13
+
14
+ Credit to: fs-extra (https://github.com/jprichardson/node-fs-extra)
15
+
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports._movePathSync = exports._movePath = exports._copyPathSync = exports._copyPath = exports._emptyDirSync = exports._emptyDir = exports._removePathSync = exports._removePath = exports._ensureFileSync = exports._ensureDirSync = exports._ensureDir = exports._pathExistsSync = exports._pathExists = exports._outputJsonFileSync = exports._outputJsonFile = exports._writeJsonFileSync = exports._writeJsonFile = exports._outputFileSync = exports._outputFile = exports._writeFileSync = exports._writeFile = exports._readJsonFileSync = exports._readJsonFile = exports._readFileSync = exports._readFile = void 0;
19
+ const fs = require("node:fs");
20
+ const fsp = require("node:fs/promises");
21
+ const path = require("node:path");
22
+ const js_lib_1 = require("@naturalcycles/js-lib");
23
+ const fse = require("fs-extra");
24
+ /**
25
+ * Convenience wrapper that defaults to utf-8 string output.
26
+ */
27
+ async function _readFile(filePath) {
28
+ return await fsp.readFile(filePath, 'utf8');
29
+ }
30
+ exports._readFile = _readFile;
31
+ /**
32
+ * Convenience wrapper that defaults to utf-8 string output.
33
+ */
34
+ function _readFileSync(filePath) {
35
+ return fs.readFileSync(filePath, 'utf8');
36
+ }
37
+ exports._readFileSync = _readFileSync;
38
+ async function _readJsonFile(filePath) {
39
+ const str = await fsp.readFile(filePath, 'utf8');
40
+ return (0, js_lib_1._jsonParse)(str);
41
+ }
42
+ exports._readJsonFile = _readJsonFile;
43
+ function _readJsonFileSync(filePath) {
44
+ const str = fs.readFileSync(filePath, 'utf8');
45
+ return (0, js_lib_1._jsonParse)(str);
46
+ }
47
+ exports._readJsonFileSync = _readJsonFileSync;
48
+ async function _writeFile(filePath, data) {
49
+ await fsp.writeFile(filePath, data);
50
+ }
51
+ exports._writeFile = _writeFile;
52
+ function _writeFileSync(filePath, data) {
53
+ fs.writeFileSync(filePath, data);
54
+ }
55
+ exports._writeFileSync = _writeFileSync;
56
+ async function _outputFile(filePath, data) {
57
+ const dirPath = path.dirname(filePath);
58
+ if (!(await _pathExists(dirPath))) {
59
+ await _ensureDir(dirPath);
60
+ }
61
+ await fsp.writeFile(filePath, data);
62
+ }
63
+ exports._outputFile = _outputFile;
64
+ function _outputFileSync(filePath, data) {
65
+ const dirPath = path.dirname(filePath);
66
+ if (!fs.existsSync(dirPath)) {
67
+ _ensureDirSync(dirPath);
68
+ }
69
+ fs.writeFileSync(filePath, data);
70
+ }
71
+ exports._outputFileSync = _outputFileSync;
72
+ async function _writeJsonFile(filePath, data, opt) {
73
+ const str = JSON.stringify(data, null, opt?.spaces);
74
+ await fsp.writeFile(filePath, str);
75
+ }
76
+ exports._writeJsonFile = _writeJsonFile;
77
+ function _writeJsonFileSync(filePath, data, opt) {
78
+ const str = JSON.stringify(data, null, opt?.spaces);
79
+ fs.writeFileSync(filePath, str);
80
+ }
81
+ exports._writeJsonFileSync = _writeJsonFileSync;
82
+ async function _outputJsonFile(filePath, data, opt) {
83
+ const str = JSON.stringify(data, null, opt?.spaces);
84
+ await _outputFile(filePath, str);
85
+ }
86
+ exports._outputJsonFile = _outputJsonFile;
87
+ function _outputJsonFileSync(filePath, data, opt) {
88
+ const str = JSON.stringify(data, null, opt?.spaces);
89
+ _outputFileSync(filePath, str);
90
+ }
91
+ exports._outputJsonFileSync = _outputJsonFileSync;
92
+ async function _pathExists(filePath) {
93
+ try {
94
+ await fsp.access(filePath);
95
+ return true;
96
+ }
97
+ catch {
98
+ return false;
99
+ }
100
+ }
101
+ exports._pathExists = _pathExists;
102
+ function _pathExistsSync(filePath) {
103
+ return fs.existsSync(filePath);
104
+ }
105
+ exports._pathExistsSync = _pathExistsSync;
106
+ async function _ensureDir(dirPath) {
107
+ await fsp.mkdir(dirPath, {
108
+ mode: 0o777,
109
+ recursive: true,
110
+ });
111
+ }
112
+ exports._ensureDir = _ensureDir;
113
+ function _ensureDirSync(dirPath) {
114
+ fs.mkdirSync(dirPath, {
115
+ mode: 0o777,
116
+ recursive: true,
117
+ });
118
+ }
119
+ exports._ensureDirSync = _ensureDirSync;
120
+ // Skipping `_ensureFile` (async), until it's needed
121
+ function _ensureFileSync(filePath) {
122
+ let stats;
123
+ try {
124
+ stats = fs.statSync(filePath);
125
+ }
126
+ catch { }
127
+ if (stats?.isFile())
128
+ return;
129
+ const dir = path.dirname(filePath);
130
+ try {
131
+ if (!fs.statSync(dir).isDirectory()) {
132
+ // parent is not a directory
133
+ // This is just to cause an internal ENOTDIR error to be thrown
134
+ fs.readdirSync(dir);
135
+ }
136
+ }
137
+ catch (err) {
138
+ // If the stat call above failed because the directory doesn't exist, create it
139
+ if (err?.code === 'ENOENT')
140
+ return _ensureDirSync(dir);
141
+ throw err;
142
+ }
143
+ fs.writeFileSync(filePath, '');
144
+ }
145
+ exports._ensureFileSync = _ensureFileSync;
146
+ async function _removePath(fileOrDirPath) {
147
+ await fsp.rm(fileOrDirPath, { recursive: true, force: true });
148
+ }
149
+ exports._removePath = _removePath;
150
+ function _removePathSync(fileOrDirPath) {
151
+ fs.rmSync(fileOrDirPath, { recursive: true, force: true });
152
+ }
153
+ exports._removePathSync = _removePathSync;
154
+ async function _emptyDir(dirPath) {
155
+ let items;
156
+ try {
157
+ items = await fsp.readdir(dirPath);
158
+ }
159
+ catch {
160
+ return await _ensureDir(dirPath);
161
+ }
162
+ await Promise.all(items.map(item => _removePath(path.join(dirPath, item))));
163
+ }
164
+ exports._emptyDir = _emptyDir;
165
+ function _emptyDirSync(dirPath) {
166
+ let items;
167
+ try {
168
+ items = fs.readdirSync(dirPath);
169
+ }
170
+ catch {
171
+ return _ensureDirSync(dirPath);
172
+ }
173
+ items.forEach(item => _removePathSync(path.join(dirPath, item)));
174
+ }
175
+ exports._emptyDirSync = _emptyDirSync;
176
+ // copyFile/moveFile - let's keep using fs-extra for now
177
+ async function _copyPath(src, dest, opt) {
178
+ await fse.copy(src, dest, opt);
179
+ }
180
+ exports._copyPath = _copyPath;
181
+ function _copyPathSync(src, dest, opt) {
182
+ fse.copySync(src, dest, opt);
183
+ }
184
+ exports._copyPathSync = _copyPathSync;
185
+ async function _movePath(src, dest, opt) {
186
+ await fse.move(src, dest, opt);
187
+ }
188
+ exports._movePath = _movePath;
189
+ function _movePathSync(src, dest, opt) {
190
+ fse.moveSync(src, dest, opt);
191
+ }
192
+ exports._movePathSync = _movePathSync;
package/dist/fs/kpy.js CHANGED
@@ -3,9 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.kpySync = exports.kpy = void 0;
4
4
  const path = require("node:path");
5
5
  const js_lib_1 = require("@naturalcycles/js-lib");
6
- const cpFile = require("cp-file");
7
- const fs = require("fs-extra");
8
- const moveFile = require("move-file");
9
6
  const colors_1 = require("../colors");
10
7
  const index_1 = require("../index");
11
8
  async function kpy(opt) {
@@ -23,10 +20,10 @@ async function kpy(opt) {
23
20
  const destFilename = path.resolve(opt.outputDir, opt.flat ? basename : filename);
24
21
  if (!opt.dry) {
25
22
  if (opt.move) {
26
- await moveFile(srcFilename, destFilename, { overwrite });
23
+ await (0, index_1._movePath)(srcFilename, destFilename, { overwrite });
27
24
  }
28
25
  else {
29
- await cpFile(srcFilename, destFilename, { overwrite });
26
+ await (0, index_1._copyPath)(srcFilename, destFilename, { overwrite });
30
27
  }
31
28
  }
32
29
  if (opt.verbose) {
@@ -51,10 +48,10 @@ function kpySync(opt) {
51
48
  const destFilename = path.resolve(opt.outputDir, opt.flat ? basename : filename);
52
49
  if (!opt.dry) {
53
50
  if (opt.move) {
54
- moveFile.sync(srcFilename, destFilename, { overwrite });
51
+ (0, index_1._movePathSync)(srcFilename, destFilename, { overwrite });
55
52
  }
56
53
  else {
57
- cpFile.sync(srcFilename, destFilename, { overwrite });
54
+ (0, index_1._copyPathSync)(srcFilename, destFilename, { overwrite });
58
55
  }
59
56
  }
60
57
  if (opt.verbose) {
@@ -71,11 +68,11 @@ function kpyPrepare(opt) {
71
68
  // default to cwd
72
69
  opt.baseDir ||= '.';
73
70
  opt.outputDir ||= '.';
74
- if (!fs.existsSync(opt.baseDir)) {
71
+ if (!(0, index_1._pathExistsSync)(opt.baseDir)) {
75
72
  console.log(`kpy: baseDir doesn't exist: ${(0, colors_1.boldWhite)(opt.baseDir)}`);
76
73
  return;
77
74
  }
78
- fs.ensureDirSync(opt.outputDir);
75
+ (0, index_1._ensureDirSync)(opt.outputDir);
79
76
  }
80
77
  function kpyLogFilenames(opt, filenames) {
81
78
  if (opt.silent)
package/dist/index.d.ts CHANGED
@@ -76,5 +76,6 @@ export * from './validation/joi/joi.validation.error';
76
76
  export * from './validation/joi/joi.validation.util';
77
77
  export * from './script';
78
78
  export * from './jwt/jwt.service';
79
+ export * from './fs/fs.util';
79
80
  export type { GlobbyOptions, FastGlobOptions, ValidationErrorItem, AnySchema, Got, AfterResponseHook, BeforeErrorHook, BeforeRequestHook, };
80
81
  export { globby, fastGlob, RequestError, TimeoutError, Ajv };
package/dist/index.js CHANGED
@@ -81,3 +81,4 @@ tslib_1.__exportStar(require("./validation/joi/joi.validation.error"), exports);
81
81
  tslib_1.__exportStar(require("./validation/joi/joi.validation.util"), exports);
82
82
  tslib_1.__exportStar(require("./script"), exports);
83
83
  tslib_1.__exportStar(require("./jwt/jwt.service"), exports);
84
+ tslib_1.__exportStar(require("./fs/fs.util"), exports);
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readAjvSchemas = exports.readJsonSchemas = void 0;
4
- const fs = require("node:fs");
5
4
  const __1 = require("../..");
6
5
  const ajvSchema_1 = require("./ajvSchema");
7
6
  /**
@@ -13,7 +12,7 @@ const ajvSchema_1 = require("./ajvSchema");
13
12
  * @experimental
14
13
  */
15
14
  function readJsonSchemas(patterns, opt) {
16
- return __1.fastGlob.sync(patterns, opt).map(fileName => JSON.parse(fs.readFileSync(fileName, 'utf8')));
15
+ return __1.fastGlob.sync(patterns, opt).map(fileName => (0, __1._readJsonFileSync)(fileName));
17
16
  }
18
17
  exports.readJsonSchemas = readJsonSchemas;
19
18
  /**
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AjvSchema = void 0;
4
- const fs = require("node:fs");
5
4
  const js_lib_1 = require("@naturalcycles/js-lib");
6
5
  const index_1 = require("../../index");
7
6
  const ajvValidationError_1 = require("./ajvValidationError");
@@ -60,7 +59,7 @@ class AjvSchema {
60
59
  */
61
60
  static readJsonSync(filePath, cfg = {}) {
62
61
  (0, index_1.requireFileToExist)(filePath);
63
- const schema = JSON.parse(fs.readFileSync(filePath, 'utf8'));
62
+ const schema = (0, index_1._readJsonFileSync)(filePath);
64
63
  return new AjvSchema(schema, cfg);
65
64
  }
66
65
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "12.90.4",
3
+ "version": "12.91.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "docs-serve": "vuepress dev docs",
@@ -23,7 +23,6 @@
23
23
  "ajv-merge-patch": "^5.0.1",
24
24
  "binary-split": "^1.0.5",
25
25
  "chalk": "^4.0.0",
26
- "cp-file": "^9.0.0",
27
26
  "debug": "^4.1.1",
28
27
  "dotenv": "^16.0.0",
29
28
  "execa": "^5.0.0",
@@ -34,18 +33,16 @@
34
33
  "joi": "17.4.2",
35
34
  "jsonwebtoken": "^9.0.0",
36
35
  "lru-cache": "^9.0.2",
37
- "move-file": "^2.0.0",
38
36
  "through2-concurrent": "^2.0.0",
39
37
  "yargs": "^17.0.0"
40
38
  },
41
39
  "devDependencies": {
42
40
  "@naturalcycles/bench-lib": "^1.0.7",
43
41
  "@naturalcycles/dev-lib": "^13.0.0",
44
- "@types/node": "^18.0.0",
42
+ "@types/node": "^20.1.0",
45
43
  "@types/yargs": "^16.0.0",
46
44
  "jest": "^29.0.0",
47
45
  "nock": "^13.0.2",
48
- "patch-package": "^6.2.1",
49
46
  "prettier": "^2.0.0",
50
47
  "vue-class-component": "^7.2.6",
51
48
  "vuepress": "^1.7.1",
@@ -65,7 +65,7 @@ export function csvStringToArray(str: string): string[][] {
65
65
  arr.push([])
66
66
  }
67
67
  arr[arr.length - 1]!.push(
68
- matches[2] ? matches[2].replace(new RegExp('""', 'g'), '"') : matches[3],
68
+ matches[2] ? matches[2].replaceAll(new RegExp('""', 'g'), '"') : matches[3],
69
69
  )
70
70
  }
71
71
  return arr
@@ -59,7 +59,7 @@ export class CSVWriter {
59
59
  }
60
60
 
61
61
  private quote(s: string): string {
62
- return `"${s.replace(/"/g, '""')}"`
62
+ return `"${s.replaceAll('"', '""')}"`
63
63
  }
64
64
 
65
65
  private shouldQuote(s: string): boolean {
@@ -0,0 +1,204 @@
1
+ /*
2
+
3
+ Why?
4
+
5
+ Convenience re-export/re-implementation of most common fs functions from
6
+ node:fs, node:fs/promises and fs-extra
7
+
8
+ Defaults to string input/output, as it's used in 80% of time. For the rest - you can use native fs.
9
+
10
+ Allows to import it easier, so you don't have to choose between the 3 import locations.
11
+ That's why function names are slightly renamed, to avoid conflict.
12
+
13
+ Credit to: fs-extra (https://github.com/jprichardson/node-fs-extra)
14
+
15
+ */
16
+
17
+ import * as fs from 'node:fs'
18
+ import * as fsp from 'node:fs/promises'
19
+ import * as path from 'node:path'
20
+ import { _jsonParse } from '@naturalcycles/js-lib'
21
+ import type { CopyOptions, CopyOptionsSync, MoveOptions } from 'fs-extra'
22
+ import * as fse from 'fs-extra'
23
+
24
+ export interface JsonOptions {
25
+ spaces?: number
26
+ }
27
+
28
+ /**
29
+ * Convenience wrapper that defaults to utf-8 string output.
30
+ */
31
+ export async function _readFile(filePath: string): Promise<string> {
32
+ return await fsp.readFile(filePath, 'utf8')
33
+ }
34
+
35
+ /**
36
+ * Convenience wrapper that defaults to utf-8 string output.
37
+ */
38
+ export function _readFileSync(filePath: string): string {
39
+ return fs.readFileSync(filePath, 'utf8')
40
+ }
41
+
42
+ export async function _readJsonFile<T = unknown>(filePath: string): Promise<T> {
43
+ const str = await fsp.readFile(filePath, 'utf8')
44
+ return _jsonParse(str)
45
+ }
46
+
47
+ export function _readJsonFileSync<T = unknown>(filePath: string): T {
48
+ const str = fs.readFileSync(filePath, 'utf8')
49
+ return _jsonParse(str)
50
+ }
51
+
52
+ export async function _writeFile(filePath: string, data: string | Buffer): Promise<void> {
53
+ await fsp.writeFile(filePath, data)
54
+ }
55
+
56
+ export function _writeFileSync(filePath: string, data: string | Buffer): void {
57
+ fs.writeFileSync(filePath, data)
58
+ }
59
+
60
+ export async function _outputFile(filePath: string, data: string | Buffer): Promise<void> {
61
+ const dirPath = path.dirname(filePath)
62
+ if (!(await _pathExists(dirPath))) {
63
+ await _ensureDir(dirPath)
64
+ }
65
+
66
+ await fsp.writeFile(filePath, data)
67
+ }
68
+
69
+ export function _outputFileSync(filePath: string, data: string | Buffer): void {
70
+ const dirPath = path.dirname(filePath)
71
+ if (!fs.existsSync(dirPath)) {
72
+ _ensureDirSync(dirPath)
73
+ }
74
+
75
+ fs.writeFileSync(filePath, data)
76
+ }
77
+
78
+ export async function _writeJsonFile(
79
+ filePath: string,
80
+ data: any,
81
+ opt?: JsonOptions,
82
+ ): Promise<void> {
83
+ const str = JSON.stringify(data, null, opt?.spaces)
84
+ await fsp.writeFile(filePath, str)
85
+ }
86
+
87
+ export function _writeJsonFileSync(filePath: string, data: any, opt?: JsonOptions): void {
88
+ const str = JSON.stringify(data, null, opt?.spaces)
89
+ fs.writeFileSync(filePath, str)
90
+ }
91
+
92
+ export async function _outputJsonFile(
93
+ filePath: string,
94
+ data: any,
95
+ opt?: JsonOptions,
96
+ ): Promise<void> {
97
+ const str = JSON.stringify(data, null, opt?.spaces)
98
+ await _outputFile(filePath, str)
99
+ }
100
+
101
+ export function _outputJsonFileSync(filePath: string, data: any, opt?: JsonOptions): void {
102
+ const str = JSON.stringify(data, null, opt?.spaces)
103
+ _outputFileSync(filePath, str)
104
+ }
105
+
106
+ export async function _pathExists(filePath: string): Promise<boolean> {
107
+ try {
108
+ await fsp.access(filePath)
109
+ return true
110
+ } catch {
111
+ return false
112
+ }
113
+ }
114
+
115
+ export function _pathExistsSync(filePath: string): boolean {
116
+ return fs.existsSync(filePath)
117
+ }
118
+
119
+ export async function _ensureDir(dirPath: string): Promise<void> {
120
+ await fsp.mkdir(dirPath, {
121
+ mode: 0o777,
122
+ recursive: true,
123
+ })
124
+ }
125
+
126
+ export function _ensureDirSync(dirPath: string): void {
127
+ fs.mkdirSync(dirPath, {
128
+ mode: 0o777,
129
+ recursive: true,
130
+ })
131
+ }
132
+
133
+ // Skipping `_ensureFile` (async), until it's needed
134
+
135
+ export function _ensureFileSync(filePath: string): void {
136
+ let stats
137
+ try {
138
+ stats = fs.statSync(filePath)
139
+ } catch {}
140
+ if (stats?.isFile()) return
141
+
142
+ const dir = path.dirname(filePath)
143
+ try {
144
+ if (!fs.statSync(dir).isDirectory()) {
145
+ // parent is not a directory
146
+ // This is just to cause an internal ENOTDIR error to be thrown
147
+ fs.readdirSync(dir)
148
+ }
149
+ } catch (err) {
150
+ // If the stat call above failed because the directory doesn't exist, create it
151
+ if ((err as any)?.code === 'ENOENT') return _ensureDirSync(dir)
152
+ throw err
153
+ }
154
+
155
+ fs.writeFileSync(filePath, '')
156
+ }
157
+
158
+ export async function _removePath(fileOrDirPath: string): Promise<void> {
159
+ await fsp.rm(fileOrDirPath, { recursive: true, force: true })
160
+ }
161
+
162
+ export function _removePathSync(fileOrDirPath: string): void {
163
+ fs.rmSync(fileOrDirPath, { recursive: true, force: true })
164
+ }
165
+
166
+ export async function _emptyDir(dirPath: string): Promise<void> {
167
+ let items
168
+ try {
169
+ items = await fsp.readdir(dirPath)
170
+ } catch {
171
+ return await _ensureDir(dirPath)
172
+ }
173
+
174
+ await Promise.all(items.map(item => _removePath(path.join(dirPath, item))))
175
+ }
176
+
177
+ export function _emptyDirSync(dirPath: string): void {
178
+ let items
179
+ try {
180
+ items = fs.readdirSync(dirPath)
181
+ } catch {
182
+ return _ensureDirSync(dirPath)
183
+ }
184
+
185
+ items.forEach(item => _removePathSync(path.join(dirPath, item)))
186
+ }
187
+
188
+ // copyFile/moveFile - let's keep using fs-extra for now
189
+
190
+ export async function _copyPath(src: string, dest: string, opt?: CopyOptions): Promise<void> {
191
+ await fse.copy(src, dest, opt)
192
+ }
193
+
194
+ export function _copyPathSync(src: string, dest: string, opt?: CopyOptionsSync): void {
195
+ fse.copySync(src, dest, opt)
196
+ }
197
+
198
+ export async function _movePath(src: string, dest: string, opt?: MoveOptions): Promise<void> {
199
+ await fse.move(src, dest, opt)
200
+ }
201
+
202
+ export function _movePathSync(src: string, dest: string, opt?: MoveOptions): void {
203
+ fse.moveSync(src, dest, opt)
204
+ }
package/src/fs/kpy.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  import * as path from 'node:path'
2
2
  import { _since } from '@naturalcycles/js-lib'
3
- import * as cpFile from 'cp-file'
4
- import * as fs from 'fs-extra'
5
- import * as moveFile from 'move-file'
6
3
  import { boldWhite, dimGrey, grey, yellow } from '../colors'
7
- import { globby } from '../index'
4
+ import {
5
+ _copyPath,
6
+ _copyPathSync,
7
+ _ensureDirSync,
8
+ _movePath,
9
+ _movePathSync,
10
+ _pathExistsSync,
11
+ globby,
12
+ } from '../index'
8
13
 
9
14
  /**
10
15
  * Everything defaults to `undefined`.
@@ -67,9 +72,9 @@ export async function kpy(opt: KpyOptions): Promise<void> {
67
72
 
68
73
  if (!opt.dry) {
69
74
  if (opt.move) {
70
- await moveFile(srcFilename, destFilename, { overwrite })
75
+ await _movePath(srcFilename, destFilename, { overwrite })
71
76
  } else {
72
- await cpFile(srcFilename, destFilename, { overwrite })
77
+ await _copyPath(srcFilename, destFilename, { overwrite })
73
78
  }
74
79
  }
75
80
 
@@ -103,9 +108,9 @@ export function kpySync(opt: KpyOptions): void {
103
108
 
104
109
  if (!opt.dry) {
105
110
  if (opt.move) {
106
- moveFile.sync(srcFilename, destFilename, { overwrite })
111
+ _movePathSync(srcFilename, destFilename, { overwrite })
107
112
  } else {
108
- cpFile.sync(srcFilename, destFilename, { overwrite })
113
+ _copyPathSync(srcFilename, destFilename, { overwrite })
109
114
  }
110
115
  }
111
116
 
@@ -125,12 +130,12 @@ function kpyPrepare(opt: KpyOptions): void {
125
130
  opt.baseDir ||= '.'
126
131
  opt.outputDir ||= '.'
127
132
 
128
- if (!fs.existsSync(opt.baseDir)) {
133
+ if (!_pathExistsSync(opt.baseDir)) {
129
134
  console.log(`kpy: baseDir doesn't exist: ${boldWhite(opt.baseDir)}`)
130
135
  return
131
136
  }
132
137
 
133
- fs.ensureDirSync(opt.outputDir)
138
+ _ensureDirSync(opt.outputDir)
134
139
  }
135
140
 
136
141
  function kpyLogFilenames(opt: KpyOptions, filenames: string[]): void {
package/src/index.ts CHANGED
@@ -76,6 +76,7 @@ export * from './validation/joi/joi.validation.error'
76
76
  export * from './validation/joi/joi.validation.util'
77
77
  export * from './script'
78
78
  export * from './jwt/jwt.service'
79
+ export * from './fs/fs.util'
79
80
 
80
81
  export type {
81
82
  GlobbyOptions,
@@ -122,7 +122,7 @@ export function secretOptional<T = string>(k: string, parseJson = false): T | un
122
122
  if (!v) return
123
123
 
124
124
  if (parseJson) {
125
- v = _jsonParseIfPossible(v)
125
+ v = _jsonParseIfPossible(v) as any
126
126
  }
127
127
 
128
128
  return v as T
@@ -1,6 +1,5 @@
1
- import * as fs from 'node:fs'
2
1
  import { JsonSchema } from '@naturalcycles/js-lib'
3
- import { fastGlob } from '../..'
2
+ import { _readJsonFileSync, fastGlob } from '../..'
4
3
  import type { FastGlobOptions } from '../..'
5
4
  import { AjvSchema, AjvSchemaCfg } from './ajvSchema'
6
5
 
@@ -13,7 +12,7 @@ import { AjvSchema, AjvSchemaCfg } from './ajvSchema'
13
12
  * @experimental
14
13
  */
15
14
  export function readJsonSchemas(patterns: string | string[], opt?: FastGlobOptions): JsonSchema[] {
16
- return fastGlob.sync(patterns, opt).map(fileName => JSON.parse(fs.readFileSync(fileName, 'utf8')))
15
+ return fastGlob.sync(patterns, opt).map(fileName => _readJsonFileSync(fileName))
17
16
  }
18
17
 
19
18
  /**
@@ -1,4 +1,3 @@
1
- import * as fs from 'node:fs'
2
1
  import {
3
2
  JsonSchema,
4
3
  JsonSchemaAnyBuilder,
@@ -9,7 +8,7 @@ import {
9
8
  CommonLogger,
10
9
  } from '@naturalcycles/js-lib'
11
10
  import Ajv, { ValidateFunction } from 'ajv'
12
- import { inspectAny, requireFileToExist } from '../../index'
11
+ import { _readJsonFileSync, inspectAny, requireFileToExist } from '../../index'
13
12
  import { AjvValidationError } from './ajvValidationError'
14
13
  import { getAjv } from './getAjv'
15
14
 
@@ -132,7 +131,7 @@ export class AjvSchema<T = unknown> {
132
131
  cfg: Partial<AjvSchemaCfg> = {},
133
132
  ): AjvSchema<T> {
134
133
  requireFileToExist(filePath)
135
- const schema = JSON.parse(fs.readFileSync(filePath, 'utf8'))
134
+ const schema = _readJsonFileSync<JsonSchema<T>>(filePath)
136
135
  return new AjvSchema<T>(schema, cfg)
137
136
  }
138
137