@naturalcycles/nodejs-lib 13.5.0 → 13.7.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.
- package/dist/fs/del.js +8 -13
- package/dist/fs/fs2.d.ts +83 -0
- package/dist/fs/fs2.js +279 -0
- package/dist/fs/json2env.js +4 -4
- package/dist/fs/kpy.js +6 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/secret/secrets-decrypt.util.js +2 -2
- package/dist/secret/secrets-encrypt.util.js +2 -2
- package/dist/stream/ndjson/pipelineToNDJsonFile.js +2 -2
- package/dist/util/buildInfo.util.js +3 -3
- package/dist/validation/ajv/ajv.util.js +1 -1
- package/dist/validation/ajv/ajvSchema.js +1 -1
- package/package.json +3 -1
- package/src/fs/del.ts +9 -20
- package/src/fs/fs2.ts +319 -0
- package/src/fs/json2env.ts +4 -4
- package/src/fs/kpy.ts +7 -15
- package/src/index.ts +1 -1
- package/src/secret/secrets-decrypt.util.ts +3 -3
- package/src/secret/secrets-encrypt.util.ts +3 -3
- package/src/slack/slack.service.ts +1 -1
- package/src/stream/ndjson/pipelineToNDJsonFile.ts +3 -3
- package/src/util/buildInfo.util.ts +3 -3
- package/src/validation/ajv/ajv.util.ts +2 -2
- package/src/validation/ajv/ajvSchema.ts +2 -2
- package/dist/fs/fs.util.d.ts +0 -184
- package/dist/fs/fs.util.js +0 -287
- package/src/fs/fs.util.ts +0 -287
package/src/fs/del.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import fsp from 'node:fs/promises'
|
|
3
1
|
import { pFilter, pMap, _since } from '@naturalcycles/js-lib'
|
|
4
2
|
import { dimGrey, yellow } from '../colors/colors'
|
|
5
|
-
import {
|
|
3
|
+
import { fs2, globby } from '../index'
|
|
6
4
|
|
|
7
5
|
export interface DelOptions {
|
|
8
6
|
/**
|
|
@@ -71,14 +69,7 @@ export async function del(_opt: DelOptions | DelSingleOption): Promise<void> {
|
|
|
71
69
|
|
|
72
70
|
if (dry) return
|
|
73
71
|
|
|
74
|
-
await pMap(
|
|
75
|
-
filenames,
|
|
76
|
-
filepath =>
|
|
77
|
-
fsp.rm(filepath, {
|
|
78
|
-
force: true,
|
|
79
|
-
}),
|
|
80
|
-
{ concurrency },
|
|
81
|
-
)
|
|
72
|
+
await pMap(filenames, filepath => fs2.removePath(filepath), { concurrency })
|
|
82
73
|
|
|
83
74
|
// 2. glob only dirs, expand, delete only empty!
|
|
84
75
|
let dirnames = await globby(patterns, {
|
|
@@ -90,7 +81,7 @@ export async function del(_opt: DelOptions | DelSingleOption): Promise<void> {
|
|
|
90
81
|
// Add original patterns (if any of them are dirs)
|
|
91
82
|
dirnames = dirnames.concat(
|
|
92
83
|
await pFilter(patterns, async pattern => {
|
|
93
|
-
return (await
|
|
84
|
+
return (await fs2.pathExistsAsync(pattern)) && (await fs2.lstatAsync(pattern)).isDirectory()
|
|
94
85
|
}),
|
|
95
86
|
)
|
|
96
87
|
|
|
@@ -102,7 +93,7 @@ export async function del(_opt: DelOptions | DelSingleOption): Promise<void> {
|
|
|
102
93
|
for await (const dirpath of dirnamesSorted) {
|
|
103
94
|
if (await isEmptyDir(dirpath)) {
|
|
104
95
|
// console.log(`empty dir: ${dirpath}`)
|
|
105
|
-
await
|
|
96
|
+
await fs2.removePathAsync(dirpath)
|
|
106
97
|
deletedDirs.push(dirpath)
|
|
107
98
|
}
|
|
108
99
|
}
|
|
@@ -152,7 +143,7 @@ export function delSync(_opt: DelOptions | DelSingleOption): void {
|
|
|
152
143
|
|
|
153
144
|
if (dry) return
|
|
154
145
|
|
|
155
|
-
filenames.forEach(filepath =>
|
|
146
|
+
filenames.forEach(filepath => fs2.removePath(filepath))
|
|
156
147
|
|
|
157
148
|
// 2. glob only dirs, expand, delete only empty!
|
|
158
149
|
let dirnames = globby.sync(patterns, {
|
|
@@ -162,9 +153,7 @@ export function delSync(_opt: DelOptions | DelSingleOption): void {
|
|
|
162
153
|
})
|
|
163
154
|
|
|
164
155
|
// Add original patterns (if any of them are dirs)
|
|
165
|
-
dirnames = dirnames.concat(
|
|
166
|
-
patterns.filter(p => _pathExistsSync(p) && fs.lstatSync(p).isDirectory()),
|
|
167
|
-
)
|
|
156
|
+
dirnames = dirnames.concat(patterns.filter(p => fs2.pathExists(p) && fs2.lstat(p).isDirectory()))
|
|
168
157
|
|
|
169
158
|
const dirnamesSorted = dirnames.sort().reverse()
|
|
170
159
|
|
|
@@ -174,7 +163,7 @@ export function delSync(_opt: DelOptions | DelSingleOption): void {
|
|
|
174
163
|
for (const dirpath of dirnamesSorted) {
|
|
175
164
|
if (isEmptyDirSync(dirpath)) {
|
|
176
165
|
// console.log(`empty dir: ${dirpath}`)
|
|
177
|
-
|
|
166
|
+
fs2.removePath(dirpath)
|
|
178
167
|
deletedDirs.push(dirpath)
|
|
179
168
|
}
|
|
180
169
|
}
|
|
@@ -196,9 +185,9 @@ export function delSync(_opt: DelOptions | DelSingleOption): void {
|
|
|
196
185
|
// 3. test each original pattern, if it exists and is directory and is empty - delete
|
|
197
186
|
|
|
198
187
|
async function isEmptyDir(dir: string): Promise<boolean> {
|
|
199
|
-
return (await
|
|
188
|
+
return (await fs2.readdirAsync(dir)).length === 0
|
|
200
189
|
}
|
|
201
190
|
|
|
202
191
|
function isEmptyDirSync(dir: string): boolean {
|
|
203
|
-
return
|
|
192
|
+
return fs2.readdir(dir).length === 0
|
|
204
193
|
}
|
package/src/fs/fs2.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
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 type { RmOptions } from 'node:fs'
|
|
18
|
+
import fs from 'node:fs'
|
|
19
|
+
import fsp from 'node:fs/promises'
|
|
20
|
+
import path from 'node:path'
|
|
21
|
+
import { _jsonParse } from '@naturalcycles/js-lib'
|
|
22
|
+
import yaml, { DumpOptions } from 'js-yaml'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* fs2 conveniently groups filesystem functions together.
|
|
26
|
+
* Supposed to be almost a drop-in replacement for these things together:
|
|
27
|
+
*
|
|
28
|
+
* 1. node:fs
|
|
29
|
+
* 2. node:fs/promises
|
|
30
|
+
* 3. fs-extra
|
|
31
|
+
*/
|
|
32
|
+
class FS2 {
|
|
33
|
+
// Naming convention is:
|
|
34
|
+
// - async function has Async in the name, e.g readTextAsync
|
|
35
|
+
// - sync function has postfix in the name, e.g readText
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Convenience wrapper that defaults to utf-8 string output.
|
|
39
|
+
*/
|
|
40
|
+
readText(filePath: string): string {
|
|
41
|
+
return fs.readFileSync(filePath, 'utf8')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Convenience wrapper that defaults to utf-8 string output.
|
|
46
|
+
*/
|
|
47
|
+
async readTextAsync(filePath: string): Promise<string> {
|
|
48
|
+
return await fsp.readFile(filePath, 'utf8')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
readBuffer(filePath: string): Buffer {
|
|
52
|
+
return fs.readFileSync(filePath)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async readBufferAsync(filePath: string): Promise<Buffer> {
|
|
56
|
+
return await fsp.readFile(filePath)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
readJson<T = unknown>(filePath: string): T {
|
|
60
|
+
const str = fs.readFileSync(filePath, 'utf8')
|
|
61
|
+
return _jsonParse(str)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async readJsonAsync<T = unknown>(filePath: string): Promise<T> {
|
|
65
|
+
const str = await fsp.readFile(filePath, 'utf8')
|
|
66
|
+
return _jsonParse(str)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
readYaml<T = unknown>(filePath: string): T {
|
|
70
|
+
return yaml.load(fs.readFileSync(filePath, 'utf8')) as T
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async readYamlAsync<T = unknown>(filePath: string): Promise<T> {
|
|
74
|
+
return yaml.load(await fsp.readFile(filePath, 'utf8')) as T
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
writeFile(filePath: string, data: string | Buffer): void {
|
|
78
|
+
fs.writeFileSync(filePath, data)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async writeFileAsync(filePath: string, data: string | Buffer): Promise<void> {
|
|
82
|
+
await fsp.writeFile(filePath, data)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
writeJson(filePath: string, data: any, opt?: JsonOptions): void {
|
|
86
|
+
const str = stringify(data, opt)
|
|
87
|
+
fs.writeFileSync(filePath, str)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async writeJsonAsync(filePath: string, data: any, opt?: JsonOptions): Promise<void> {
|
|
91
|
+
const str = stringify(data, opt)
|
|
92
|
+
await fsp.writeFile(filePath, str)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
writeYaml(filePath: string, data: any, opt?: DumpOptions): void {
|
|
96
|
+
const str = yaml.dump(data, opt)
|
|
97
|
+
fs.writeFileSync(filePath, str)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async writeYamlAsync(filePath: string, data: any, opt?: DumpOptions): Promise<void> {
|
|
101
|
+
const str = yaml.dump(data, opt)
|
|
102
|
+
await fsp.writeFile(filePath, str)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
appendFile(filePath: string, data: string | Buffer): void {
|
|
106
|
+
fs.appendFileSync(filePath, data)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async appendFileAsync(filePath: string, data: string | Buffer): Promise<void> {
|
|
110
|
+
await fsp.appendFile(filePath, data)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
outputJson(filePath: string, data: any, opt?: JsonOptions): void {
|
|
114
|
+
const str = stringify(data, opt)
|
|
115
|
+
this.outputFile(filePath, str)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async outputJsonAsync(filePath: string, data: any, opt?: JsonOptions): Promise<void> {
|
|
119
|
+
const str = stringify(data, opt)
|
|
120
|
+
await this.outputFileAsync(filePath, str)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
outputYaml(filePath: string, data: any, opt?: DumpOptions): void {
|
|
124
|
+
const str = yaml.dump(data, opt)
|
|
125
|
+
this.outputFile(filePath, str)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async outputYamlAsync(filePath: string, data: any, opt?: DumpOptions): Promise<void> {
|
|
129
|
+
const str = yaml.dump(data, opt)
|
|
130
|
+
await this.outputFileAsync(filePath, str)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
outputFile(filePath: string, data: string | Buffer): void {
|
|
134
|
+
const dirPath = path.dirname(filePath)
|
|
135
|
+
if (!fs.existsSync(dirPath)) {
|
|
136
|
+
this.ensureDir(dirPath)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
fs.writeFileSync(filePath, data)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async outputFileAsync(filePath: string, data: string | Buffer): Promise<void> {
|
|
143
|
+
const dirPath = path.dirname(filePath)
|
|
144
|
+
if (!(await this.pathExistsAsync(dirPath))) {
|
|
145
|
+
await this.ensureDirAsync(dirPath)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
await fsp.writeFile(filePath, data)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
pathExists(filePath: string): boolean {
|
|
152
|
+
return fs.existsSync(filePath)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async pathExistsAsync(filePath: string): Promise<boolean> {
|
|
156
|
+
try {
|
|
157
|
+
await fsp.access(filePath)
|
|
158
|
+
return true
|
|
159
|
+
} catch {
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
ensureDir(dirPath: string): void {
|
|
165
|
+
fs.mkdirSync(dirPath, {
|
|
166
|
+
mode: 0o777,
|
|
167
|
+
recursive: true,
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async ensureDirAsync(dirPath: string): Promise<void> {
|
|
172
|
+
await fsp.mkdir(dirPath, {
|
|
173
|
+
mode: 0o777,
|
|
174
|
+
recursive: true,
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
ensureFile(filePath: string): void {
|
|
179
|
+
let stats
|
|
180
|
+
try {
|
|
181
|
+
stats = fs.statSync(filePath)
|
|
182
|
+
} catch {}
|
|
183
|
+
if (stats?.isFile()) return
|
|
184
|
+
|
|
185
|
+
const dir = path.dirname(filePath)
|
|
186
|
+
try {
|
|
187
|
+
if (!fs.statSync(dir).isDirectory()) {
|
|
188
|
+
// parent is not a directory
|
|
189
|
+
// This is just to cause an internal ENOTDIR error to be thrown
|
|
190
|
+
fs.readdirSync(dir)
|
|
191
|
+
}
|
|
192
|
+
} catch (err) {
|
|
193
|
+
// If the stat call above failed because the directory doesn't exist, create it
|
|
194
|
+
if ((err as any)?.code === 'ENOENT') return this.ensureDir(dir)
|
|
195
|
+
throw err
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
fs.writeFileSync(filePath, '')
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async ensureFileAsync(filePath: string): Promise<void> {
|
|
202
|
+
let stats
|
|
203
|
+
try {
|
|
204
|
+
stats = await fsp.stat(filePath)
|
|
205
|
+
} catch {}
|
|
206
|
+
if (stats?.isFile()) return
|
|
207
|
+
|
|
208
|
+
const dir = path.dirname(filePath)
|
|
209
|
+
try {
|
|
210
|
+
if (!(await fsp.stat(dir)).isDirectory()) {
|
|
211
|
+
// parent is not a directory
|
|
212
|
+
// This is just to cause an internal ENOTDIR error to be thrown
|
|
213
|
+
await fsp.readdir(dir)
|
|
214
|
+
}
|
|
215
|
+
} catch (err) {
|
|
216
|
+
// If the stat call above failed because the directory doesn't exist, create it
|
|
217
|
+
if ((err as any)?.code === 'ENOENT') return await this.ensureDirAsync(dir)
|
|
218
|
+
throw err
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
await fsp.writeFile(filePath, '')
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
removePath(fileOrDirPath: string, opt?: RmOptions): void {
|
|
225
|
+
fs.rmSync(fileOrDirPath, { recursive: true, force: true, ...opt })
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async removePathAsync(fileOrDirPath: string, opt?: RmOptions): Promise<void> {
|
|
229
|
+
await fsp.rm(fileOrDirPath, { recursive: true, force: true, ...opt })
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
emptyDir(dirPath: string): void {
|
|
233
|
+
let items
|
|
234
|
+
try {
|
|
235
|
+
items = fs.readdirSync(dirPath)
|
|
236
|
+
} catch {
|
|
237
|
+
return this.ensureDir(dirPath)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
items.forEach(item => this.removePath(path.join(dirPath, item)))
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async emptyDirAsync(dirPath: string): Promise<void> {
|
|
244
|
+
let items
|
|
245
|
+
try {
|
|
246
|
+
items = await fsp.readdir(dirPath)
|
|
247
|
+
} catch {
|
|
248
|
+
return await this.ensureDirAsync(dirPath)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
await Promise.all(items.map(item => this.removePathAsync(path.join(dirPath, item))))
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Cautious, underlying Node function is currently Experimental.
|
|
256
|
+
*/
|
|
257
|
+
copyPath(src: string, dest: string, opt?: fs.CopySyncOptions): void {
|
|
258
|
+
fs.cpSync(src, dest, {
|
|
259
|
+
recursive: true,
|
|
260
|
+
...opt,
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Cautious, underlying Node function is currently Experimental.
|
|
266
|
+
*/
|
|
267
|
+
async copyPathAsync(src: string, dest: string, opt?: fs.CopyOptions): Promise<void> {
|
|
268
|
+
await fsp.cp(src, dest, {
|
|
269
|
+
recursive: true,
|
|
270
|
+
...opt,
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
renamePath(src: string, dest: string): void {
|
|
275
|
+
fs.renameSync(src, dest)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async renamePathAsync(src: string, dest: string): Promise<void> {
|
|
279
|
+
await fsp.rename(src, dest)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
movePath(src: string, dest: string, opt?: fs.CopySyncOptions): void {
|
|
283
|
+
this.copyPath(src, dest, opt)
|
|
284
|
+
this.removePath(src)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async movePathAsync(src: string, dest: string, opt?: fs.CopyOptions): Promise<void> {
|
|
288
|
+
await this.copyPathAsync(src, dest, opt)
|
|
289
|
+
await this.removePathAsync(src)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Re-export the whole fs/fsp, for the edge cases where they are needed
|
|
293
|
+
fs = fs
|
|
294
|
+
fsp = fsp
|
|
295
|
+
|
|
296
|
+
// Re-export existing fs/fsp functions
|
|
297
|
+
// rm/rmAsync are replaced with removePath/removePathAsync
|
|
298
|
+
lstat = fs.lstatSync
|
|
299
|
+
lstatAsync = fsp.lstat
|
|
300
|
+
stat = fs.statSync
|
|
301
|
+
statAsync = fsp.stat
|
|
302
|
+
mkdir = fs.mkdirSync
|
|
303
|
+
mkdirAsync = fsp.mkdir
|
|
304
|
+
readdir = fs.readdirSync
|
|
305
|
+
readdirAsync = fsp.readdir
|
|
306
|
+
createWriteStream = fs.createWriteStream
|
|
307
|
+
createReadStream = fs.createReadStream
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export const fs2 = new FS2()
|
|
311
|
+
|
|
312
|
+
export interface JsonOptions {
|
|
313
|
+
spaces?: number
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function stringify(data: any, opt?: JsonOptions): string {
|
|
317
|
+
// If pretty-printing is enabled (spaces) - also add a newline at the end (to match our prettier config)
|
|
318
|
+
return JSON.stringify(data, null, opt?.spaces) + (opt?.spaces ? '\n' : '')
|
|
319
|
+
}
|
package/src/fs/json2env.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import { AnyObject } from '@naturalcycles/js-lib'
|
|
3
3
|
import { dimGrey } from '../colors/colors'
|
|
4
|
-
import {
|
|
4
|
+
import { fs2 } from './fs2'
|
|
5
5
|
|
|
6
6
|
export interface Json2EnvOptions {
|
|
7
7
|
jsonPath: string
|
|
@@ -46,7 +46,7 @@ export function json2env(opt: Json2EnvOptions): void {
|
|
|
46
46
|
...opt,
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
if (!
|
|
49
|
+
if (!fs2.pathExists(jsonPath)) {
|
|
50
50
|
if (fail) {
|
|
51
51
|
throw new Error(`Path doesn't exist: ${jsonPath}`)
|
|
52
52
|
}
|
|
@@ -63,7 +63,7 @@ export function json2env(opt: Json2EnvOptions): void {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// read file
|
|
66
|
-
const json: AnyObject =
|
|
66
|
+
const json: AnyObject = fs2.readJson(jsonPath)
|
|
67
67
|
|
|
68
68
|
if (debug) {
|
|
69
69
|
console.log(json)
|
|
@@ -72,7 +72,7 @@ export function json2env(opt: Json2EnvOptions): void {
|
|
|
72
72
|
if (saveEnvFile) {
|
|
73
73
|
const shPath = `${jsonPath}.sh`
|
|
74
74
|
const exportStr = objectToShellExport(json, prefix)
|
|
75
|
-
|
|
75
|
+
fs2.writeFile(shPath, exportStr)
|
|
76
76
|
|
|
77
77
|
if (!silent) {
|
|
78
78
|
console.log(`json2env created ${dimGrey(shPath)}:`)
|
package/src/fs/kpy.ts
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { _since } from '@naturalcycles/js-lib'
|
|
3
3
|
import { boldWhite, dimGrey, grey, yellow } from '../colors/colors'
|
|
4
|
-
import {
|
|
5
|
-
_copyPath,
|
|
6
|
-
_copyPathSync,
|
|
7
|
-
_ensureDirSync,
|
|
8
|
-
_movePath,
|
|
9
|
-
_movePathSync,
|
|
10
|
-
_pathExistsSync,
|
|
11
|
-
globby,
|
|
12
|
-
} from '../index'
|
|
4
|
+
import { fs2, globby } from '../index'
|
|
13
5
|
|
|
14
6
|
/**
|
|
15
7
|
* Everything defaults to `undefined`.
|
|
@@ -72,11 +64,11 @@ export async function kpy(opt: KpyOptions): Promise<void> {
|
|
|
72
64
|
|
|
73
65
|
if (!opt.dry) {
|
|
74
66
|
if (opt.move) {
|
|
75
|
-
await
|
|
67
|
+
await fs2.movePathAsync(srcFilename, destFilename, {
|
|
76
68
|
force: overwrite,
|
|
77
69
|
})
|
|
78
70
|
} else {
|
|
79
|
-
await
|
|
71
|
+
await fs2.copyPathAsync(srcFilename, destFilename, { force: overwrite })
|
|
80
72
|
}
|
|
81
73
|
}
|
|
82
74
|
|
|
@@ -110,9 +102,9 @@ export function kpySync(opt: KpyOptions): void {
|
|
|
110
102
|
|
|
111
103
|
if (!opt.dry) {
|
|
112
104
|
if (opt.move) {
|
|
113
|
-
|
|
105
|
+
fs2.movePath(srcFilename, destFilename, { force: overwrite })
|
|
114
106
|
} else {
|
|
115
|
-
|
|
107
|
+
fs2.copyPath(srcFilename, destFilename, { force: overwrite })
|
|
116
108
|
}
|
|
117
109
|
}
|
|
118
110
|
|
|
@@ -132,12 +124,12 @@ function kpyPrepare(opt: KpyOptions): void {
|
|
|
132
124
|
opt.baseDir ||= '.'
|
|
133
125
|
opt.outputDir ||= '.'
|
|
134
126
|
|
|
135
|
-
if (!
|
|
127
|
+
if (!fs2.pathExists(opt.baseDir)) {
|
|
136
128
|
console.log(`kpy: baseDir doesn't exist: ${boldWhite(opt.baseDir)}`)
|
|
137
129
|
return
|
|
138
130
|
}
|
|
139
131
|
|
|
140
|
-
|
|
132
|
+
fs2.ensureDir(opt.outputDir)
|
|
141
133
|
}
|
|
142
134
|
|
|
143
135
|
function kpyLogFilenames(opt: KpyOptions, filenames: string[]): void {
|
package/src/index.ts
CHANGED
|
@@ -86,7 +86,7 @@ export * from './validation/joi/joi.validation.error'
|
|
|
86
86
|
export * from './validation/joi/joi.validation.util'
|
|
87
87
|
export * from './script/runScript'
|
|
88
88
|
export * from './jwt/jwt.service'
|
|
89
|
-
export * from './fs/
|
|
89
|
+
export * from './fs/fs2'
|
|
90
90
|
export * from './fs/del'
|
|
91
91
|
export * from './fs/json2env'
|
|
92
92
|
export * from './fs/kpy'
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { _assert } from '@naturalcycles/js-lib'
|
|
4
4
|
import { dimGrey, yellow } from '../colors/colors'
|
|
5
|
-
import {
|
|
5
|
+
import { fastGlob, fs2 } from '../index'
|
|
6
6
|
import { decryptObject, decryptRandomIVBuffer } from '../security/crypto.util'
|
|
7
7
|
|
|
8
8
|
export interface DecryptCLIOptions {
|
|
@@ -47,9 +47,9 @@ export function secretsDecrypt(
|
|
|
47
47
|
)
|
|
48
48
|
plainFilename = filename.replace('.json', '.plain.json')
|
|
49
49
|
|
|
50
|
-
const json = decryptObject(
|
|
50
|
+
const json = decryptObject(fs2.readJson(filename), encKeyBuffer)
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
fs2.writeJson(plainFilename, json, { spaces: 2 })
|
|
53
53
|
} else {
|
|
54
54
|
const enc = fs.readFileSync(filename)
|
|
55
55
|
const plain = decryptRandomIVBuffer(enc, encKeyBuffer)
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { _assert } from '@naturalcycles/js-lib'
|
|
4
4
|
import { dimGrey, yellow } from '../colors/colors'
|
|
5
|
-
import {
|
|
5
|
+
import { fastGlob, fs2 } from '../index'
|
|
6
6
|
import { encryptObject, encryptRandomIVBuffer } from '../security/crypto.util'
|
|
7
7
|
|
|
8
8
|
export interface EncryptCLIOptions {
|
|
@@ -41,9 +41,9 @@ export function secretsEncrypt(
|
|
|
41
41
|
)
|
|
42
42
|
encFilename = filename.replace('.plain', '')
|
|
43
43
|
|
|
44
|
-
const json = encryptObject(
|
|
44
|
+
const json = encryptObject(fs2.readJson(filename), encKeyBuffer)
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
fs2.writeJson(encFilename, json, { spaces: 2 })
|
|
47
47
|
} else {
|
|
48
48
|
const plain = fs.readFileSync(filename)
|
|
49
49
|
const enc = encryptRandomIVBuffer(plain, encKeyBuffer)
|
|
@@ -185,7 +185,7 @@ export function slackDefaultMessagePrefixHook(msg: SlackMessage): string[] {
|
|
|
185
185
|
|
|
186
186
|
// AppEngine-specific decoration
|
|
187
187
|
if (GAE && ctx && typeof ctx === 'object' && typeof ctx.header === 'function') {
|
|
188
|
-
tokens.push(ctx.header('x-appengine-country')
|
|
188
|
+
tokens.push(ctx.header('x-appengine-country'), ctx.header('x-appengine-city'))
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
return tokens.filter(Boolean)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import { createGzip, ZlibOptions } from 'node:zlib'
|
|
3
3
|
import { AppError } from '@naturalcycles/js-lib'
|
|
4
|
-
import { transformTap, _pipeline,
|
|
4
|
+
import { transformTap, _pipeline, fs2 } from '../..'
|
|
5
5
|
import { grey } from '../../colors/colors'
|
|
6
6
|
import { NDJsonStats } from './ndjson.model'
|
|
7
7
|
import { transformToNDJson, TransformToNDJsonOptions } from './transformToNDJson'
|
|
@@ -37,14 +37,14 @@ export async function pipelineToNDJsonFile(
|
|
|
37
37
|
): Promise<NDJsonStats> {
|
|
38
38
|
const { filePath, gzip, protectFromOverwrite = false } = opt
|
|
39
39
|
|
|
40
|
-
if (protectFromOverwrite &&
|
|
40
|
+
if (protectFromOverwrite && fs2.pathExists(filePath)) {
|
|
41
41
|
throw new AppError(`pipelineToNDJsonFile: output file exists: ${filePath}`)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const started = Date.now()
|
|
45
45
|
let rows = 0
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
fs2.ensureFile(filePath)
|
|
48
48
|
|
|
49
49
|
console.log(`>> ${grey(filePath)} started...`)
|
|
50
50
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
localTimeOrNow,
|
|
6
6
|
UnixTimestampNumber,
|
|
7
7
|
} from '@naturalcycles/js-lib'
|
|
8
|
-
import {
|
|
8
|
+
import { fs2 } from '../fs/fs2'
|
|
9
9
|
import {
|
|
10
10
|
gitCurrentBranchName,
|
|
11
11
|
gitCurrentCommitSha,
|
|
@@ -36,8 +36,8 @@ export function generateBuildInfo(opt: GenerateBuildInfoOptions = {}): BuildInfo
|
|
|
36
36
|
if (!env) {
|
|
37
37
|
// Attempt to read `envByBranch` from package.json root
|
|
38
38
|
try {
|
|
39
|
-
if (
|
|
40
|
-
const packageJson =
|
|
39
|
+
if (fs2.pathExists('package.json')) {
|
|
40
|
+
const packageJson = fs2.readJson<AnyObject>('package.json')
|
|
41
41
|
env = packageJson?.['envByBranch']?.[branchName] || packageJson?.['envByBranch']?.['*']
|
|
42
42
|
}
|
|
43
43
|
} catch {}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JsonSchema } from '@naturalcycles/js-lib'
|
|
2
|
-
import {
|
|
2
|
+
import { fastGlob, fs2 } from '../..'
|
|
3
3
|
import type { FastGlobOptions } from '../..'
|
|
4
4
|
import { AjvSchema, AjvSchemaCfg } from './ajvSchema'
|
|
5
5
|
|
|
@@ -12,7 +12,7 @@ import { AjvSchema, AjvSchemaCfg } from './ajvSchema'
|
|
|
12
12
|
* @experimental
|
|
13
13
|
*/
|
|
14
14
|
export function readJsonSchemas(patterns: string | string[], opt?: FastGlobOptions): JsonSchema[] {
|
|
15
|
-
return fastGlob.sync(patterns, opt).map(fileName =>
|
|
15
|
+
return fastGlob.sync(patterns, opt).map(fileName => fs2.readJson(fileName))
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
CommonLogger,
|
|
9
9
|
} from '@naturalcycles/js-lib'
|
|
10
10
|
import Ajv, { ValidateFunction } from 'ajv'
|
|
11
|
-
import {
|
|
11
|
+
import { _inspect, fs2, requireFileToExist } from '../../index'
|
|
12
12
|
import { AjvValidationError } from './ajvValidationError'
|
|
13
13
|
import { getAjv } from './getAjv'
|
|
14
14
|
|
|
@@ -134,7 +134,7 @@ export class AjvSchema<T = unknown> {
|
|
|
134
134
|
cfg: Partial<AjvSchemaCfg> = {},
|
|
135
135
|
): AjvSchema<T> {
|
|
136
136
|
requireFileToExist(filePath)
|
|
137
|
-
const schema =
|
|
137
|
+
const schema = fs2.readJson<JsonSchema<T>>(filePath)
|
|
138
138
|
return new AjvSchema<T>(schema, cfg)
|
|
139
139
|
}
|
|
140
140
|
|