@karmaniverous/jsonmap 0.0.6 → 0.1.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/README.md CHANGED
@@ -46,6 +46,9 @@ const map = {
46
46
  bar: [
47
47
  {
48
48
  static: 'another static value',
49
+ // Keys starting with $ are available for progressive transformations but
50
+ // are not passed to the output object.
51
+ $remove: 'this should be removed from the output',
49
52
  // Value defined by a mapping rule expressing an array of transformation
50
53
  // objects. If there is only a single transformation object, no array is
51
54
  // necessary. The output of the last transformation step is returned as
@@ -87,6 +90,7 @@ const map = {
87
90
  params: '$.output.bar[0].static',
88
91
  },
89
92
  },
93
+ $remove: 'this should be removed from the output',
90
94
  };
91
95
  ```
92
96
 
@@ -103,8 +107,8 @@ Once a `JsonMap` instance is configured, it can be executed against any input. C
103
107
  ```js
104
108
  import { JsonMap } from '@karmaniverous/jsonmap';
105
109
 
106
- // Assumes lib & map are already defined as above.
107
- const jsonMap = new JsonMap(lib, map);
110
+ // Assumes map & lib are already defined as above.
111
+ const jsonMap = new JsonMap(map, lib);
108
112
 
109
113
  // Assumes some input data object is already defined.
110
114
  const output = await jsonMap.transform(input);
@@ -122,19 +126,19 @@ JsonMap class to apply transformations to a JSON object
122
126
  **Kind**: global class
123
127
 
124
128
  * [JsonMap](#JsonMap)
125
- * [new JsonMap(lib, map)](#new_JsonMap_new)
129
+ * [new JsonMap([map], [lib])](#new_JsonMap_new)
126
130
  * [.transform(input)](#JsonMap+transform) ⇒ <code>object</code>
127
131
 
128
132
  <a name="new_JsonMap_new"></a>
129
133
 
130
- ### new JsonMap(lib, map)
134
+ ### new JsonMap([map], [lib])
131
135
  Creates an instance of JsonMap.
132
136
 
133
137
 
134
138
  | Param | Type | Description |
135
139
  | --- | --- | --- |
136
- | lib | <code>object</code> | A collection of function libraries. |
137
- | map | <code>object</code> | The data mapping configuration. |
140
+ | [map] | <code>object</code> | The data mapping configuration. |
141
+ | [lib] | <code>object</code> | A collection of function libraries. |
138
142
 
139
143
  <a name="JsonMap+transform"></a>
140
144
 
@@ -5,20 +5,19 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.JsonMap = void 0;
7
7
  var _lodash = _interopRequireDefault(require("lodash.castarray"));
8
- var _lodash2 = _interopRequireDefault(require("lodash.get"));
9
- var _lodash3 = _interopRequireDefault(require("lodash.isnil"));
8
+ var _lodash2 = _interopRequireDefault(require("lodash.clonedeepwith"));
9
+ var _lodash3 = _interopRequireDefault(require("lodash.get"));
10
10
  var _lodash4 = _interopRequireDefault(require("lodash.isarray"));
11
11
  var _lodash5 = _interopRequireDefault(require("lodash.isobject"));
12
- var _lodash6 = _interopRequireDefault(require("lodash.isstring"));
13
- var _lodash7 = _interopRequireDefault(require("lodash.last"));
14
- var _lodash8 = _interopRequireDefault(require("lodash.parseint"));
15
- var _lodash9 = _interopRequireDefault(require("lodash.set"));
12
+ var _lodash6 = _interopRequireDefault(require("lodash.isplainobject"));
13
+ var _lodash7 = _interopRequireDefault(require("lodash.isstring"));
14
+ var _lodash8 = _interopRequireDefault(require("lodash.mapvalues"));
15
+ var _lodash9 = _interopRequireDefault(require("lodash.pickby"));
16
+ var _lodash10 = _interopRequireDefault(require("lodash.set"));
17
+ var _lodash11 = _interopRequireDefault(require("lodash.size"));
16
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
- function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
18
- function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
19
- function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
20
- var _transform = /*#__PURE__*/new WeakSet();
21
- var _resolvePath = /*#__PURE__*/new WeakSet();
19
+ // npm imports
20
+
22
21
  /**
23
22
  * JsonMap class to apply transformations to a JSON object
24
23
  */
@@ -26,21 +25,21 @@ class JsonMap {
26
25
  /**
27
26
  * Creates an instance of JsonMap.
28
27
  *
29
- * @param {object} lib - A collection of function libraries.
30
- * @param {object} map - The data mapping configuration.
28
+ * @param {object} [map] - The data mapping configuration.
29
+ * @param {object} [lib] - A collection of function libraries.
31
30
  */
32
- constructor(lib, map) {
33
- _classPrivateMethodInitSpec(this, _resolvePath);
34
- _classPrivateMethodInitSpec(this, _transform);
35
- this.lib = lib;
31
+ constructor() {
32
+ let map = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
33
+ let lib = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
36
34
  this.map = map;
35
+ this.lib = lib;
37
36
  }
38
37
 
39
38
  /**
40
39
  * Transforms the input data according to the map configuration.
41
40
  *
42
41
  * @param {object} input - The input data to be transformed.
43
- * @returns {object} - The transformed data.
42
+ * @return {object} - The transformed data.
44
43
  */
45
44
  async transform(input) {
46
45
  // Sets the input data and initializes an empty output object
@@ -48,7 +47,11 @@ class JsonMap {
48
47
  this.output = {};
49
48
 
50
49
  // Calls the #transform method to perform the transformation
51
- return await _classPrivateMethodGet(this, _transform, _transform2).call(this, this.map, this.input, this.output);
50
+ const result = await this.#transform(this.map, this.input, this.output);
51
+
52
+ // Recursively eliminate keys starting with $.
53
+ const deep = value => (0, _lodash6.default)(value) ? (0, _lodash8.default)((0, _lodash9.default)(value, (v, k) => /^[^$]/.test(k)), value => (0, _lodash2.default)(value, deep)) : undefined;
54
+ return (0, _lodash2.default)(result, deep);
52
55
  }
53
56
 
54
57
  /**
@@ -58,105 +61,105 @@ class JsonMap {
58
61
  * @param {object} input - The current input node.
59
62
  * @param {object} output - The current output node.
60
63
  * @param {string} path - The path to the current node.
61
- * @returns {object} - The transformed node.
64
+ * @return {object} - The transformed node.
62
65
  * @private
63
66
  */
64
- }
65
-
66
- // Exports the JsonMap class as the default export of this module
67
- exports.JsonMap = JsonMap;
68
- async function _transform2(node, input, output) {
69
- let path = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
70
- // Checks if the current node is an object and has a '$' key
71
- if ((0, _lodash5.default)(node) && '$' in node) {
72
- // Retrieves the transformations to be applied (can be an array or a single object)
73
- const transformations = (0, _lodash4.default)(node['$']) ? node['$'] : [node['$']];
74
-
75
- // Array to store the results of the transformations
76
- let results = [];
77
-
78
- // Iterates over each transformation
79
- for (const transformation of transformations) {
80
- // Resolves the object path for the transformation
81
- const object = _classPrivateMethodGet(this, _resolvePath, _resolvePath2).call(this, transformation.object, results);
82
-
83
- // Resolves the parameter paths for the transformation
84
- const params = await Promise.all((0, _lodash.default)(transformation.params).map(param => _classPrivateMethodGet(this, _resolvePath, _resolvePath2).call(this, param, results)));
85
-
86
- // Calls the specified method on the resolved object with the resolved parameters
87
- const result = await object[transformation.method](...params);
88
-
89
- // Stores the result of the transformation
90
- results.push(result);
67
+ async #transform(node, input, output) {
68
+ let path = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
69
+ // Checks if the current node is an object and has a '$' key
70
+ if ((0, _lodash6.default)(node) && (0, _lodash11.default)(node) === 1 && '$' in node) {
71
+ // Retrieves the transformations to be applied (can be an array or a single object)
72
+ const transformations = (0, _lodash.default)(node['$']);
73
+
74
+ // Array to store the results of the transformations
75
+ let results = [];
76
+
77
+ // Iterates over each transformation
78
+ for (const transformation of transformations) {
79
+ // Resolves the object path for the transformation
80
+ const object = this.#resolvePath(transformation.object, results);
81
+
82
+ // Resolves the parameter paths for the transformation
83
+ const params = await Promise.all((0, _lodash.default)(transformation.params).map(param => this.#resolvePath(param, results)));
84
+
85
+ // Calls the specified method on the resolved object with the resolved parameters
86
+ const result = await object[transformation.method](...params);
87
+
88
+ // Stores the result of the transformation
89
+ results.unshift(result);
90
+ }
91
+
92
+ // Sets the output at the specified path to the last result of the transformations & returns.
93
+ (0, _lodash10.default)(output, path, results[0]);
94
+ return results[0];
91
95
  }
92
96
 
93
- // Sets the output at the specified path to the last result of the transformations & returns.
94
- const lastResult = (0, _lodash7.default)(results);
95
- (0, _lodash9.default)(output, path, lastResult);
96
- return lastResult;
97
- }
97
+ // Checks if the current node is an object
98
+ if ((0, _lodash5.default)(node)) {
99
+ // Creates an empty array or object based on whether the current node is an array or not
100
+ const transformedNode = (0, _lodash4.default)(node) ? [] : {};
98
101
 
99
- // Checks if the current node is an object
100
- if ((0, _lodash5.default)(node)) {
101
- // Creates an empty array or object based on whether the current node is an array or not
102
- const transformedNode = (0, _lodash4.default)(node) ? [] : {};
102
+ // Iterates over each key-value pair in the current node
103
+ for (const [key, value] of Object.entries(node)) {
104
+ // Constructs the current path by appending the current key to the previous path (if any)
105
+ const currentPath = path ? `${path}.${key}` : key;
103
106
 
104
- // Iterates over each key-value pair in the current node
105
- for (const [key, value] of Object.entries(node)) {
106
- // Constructs the current path by appending the current key to the previous path (if any)
107
- const currentPath = path ? `${path}.${key}` : key;
107
+ // Recursively calls #transform with the current value, input, output, and path
108
+ // Assigns the transformed value to the corresponding key in the transformedNode
109
+ transformedNode[key] = await this.#transform(value, input, output, currentPath);
110
+ }
108
111
 
109
- // Recursively calls #transform with the current value, input, output, and path
110
- // Assigns the transformed value to the corresponding key in the transformedNode
111
- transformedNode[key] = await _classPrivateMethodGet(this, _transform, _transform2).call(this, value, input, output, currentPath);
112
+ // Sets the output at the specified path to the transformedNode & returnsd.
113
+ (0, _lodash10.default)(output, path, transformedNode);
114
+ return transformedNode;
112
115
  }
113
116
 
114
- // Sets the output at the specified path to the transformedNode & returnsd.
115
- (0, _lodash9.default)(output, path, transformedNode);
116
- return transformedNode;
117
- }
118
-
119
- // Sets the output at the specified path to the current node & returns.
120
- (0, _lodash9.default)(output, path, node);
121
- return node;
122
- }
123
- function _resolvePath2(path, results) {
124
- // If the path is not a string, return it as is
125
- if (!(0, _lodash6.default)(path)) {
126
- return path;
127
- }
128
-
129
- // Defines special patterns and their corresponding values for resolution
130
- const specialPatterns = {
131
- '$.lib': this.lib,
132
- '$.input': this.input,
133
- '$.output': this.output
134
- };
135
-
136
- // Checks if the path matches the pattern for accessing previous results
137
- const match = path.match(/^\$\[(\d+)\](.*)$/);
138
-
139
- // Retrieves the value from the previous results based on the index and any remaining path
140
- if (match) {
141
- const [, index, rest] = match;
142
- const value = (0, _lodash2.default)(results, [results.length - 1 - (0, _lodash8.default)(index), ...(rest.length ? rest.split('.') : [])]);
143
-
144
- // Returns the value if it exists, otherwise returns the original path
145
- return value != null ? value : path;
117
+ // Sets the output at the specified path to the current node & returns.
118
+ (0, _lodash10.default)(output, path, node);
119
+ return node;
146
120
  }
147
121
 
148
- // Iterates over the special patterns
149
- for (const [pattern, replacement] of Object.entries(specialPatterns)) if (path.startsWith(pattern)) {
150
- // Removes the pattern from the beginning of the path
151
- const p = path.slice(pattern.length + 1);
122
+ /**
123
+ * Resolves the object/method/params path for a transformation
124
+ *
125
+ * @param {string} path - The path to be resolved.
126
+ * @param {Array} results - The results from previous transformations.
127
+ * @return {string} - The resolved path.
128
+ * @private
129
+ */
130
+ #resolvePath(path, results) {
131
+ // If the path is not a string, return it as is
132
+ if (!(0, _lodash7.default)(path)) {
133
+ return path;
134
+ }
152
135
 
153
- // Retrieves the value from the replacement object based on the remaining path
154
- const value = p.length ? (0, _lodash2.default)(replacement, p) : replacement;
136
+ // Defines special patterns and their corresponding resolution functions
137
+ const patterns = {
138
+ '^\\$\\.(?<obj>lib|input|output)\\.?(?<path>.*)': _ref => {
139
+ let {
140
+ obj,
141
+ path
142
+ } = _ref;
143
+ return path.length ? (0, _lodash3.default)(this[obj], path) : this[obj];
144
+ },
145
+ '^\\$(?<path>\\[\\d+\\].*)': _ref2 => {
146
+ let {
147
+ path
148
+ } = _ref2;
149
+ return (0, _lodash3.default)(results, path);
150
+ }
151
+ };
152
+
153
+ // Iterates over the special patterns
154
+ for (const [pattern, resolve] of Object.entries(patterns)) {
155
+ const match = path.match(pattern);
156
+ if (match) return resolve(match.groups);
157
+ }
155
158
 
156
- // Returns the value if it exists, otherwise returns the original path
157
- return (0, _lodash3.default)(value) ? path : value;
159
+ // Returns the path as is if it does not match any special patterns
160
+ return path;
158
161
  }
162
+ }
159
163
 
160
- // Returns the path as is if it does not match any special patterns
161
- return path;
162
- }
164
+ // Exports the JsonMap class as the default export of this module
165
+ exports.JsonMap = JsonMap;
@@ -1,13 +1,15 @@
1
1
  // npm imports
2
2
  import castArray from 'lodash.castarray';
3
+ import cloneDeepWith from 'lodash.clonedeepwith';
3
4
  import get from 'lodash.get';
4
- import isNil from 'lodash.isnil';
5
5
  import isArray from 'lodash.isarray';
6
6
  import isObject from 'lodash.isobject';
7
+ import isPlainObject from 'lodash.isplainobject';
7
8
  import isString from 'lodash.isstring';
8
- import last from 'lodash.last';
9
- import parseInt from 'lodash.parseint';
9
+ import mapValues from 'lodash.mapvalues';
10
+ import pickBy from 'lodash.pickby';
10
11
  import set from 'lodash.set';
12
+ import size from 'lodash.size';
11
13
 
12
14
  /**
13
15
  * JsonMap class to apply transformations to a JSON object
@@ -16,19 +18,19 @@ class JsonMap {
16
18
  /**
17
19
  * Creates an instance of JsonMap.
18
20
  *
19
- * @param {object} lib - A collection of function libraries.
20
- * @param {object} map - The data mapping configuration.
21
+ * @param {object} [map] - The data mapping configuration.
22
+ * @param {object} [lib] - A collection of function libraries.
21
23
  */
22
- constructor(lib, map) {
23
- this.lib = lib;
24
+ constructor(map = {}, lib = {}) {
24
25
  this.map = map;
26
+ this.lib = lib;
25
27
  }
26
28
 
27
29
  /**
28
30
  * Transforms the input data according to the map configuration.
29
31
  *
30
32
  * @param {object} input - The input data to be transformed.
31
- * @returns {object} - The transformed data.
33
+ * @return {object} - The transformed data.
32
34
  */
33
35
  async transform(input) {
34
36
  // Sets the input data and initializes an empty output object
@@ -36,7 +38,18 @@ class JsonMap {
36
38
  this.output = {};
37
39
 
38
40
  // Calls the #transform method to perform the transformation
39
- return await this.#transform(this.map, this.input, this.output);
41
+ const result = await this.#transform(this.map, this.input, this.output);
42
+
43
+ // Recursively eliminate keys starting with $.
44
+ const deep = (value) =>
45
+ isPlainObject(value)
46
+ ? mapValues(
47
+ pickBy(value, (v, k) => /^[^$]/.test(k)),
48
+ (value) => cloneDeepWith(value, deep)
49
+ )
50
+ : undefined;
51
+
52
+ return cloneDeepWith(result, deep);
40
53
  }
41
54
 
42
55
  /**
@@ -46,14 +59,14 @@ class JsonMap {
46
59
  * @param {object} input - The current input node.
47
60
  * @param {object} output - The current output node.
48
61
  * @param {string} path - The path to the current node.
49
- * @returns {object} - The transformed node.
62
+ * @return {object} - The transformed node.
50
63
  * @private
51
64
  */
52
65
  async #transform(node, input, output, path = '') {
53
66
  // Checks if the current node is an object and has a '$' key
54
- if (isObject(node) && '$' in node) {
67
+ if (isPlainObject(node) && size(node) === 1 && '$' in node) {
55
68
  // Retrieves the transformations to be applied (can be an array or a single object)
56
- const transformations = isArray(node['$']) ? node['$'] : [node['$']];
69
+ const transformations = castArray(node['$']);
57
70
 
58
71
  // Array to store the results of the transformations
59
72
  let results = [];
@@ -74,13 +87,12 @@ class JsonMap {
74
87
  const result = await object[transformation.method](...params);
75
88
 
76
89
  // Stores the result of the transformation
77
- results.push(result);
90
+ results.unshift(result);
78
91
  }
79
92
 
80
93
  // Sets the output at the specified path to the last result of the transformations & returns.
81
- const lastResult = last(results);
82
- set(output, path, lastResult);
83
- return lastResult;
94
+ set(output, path, results[0]);
95
+ return results[0];
84
96
  }
85
97
 
86
98
  // Checks if the current node is an object
@@ -127,40 +139,18 @@ class JsonMap {
127
139
  return path;
128
140
  }
129
141
 
130
- // Defines special patterns and their corresponding values for resolution
131
- const specialPatterns = {
132
- '$.lib': this.lib,
133
- '$.input': this.input,
134
- '$.output': this.output,
142
+ // Defines special patterns and their corresponding resolution functions
143
+ const patterns = {
144
+ '^\\$\\.(?<obj>lib|input|output)\\.?(?<path>.*)': ({ obj, path }) =>
145
+ path.length ? get(this[obj], path) : this[obj],
146
+ '^\\$(?<path>\\[\\d+\\].*)': ({ path }) => get(results, path),
135
147
  };
136
148
 
137
- // Checks if the path matches the pattern for accessing previous results
138
- const match = path.match(/^\$\[(\d+)\](.*)$/);
139
-
140
- // Retrieves the value from the previous results based on the index and any remaining path
141
- if (match) {
142
- const [, index, rest] = match;
143
- const value = get(results, [
144
- results.length - 1 - parseInt(index),
145
- ...(rest.length ? rest.split('.') : []),
146
- ]);
147
-
148
- // Returns the value if it exists, otherwise returns the original path
149
- return value != null ? value : path;
150
- }
151
-
152
149
  // Iterates over the special patterns
153
- for (const [pattern, replacement] of Object.entries(specialPatterns))
154
- if (path.startsWith(pattern)) {
155
- // Removes the pattern from the beginning of the path
156
- const p = path.slice(pattern.length + 1);
157
-
158
- // Retrieves the value from the replacement object based on the remaining path
159
- const value = p.length ? get(replacement, p) : replacement;
160
-
161
- // Returns the value if it exists, otherwise returns the original path
162
- return isNil(value) ? path : value;
163
- }
150
+ for (const [pattern, resolve] of Object.entries(patterns)) {
151
+ const match = path.match(pattern);
152
+ if (match) return resolve(match.groups);
153
+ }
164
154
 
165
155
  // Returns the path as is if it does not match any special patterns
166
156
  return path;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karmaniverous/jsonmap",
3
- "version": "0.0.6",
3
+ "version": "0.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,36 +23,38 @@
23
23
  "license": "BSD-3-Clause",
24
24
  "dependencies": {
25
25
  "lodash.castarray": "^4.4.0",
26
+ "lodash.clonedeepwith": "^4.5.0",
26
27
  "lodash.get": "^4.4.2",
27
28
  "lodash.isarray": "^4.0.0",
28
- "lodash.isnil": "^4.0.0",
29
29
  "lodash.isobject": "^3.0.2",
30
+ "lodash.isplainobject": "^4.0.6",
30
31
  "lodash.isstring": "^4.0.1",
31
- "lodash.last": "^3.0.0",
32
- "lodash.parseint": "^4.0.2",
33
- "lodash.set": "^4.3.2"
32
+ "lodash.mapvalues": "^4.6.0",
33
+ "lodash.pickby": "^4.6.0",
34
+ "lodash.set": "^4.3.2",
35
+ "lodash.size": "^4.2.0"
34
36
  },
35
37
  "devDependencies": {
36
- "@babel/cli": "^7.21.0",
37
- "@babel/core": "^7.21.3",
38
- "@babel/eslint-parser": "^7.21.3",
38
+ "@babel/cli": "^7.21.5",
39
+ "@babel/core": "^7.22.1",
40
+ "@babel/eslint-parser": "^7.21.8",
39
41
  "@babel/plugin-syntax-import-assertions": "^7.20.0",
40
- "@babel/preset-env": "^7.20.2",
42
+ "@babel/preset-env": "^7.22.4",
41
43
  "@babel/register": "^7.21.0",
42
- "@karmaniverous/get-dotenv": "^1.0.0",
43
- "@types/node": "^18.15.5",
44
+ "@karmaniverous/get-dotenv": "^2.4.1",
45
+ "@types/node": "^20.2.5",
44
46
  "chai": "^4.3.7",
45
47
  "concat-md": "^0.5.1",
46
- "eslint": "^8.36.0",
47
- "eslint-config-standard": "^17.0.0",
48
- "eslint-plugin-jsdoc": "^40.1.0",
48
+ "eslint": "^8.41.0",
49
+ "eslint-config-standard": "^17.1.0",
50
+ "eslint-plugin-jsdoc": "^46.1.0",
49
51
  "eslint-plugin-mocha": "^10.1.0",
50
52
  "jsdoc-to-markdown": "^8.0.0",
51
53
  "lodash": "^4.17.21",
52
54
  "mocha": "^10.2.0",
53
55
  "numeral": "^2.0.6",
54
- "prettier": "^2.8.5",
55
- "release-it": "^15.9.0"
56
+ "prettier": "^2.8.8",
57
+ "release-it": "^15.10.3"
56
58
  },
57
59
  "exports": {
58
60
  ".": {
@@ -84,8 +86,8 @@
84
86
  "build": "babel lib -d dist/default/lib --delete-dir-on-start --config-file ./dist/default/.babelrc",
85
87
  "doc": "jsdoc2md -c doc/jsdoc.config.json -f lib/**/*.* -t doc/api-template.hbs > doc/2-api.jsdoc2.md && concat-md doc --hide-anchor-links > README.md",
86
88
  "lint": "eslint lib/**",
87
- "package": "npm run lint && npm run test && npm run build && npm run doc",
88
- "release": "npm run package && getdotenv -- release-it",
89
+ "prerelease": "npm run lint && npm run test && npm run build && npm run doc",
90
+ "release": "release-it",
89
91
  "test": "getdotenv -c \"mocha\" -p ./ ./env -d dev -y ./env/dynamic.js"
90
92
  },
91
93
  "type": "module"