celery-env 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/LICENSE +21 -0
- package/README.md +151 -0
- package/SECURITY.md +75 -0
- package/docs/BENCHMARKS.md +44 -0
- package/docs/CLI.md +68 -0
- package/docs/COMPARISON.md +58 -0
- package/docs/GETTING_STARTED.md +134 -0
- package/docs/MIGRATION.md +54 -0
- package/docs/README.md +15 -0
- package/docs/RUNTIME.md +43 -0
- package/docs/SCHEMA.md +149 -0
- package/docs/TROUBLESHOOTING.md +74 -0
- package/docs/TYPESCRIPT.md +105 -0
- package/docs/assets/celery-mark.svg +7 -0
- package/package.json +77 -0
- package/src/cli.js +133 -0
- package/src/compiler.d.ts +7 -0
- package/src/compiler.js +811 -0
- package/src/index.d.ts +22 -0
- package/src/index.js +375 -0
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare const specBrand: unique symbol;
|
|
2
|
+
export type BaseOptions<T> = { default?: T; devDefault?: T; testDefault?: T; optional?: boolean; requiredWhen?: (env: Record<string, string | undefined>) => boolean; desc?: string; example?: T | string; docs?: string };
|
|
3
|
+
export type StringOptions<T = string> = BaseOptions<T> & { min?: number; max?: number; startsWith?: string; includes?: string };
|
|
4
|
+
export type NumberOptions<T = number> = BaseOptions<T> & { min?: number; max?: number; strict?: boolean };
|
|
5
|
+
export type BoolOptions<T = boolean> = BaseOptions<T>;
|
|
6
|
+
export type Spec<T> = { readonly [specBrand]: T };
|
|
7
|
+
export type InferSpec<T> = T extends Spec<infer V> ? V : never;
|
|
8
|
+
export type InferEnv<T extends Record<string, Spec<unknown>>> = { readonly [K in keyof T]: InferSpec<T[K]> };
|
|
9
|
+
export type EnvResult<T extends Record<string, Spec<unknown>>> = InferEnv<T>;
|
|
10
|
+
type Output<T, O> = O extends { default: infer D } ? D : O extends { optional: true } ? T | undefined : T;
|
|
11
|
+
export function defineEnv<T extends Record<string, Spec<unknown>>>(schema: T): Readonly<T>;
|
|
12
|
+
export function str<O extends StringOptions | undefined = undefined>(options?: O): Spec<Output<string, O>>;
|
|
13
|
+
export function int<O extends NumberOptions | undefined = undefined>(options?: O): Spec<Output<number, O>>;
|
|
14
|
+
export function num<O extends NumberOptions | undefined = undefined>(options?: O): Spec<Output<number, O>>;
|
|
15
|
+
export function bool<O extends BoolOptions | undefined = undefined>(options?: O): Spec<Output<boolean, O>>;
|
|
16
|
+
export function oneOf<const T extends readonly [string | number | boolean, ...(string | number | boolean)[]], O extends BaseOptions<T[number]> | undefined = undefined>(values: T, options?: O): Spec<Output<T[number], O>>;
|
|
17
|
+
export function url<O extends (StringOptions & { protocols?: readonly string[] }) | undefined = undefined>(options?: O): Spec<Output<string, O>>;
|
|
18
|
+
export function json<T = unknown, O extends BaseOptions<T> | undefined = undefined>(options?: O): Spec<Output<T, O>>;
|
|
19
|
+
export function list<T, O extends BaseOptions<readonly T[]> & { separator?: string; trim?: boolean } | undefined = undefined>(item: Spec<T>, options?: O): Spec<Output<readonly T[], O>>;
|
|
20
|
+
export function parseEnv<T extends Record<string, Spec<unknown>>>(schema: T, env?: Record<string, string | undefined>): EnvResult<T>;
|
|
21
|
+
export function isCelerySpec(value: unknown): value is Spec<unknown>;
|
|
22
|
+
export class EnvError extends Error { readonly errors: readonly string[]; constructor(errors: readonly string[]); }
|
package/src/index.js
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
const STR = 0, INT = 1, NUM = 2, BOOL = 3, ENUM = 4, URL_T = 5, JSON_T = 6, LIST = 7;
|
|
2
|
+
const K = Symbol();
|
|
3
|
+
const C = new WeakMap();
|
|
4
|
+
const H = Object.hasOwn;
|
|
5
|
+
|
|
6
|
+
export class EnvError extends Error {
|
|
7
|
+
constructor(e) {
|
|
8
|
+
super(`Invalid environment:\n- ${e.join("\n- ")}`);
|
|
9
|
+
this.name = "EnvError";
|
|
10
|
+
this.errors = e;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function spec(t, options) {
|
|
15
|
+
const rule = Object.create(null);
|
|
16
|
+
rule.t = t;
|
|
17
|
+
if (options) for (const key of Object.keys(options)) rule[key] = options[key];
|
|
18
|
+
return rule;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function defineEnv(schema) {
|
|
22
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) throw new TypeError("defineEnv() expects an object schema");
|
|
23
|
+
const entries = schemaEntries(schema);
|
|
24
|
+
Object.isExtensible(schema)?Object.defineProperty(schema,K,{value:entries}):C.set(schema,entries)
|
|
25
|
+
return Object.freeze(schema);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function str(options) {
|
|
29
|
+
return spec(STR, options);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function int(options) {
|
|
33
|
+
return spec(INT, options);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function num(options) {
|
|
37
|
+
return spec(NUM, options);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function bool(options) {
|
|
41
|
+
return spec(BOOL, options);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function oneOf(values, options) {
|
|
45
|
+
if (!Array.isArray(values) || !values.length) throw new TypeError("oneOf() expects a non-empty array");
|
|
46
|
+
const mixed = values.some(v=>typeof v!="string");
|
|
47
|
+
const strings = mixed ? values.map(String) : values.slice();
|
|
48
|
+
const rule = {...options,values,strings};
|
|
49
|
+
if (!mixed && values.length>4) rule.m = new Set(values);
|
|
50
|
+
return spec(ENUM, rule);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function url(options) {
|
|
54
|
+
return spec(URL_T, options && H(options, "protocols") ? {...options,ps:options.protocols.map(p=>p+":")} : options);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function json(options) {
|
|
58
|
+
return spec(JSON_T, options);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function list(item, options) {
|
|
62
|
+
if (!isCelerySpec(item)) throw new TypeError("list() expects a celery-env spec item");
|
|
63
|
+
return spec(LIST, {separator:",",...options,item});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function parseEnv(schema, env = process.env) {
|
|
67
|
+
const out = {}, e = [];
|
|
68
|
+
const entries = schema[K] || C.get(schema) || schemaEntries(schema);
|
|
69
|
+
|
|
70
|
+
for (let i = 0; i < entries.length; i += 2) {
|
|
71
|
+
const key = entries[i];
|
|
72
|
+
const rule = entries[i + 1];
|
|
73
|
+
set(out, key, readValue(key, rule, H(env, key) ? env[key] : undefined, e, -1, env));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (e.length) throw new EnvError(e);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function isCelerySpec(value) {
|
|
81
|
+
return !!value && typeof value === "object" && H(value, "t") && typeof value.t === "number";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function schemaEntries(schema) {
|
|
85
|
+
const entries = [];
|
|
86
|
+
for (const key of Object.keys(schema)) {
|
|
87
|
+
const rule = schema[key];
|
|
88
|
+
if (!isCelerySpec(rule)) throw new TypeError(`${key}: schema entry is not a celery-env spec`);
|
|
89
|
+
if (rule.requiredWhen != null && typeof rule.requiredWhen !== "function") throw new TypeError(`${key}: requiredWhen must be a function`);
|
|
90
|
+
entries.push(key, rule);
|
|
91
|
+
}
|
|
92
|
+
return entries;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function readValue(key, rule, value, e, i, env) {
|
|
96
|
+
if (value == null || value === "") {
|
|
97
|
+
if (H(rule, "testDefault") || H(rule, "devDefault")) {
|
|
98
|
+
const n = H(env, "NODE_ENV") ? env.NODE_ENV : undefined;
|
|
99
|
+
if (n === "test" && H(rule, "testDefault")) return rule.testDefault;
|
|
100
|
+
if (n !== "production" && H(rule, "devDefault")) return rule.devDefault;
|
|
101
|
+
}
|
|
102
|
+
if (H(rule, "default")) return rule.default;
|
|
103
|
+
if (H(rule, "optional") && rule.optional && (!H(rule, "requiredWhen") || rule.requiredWhen(ownEnv(env)) !== true)) return;
|
|
104
|
+
e.push(`${k(key, i)} is required`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
switch (rule.t) {
|
|
109
|
+
case STR:
|
|
110
|
+
return readString(key, rule, value, e, i);
|
|
111
|
+
case INT:
|
|
112
|
+
return readNumber(key, rule, value, true, e, i);
|
|
113
|
+
case NUM:
|
|
114
|
+
return readNumber(key, rule, value, false, e, i);
|
|
115
|
+
case BOOL: {
|
|
116
|
+
const p = boolValue(value);
|
|
117
|
+
if (p !== undefined) return p;
|
|
118
|
+
e.push(`${k(key, i)} must be a boolean`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
case ENUM:
|
|
122
|
+
return readOneOf(key, rule, value, e, i);
|
|
123
|
+
case URL_T:
|
|
124
|
+
return readUrl(key, rule, value, e, i);
|
|
125
|
+
case JSON_T:
|
|
126
|
+
if(!j(value))try{return JSON.parse(value)}catch{}
|
|
127
|
+
e.push(`${k(key, i)} must be valid JSON`);
|
|
128
|
+
return;
|
|
129
|
+
case LIST:
|
|
130
|
+
return readList(k(key, i), rule, value, e, env);
|
|
131
|
+
default:
|
|
132
|
+
throw new Error(`${key}: unknown validator kind ${rule.t}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function readString(key, rule, value, e, i) {
|
|
137
|
+
const p = rule.startsWith;
|
|
138
|
+
if (rule.min != null && (p == null || p.length < rule.min) && value.length < rule.min) e.push(`${k(key, i)} must have length >= ${rule.min}`);
|
|
139
|
+
else if (rule.max != null && value.length > rule.max) e.push(`${k(key, i)} must have length <= ${rule.max}`);
|
|
140
|
+
else if (p != null && !value.startsWith(p)) e.push(`${k(key, i)} must start with ${p}`);
|
|
141
|
+
else if (rule.includes != null && !value.includes(rule.includes)) e.push(`${k(key, i)} must include ${rule.includes}`);
|
|
142
|
+
else return value;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function readNumber(key, rule, value, integer, e, i) {
|
|
146
|
+
if (rule.strict && !sn(value, integer)) {
|
|
147
|
+
e.push(`${k(key, i)} must be ${integer?"a strict integer":"a strict number"}`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const n = +value;
|
|
151
|
+
if (!isFinite(n) || integer && !Number.isInteger(n)) e.push(`${k(key, i)} must be ${integer?"an integer":"a number"}`);
|
|
152
|
+
else if (rule.min != null && n < rule.min) e.push(`${k(key, i)} must be >= ${rule.min}`);
|
|
153
|
+
else if (rule.max != null && n > rule.max) e.push(`${k(key, i)} must be <= ${rule.max}`);
|
|
154
|
+
else return n;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function sn(v, i) {
|
|
158
|
+
let q = 0, d, h, c = v.charCodeAt(q);
|
|
159
|
+
if (c === 43 || c === 45) q++;
|
|
160
|
+
for (; q < v.length; q++) {
|
|
161
|
+
c = v.charCodeAt(q);
|
|
162
|
+
if (c === 46 && !i && !h) h = 1;
|
|
163
|
+
else if (c < 48 || c > 57) return;
|
|
164
|
+
else d = 1;
|
|
165
|
+
}
|
|
166
|
+
return d;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function j(v){return v[0]=="{"&&v[v.length-1]!="}"||v[0]=="["&&v[v.length-1]!="]"}
|
|
170
|
+
|
|
171
|
+
function set(o, k, v) {
|
|
172
|
+
if (k === "__proto__") Object.defineProperty(o, k, { value: v, enumerable: true, configurable: true, writable: true });
|
|
173
|
+
else o[k] = v;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function ownEnv(env) {
|
|
177
|
+
const o = Object.create(null);
|
|
178
|
+
for (const key of Object.keys(env)) o[key] = env[key];
|
|
179
|
+
return o;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function boolValue(value) {
|
|
183
|
+
switch (value.length) {
|
|
184
|
+
case 1:
|
|
185
|
+
if (value === "1") return true
|
|
186
|
+
if (value === "0") return false
|
|
187
|
+
case 2:
|
|
188
|
+
if (value === "on") return true
|
|
189
|
+
if (value === "no") return false
|
|
190
|
+
case 3:
|
|
191
|
+
if (value === "yes") return true
|
|
192
|
+
if (value === "off") return false
|
|
193
|
+
case 4:
|
|
194
|
+
if (value === "true") return true
|
|
195
|
+
case 5:
|
|
196
|
+
if (value === "false") return false
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function readOneOf(key, rule, value, e, i) {
|
|
201
|
+
if (rule.m?.has(value)) return value;
|
|
202
|
+
for (let j = 0; j < rule.values.length; j++) {
|
|
203
|
+
if (value === rule.strings[j]) return rule.values[j];
|
|
204
|
+
}
|
|
205
|
+
e.push(`${k(key, i)} must be one of ${rule.values.join(", ")}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function readUrl(key, rule, value, e, i) {
|
|
209
|
+
try {
|
|
210
|
+
if (rule.ps ? rule.ps.includes(new URL(value).protocol) : new URL(value)) return value;
|
|
211
|
+
} catch {
|
|
212
|
+
e.push(`${k(key, i)} must be a URL`);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
e.push(`${k(key, i)} must use protocol ${rule.protocols.join(", ")}`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function readList(key, rule, value, e, env) {
|
|
219
|
+
const sep=rule.separator, item=rule.item, trim=rule.trim !== false;
|
|
220
|
+
const fast=!item.requiredWhen && !("devDefault" in item) && !("testDefault" in item);
|
|
221
|
+
if (sep !== "" && item.t === INT && item.strict && fast && int32Bounded(item)) return readStrictIntList(key, item, sep, trim, value, e);
|
|
222
|
+
if (sep !== "" && item.t === NUM && item.strict && fast) return readStrictNumList(key, item, sep, trim, value, e);
|
|
223
|
+
if (item.t === BOOL && fast) return readBoolList(key, item, sep, trim, value, e);
|
|
224
|
+
if (sep !== "" && item.t === ENUM && fast) return readEnums(key, item, sep, trim, value, e);
|
|
225
|
+
if (item.t === STR && fast) return readStringList(key, item, sep, trim, value, e);
|
|
226
|
+
const z = sep === "";
|
|
227
|
+
const out = z ? new Array(value.length) : [];
|
|
228
|
+
for (let i = 0, s = 0, end;; i++, s = end + sep.length) {
|
|
229
|
+
end = z ? i : value.indexOf(sep, s);
|
|
230
|
+
if (z && i === value.length) break;
|
|
231
|
+
let x = z ? value[i] : end < 0 ? value.slice(s) : value.slice(s, end);
|
|
232
|
+
if (trim) x = x.trim();
|
|
233
|
+
out[i] = readValue(key, item, x, e, i, env);
|
|
234
|
+
if (end < 0) break;
|
|
235
|
+
}
|
|
236
|
+
return out;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function readBoolList(key, item, sep, trim, value, e) {
|
|
240
|
+
const z = sep === "";
|
|
241
|
+
const out = z ? new Array(value.length) : [];
|
|
242
|
+
for (let i = 0, s = 0, end;; i++, s = end + sep.length) {
|
|
243
|
+
end = z ? i : value.indexOf(sep, s);
|
|
244
|
+
if (z && i === value.length) break;
|
|
245
|
+
let x = z ? value[i] : end < 0 ? value.slice(s) : value.slice(s, end);
|
|
246
|
+
if (trim) x = x.trim();
|
|
247
|
+
if (x === "") {
|
|
248
|
+
if (!("default" in item) && !item.optional) e.push(`${k(key, i)} is required`);
|
|
249
|
+
else out[i] = item.default;
|
|
250
|
+
} else {
|
|
251
|
+
const p = boolValue(x);
|
|
252
|
+
if (p === undefined) e.push(`${k(key, i)} must be a boolean`);
|
|
253
|
+
else out[i] = p;
|
|
254
|
+
}
|
|
255
|
+
if (end < 0) break;
|
|
256
|
+
}
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function readEnums(key, item, sep, trim, value, e) {
|
|
261
|
+
const out = [];
|
|
262
|
+
for (let i = 0, s = 0, end;; i++, s = end + sep.length) {
|
|
263
|
+
end = value.indexOf(sep, s);
|
|
264
|
+
let x = end < 0 ? value.slice(s) : value.slice(s, end);
|
|
265
|
+
if (trim) x = x.trim();
|
|
266
|
+
if (x === "") {
|
|
267
|
+
if (!("default" in item) && !item.optional) e.push(`${k(key, i)} is required`);
|
|
268
|
+
else out[i] = item.default;
|
|
269
|
+
} else out[i] = readOneOf(key, item, x, e, i);
|
|
270
|
+
if (end < 0) break;
|
|
271
|
+
}
|
|
272
|
+
return out;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function readStringList(key, item, sep, trim, value, e) {
|
|
276
|
+
const p = item.startsWith;
|
|
277
|
+
if (sep === "" && !trim && item.min == null && item.max == null && p == null && item.includes == null) return value.split("");
|
|
278
|
+
const z = sep === "";
|
|
279
|
+
const out = z ? new Array(value.length) : [];
|
|
280
|
+
for (let i = 0, s = 0, end;; i++, s = end + sep.length) {
|
|
281
|
+
end = z ? i : value.indexOf(sep, s);
|
|
282
|
+
if (z && i === value.length) break;
|
|
283
|
+
let x = z ? value[i] : end < 0 ? value.slice(s) : value.slice(s, end);
|
|
284
|
+
if (trim) x = x.trim();
|
|
285
|
+
if (x === "") {
|
|
286
|
+
if (!("default" in item) && !item.optional) e.push(`${k(key, i)} is required`);
|
|
287
|
+
else out[i] = item.default;
|
|
288
|
+
} else if (item.min != null && (p == null || p.length < item.min) && x.length < item.min) e.push(`${k(key, i)} must have length >= ${item.min}`);
|
|
289
|
+
else if (item.max != null && x.length > item.max) e.push(`${k(key, i)} must have length <= ${item.max}`);
|
|
290
|
+
else if (p != null && !x.startsWith(p)) e.push(`${k(key, i)} must start with ${p}`);
|
|
291
|
+
else if (item.includes != null && !x.includes(item.includes)) e.push(`${k(key, i)} must include ${item.includes}`);
|
|
292
|
+
else out[i] = x;
|
|
293
|
+
if (end < 0) break;
|
|
294
|
+
}
|
|
295
|
+
return out;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function readStrictIntList(key, item, sep, trim, value, e) {
|
|
299
|
+
const out = [];
|
|
300
|
+
for (let i = 0, s = 0, end;; i++, s = end + sep.length) {
|
|
301
|
+
end = value.indexOf(sep, s);
|
|
302
|
+
let a = s;
|
|
303
|
+
let z = end < 0 ? value.length : end;
|
|
304
|
+
if (trim) {
|
|
305
|
+
while (a < z && ws(value.charCodeAt(a))) a++;
|
|
306
|
+
while (z > a && ws(value.charCodeAt(z - 1))) z--;
|
|
307
|
+
}
|
|
308
|
+
if (a === z) {
|
|
309
|
+
if (!("default" in item) && !item.optional) e.push(`${k(key, i)} must be a strict integer`);
|
|
310
|
+
else out[i] = item.default;
|
|
311
|
+
} else {
|
|
312
|
+
let q = a;
|
|
313
|
+
let c = value.charCodeAt(q);
|
|
314
|
+
let g = 1;
|
|
315
|
+
if (c === 43 || c === 45) {
|
|
316
|
+
g = c === 45 ? -1 : 1;
|
|
317
|
+
q++;
|
|
318
|
+
}
|
|
319
|
+
if (q === z) {
|
|
320
|
+
e.push(`${k(key, i)} must be a strict integer`);
|
|
321
|
+
} else {
|
|
322
|
+
let n = 0;
|
|
323
|
+
for (; q < z; q++) {
|
|
324
|
+
c = value.charCodeAt(q);
|
|
325
|
+
if (c < 48 || c > 57) break;
|
|
326
|
+
n = n * 10 + c - 48;
|
|
327
|
+
}
|
|
328
|
+
if (q !== z) e.push(`${k(key, i)} must be a strict integer`);
|
|
329
|
+
else {
|
|
330
|
+
n *= g;
|
|
331
|
+
if ((n | 0) !== n) e.push(`${k(key, i)} must be an integer`);
|
|
332
|
+
else if (item.min != null && n < item.min) e.push(`${k(key, i)} must be >= ${item.min}`);
|
|
333
|
+
else if (item.max != null && n > item.max) e.push(`${k(key, i)} must be <= ${item.max}`);
|
|
334
|
+
else out[i] = n;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (end < 0) break;
|
|
339
|
+
}
|
|
340
|
+
return out;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function readStrictNumList(key, item, sep, trim, value, e) {
|
|
344
|
+
const out = [];
|
|
345
|
+
for (let i = 0, s = 0, end;; i++, s = end + sep.length) {
|
|
346
|
+
end = value.indexOf(sep, s);
|
|
347
|
+
let x = end < 0 ? value.slice(s) : value.slice(s, end);
|
|
348
|
+
if (trim) x = x.trim();
|
|
349
|
+
if (x === "") {
|
|
350
|
+
if (!("default" in item) && !item.optional) e.push(`${k(key, i)} is required`);
|
|
351
|
+
else out[i] = item.default;
|
|
352
|
+
} else if (!sn(x)) e.push(`${k(key, i)} must be a strict number`);
|
|
353
|
+
else {
|
|
354
|
+
const n = +x;
|
|
355
|
+
if (!isFinite(n)) e.push(`${k(key, i)} must be a number`);
|
|
356
|
+
else if (item.min != null && n < item.min) e.push(`${k(key, i)} must be >= ${item.min}`);
|
|
357
|
+
else if (item.max != null && n > item.max) e.push(`${k(key, i)} must be <= ${item.max}`);
|
|
358
|
+
else out[i] = n;
|
|
359
|
+
}
|
|
360
|
+
if (end < 0) break;
|
|
361
|
+
}
|
|
362
|
+
return out;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function int32Bounded(rule) {
|
|
366
|
+
return Number.isInteger(rule.min) && Number.isInteger(rule.max) && rule.min >= -2147483648 && rule.max <= 2147483647;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function ws(c) {
|
|
370
|
+
return c > 8 && c < 14 || c === 32 || c === 160 || c === 5760 || c > 8191 && c < 8203 || c === 8232 || c === 8233 || c === 8239 || c === 8287 || c === 12288 || c === 65279;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function k(key, i) {
|
|
374
|
+
return i<0?key:`${key}[${i}]`;
|
|
375
|
+
}
|