bajo-extra 0.2.16 → 0.3.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/bajo/config.json CHANGED
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "alias": "x",
3
+ "fetch": {
4
+ "agent": {}
5
+ },
3
6
  "stream": {
4
7
  "export": {
5
8
  "maxBatch": 1000,
@@ -0,0 +1,23 @@
1
+ // taken from: https://stackoverflow.com/a/41439945
2
+ import fs from 'fs'
3
+
4
+ function countFileLines (file) {
5
+ return new Promise((resolve, reject) => {
6
+ let lineCount = 0
7
+ fs.createReadStream(file)
8
+ .on('data', (buffer) => {
9
+ let idx = -1
10
+ lineCount--
11
+ do {
12
+ idx = buffer.indexOf(10, idx + 1)
13
+ lineCount++
14
+ } while (idx !== -1)
15
+ })
16
+ .on('end', () => {
17
+ resolve(lineCount)
18
+ })
19
+ .on('error', reject)
20
+ })
21
+ }
22
+
23
+ export default countFileLines
@@ -0,0 +1,45 @@
1
+ import path from 'path'
2
+
3
+ async function download (url, opts = {}) {
4
+ const { fs, getPluginDataDir, importPkg, error, generateId } = this.bajo.helper
5
+ const { fetch, formatByte, formatPercentage } = this.bajoExtra.helper
6
+ const { isFunction } = this.bajo.helper._
7
+ if (typeof opts === 'string') opts = { dir: opts }
8
+ const increment = await importPkg('add-filename-increment')
9
+ if (!opts.dir) {
10
+ opts.dir = `${getPluginDataDir('bajoExtra')}/download`
11
+ fs.ensureDirSync(opts.dir)
12
+ }
13
+ const fetchOpts = opts.fetchOpts ?? {}
14
+ if (!fs.existsSync(opts.dir)) throw error('Download dir \'%s\' doesn\'t exists', opts.dir)
15
+ if (opts.randomFileName) {
16
+ const ext = path.extname(url)
17
+ opts.fileName = `${generateId()}${ext}`
18
+ }
19
+ if (!opts.fileName) opts.fileName = path.basename(url)
20
+ const file = path.resolve(increment(`${opts.dir}/${opts.fileName}`, { fs: true }))
21
+ const writer = fs.createWriteStream(file)
22
+ fetchOpts.responseType = 'stream'
23
+ const { headers, data } = await fetch(url, fetchOpts, { rawResponse: true })
24
+ const total = headers['content-length'] ?? 0
25
+ let length = 0
26
+ data.on('data', chunk => {
27
+ length += chunk.length
28
+ if (isFunction(opts.progressFn)) opts.progressFn.call(this, length, total)
29
+ else if (opts.spin) {
30
+ opts.spinText = opts.spinText ?? 'Downloading...'
31
+ if (total === 0) opts.spin.setText(`${opts.spinText} %s`, formatByte(length))
32
+ else opts.spin.setText(`${opts.spinText} %s of %s (%s)`, formatByte(length), formatByte(total), formatPercentage(length / total))
33
+ }
34
+ })
35
+ data.pipe(writer)
36
+
37
+ return new Promise((resolve, reject) => {
38
+ writer.on('error', reject)
39
+ writer.on('finish', () => {
40
+ resolve(file)
41
+ })
42
+ })
43
+ }
44
+
45
+ export default download
@@ -9,8 +9,8 @@ const { DataStream } = scramjet
9
9
  const supportedExt = ['.json', '.jsonl', '.ndjson', '.csv', '.xlsx', '.tsv']
10
10
 
11
11
  async function getFile (dest, ensureDir) {
12
- const { importPkg, error, getPluginDataDir } = this.bajo.helper
13
- const [fs, increment] = await importPkg('fs-extra', 'add-filename-increment')
12
+ const { fs, importPkg, error, getPluginDataDir } = this.bajo.helper
13
+ const increment = await importPkg('add-filename-increment')
14
14
  let file
15
15
  if (path.isAbsolute(dest)) file = dest
16
16
  else {
@@ -51,7 +51,7 @@ async function getData ({ source, filter, count, stream, progressFn }) {
51
51
  }
52
52
 
53
53
  function exportTo (source, dest, { filter = {}, ensureDir, useHeader = true, batch = 500, progressFn } = {}, opts = {}) {
54
- const { error, importPkg, getConfig } = this.bajo.helper
54
+ const { fs, error, getConfig } = this.bajo.helper
55
55
  const cfg = getConfig('bajoExtra')
56
56
  if (!this.bajoDb) throw error('Bajo DB isn\'t loaded')
57
57
  filter.page = 1
@@ -59,27 +59,18 @@ function exportTo (source, dest, { filter = {}, ensureDir, useHeader = true, bat
59
59
  if (batch > cfg.stream.export.maxBatch) batch = cfg.stream.export.maxBatch
60
60
  if (batch < 0) batch = 1
61
61
  filter.limit = batch
62
+ const { merge } = this.bajo.helper._
62
63
 
63
64
  return new Promise((resolve, reject) => {
64
65
  const { getInfo } = this.bajoDb.helper
65
66
  let count = 0
66
- let fs
67
- let merge
68
67
  let file
69
68
  let ext
70
69
  let stream
71
70
  let compress
72
71
  let writer
73
72
  getInfo(source)
74
- .then(() => {
75
- return importPkg('lodash-es')
76
- })
77
- .then(l => {
78
- merge = l.merge
79
- return importPkg('fs-extra')
80
- })
81
73
  .then(res => {
82
- fs = res
83
74
  return getFile.call(this, dest, ensureDir)
84
75
  })
85
76
  .then(res => {
@@ -1,6 +1,5 @@
1
1
  async function handler (rec, bulk) {
2
- const { importPkg } = this.bajo.helper
3
- const { isFunction, set } = await importPkg('lodash-es')
2
+ const { isFunction, set } = this.bajo.helper._
4
3
  const { recordCreate, recordFind, recordUpdate } = this.bajoDb.helper
5
4
  const save = bulk.save ?? {}
6
5
  const current = save.current ?? {}
@@ -52,9 +51,9 @@ async function handler (rec, bulk) {
52
51
  }
53
52
 
54
53
  async function fetchAndSave ({ url, bulk, save = {}, opts = {} } = {}) {
55
- const { importPkg, getConfig, importModule } = this.bajo.helper
54
+ const { getConfig, importModule } = this.bajo.helper
56
55
  const { fetchBulk } = this.bajoExtra.helper
57
- const { merge } = await importPkg('lodash-es')
56
+ const { merge } = this.bajo.helper._
58
57
  merge(bulk, { handler, save })
59
58
  const cfgDb = getConfig('bajoDb', { full: true })
60
59
  const start = await importModule(`${cfgDb.dir.pkg}/bajo/start.js`)
@@ -1,6 +1,6 @@
1
1
  async function fetching ({ url, opts, bulk, spin }) {
2
- const { setImmediate, importPkg, print } = this.bajo.helper
3
- const { isEmpty, isFunction, has } = await importPkg('lodash-es')
2
+ const { setImmediate, print } = this.bajo.helper
3
+ const { isEmpty, isFunction, has } = this.bajo.helper._
4
4
  const { validationErrorMessage } = this.bajoDb.helper
5
5
  const { fetch } = this.bajoExtra.helper
6
6
  const resp = await fetch(url, opts ?? {})
@@ -49,8 +49,8 @@ async function fetching ({ url, opts, bulk, spin }) {
49
49
  }
50
50
 
51
51
  async function fetchBulk (url, bulk = {}, opts = {}) {
52
- const { print, spinner, importPkg, error } = this.bajo.helper
53
- const { isFunction } = await importPkg('lodash-es')
52
+ const { print, spinner, error } = this.bajo.helper
53
+ const { isFunction } = this.bajo.helper._
54
54
  opts.params = opts.params ?? {}
55
55
  bulk.maxStep = bulk.maxStep ?? 0
56
56
  if (!isFunction(bulk.handler)) throw error('A function handler must be provided')
@@ -1,8 +1,11 @@
1
1
  import axios from 'axios'
2
+ import http from 'http'
3
+ import https from 'https'
2
4
 
3
5
  async function fetch (url, opts = {}, ext = {}) {
4
- const { importPkg } = this.bajo.helper
5
- const { has, isPlainObject, cloneDeep } = await importPkg('lodash-es')
6
+ const { getConfig } = this.bajo.helper
7
+ const { has, isPlainObject, cloneDeep, isEmpty } = this.bajo.helper._
8
+ const cfg = getConfig('bajoExtra')
6
9
  if (isPlainObject(url)) {
7
10
  ext = cloneDeep(opts)
8
11
  opts = cloneDeep(url)
@@ -10,6 +13,10 @@ async function fetch (url, opts = {}, ext = {}) {
10
13
  opts.params = opts.params ?? {}
11
14
  if (!has(ext, 'cacheBuster')) ext.cacheBuster = true
12
15
  if (ext.cacheBuster) opts.params[ext.cacheBusterKey ?? '_'] = Date.now()
16
+ if (!isEmpty(cfg.fetch.agent)) {
17
+ opts.httpAgent = opts.httpAgent ?? new http.Agent(cfg.fetch.agent)
18
+ opts.httpsAgent = opts.httpsAgent ?? new https.Agent(cfg.fetch.agent)
19
+ }
13
20
  const resp = await axios(opts)
14
21
  if (ext.rawResponse) return resp
15
22
  return resp.data
@@ -0,0 +1,11 @@
1
+ import numbro from 'numbro'
2
+
3
+ function byte (value, opts = {}) {
4
+ opts.output = 'byte'
5
+ opts.base = 'binary'
6
+ opts.mantissa = opts.mantissa ?? opts.scale ?? 2
7
+ opts.spaceSeparated = opts.spaceSeparated ?? true
8
+ return numbro(value).format(opts)
9
+ }
10
+
11
+ export default byte
@@ -0,0 +1,9 @@
1
+ import numbro from 'numbro'
2
+
3
+ function float (value, opts = {}) {
4
+ opts.mantissa = opts.mantissa ?? opts.scale ?? 2
5
+ opts.thousandSeparated = opts.thousandSeparated ?? true
6
+ return numbro(value).format(opts)
7
+ }
8
+
9
+ export default float
@@ -0,0 +1,9 @@
1
+ import numbro from 'numbro'
2
+
3
+ function integer (value, opts = {}) {
4
+ opts.mantissa = 0
5
+ opts.thousandSeparated = opts.thousandSeparated ?? true
6
+ return numbro(value).format(opts)
7
+ }
8
+
9
+ export default integer
@@ -0,0 +1,10 @@
1
+ import numbro from 'numbro'
2
+
3
+ function percentage (value, opts = {}) {
4
+ opts.output = 'percent'
5
+ opts.mantissa = opts.mantissa ?? opts.scale ?? 2
6
+ opts.spaceSeparated = opts.spaceSeparated ?? true
7
+ return numbro(value).format(opts)
8
+ }
9
+
10
+ export default percentage
@@ -1,22 +1,19 @@
1
1
  import { createGzip, createGunzip } from 'zlib'
2
2
 
3
- function gzip (file, deleteOld, unzip) {
3
+ function gzip (file, deleteOld, expand) {
4
+ const { fs } = this.bajo.helper
4
5
  return new Promise((resolve, reject) => {
5
- const { importPkg } = this.bajo.helper
6
- importPkg('fs-extra')
7
- .then(fs => {
8
- const newFile = unzip ? file.slice(0, file.length - 3) : (file + '.gz')
9
- const reader = fs.createReadStream(file)
10
- const writer = fs.createWriteStream(newFile)
11
- const method = unzip ? createGunzip() : createGzip()
12
- reader.pipe(method).pipe(writer)
13
- writer.on('error', reject)
14
- writer.on('finish', err => {
15
- if (err) return reject(err)
16
- if (deleteOld) fs.unlinkSync(file)
17
- resolve()
18
- })
19
- })
6
+ const newFile = expand ? file.slice(0, file.length - 3) : (file + '.gz')
7
+ const reader = fs.createReadStream(file)
8
+ const writer = fs.createWriteStream(newFile)
9
+ const method = expand ? createGunzip() : createGzip()
10
+ reader.pipe(method).pipe(writer)
11
+ writer.on('error', reject)
12
+ writer.on('finish', err => {
13
+ if (err) return reject(err)
14
+ if (deleteOld) fs.unlinkSync(file)
15
+ resolve()
16
+ })
20
17
  })
21
18
  }
22
19
 
@@ -8,12 +8,12 @@ const { DataStream } = scramjet
8
8
  const supportedExt = ['.json', '.jsonl', '.ndjson', '.csv', '.xlsx', '.tsv']
9
9
 
10
10
  async function importFrom (source, dest, { trashOld = true, batch = 1, progressFn, converterFn, useHeader = true, fileType, createOpts = {} } = {}, opts = {}) {
11
- const { error, importPkg, getConfig, getPluginDataDir } = this.bajo.helper
12
- if (!this.bajoDb) throw error('Bajo DB isn\'t loaded')
13
- const { getInfo, recordClear, recordCreate } = this.bajoDb.helper
14
- await getInfo(dest)
15
- const { merge } = await importPkg('lodash-es')
16
- const fs = await importPkg('fs-extra')
11
+ const { fs, error, getConfig, getPluginDataDir } = this.bajo.helper
12
+ if (dest !== false) {
13
+ if (!this.bajoDb) throw error('Bajo DB isn\'t loaded')
14
+ await this.bajoDb.helper.getInfo(dest)
15
+ }
16
+ const { merge } = this.bajo.helper._
17
17
  const cfg = getConfig('bajoExtra')
18
18
 
19
19
  let file
@@ -30,7 +30,7 @@ async function importFrom (source, dest, { trashOld = true, batch = 1, progressF
30
30
  decompress = true
31
31
  }
32
32
  if (!supportedExt.includes(ext)) throw error('Unsupported format \'%s\'', ext.slice(1))
33
- if (trashOld) await recordClear(dest)
33
+ if (trashOld && dest !== false) await this.bajoDb.helper.recordClear(dest)
34
34
  const reader = fs.createReadStream(file)
35
35
  batch = parseInt(batch) || 100
36
36
  if (batch > cfg.stream.import.maxBatch) batch = cfg.stream.import.maxBatch
@@ -46,6 +46,7 @@ async function importFrom (source, dest, { trashOld = true, batch = 1, progressF
46
46
 
47
47
  const stream = DataStream.pipeline(...pipes)
48
48
  let batchNo = 1
49
+ const data = []
49
50
  await stream
50
51
  .batch(batch)
51
52
  .map(async items => {
@@ -54,14 +55,15 @@ async function importFrom (source, dest, { trashOld = true, batch = 1, progressF
54
55
  for (let item of items) {
55
56
  count++
56
57
  item = converterFn ? await converterFn.call(this, item) : item
57
- await recordCreate(dest, item, createOpts)
58
+ if (dest !== false) await this.bajoDb.helper.recordCreate(dest, item, createOpts)
59
+ else data.push(item)
58
60
  }
59
61
  if (progressFn) await progressFn.call(this, { batchNo, data: items, batchStart, batchEnd: new Date() })
60
62
  batchNo++
61
63
  })
62
64
  .run()
63
65
 
64
- return { file, count }
66
+ return dest === false ? data : { file, count }
65
67
  }
66
68
 
67
69
  export default importFrom
@@ -0,0 +1,17 @@
1
+ async function download ({ path, args }) {
2
+ const { spinner } = this.bajo.helper
3
+ const { download } = this.bajoExtra.helper
4
+ const url = args[0]
5
+ const spinText = 'Downloading file...'
6
+ const spin = spinner({ showCounter: true }).start(spinText)
7
+
8
+ let dest
9
+ try {
10
+ dest = await download(url, { spin, spinText })
11
+ } catch (err) {
12
+ spin.fatal('Error: %s', err.message)
13
+ }
14
+ spin.succeed('File saved as \'%s\'', dest)
15
+ }
16
+
17
+ export default download
@@ -12,8 +12,8 @@ function makeProgress (spin) {
12
12
 
13
13
  async function exportTo ({ path, args }) {
14
14
  const { importPkg, print, dayjs, getConfig, importModule, spinner } = this.bajo.helper
15
- const { isEmpty, map } = await importPkg('lodash-es')
16
- const [input, select] = await importPkg('bajo-cli:@inquirer/input',
15
+ const { isEmpty, map } = this.bajo.helper._
16
+ const [input, select] = await importPkg('bajoCli:@inquirer/input',
17
17
  'bajo-cli:@inquirer/select')
18
18
  const config = getConfig()
19
19
  if (!this.bajoDb) return print.fail('Bajo DB isn\'t loaded', { exit: config.tool })
@@ -11,9 +11,9 @@ function makeProgress (spin) {
11
11
 
12
12
  async function importFrom ({ path, args }) {
13
13
  const { importPkg, print, importModule, getConfig, spinner } = this.bajo.helper
14
- const { isEmpty, map } = await importPkg('lodash-es')
15
- const [input, select, confirm] = await importPkg('bajo-cli:@inquirer/input',
16
- 'bajo-cli:@inquirer/select', 'bajo-cli:@inquirer/confirm')
14
+ const { isEmpty, map } = this.bajo.helper._
15
+ const [input, select, confirm] = await importPkg('bajoCli:@inquirer/input',
16
+ 'bajoCli:@inquirer/select', 'bajoCli:@inquirer/confirm')
17
17
  const config = getConfig()
18
18
  if (!this.bajoDb) return print.fail('Bajo DB isn\'t loaded', { exit: config.tool })
19
19
  const schemas = map(this.bajoDb.schemas, 'name')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bajo-extra",
3
- "version": "0.2.16",
3
+ "version": "0.3.0",
4
4
  "description": "Extra package for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -35,6 +35,7 @@
35
35
  "fast-jwt": "^3.2.0",
36
36
  "fast-xml-parser": "^4.3.2",
37
37
  "ndjson": "^2.0.0",
38
+ "numbro": "^2.5.0",
38
39
  "performant-array-to-tree": "^1.11.0",
39
40
  "query-string": "^8.1.0",
40
41
  "scramjet": "^4.36.9",