@briklab/malle 1.0.2 → 1.0.3
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/index.js +4 -3
- package/package.json +6 -6
- package/class/index.cjs +0 -3
- package/class/index.js +0 -8
- package/core/class.js +0 -294
- package/core/main.js +0 -46
- package/helpers/arrHelpers.js +0 -14
- package/helpers/consoleManager.js +0 -22
- package/helpers/isUndefined.js +0 -1
- package/helpers/loop.js +0 -1
- package/helpers/objHelpers.js +0 -8
- package/helpers/typeHelpers.js +0 -50
- package/index.cjs +0 -3
package/index.js
CHANGED
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
* @example
|
|
9
9
|
* import malle from "@briklab/malle";
|
|
10
10
|
* function calc(...args) {
|
|
11
|
-
* const {Number1, Number2, Mode} = malle.expect(
|
|
11
|
+
* const {Number1, Number2, Mode} = malle({mode:"strict"}).expect(
|
|
12
12
|
* {name:"Number1", type:"number"},
|
|
13
13
|
* {name:"Number2", type:"number"},
|
|
14
14
|
* {name:"Mode", type:"string"}
|
|
15
|
-
* );
|
|
15
|
+
* ).guess(args);
|
|
16
16
|
* return Mode === "add" ? Number1 + Number2 : Number1 - Number2;
|
|
17
17
|
* }
|
|
18
18
|
*/
|
|
19
|
-
export
|
|
19
|
+
export { default } from "./core/main.js";
|
|
20
|
+
export * from "./core/main.js";
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@briklab/malle",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A fast, flexible, developer-first argument parser for modern JavaScript and Node.js.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./index.js",
|
|
11
|
+
"./class": "./class/index.js"
|
|
12
|
+
},
|
|
9
13
|
"private": false,
|
|
10
14
|
"keywords": [],
|
|
11
15
|
"author": "EkaanshPC",
|
|
12
16
|
"license": "Apache 2.0",
|
|
13
17
|
"files": [
|
|
14
|
-
"
|
|
15
|
-
"core/**",
|
|
16
|
-
"helpers/**",
|
|
17
|
-
"index.js",
|
|
18
|
-
"index.cjs"
|
|
18
|
+
"index.js"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {}
|
|
21
21
|
}
|
package/class/index.cjs
DELETED
package/class/index.js
DELETED
package/core/class.js
DELETED
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
//-----------------------------------------------------------------------------------------------------------
|
|
2
|
-
//#region Helpers
|
|
3
|
-
import getArrFromSpread, { areAllTypes } from "../helpers/arrHelpers";
|
|
4
|
-
import { cM } from "../helpers/consoleManager";
|
|
5
|
-
import isUndefined from "../helpers/isUndefined";
|
|
6
|
-
import loop from "../helpers/loop";
|
|
7
|
-
import checkFormat from "../helpers/objHelpers";
|
|
8
|
-
import isType from "../helpers/typeHelpers";
|
|
9
|
-
|
|
10
|
-
const expector = {
|
|
11
|
-
checkSchemas(schemas, debug = false) {
|
|
12
|
-
const schemasArr = getArrFromSpread(schemas);
|
|
13
|
-
if (!schemasArr) {
|
|
14
|
-
new cM.error("Could not get array from spread in expector.", debug);
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (!areAllTypes(schemasArr, "object")) {
|
|
19
|
-
new cM.error("The schema array must consist of only objects.", debug);
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
for (const schema of schemasArr) {
|
|
24
|
-
if (
|
|
25
|
-
!checkFormat(
|
|
26
|
-
{ name: "string", type: "string", optional: "boolean", aliasNames: "array", spread: "boolean" },
|
|
27
|
-
schema,
|
|
28
|
-
)
|
|
29
|
-
) {
|
|
30
|
-
new cM.error(
|
|
31
|
-
"Invalid format in schema object. (expected {name, type, optional?, aliasNames?, spread?})",
|
|
32
|
-
debug,
|
|
33
|
-
);
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
schema.optional = !!schema.optional;
|
|
38
|
-
schema.spread = !!schema.spread;
|
|
39
|
-
|
|
40
|
-
if (!isUndefined(schema.aliasNames)) {
|
|
41
|
-
if (!Array.isArray(schema.aliasNames) || !areAllTypes(schema.aliasNames, "string")) {
|
|
42
|
-
new cM.error("schema.aliasNames must be an array of strings", debug);
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
} else {
|
|
46
|
-
schema.aliasNames = [];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (!schema.spread && typeof schema.type === "string" && /\[\]$/.test(schema.type)) {
|
|
50
|
-
schema.spread = true;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return schemasArr;
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const guessor = {
|
|
59
|
-
guessBy(args, schemas, mode, debug = false) {
|
|
60
|
-
if (debug) {
|
|
61
|
-
cM.log(`[Malle] guessing with mode: ${mode}`, true);
|
|
62
|
-
cM.log(["args:", args], true);
|
|
63
|
-
cM.log(["schemas:", schemas], true);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (mode === "loose") return this.looseModeGuessor(args, schemas, debug);
|
|
67
|
-
return this.strictModeGuessor(args, schemas, debug);
|
|
68
|
-
},
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
* @param {Array} args
|
|
72
|
-
* @param {Array} schemas
|
|
73
|
-
* @param {"strict"|"loose"} mode
|
|
74
|
-
* @param {Boolean} debug
|
|
75
|
-
*/
|
|
76
|
-
looseModeGuessor(args, schemas, debug) {
|
|
77
|
-
const result = {};
|
|
78
|
-
const errors = [];
|
|
79
|
-
const consumed = new Set();
|
|
80
|
-
|
|
81
|
-
for (let s = 0; s < schemas.length; s++) {
|
|
82
|
-
const schema = schemas[s];
|
|
83
|
-
let found = false;
|
|
84
|
-
|
|
85
|
-
for (let a = 0; a < args.length; a++) {
|
|
86
|
-
if (consumed.has(a)) continue;
|
|
87
|
-
if (isType(args[a], "object")) {
|
|
88
|
-
const keys = [schema.name].concat(schema.aliasNames || []);
|
|
89
|
-
for (const k of keys) {
|
|
90
|
-
if (!isUndefined(args[a][k])) {
|
|
91
|
-
result[schema.name] = args[a][k];
|
|
92
|
-
consumed.add(a);
|
|
93
|
-
found = true;
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (found) break;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (!found && schema.spread) {
|
|
102
|
-
let elemType = null;
|
|
103
|
-
if (typeof schema.type === "string") {
|
|
104
|
-
if (/\[\]$/.test(schema.type)) elemType = schema.type.replace(/\[\]$/, "");
|
|
105
|
-
else elemType = schema.type;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const collected = [];
|
|
109
|
-
for (let a = 0; a < args.length; a++) {
|
|
110
|
-
if (consumed.has(a)) continue;
|
|
111
|
-
if (isType(args[a], elemType)) {
|
|
112
|
-
collected.push(args[a]);
|
|
113
|
-
consumed.add(a);
|
|
114
|
-
}
|
|
115
|
-
else if (isType(args[a], elemType + "[]")) {
|
|
116
|
-
collected.push(...args[a]);
|
|
117
|
-
consumed.add(a);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (collected.length > 0) {
|
|
122
|
-
result[schema.name] = collected;
|
|
123
|
-
found = true;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (!found) {
|
|
128
|
-
for (let a = 0; a < args.length; a++) {
|
|
129
|
-
if (consumed.has(a)) continue;
|
|
130
|
-
if (isType(args[a], schema.type)) {
|
|
131
|
-
result[schema.name] = args[a];
|
|
132
|
-
consumed.add(a);
|
|
133
|
-
found = true;
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (!found) {
|
|
140
|
-
if (schema.optional) {
|
|
141
|
-
result[schema.name] = undefined;
|
|
142
|
-
} else {
|
|
143
|
-
errors.push({
|
|
144
|
-
name: schema.name,
|
|
145
|
-
expected: schema.type,
|
|
146
|
-
message: `missing required argument '${schema.name}' of type '${schema.type}' (loose mode)`,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const success = errors.length === 0;
|
|
153
|
-
const report = Object.assign({}, result, { __DidSucceed: success, __errors: errors });
|
|
154
|
-
if (!success && debug) cM.log(["malle: loose-mode guess errors", errors], true);
|
|
155
|
-
return report;
|
|
156
|
-
}, strictModeGuessor(args, schemas, debug) {
|
|
157
|
-
const result = {};
|
|
158
|
-
const errors = [];
|
|
159
|
-
let onArgCounter = 0;
|
|
160
|
-
|
|
161
|
-
for (let s = 0; s < schemas.length; s++) {
|
|
162
|
-
const schema = schemas[s];
|
|
163
|
-
let found = false;
|
|
164
|
-
|
|
165
|
-
// 1) try named object property or any alias
|
|
166
|
-
for (let a = 0; a < args.length; a++) {
|
|
167
|
-
if (isType(args[a], "object")) {
|
|
168
|
-
const keys = [schema.name].concat(schema.aliasNames || []);
|
|
169
|
-
for (const k of keys) {
|
|
170
|
-
if (!isUndefined(args[a][k])) {
|
|
171
|
-
result[schema.name] = args[a][k];
|
|
172
|
-
found = true;
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (found) break;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (!found) {
|
|
181
|
-
if (schema.spread) {
|
|
182
|
-
let elemType = null;
|
|
183
|
-
if (typeof schema.type === "string") {
|
|
184
|
-
if (/\[\]$/.test(schema.type)) elemType = schema.type.replace(/\[\]$/, "");
|
|
185
|
-
else elemType = schema.type;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const collected = [];
|
|
189
|
-
let i = onArgCounter;
|
|
190
|
-
for (; i < args.length; i++) {
|
|
191
|
-
if (isType(args[i], elemType)) {
|
|
192
|
-
collected.push(args[i]);
|
|
193
|
-
} else break;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (collected.length > 0) {
|
|
197
|
-
result[schema.name] = collected;
|
|
198
|
-
onArgCounter = i;
|
|
199
|
-
found = true;
|
|
200
|
-
} else if (isType(args[onArgCounter], elemType + "[]")) {
|
|
201
|
-
result[schema.name] = args[onArgCounter];
|
|
202
|
-
onArgCounter = onArgCounter + 1;
|
|
203
|
-
found = true;
|
|
204
|
-
}
|
|
205
|
-
} else {
|
|
206
|
-
let consumedIndex = -1;
|
|
207
|
-
for (let i = onArgCounter; i < args.length; i++) {
|
|
208
|
-
if (isType(args[i], schema.type)) {
|
|
209
|
-
consumedIndex = i;
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (consumedIndex !== -1) {
|
|
215
|
-
result[schema.name] = args[consumedIndex];
|
|
216
|
-
onArgCounter = consumedIndex + 1;
|
|
217
|
-
found = true;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (!found) {
|
|
222
|
-
if (schema.optional) {
|
|
223
|
-
result[schema.name] = undefined;
|
|
224
|
-
} else {
|
|
225
|
-
errors.push({
|
|
226
|
-
name: schema.name,
|
|
227
|
-
expected: schema.type,
|
|
228
|
-
message: `missing required argument '${schema.name}' of type '${schema.type}'`,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const success = errors.length === 0;
|
|
236
|
-
const report = Object.assign({}, result, { __DidSucceed: success, __errors: errors });
|
|
237
|
-
if (!success && debug) cM.log(["malle: guess errors", errors], true);
|
|
238
|
-
return report;
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
//#endregion Helpers
|
|
242
|
-
//-----------------------------------------------------------------------------------------------------------
|
|
243
|
-
//#region Main Class
|
|
244
|
-
/**
|
|
245
|
-
* Class representing a Malle argument parser instance.
|
|
246
|
-
*/
|
|
247
|
-
export default class MalleClass {
|
|
248
|
-
#modes = ["strict", "loose"];
|
|
249
|
-
#mode = "strict";
|
|
250
|
-
#debug = false;
|
|
251
|
-
|
|
252
|
-
#isValidMode(mode) {
|
|
253
|
-
return this.#modes.includes(mode);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
constructor(config = {}) {
|
|
257
|
-
const { mode, debug } = config;
|
|
258
|
-
|
|
259
|
-
if (!isUndefined(mode) && this.#isValidMode(mode)) {
|
|
260
|
-
this.#mode = mode;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (!isUndefined(debug)) {
|
|
264
|
-
this.#debug = !!debug;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
setDebug(value) {
|
|
269
|
-
this.#debug = !!value;
|
|
270
|
-
return this;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
setMode(mode) {
|
|
274
|
-
if (this.#isValidMode(mode)) {
|
|
275
|
-
this.#mode = mode;
|
|
276
|
-
}
|
|
277
|
-
return this;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Define expected argument schemas
|
|
282
|
-
*/
|
|
283
|
-
expect(...schemas) {
|
|
284
|
-
const arr = expector.checkSchemas(schemas, this.#debug);
|
|
285
|
-
if (!arr) return false;
|
|
286
|
-
|
|
287
|
-
return {
|
|
288
|
-
guess: (...args) =>
|
|
289
|
-
guessor.guessBy(getArrFromSpread(args), arr, this.#mode, this.#debug),
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
//#endregion Main Class
|
|
294
|
-
//-----------------------------------------------------------------------------------------------------------
|
package/core/main.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import MalleClass from "./class";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The **Malle** argument parser.
|
|
5
|
-
*
|
|
6
|
-
* Allows functions to accept arguments in **any order**, infer intent,
|
|
7
|
-
* and validate inputs according to schemas.
|
|
8
|
-
*
|
|
9
|
-
* @param {Object} [config] - Optional configuration object.
|
|
10
|
-
* @param {"strict"|"loose"} [config.mode="strict"] - Parsing mode.
|
|
11
|
-
* - `"strict"`: matches types and positional args conservatively.
|
|
12
|
-
* - `"loose"`: more permissive (order-agnostic, type-aliases such as `arr`/`array` allowed).
|
|
13
|
-
* @param {boolean} [config.debug=false] - If `true`, prints debug info to console.
|
|
14
|
-
*
|
|
15
|
-
* @returns {MalleClass}
|
|
16
|
-
*
|
|
17
|
-
* @remarks
|
|
18
|
-
* The object returned by `expect(...).guess(...)` contains the matched keys
|
|
19
|
-
* plus two meta-keys:
|
|
20
|
-
* - `__DidSucceed` (boolean) — true when all *required* schemas were satisfied
|
|
21
|
-
* - `__errors` (Array) — list of reported issues when parsing failed
|
|
22
|
-
*
|
|
23
|
-
* Schema notes:
|
|
24
|
-
* - `type` supports unions (`string|number`), generic arrays (`T[]`, e.g. `number[]`) and `any`.
|
|
25
|
-
* - `aliasNames` accepts an array of alternate object-property names.
|
|
26
|
-
* - `spread: true` collects multiple matching positional values into an array.
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* import malle from "@briklab/malle";
|
|
30
|
-
*
|
|
31
|
-
* function calc(...args) {
|
|
32
|
-
* const { Number1, Number2, Mode, __DidSucceed } = malle({mode: "strict"})
|
|
33
|
-
* .expect(
|
|
34
|
-
* {name:"Number1", type:"number"},
|
|
35
|
-
* {name:"Number2", type:"number"},
|
|
36
|
-
* {name:"Mode", type:"string"}
|
|
37
|
-
* );
|
|
38
|
-
*
|
|
39
|
-
* if(!__DidSucceed) return;
|
|
40
|
-
* return Mode === "add" ? Number1 + Number2 : Number1 - Number2;
|
|
41
|
-
* }
|
|
42
|
-
*/
|
|
43
|
-
export default function malle(config) {
|
|
44
|
-
return new MalleClass(config)
|
|
45
|
-
}
|
|
46
|
-
|
package/helpers/arrHelpers.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import isType from "./typeHelpers";
|
|
2
|
-
|
|
3
|
-
export default function getArrFromSpread(args) {
|
|
4
|
-
if (!Array.isArray(args)) return false;
|
|
5
|
-
if (args.length === 1 && Array.isArray(args[0])) return args[0];
|
|
6
|
-
return args;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function areAllTypes(arr, type) {
|
|
10
|
-
for (let i = 0; i < arr.length; i++) {
|
|
11
|
-
if (!isType(arr[i], type)) return false;
|
|
12
|
-
}
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export const cM = {
|
|
2
|
-
__name: "Malle",
|
|
3
|
-
error: class extends Error {
|
|
4
|
-
constructor(message, debug = false) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = cM.__name;
|
|
7
|
-
|
|
8
|
-
if (debug) {
|
|
9
|
-
console.log(
|
|
10
|
-
"%c[Malle]: Error: %c",
|
|
11
|
-
"color:red;font-weight:bold;",
|
|
12
|
-
message,
|
|
13
|
-
""
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
log(message,debug){
|
|
19
|
-
if(!debug)return
|
|
20
|
-
console.log("%c[Malle] Log: %c","color:lime;font-weight:bold;","",message)
|
|
21
|
-
}
|
|
22
|
-
};
|
package/helpers/isUndefined.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function isUndefined(a){return typeof a === "undefined"}
|
package/helpers/loop.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function loop(t,f,...a){for(let i=0;i<t;i++){f(...a)}}
|
package/helpers/objHelpers.js
DELETED
package/helpers/typeHelpers.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const typeofvalidtypes = [
|
|
2
|
-
"boolean",
|
|
3
|
-
"number",
|
|
4
|
-
"function",
|
|
5
|
-
"object",
|
|
6
|
-
"string",
|
|
7
|
-
"symbol",
|
|
8
|
-
"undefined",
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
const aliasMap = {
|
|
12
|
-
arr: "array",
|
|
13
|
-
array: "array",
|
|
14
|
-
"[]": "array",
|
|
15
|
-
null: "null",
|
|
16
|
-
any: "any",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
function _isPrimitiveMatch(stuff, norm) {
|
|
20
|
-
if (norm === "array") return Array.isArray(stuff);
|
|
21
|
-
if (norm === "null") return stuff === null;
|
|
22
|
-
if (norm === "any") return true;
|
|
23
|
-
if (typeofvalidtypes.includes(norm)) return typeof stuff === norm;
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default function isType(stuff, type) {
|
|
28
|
-
if (!type) return false;
|
|
29
|
-
const raw = String(type).trim();
|
|
30
|
-
|
|
31
|
-
// union (e.g. "string|number[]")
|
|
32
|
-
if (raw.includes("|")) {
|
|
33
|
-
return raw.split("|").map((p) => p.trim()).some((part) => isType(stuff, part));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// array-of-type syntax (T[])
|
|
37
|
-
if (raw.endsWith("[]")) {
|
|
38
|
-
const elemType = raw.slice(0, -2) || "any";
|
|
39
|
-
if (!Array.isArray(stuff)) return false;
|
|
40
|
-
return stuff.every((el) => isType(el, elemType));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const t = raw.toLowerCase();
|
|
44
|
-
const norm = aliasMap[t] || t;
|
|
45
|
-
|
|
46
|
-
if (_isPrimitiveMatch(stuff, norm)) return true;
|
|
47
|
-
if (raw === "Array") return Array.isArray(stuff);
|
|
48
|
-
|
|
49
|
-
return false;
|
|
50
|
-
}
|
package/index.cjs
DELETED