@naturalcycles/nodejs-lib 13.31.1 → 13.33.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/csv/csvReader.js +2 -2
- package/dist/fs/fs2.js +6 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/slack/slack.service.js +2 -4
- package/dist/stream/ndjson/transformJsonParse.js +1 -1
- package/dist/stream/transform/transformMap.d.ts +4 -2
- package/dist/stream/transform/transformMap.js +2 -2
- package/dist/stream/transform/transformSplit.js +2 -2
- package/dist/stream/transform/worker/workerClassProxy.js +2 -2
- package/dist/stream/writable/writableLimit.js +1 -1
- package/dist/stream/writable/writableVoid.js +1 -1
- package/dist/util/buildInfo.util.js +5 -5
- package/dist/util/exec2.d.ts +167 -0
- package/dist/util/exec2.js +204 -0
- package/dist/util/git2.d.ts +25 -0
- package/dist/util/git2.js +95 -0
- package/dist/validation/joi/number.extensions.d.ts +2 -1
- package/dist/validation/joi/string.extensions.d.ts +2 -1
- package/package.json +3 -2
- package/src/csv/csvReader.ts +2 -7
- package/src/fs/fs2.ts +11 -7
- package/src/index.ts +2 -2
- package/src/secret/secrets-decrypt.util.ts +1 -1
- package/src/secret/secrets-encrypt.util.ts +1 -1
- package/src/slack/slack.service.ts +2 -3
- package/src/stream/ndjson/transformJsonParse.ts +1 -1
- package/src/stream/stream.model.ts +2 -2
- package/src/stream/transform/transformMap.ts +5 -3
- package/src/stream/transform/transformSplit.ts +3 -3
- package/src/stream/transform/worker/workerClassProxy.js +2 -2
- package/src/stream/writable/writableLimit.ts +1 -1
- package/src/stream/writable/writableVoid.ts +1 -1
- package/src/util/buildInfo.util.ts +5 -10
- package/src/util/exec2.ts +326 -0
- package/src/util/git2.ts +105 -0
- package/src/validation/joi/number.extensions.ts +2 -1
- package/src/validation/joi/string.extensions.ts +2 -1
- package/dist/util/exec.util.d.ts +0 -10
- package/dist/util/exec.util.js +0 -58
- package/dist/util/git.util.d.ts +0 -18
- package/dist/util/git.util.js +0 -109
- package/src/util/exec.util.ts +0 -79
- package/src/util/git.util.ts +0 -113
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.git2 = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_child_process_1 = tslib_1.__importDefault(require("node:child_process"));
|
|
6
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
|
+
const colors_1 = require("../colors/colors");
|
|
8
|
+
const exec2_1 = require("./exec2");
|
|
9
|
+
/**
|
|
10
|
+
* Set of utility functions to work with git.
|
|
11
|
+
*/
|
|
12
|
+
class Git2 {
|
|
13
|
+
getLastGitCommitMsg() {
|
|
14
|
+
return exec2_1.exec2.exec('git log -1 --pretty=%B');
|
|
15
|
+
}
|
|
16
|
+
commitMessageToTitleMessage(msg) {
|
|
17
|
+
const firstLine = msg.split('\n')[0];
|
|
18
|
+
const [preTitle, title] = firstLine.split(': ');
|
|
19
|
+
return title || preTitle;
|
|
20
|
+
}
|
|
21
|
+
gitHasUncommittedChanges() {
|
|
22
|
+
// git diff-index --quiet HEAD -- || echo "untracked"
|
|
23
|
+
try {
|
|
24
|
+
node_child_process_1.default.execSync('git diff-index --quiet HEAD --', {
|
|
25
|
+
encoding: 'utf8',
|
|
26
|
+
});
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns true if there were changes
|
|
35
|
+
*/
|
|
36
|
+
gitCommitAll(msg) {
|
|
37
|
+
// git commit -a -m "style(lint-all): $GIT_MSG" || true
|
|
38
|
+
const cmd = `git commit -a --no-verify -m "${msg}"`;
|
|
39
|
+
// const cmd = `git`
|
|
40
|
+
// const args = ['commit', '-a', '--no-verify', '-m', msg]
|
|
41
|
+
console.log((0, colors_1.grey)(cmd));
|
|
42
|
+
try {
|
|
43
|
+
node_child_process_1.default.execSync(cmd, {
|
|
44
|
+
stdio: 'inherit',
|
|
45
|
+
});
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @returns true if there are not pushed commits.
|
|
54
|
+
*/
|
|
55
|
+
gitIsAhead() {
|
|
56
|
+
// ahead=`git rev-list HEAD --not --remotes | wc -l | awk '{print $1}'`
|
|
57
|
+
const cmd = `git rev-list HEAD --not --remotes | wc -l | awk '{print $1}'`;
|
|
58
|
+
const stdout = exec2_1.exec2.exec(cmd);
|
|
59
|
+
// console.log(`gitIsAhead: ${stdout}`)
|
|
60
|
+
return Number(stdout) > 0;
|
|
61
|
+
}
|
|
62
|
+
gitPull() {
|
|
63
|
+
const cmd = 'git pull';
|
|
64
|
+
try {
|
|
65
|
+
node_child_process_1.default.execSync(cmd, {
|
|
66
|
+
stdio: 'inherit',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
70
|
+
}
|
|
71
|
+
gitPush() {
|
|
72
|
+
// git push --set-upstream origin $CIRCLE_BRANCH && echo "pushed, exiting" && exit 0
|
|
73
|
+
let cmd = 'git push';
|
|
74
|
+
const branchName = this.gitCurrentBranchName();
|
|
75
|
+
if (branchName) {
|
|
76
|
+
cmd += ` --set-upstream origin ${branchName}`;
|
|
77
|
+
}
|
|
78
|
+
exec2_1.exec2.spawn(cmd, { logStart: true });
|
|
79
|
+
}
|
|
80
|
+
gitCurrentCommitSha(full = false) {
|
|
81
|
+
const sha = exec2_1.exec2.exec('git rev-parse HEAD');
|
|
82
|
+
return full ? sha : sha.slice(0, 7);
|
|
83
|
+
}
|
|
84
|
+
gitCurrentCommitTimestamp() {
|
|
85
|
+
return Number(exec2_1.exec2.exec('git log -1 --format=%ct'));
|
|
86
|
+
}
|
|
87
|
+
gitCurrentBranchName() {
|
|
88
|
+
return exec2_1.exec2.exec('git rev-parse --abbrev-ref HEAD');
|
|
89
|
+
}
|
|
90
|
+
gitCurrentRepoName() {
|
|
91
|
+
const originUrl = exec2_1.exec2.exec('git config --get remote.origin.url');
|
|
92
|
+
return node_path_1.default.basename(originUrl, '.git');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.git2 = new Git2();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import Joi
|
|
1
|
+
import type Joi from 'joi';
|
|
2
|
+
import { Extension, NumberSchema as JoiNumberSchema } from 'joi';
|
|
2
3
|
export interface NumberSchema<TSchema = number> extends JoiNumberSchema<TSchema> {
|
|
3
4
|
dividable: (q: number) => this;
|
|
4
5
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import Joi
|
|
1
|
+
import type Joi from 'joi';
|
|
2
|
+
import { Extension, StringSchema as JoiStringSchema } from 'joi';
|
|
2
3
|
export interface StringSchema<TSchema = string> extends JoiStringSchema<TSchema> {
|
|
3
4
|
dateString: (min?: string, max?: string) => this;
|
|
4
5
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/nodejs-lib",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.33.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"prepare": "husky",
|
|
6
6
|
"build": "dev-lib build",
|
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
"yargs": "^17.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
+
"@biomejs/biome": "^1.8.3",
|
|
42
43
|
"@naturalcycles/bench-lib": "^3.0.0",
|
|
43
44
|
"@naturalcycles/dev-lib": "^15.0.3",
|
|
44
|
-
"@types/node": "^
|
|
45
|
+
"@types/node": "^22.1.0",
|
|
45
46
|
"@types/yargs": "^16.0.0",
|
|
46
47
|
"jest": "^29.0.0"
|
|
47
48
|
},
|
package/src/csv/csvReader.ts
CHANGED
|
@@ -56,10 +56,7 @@ export function csvStringParse<T extends AnyObject = any>(
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
export function csvStringToArray(str: string): string[][] {
|
|
59
|
-
const objPattern =
|
|
60
|
-
String.raw`(,|\r?\n|\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^,\r\n]*))`,
|
|
61
|
-
'gi',
|
|
62
|
-
)
|
|
59
|
+
const objPattern = /(,|\r?\n|\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^,\r\n]*))/gi
|
|
63
60
|
let matches: RegExpExecArray | null
|
|
64
61
|
const arr: any[][] = [[]]
|
|
65
62
|
|
|
@@ -67,9 +64,7 @@ export function csvStringToArray(str: string): string[][] {
|
|
|
67
64
|
if (matches[1]!.length && matches[1] !== ',') {
|
|
68
65
|
arr.push([])
|
|
69
66
|
}
|
|
70
|
-
arr[arr.length - 1]!.push(
|
|
71
|
-
matches[2] ? matches[2].replaceAll(new RegExp('""', 'g'), '"') : matches[3],
|
|
72
|
-
)
|
|
67
|
+
arr[arr.length - 1]!.push(matches[2] ? matches[2].replaceAll('""', '"') : matches[3])
|
|
73
68
|
}
|
|
74
69
|
return arr
|
|
75
70
|
}
|
package/src/fs/fs2.ts
CHANGED
|
@@ -14,7 +14,7 @@ Credit to: fs-extra (https://github.com/jprichardson/node-fs-extra)
|
|
|
14
14
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { RmOptions } from 'node:fs'
|
|
17
|
+
import type { RmOptions, Stats } from 'node:fs'
|
|
18
18
|
import fs from 'node:fs'
|
|
19
19
|
import fsp from 'node:fs/promises'
|
|
20
20
|
import path from 'node:path'
|
|
@@ -182,7 +182,7 @@ class FS2 {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
ensureFile(filePath: string): void {
|
|
185
|
-
let stats
|
|
185
|
+
let stats: Stats | undefined
|
|
186
186
|
try {
|
|
187
187
|
stats = fs.statSync(filePath)
|
|
188
188
|
} catch {}
|
|
@@ -197,7 +197,10 @@ class FS2 {
|
|
|
197
197
|
}
|
|
198
198
|
} catch (err) {
|
|
199
199
|
// If the stat call above failed because the directory doesn't exist, create it
|
|
200
|
-
if ((err as any)?.code === 'ENOENT')
|
|
200
|
+
if ((err as any)?.code === 'ENOENT') {
|
|
201
|
+
this.ensureDir(dir)
|
|
202
|
+
return
|
|
203
|
+
}
|
|
201
204
|
throw err
|
|
202
205
|
}
|
|
203
206
|
|
|
@@ -205,7 +208,7 @@ class FS2 {
|
|
|
205
208
|
}
|
|
206
209
|
|
|
207
210
|
async ensureFileAsync(filePath: string): Promise<void> {
|
|
208
|
-
let stats
|
|
211
|
+
let stats: Stats | undefined
|
|
209
212
|
try {
|
|
210
213
|
stats = await fsp.stat(filePath)
|
|
211
214
|
} catch {}
|
|
@@ -236,18 +239,19 @@ class FS2 {
|
|
|
236
239
|
}
|
|
237
240
|
|
|
238
241
|
emptyDir(dirPath: string): void {
|
|
239
|
-
let items
|
|
242
|
+
let items: string[]
|
|
240
243
|
try {
|
|
241
244
|
items = fs.readdirSync(dirPath)
|
|
242
245
|
} catch {
|
|
243
|
-
|
|
246
|
+
this.ensureDir(dirPath)
|
|
247
|
+
return
|
|
244
248
|
}
|
|
245
249
|
|
|
246
250
|
items.forEach(item => this.removePath(path.join(dirPath, item)))
|
|
247
251
|
}
|
|
248
252
|
|
|
249
253
|
async emptyDirAsync(dirPath: string): Promise<void> {
|
|
250
|
-
let items
|
|
254
|
+
let items: string[]
|
|
251
255
|
try {
|
|
252
256
|
items = await fsp.readdir(dirPath)
|
|
253
257
|
} catch {
|
package/src/index.ts
CHANGED
|
@@ -72,8 +72,8 @@ export * from './stream/writable/writableVoid'
|
|
|
72
72
|
export * from './string/inspect'
|
|
73
73
|
export * from './util/buildInfo.util'
|
|
74
74
|
export * from './util/env.util'
|
|
75
|
-
export * from './util/
|
|
76
|
-
export * from './util/
|
|
75
|
+
export * from './util/exec2'
|
|
76
|
+
export * from './util/git2'
|
|
77
77
|
export * from './util/lruMemoCache'
|
|
78
78
|
export * from './util/zip.util'
|
|
79
79
|
export * from './validation/ajv/ajv.util'
|
|
@@ -37,7 +37,7 @@ export function secretsDecrypt(
|
|
|
37
37
|
const filenames = fastGlob.sync(patterns)
|
|
38
38
|
|
|
39
39
|
filenames.forEach(filename => {
|
|
40
|
-
let plainFilename
|
|
40
|
+
let plainFilename: string
|
|
41
41
|
|
|
42
42
|
if (jsonMode) {
|
|
43
43
|
_assert(filename.endsWith('.json'), `${path.basename(filename)} MUST end with '.json'`)
|
|
@@ -92,7 +92,7 @@ export class SlackService<CTX = any> {
|
|
|
92
92
|
if (msg.kv) {
|
|
93
93
|
;(msg.attachments ||= []).push({ fields: this.kvToFields(msg.kv) })
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
msg.kv = undefined // to not pass it all the way to Slack Api
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
let text: string
|
|
@@ -135,9 +135,8 @@ export class SlackService<CTX = any> {
|
|
|
135
135
|
// ignore (unless throwOnError is set)
|
|
136
136
|
if (msg.throwOnError) {
|
|
137
137
|
throw err
|
|
138
|
-
} else {
|
|
139
|
-
console.log(err)
|
|
140
138
|
}
|
|
139
|
+
console.log(err)
|
|
141
140
|
})
|
|
142
141
|
}
|
|
143
142
|
|
|
@@ -55,7 +55,7 @@ export function transformJsonParse<ROW = any>(
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
// Based on: https://stackoverflow.com/a/34557997/4919972
|
|
58
|
-
export const bufferReviver: Reviver = (
|
|
58
|
+
export const bufferReviver: Reviver = (_k, v) => {
|
|
59
59
|
if (v !== null && typeof v === 'object' && v.type === 'Buffer' && Array.isArray(v.data)) {
|
|
60
60
|
return Buffer.from(v.data)
|
|
61
61
|
}
|
|
@@ -45,7 +45,7 @@ export interface ReadableTyped<T> extends Readable {
|
|
|
45
45
|
drop: (limit: number, opt?: ReadableSignalOptions) => ReadableTyped<T>
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
//
|
|
48
|
+
// biome-ignore lint/correctness/noUnusedVariables: ok
|
|
49
49
|
export interface WritableTyped<T> extends Writable {}
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -59,7 +59,7 @@ export type ReadableBinary = Readable
|
|
|
59
59
|
*/
|
|
60
60
|
export type WritableBinary = Writable
|
|
61
61
|
|
|
62
|
-
//
|
|
62
|
+
// biome-ignore lint/correctness/noUnusedVariables: ok
|
|
63
63
|
export interface TransformTyped<IN, OUT> extends Transform {}
|
|
64
64
|
|
|
65
65
|
export interface TransformOptions {
|
|
@@ -40,10 +40,12 @@ export interface TransformMapOptions<IN = any, OUT = IN> {
|
|
|
40
40
|
/**
|
|
41
41
|
* Number of concurrently pending promises returned by `mapper`.
|
|
42
42
|
*
|
|
43
|
-
* Default is
|
|
43
|
+
* Default is 16.
|
|
44
44
|
* It was recently changed up from 16, after some testing that shown that
|
|
45
45
|
* for simple low-cpu mapper functions 32 produces almost 2x throughput.
|
|
46
46
|
* For example, in scenarios like streaming a query from Datastore.
|
|
47
|
+
* UPD: changed back from 32 to 16, "to be on a safe side", as 32 sometimes
|
|
48
|
+
* causes "Datastore timeout errors".
|
|
47
49
|
*/
|
|
48
50
|
concurrency?: number
|
|
49
51
|
|
|
@@ -120,7 +122,7 @@ export interface TransformMapStatsSummary extends TransformMapStats {
|
|
|
120
122
|
*
|
|
121
123
|
* Only works in objectMode (due to through2Concurrent).
|
|
122
124
|
*
|
|
123
|
-
* Concurrency defaults to
|
|
125
|
+
* Concurrency defaults to 16.
|
|
124
126
|
*
|
|
125
127
|
* If an Array is returned by `mapper` - it will be flattened and multiple results will be emitted from it. Tested by Array.isArray().
|
|
126
128
|
*/
|
|
@@ -129,7 +131,7 @@ export function transformMap<IN = any, OUT = IN>(
|
|
|
129
131
|
opt: TransformMapOptions<IN, OUT> = {},
|
|
130
132
|
): TransformTyped<IN, OUT> {
|
|
131
133
|
const {
|
|
132
|
-
concurrency =
|
|
134
|
+
concurrency = 16,
|
|
133
135
|
predicate, // we now default to "no predicate" (meaning pass-everything)
|
|
134
136
|
errorMode = ErrorMode.THROW_IMMEDIATELY,
|
|
135
137
|
flattenArrayOutput,
|
|
@@ -18,7 +18,7 @@ export function transformSplitOnNewline(): TransformTyped<Buffer, Buffer> {
|
|
|
18
18
|
readableObjectMode: true,
|
|
19
19
|
writableHighWaterMark: 64 * 1024,
|
|
20
20
|
|
|
21
|
-
transform(buf: Buffer,
|
|
21
|
+
transform(buf: Buffer, _enc, done) {
|
|
22
22
|
let offset = 0
|
|
23
23
|
let lastMatch = 0
|
|
24
24
|
if (buffered) {
|
|
@@ -66,7 +66,7 @@ export function transformSplit(separator = '\n'): TransformTyped<Buffer, Buffer>
|
|
|
66
66
|
readableObjectMode: true,
|
|
67
67
|
writableHighWaterMark: 64 * 1024,
|
|
68
68
|
|
|
69
|
-
transform(buf: Buffer,
|
|
69
|
+
transform(buf: Buffer, _enc, done) {
|
|
70
70
|
let offset = 0
|
|
71
71
|
let lastMatch = 0
|
|
72
72
|
if (buffered) {
|
|
@@ -119,7 +119,7 @@ function firstNewlineMatch(buf: Buffer, offset: number): number {
|
|
|
119
119
|
|
|
120
120
|
function firstMatch(buf: Buffer, offset: number, matcher: Buffer): number {
|
|
121
121
|
if (offset >= buf.length) return -1
|
|
122
|
-
let i
|
|
122
|
+
let i: number
|
|
123
123
|
for (i = offset; i < buf.length; i++) {
|
|
124
124
|
if (buf[i] === matcher[0]) {
|
|
125
125
|
if (matcher.length > 1) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const started = Date.now()
|
|
2
|
-
const { workerData, parentPort } = require('worker_threads')
|
|
3
|
-
const { inspect } = require('util')
|
|
2
|
+
const { workerData, parentPort } = require('node:worker_threads')
|
|
3
|
+
const { inspect } = require('node:util')
|
|
4
4
|
const { workerFile, workerIndex, logEvery = 1000, metric = 'worker' } = workerData || {}
|
|
5
5
|
|
|
6
6
|
if (!workerFile) {
|
|
@@ -6,12 +6,7 @@ import {
|
|
|
6
6
|
UnixTimestampNumber,
|
|
7
7
|
} from '@naturalcycles/js-lib'
|
|
8
8
|
import { fs2 } from '../fs/fs2'
|
|
9
|
-
import {
|
|
10
|
-
gitCurrentBranchName,
|
|
11
|
-
gitCurrentCommitSha,
|
|
12
|
-
gitCurrentCommitTimestamp,
|
|
13
|
-
gitCurrentRepoName,
|
|
14
|
-
} from './git.util'
|
|
9
|
+
import { git2 } from './git2'
|
|
15
10
|
|
|
16
11
|
export interface GenerateBuildInfoOptions {
|
|
17
12
|
/**
|
|
@@ -24,10 +19,10 @@ export function generateBuildInfo(opt: GenerateBuildInfoOptions = {}): BuildInfo
|
|
|
24
19
|
const now = localTime.orNow(opt.overrideTimestamp)
|
|
25
20
|
const ts = now.unix
|
|
26
21
|
|
|
27
|
-
const rev = gitCurrentCommitSha()
|
|
28
|
-
const branchName = gitCurrentBranchName()
|
|
29
|
-
const repoName = gitCurrentRepoName()
|
|
30
|
-
const tsCommit = gitCurrentCommitTimestamp()
|
|
22
|
+
const rev = git2.gitCurrentCommitSha()
|
|
23
|
+
const branchName = git2.gitCurrentBranchName()
|
|
24
|
+
const repoName = git2.gitCurrentRepoName()
|
|
25
|
+
const tsCommit = git2.gitCurrentCommitTimestamp()
|
|
31
26
|
|
|
32
27
|
const ver = [now.toStringCompact(), repoName, branchName, rev].join('_')
|
|
33
28
|
|