@vbarbarosh/node-helpers 3.29.0 → 3.29.1

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Vladimir Barbarosh <vladimir.barbarosh@gmail.com>",
3
3
  "license": "MIT",
4
4
  "name": "@vbarbarosh/node-helpers",
5
- "version": "3.29.0",
5
+ "version": "3.29.1",
6
6
  "description": "A set of helpers for JavaScript/Node.js",
7
7
  "files": [
8
8
  "src"
@@ -0,0 +1,8 @@
1
+ // Since Node.js streams cannot emit `null` values (it's an eof mark),
2
+ // this is a workaround.
3
+
4
+ const const_stream = {
5
+ null: Symbol('stream[null]'),
6
+ };
7
+
8
+ module.exports = const_stream;
@@ -0,0 +1,22 @@
1
+ const const_type = require('./const_type');
2
+ const gettype = require('./gettype');
3
+ const json_stringify_stable = require('./json_stringify_stable');
4
+
5
+ function object_schema(obj)
6
+ {
7
+ const type = gettype(obj);
8
+ switch (type) {
9
+ case const_type.array:
10
+ return obj.map(object_schema).map(v => json_stringify_stable(v)).sort().filter((v,i,a) => a[i-1] !== v).map(v => JSON.parse(v));
11
+ case const_type.object:
12
+ const out = {};
13
+ Object.keys(obj).forEach(function (key) {
14
+ out[key] = object_schema(obj[key]);
15
+ });
16
+ return out;
17
+ default:
18
+ return type;
19
+ }
20
+ }
21
+
22
+ module.exports = object_schema;
@@ -0,0 +1,15 @@
1
+ const assert = require('assert');
2
+ const object_schema = require('./object_schema');
3
+
4
+ describe('object_schema', function () {
5
+ it('basic 1', function () {
6
+ const actual = object_schema({aaa: 1, bbb: 2});
7
+ const expected = {aaa: 'number', bbb: 'number'};
8
+ assert.deepStrictEqual(actual, expected);
9
+ });
10
+ it('basic 2', function () {
11
+ const actual = object_schema({aaa: 1, bbb: [1, 2, 3, 4, 'str']});
12
+ const expected = {aaa: 'number', bbb: ['number', 'string']};
13
+ assert.deepStrictEqual(actual, expected);
14
+ });
15
+ });
@@ -1,10 +1,11 @@
1
- const stream = require('stream');
1
+ const const_stream = require('./const_stream');
2
2
  const htmlparser2 = require('htmlparser2');
3
+ const stream = require('stream');
3
4
 
4
5
  /**
5
- * Parse XML stream and produce objects.
6
+ * Consume XML, produce objects.
6
7
  */
7
- function stream_parse_xml(selector, mapper = stream_parse_xml.makeobj)
8
+ function stream_parse_xml(selector, mapper = stream_parse_xml.guess)
8
9
  {
9
10
  let out;
10
11
  let elem = {name: '#doc', parent: null, attrs: {}, text: [], children: [], raw: []};
@@ -17,16 +18,15 @@ function stream_parse_xml(selector, mapper = stream_parse_xml.makeobj)
17
18
  const events = {
18
19
  onopentag: function (name, attrs) {
19
20
  elem = {name, parent: elem, attrs, text: [], children: [], raw: []};
20
- if (path.length > 1) {
21
- elem.parent.raw.push(elem);
22
- elem.parent.children.push(elem);
23
- }
21
+ elem.parent.raw.push(elem);
22
+ elem.parent.children.push(elem);
24
23
  path.push(elem.name);
25
24
  path_str = path.join('>');
26
25
  },
27
26
  onclosetag: function (name) {
28
27
  if (path_str === selector_str) {
29
- out.push(mapper(elem));
28
+ const tmp = mapper(elem);
29
+ out.push((tmp === null ? const_stream.null : tmp));
30
30
  }
31
31
  elem = elem.parent;
32
32
  path.pop();
@@ -38,7 +38,8 @@ function stream_parse_xml(selector, mapper = stream_parse_xml.makeobj)
38
38
  },
39
39
  onend: function () {
40
40
  if (selector_str === '') {
41
- out.push(mapper(elem));
41
+ const tmp = mapper(elem);
42
+ out.push((tmp === null ? const_stream.null : tmp));
42
43
  }
43
44
  },
44
45
  };
@@ -50,18 +51,71 @@ function stream_parse_xml(selector, mapper = stream_parse_xml.makeobj)
50
51
  parser.write(buf.toString());
51
52
  next();
52
53
  },
54
+ flush: function (next) {
55
+ parser.end();
56
+ next();
57
+ },
53
58
  });
54
59
  }
55
60
 
56
- stream_parse_xml.makeobj = function (node) {
57
- if (node.children.length === 0) {
58
- return node.text.join('').trim();
61
+ function guess(node)
62
+ {
63
+ const attrs = Object.keys(node.attrs);
64
+
65
+ if (attrs.length === 0) {
66
+ if (node.raw.length === 0) {
67
+ return null;
68
+ }
69
+ if (node.children.length === 0) {
70
+ return node.text.join('').trim();
71
+ }
72
+ if (node.children.length > 1) {
73
+ const tmp = node.children[0].name;
74
+ if (node.children.every(v => v.name === tmp)) {
75
+ return node.children.map(v => stream_parse_xml.guess);
76
+ }
77
+ }
78
+ }
79
+
80
+ const out = {...node.attrs};
81
+
82
+ if (node.text.length) {
83
+ const tmp = node.text.join('').trim();
84
+ if (tmp) {
85
+ out.value = tmp;
86
+ }
59
87
  }
60
- const out = {};
88
+
61
89
  node.children.forEach(function (child) {
62
- out[child.name] = stream_parse_xml.makeobj(child);
90
+ const tmp = stream_parse_xml.guess(child);
91
+ if (child.name in out) {
92
+ if (Array.isArray(out[child.name])) {
93
+ out[child.name].push(tmp);
94
+ }
95
+ else {
96
+ out[child.name] = [out[child.name], tmp];
97
+ }
98
+ }
99
+ else {
100
+ out[child.name] = tmp;
101
+ }
63
102
  });
103
+
64
104
  return out;
65
105
  }
66
106
 
107
+ function ashtml(node)
108
+ {
109
+ return node.raw.map(fn).filter(v => v).join('').trim();
110
+ function fn(item) {
111
+ if (typeof item === 'string') {
112
+ return item.replace(/\s+/g, ' ');
113
+ }
114
+ return `<${item.name}>${ashtml(item)}</${item.name}>` ;
115
+ }
116
+ }
117
+
118
+ stream_parse_xml.guess = guess;
119
+ stream_parse_xml.ashtml = ashtml;
120
+
67
121
  module.exports = stream_parse_xml;
@@ -7,7 +7,7 @@ const stream = require('stream');
7
7
  *
8
8
  * @similar https://www.npmjs.com/package/progress-stream
9
9
  */
10
- function stream_progress({total, user_friendly_status = s => console.log(s)})
10
+ function stream_progress({total, user_friendly_status = s => console.log(s)} = {})
11
11
  {
12
12
  let done = 0;
13
13
  const timer = setInterval(tick, 1000);