lightview 1.4.10-b → 1.5.1-b
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/components/chart.html +76 -0
- package/components/gauge.html +57 -0
- package/examples/chart.html +64 -0
- package/examples/counter.html +1 -2
- package/examples/directives.html +2 -2
- package/examples/foreign.html +1 -1
- package/examples/forgeinform.html +3 -3
- package/examples/form.html +9 -15
- package/examples/gauge.html +16 -0
- package/examples/message.html +1 -1
- package/examples/remote.html +1 -1
- package/examples/template.html +1 -1
- package/examples/types.html +25 -5
- package/examples/xor.html +3 -3
- package/lightview.js +171 -178
- package/package.json +36 -36
- package/test/basic.html +27 -20
- package/test/basic.test.mjs +98 -21
- package/types.js +312 -0
package/package.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "lightview",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Small, simple, powerful web UI and micro front end creation ... Great ideas from Svelte, React, Vue and Riot combined.",
|
|
5
|
-
"main": "lightview.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest ./test"
|
|
8
|
-
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/anywhichway/lightview.git"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"svelte",
|
|
15
|
-
"react",
|
|
16
|
-
"angular",
|
|
17
|
-
"riot",
|
|
18
|
-
"vue",
|
|
19
|
-
"moon",
|
|
20
|
-
"hyperapp",
|
|
21
|
-
"hyperhtml",
|
|
22
|
-
"micro front end",
|
|
23
|
-
"custom elements",
|
|
24
|
-
"web components"
|
|
25
|
-
],
|
|
26
|
-
"author": "Simon Y. Blackwell",
|
|
27
|
-
"license": "MIT",
|
|
28
|
-
"bugs": {
|
|
29
|
-
"url": "https://github.com/anywhichway/lightview/issues"
|
|
30
|
-
},
|
|
31
|
-
"homepage": "https://github.com/anywhichway/lightview#readme",
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"jest": "^27.5.1",
|
|
34
|
-
"jest-puppeteer": "^6.1.0"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "lightview",
|
|
3
|
+
"version": "1.5.1b",
|
|
4
|
+
"description": "Small, simple, powerful web UI and micro front end creation ... Great ideas from Svelte, React, Vue and Riot combined.",
|
|
5
|
+
"main": "lightview.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest ./test"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/anywhichway/lightview.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"svelte",
|
|
15
|
+
"react",
|
|
16
|
+
"angular",
|
|
17
|
+
"riot",
|
|
18
|
+
"vue",
|
|
19
|
+
"moon",
|
|
20
|
+
"hyperapp",
|
|
21
|
+
"hyperhtml",
|
|
22
|
+
"micro front end",
|
|
23
|
+
"custom elements",
|
|
24
|
+
"web components"
|
|
25
|
+
],
|
|
26
|
+
"author": "Simon Y. Blackwell",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/anywhichway/lightview/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/anywhichway/lightview#readme",
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"jest": "^27.5.1",
|
|
34
|
+
"jest-puppeteer": "^6.1.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/test/basic.html
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
<input id="itel" type="tel" value="${itel}">
|
|
20
20
|
<input id="iemail" type="email" value="${iemail}">
|
|
21
21
|
<input id="iurl" type="url" value="${iurl}">
|
|
22
|
-
<input id="iradio" type="radio"
|
|
22
|
+
<input id="iradio" type="radio" name="iradio" value="test">
|
|
23
23
|
<input id="isearch" type="search" value="${isearch}">
|
|
24
24
|
|
|
25
25
|
<input id="icolor" type="color" value="${icolor}">
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
|
|
35
35
|
<script type="lightview/module">
|
|
36
36
|
//debugger;
|
|
37
|
-
self.variables({name:string,open:boolean,count:number,children:Array},{imported,reactive});
|
|
38
|
-
self.variables({color:string,checked:boolean,age:number,hamburger:Array},{exported,reactive});
|
|
39
|
-
self.variables({counter:number},{reactive});
|
|
40
|
-
self.variables({myshare:number},{shared});
|
|
37
|
+
self.variables({name:"string",open:"boolean",count:"number",children:Array},{imported,reactive});
|
|
38
|
+
self.variables({color:"string",checked:"boolean",age:"number",hamburger:Array},{exported,reactive});
|
|
39
|
+
self.variables({counter:"number"},{reactive});
|
|
40
|
+
self.variables({myshare:"number"},{shared});
|
|
41
41
|
|
|
42
42
|
color = "green";
|
|
43
43
|
checked = true;
|
|
@@ -46,26 +46,33 @@
|
|
|
46
46
|
counter = 0;
|
|
47
47
|
myshare = 1;
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
addEventListener("connected", ({target}) => {
|
|
50
|
+
iuntyped = "test";
|
|
51
|
+
itext = "test";
|
|
52
|
+
itel = "test";
|
|
53
|
+
iemail = "test";
|
|
54
|
+
iurl = "test";
|
|
55
|
+
isearch = "test";
|
|
56
|
+
iradio = "test";
|
|
57
|
+
icolor = "test";
|
|
58
|
+
ipassword = "test";
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
inumber = 1;
|
|
61
|
+
irange = 1;
|
|
62
|
+
debugger;
|
|
63
|
+
idatetime = new Date();
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
icheckbox = true;
|
|
66
|
+
target.testId = target.id;
|
|
67
|
+
});
|
|
65
68
|
|
|
66
69
|
self.bump = () => {
|
|
67
70
|
counter++;
|
|
68
|
-
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
addEventListener("change",({variableName,value}) => {
|
|
74
|
+
self[variableName] = value;
|
|
75
|
+
});
|
|
69
76
|
</script>
|
|
70
77
|
</template>
|
|
71
78
|
<script src="../lightview.js"></script>
|
package/test/basic.test.mjs
CHANGED
|
@@ -10,7 +10,7 @@ describe('Google', () => {
|
|
|
10
10
|
});
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
describe('Lightview', () => {
|
|
13
|
+
describe('Lightview - Variables', () => {
|
|
14
14
|
beforeAll(async () => {
|
|
15
15
|
await page.goto('http://localhost:8080/test/basic.html');
|
|
16
16
|
});
|
|
@@ -22,7 +22,7 @@ describe('Lightview', () => {
|
|
|
22
22
|
test('boolean - open should be imported', async () => {
|
|
23
23
|
const result = await page.evaluate(() => {
|
|
24
24
|
const el = document.getElementById("test");
|
|
25
|
-
return JSON.parse(el.
|
|
25
|
+
return JSON.parse(el.getVariableValue("open"));
|
|
26
26
|
});
|
|
27
27
|
expect(result).toBe(true);
|
|
28
28
|
});
|
|
@@ -30,7 +30,7 @@ describe('Lightview', () => {
|
|
|
30
30
|
test('number - count should be imported', async () => {
|
|
31
31
|
const result = await page.evaluate(() => {
|
|
32
32
|
const el = document.getElementById("test");
|
|
33
|
-
return JSON.parse(el.
|
|
33
|
+
return JSON.parse(el.getVariableValue("count"));
|
|
34
34
|
});
|
|
35
35
|
expect(result).toBe(1);
|
|
36
36
|
});
|
|
@@ -38,7 +38,7 @@ describe('Lightview', () => {
|
|
|
38
38
|
test('string - name should be imported', async () => {
|
|
39
39
|
const result = await page.evaluate(() => {
|
|
40
40
|
const el = document.getElementById("test");
|
|
41
|
-
return el.
|
|
41
|
+
return el.getVariableValue("name");
|
|
42
42
|
});
|
|
43
43
|
expect(result).toBe("joe");
|
|
44
44
|
});
|
|
@@ -46,7 +46,7 @@ describe('Lightview', () => {
|
|
|
46
46
|
test('object - children should be imported', async () => {
|
|
47
47
|
const result = await page.evaluate(() => {
|
|
48
48
|
const el = document.getElementById("test");
|
|
49
|
-
return el.
|
|
49
|
+
return el.getVariableValue("children").toJSON();
|
|
50
50
|
});
|
|
51
51
|
expect(Array.isArray(result)).toBe(true);
|
|
52
52
|
expect(result[0]).toBe("mary");
|
|
@@ -167,7 +167,7 @@ describe('Lightview', () => {
|
|
|
167
167
|
const result = await page.evaluate(async () => {
|
|
168
168
|
const el0 = document.getElementById("test"),
|
|
169
169
|
el1 = document.getElementById("test1")
|
|
170
|
-
return [el0.
|
|
170
|
+
return [el0.getVariableValue("myshare"),el1.getVariableValue("myshare")];
|
|
171
171
|
});
|
|
172
172
|
expect(Array.isArray(result)).toBe(true);
|
|
173
173
|
expect(result[0]).toBe(result[1]);
|
|
@@ -182,21 +182,78 @@ describe('Lightview', () => {
|
|
|
182
182
|
expect(result).toBe("test");
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const f = Function(`return async () => {
|
|
185
|
+
|
|
186
|
+
test('text input - itext should be test', async () => {
|
|
188
187
|
const result = await page.evaluate(async () => {
|
|
189
188
|
const el = document.getElementById("test"),
|
|
190
|
-
result = el.getElementById(
|
|
191
|
-
return
|
|
189
|
+
result = el.getElementById(`itext`);
|
|
190
|
+
return result.getAttribute("value");
|
|
192
191
|
});
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
192
|
+
expect(result).toBe("test");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
test('tel input - itel should be test', async () => {
|
|
197
|
+
const result = await page.evaluate(async () => {
|
|
198
|
+
const el = document.getElementById("test"),
|
|
199
|
+
result = el.getElementById("itel");
|
|
200
|
+
return result.getAttribute("value");
|
|
201
|
+
});
|
|
202
|
+
expect(result).toBe("test");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test('email input - email should be test', async () => {
|
|
206
|
+
const result = await page.evaluate(async () => {
|
|
207
|
+
const el = document.getElementById("test"),
|
|
208
|
+
result = el.getElementById("iemail");
|
|
209
|
+
return result.getAttribute("value");
|
|
210
|
+
});
|
|
211
|
+
expect(result).toBe("test");
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test('url input - url should be test', async () => {
|
|
215
|
+
const result = await page.evaluate(async () => {
|
|
216
|
+
const el = document.getElementById("test"),
|
|
217
|
+
result = el.getElementById("iurl");
|
|
218
|
+
return result.getAttribute("value");
|
|
219
|
+
});
|
|
220
|
+
expect(result).toBe("test");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('search input - search should be test', async () => {
|
|
224
|
+
const result = await page.evaluate(async () => {
|
|
225
|
+
const el = document.getElementById("test"),
|
|
226
|
+
result = el.getElementById("isearch");
|
|
227
|
+
return result.getAttribute("value");
|
|
228
|
+
});
|
|
229
|
+
expect(result).toBe("test");
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test('radio input - radio should be test', async () => {
|
|
233
|
+
const result = await page.evaluate(async () => {
|
|
234
|
+
const el = document.getElementById("test"),
|
|
235
|
+
result = el.getElementById("iradio");
|
|
236
|
+
return result.checked;
|
|
237
|
+
});
|
|
238
|
+
expect(result).toBe(true);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('color input - color should be test', async () => {
|
|
242
|
+
const result = await page.evaluate(async () => {
|
|
243
|
+
const el = document.getElementById("test"),
|
|
244
|
+
result = el.getElementById("icolor");
|
|
245
|
+
return result.getAttribute("value");
|
|
246
|
+
});
|
|
247
|
+
expect(result).toBe("test");
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test('password input - password should be test', async () => {
|
|
251
|
+
const result = await page.evaluate(async () => {
|
|
252
|
+
const el = document.getElementById("test"),
|
|
253
|
+
result = el.getElementById("ipassword");
|
|
254
|
+
return result.getAttribute("value");
|
|
255
|
+
});
|
|
256
|
+
expect(result).toBe("test");
|
|
200
257
|
});
|
|
201
258
|
|
|
202
259
|
test('number input - inumber should be 1', async () => {
|
|
@@ -232,17 +289,37 @@ describe('Lightview', () => {
|
|
|
232
289
|
const result = await page.evaluate(async () => {
|
|
233
290
|
const el = document.getElementById("test"),
|
|
234
291
|
result = el.getElementById("icheckbox")
|
|
235
|
-
return
|
|
292
|
+
return result.checked;
|
|
236
293
|
});
|
|
237
294
|
expect(result).toBe(true);
|
|
238
295
|
});
|
|
296
|
+
});
|
|
239
297
|
|
|
298
|
+
describe("Lightview - on: directive", () => {
|
|
240
299
|
test('on:<handler> - count should be bumped', async () => {
|
|
241
300
|
await page.click("#test",{waitUntil:"load"});
|
|
242
301
|
const result = await page.evaluate(async () => {
|
|
243
302
|
const el = document.getElementById("test");
|
|
244
|
-
return JSON.parse(el.
|
|
303
|
+
return JSON.parse(el.getVariableValue("counter"));
|
|
245
304
|
});
|
|
246
305
|
expect(result).toBe(1);
|
|
247
306
|
});
|
|
248
|
-
})
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
describe("Lightview - lifecycle", () => {
|
|
310
|
+
test('connected should be called', async () => {
|
|
311
|
+
const result = await page.evaluate(async () => {
|
|
312
|
+
const el = document.getElementById("test");
|
|
313
|
+
return el.testId;
|
|
314
|
+
});
|
|
315
|
+
expect(result).toBe("test");
|
|
316
|
+
});
|
|
317
|
+
test('change should be called', async () => {
|
|
318
|
+
await page.click("#test",{waitUntil:"load"});
|
|
319
|
+
const result = await page.evaluate(async () => {
|
|
320
|
+
const el = document.getElementById("test");
|
|
321
|
+
return el.counter;
|
|
322
|
+
});
|
|
323
|
+
expect(result).toBe(2);
|
|
324
|
+
});
|
|
325
|
+
})
|
package/types.js
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
function ValidityState(options) {
|
|
2
|
+
if(!this || !(this instanceof ValidityState)) return new ValidityState(options);
|
|
3
|
+
Object.assign(this,{
|
|
4
|
+
valid:false,
|
|
5
|
+
badInput:undefined,
|
|
6
|
+
customError:undefined,
|
|
7
|
+
patternMismatch:undefined,
|
|
8
|
+
rangeUnderflow:undefined,
|
|
9
|
+
rangeOverflow:undefined,
|
|
10
|
+
typeMismatch:undefined,
|
|
11
|
+
valueMissing:undefined,
|
|
12
|
+
stepMistmatch:undefined,
|
|
13
|
+
tooLong:undefined,
|
|
14
|
+
tooShort:undefined
|
|
15
|
+
},options);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const tryParse = (value) => {
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(value+"")
|
|
21
|
+
} catch(e) {
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const ifInvalid = (variable) => {
|
|
27
|
+
variable.validityState.type = typeof(variable.type)==="string" ? variable.type : variable.type.type;
|
|
28
|
+
throw new TypeError(JSON.stringify(variable));
|
|
29
|
+
// or could return existing value variable.value
|
|
30
|
+
// or could return nothing
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const validateAny = function(value,variable) {
|
|
34
|
+
if(value===undefined && variable.value===undefined) {
|
|
35
|
+
return this.default;
|
|
36
|
+
}
|
|
37
|
+
if(this.required && value==null) {
|
|
38
|
+
variable.validityState = ValidityState({valueMissing: true});
|
|
39
|
+
} else {
|
|
40
|
+
variable.validityState = ValidityState({valid:true});
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
return this.whenInvalid(variable);
|
|
44
|
+
}
|
|
45
|
+
const any = ({required=false,whenInvalid = ifInvalid,...rest}) => { // ...rest allows use of property "default", which is otherwise reserved
|
|
46
|
+
if(typeof(required)!=="boolean") throw new TypeError(`required, ${JSON.stringify(required)}, must be a boolean`);
|
|
47
|
+
if(typeof(whenInvalid)!=="function") throw new TypeError(`whenInvalid, ${whenInvalid}, must be a function`);
|
|
48
|
+
return {
|
|
49
|
+
type: "any",
|
|
50
|
+
required,
|
|
51
|
+
whenInvalid,
|
|
52
|
+
...rest,
|
|
53
|
+
validate: validateAny
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
any.validate = validateAny;
|
|
57
|
+
any.required = false;
|
|
58
|
+
|
|
59
|
+
const validateArray = function(value,variable) {
|
|
60
|
+
if(value===undefined && variable.value===undefined) {
|
|
61
|
+
return this.default;
|
|
62
|
+
}
|
|
63
|
+
if(this.required && value==null) {
|
|
64
|
+
variable.validityState = ValidityState({valueMissing: true});
|
|
65
|
+
} else {
|
|
66
|
+
let result = this.coerce && typeof(value)==="string" ? tryParse(value.startsWith("[") ? value : `[${value}]`) : value;
|
|
67
|
+
if (!Array.isArray(result)) {
|
|
68
|
+
if (value.includes(",")) result = value.split(",");
|
|
69
|
+
}
|
|
70
|
+
if(typeof(result)!=="object" || !(result instanceof Array || Array.isArray(result))) {
|
|
71
|
+
variable.validityState = ValidityState({typeMismatch:true,value});
|
|
72
|
+
} else if(result.length<this.minlength) {
|
|
73
|
+
variable.validityState = ValidityState({tooShort:true,value});
|
|
74
|
+
} else if(result.length>this.maxlength) {
|
|
75
|
+
variable.validityState = ValidityState({tooLong:true,value});
|
|
76
|
+
} else {
|
|
77
|
+
variable.validityState = ValidityState({valid:true});
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return this.whenInvalid(variable);
|
|
82
|
+
}
|
|
83
|
+
const array = ({coerce=false, required = false,whenInvalid = ifInvalid,maxlength=Infinity,minlength=0,...rest}) => {
|
|
84
|
+
if(typeof(coerce)!=="boolean") throw new TypeError(`coerce, ${JSON.stringify(coerce)}, must be a boolean`);
|
|
85
|
+
if(typeof(required)!=="boolean") throw new TypeError(`required, ${JSON.stringify(required)}, must be a boolean`);
|
|
86
|
+
if(typeof(whenInvalid)!=="function") throw new TypeError(`whenInvalid, ${whenInvalid}, must be a function`);
|
|
87
|
+
if(typeof(maxlength)!=="number") throw new TypeError(`maxlength, ${JSON.stringify(maxlength)}, must be a number`);
|
|
88
|
+
if(typeof(minlength)!=="number") throw new TypeError(`minlength, ${JSON.stringify(minlength)}, must be a number`);
|
|
89
|
+
if(rest.default!==undefined && (typeof(rest.default)!=="object" || !(rest.default instanceof Array || Array.isArray(rest.default)))) throw new TypeError(`default, ${rest.default}, must be an Array`);
|
|
90
|
+
return {
|
|
91
|
+
type: "array",
|
|
92
|
+
coerce,
|
|
93
|
+
required,
|
|
94
|
+
whenInvalid,
|
|
95
|
+
maxlength,
|
|
96
|
+
minlength,
|
|
97
|
+
...rest,
|
|
98
|
+
validate: validateArray
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
array.validate = validateArray;
|
|
102
|
+
array.coerce = false;
|
|
103
|
+
array.required = false;
|
|
104
|
+
|
|
105
|
+
const validateBoolean = function(value,variable) {
|
|
106
|
+
if(value===undefined && variable.value===undefined) {
|
|
107
|
+
return this.default;
|
|
108
|
+
}
|
|
109
|
+
if(variable.value===undefined) value = this.default;
|
|
110
|
+
if(this.required && value==null) {
|
|
111
|
+
variable.validityState = ValidityState({valueMissing: true});
|
|
112
|
+
} else {
|
|
113
|
+
const result = !!(this.coerce ? tryParse(value) : value);
|
|
114
|
+
if(typeof(result)!=="boolean") {
|
|
115
|
+
variable.validityState = ValidityState({typeMismatch: true, value});
|
|
116
|
+
} else {
|
|
117
|
+
variable.validityState = ValidityState({valid:true});
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return this.whenInvalid(variable);
|
|
122
|
+
}
|
|
123
|
+
const boolean = ({coerce=false,required=false, whenInvalid = ifInvalid,...rest}) =>{
|
|
124
|
+
if(typeof(coerce)!=="boolean") throw new TypeError(`coerce, ${JSON.stringify(coerce)}, must be a boolean`);
|
|
125
|
+
if(typeof(required)!=="boolean") throw new TypeError(`required, ${JSON.stringify(required)}, must be a boolean`);
|
|
126
|
+
if(typeof(whenInvalid)!=="function") throw new TypeError(`whenInvalid, ${whenInvalid}, must be a function`);
|
|
127
|
+
if(rest.default!==undefined && typeof(rest.default)!=="boolean") throw new TypeError(`default, ${rest.default}, must be a boolean`);
|
|
128
|
+
return {
|
|
129
|
+
type: "boolean",
|
|
130
|
+
coerce,
|
|
131
|
+
required,
|
|
132
|
+
whenInvalid,
|
|
133
|
+
...rest,
|
|
134
|
+
validate: validateBoolean
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
boolean.validate = validateBoolean;
|
|
138
|
+
boolean.coerce = false;
|
|
139
|
+
boolean.required = false;
|
|
140
|
+
|
|
141
|
+
const validateNumber = function(value,variable) {
|
|
142
|
+
if(value===undefined && variable.value===undefined) {
|
|
143
|
+
return this.default;
|
|
144
|
+
}
|
|
145
|
+
if(this.required && value==null) {
|
|
146
|
+
variable.validityState = ValidityState({valueMissing: true});
|
|
147
|
+
} else {
|
|
148
|
+
const result = this.coerce ? tryParse(value) : value;
|
|
149
|
+
if(typeof(result)!=="number") {
|
|
150
|
+
variable.validityState = ValidityState({typeMismatch:true,value});
|
|
151
|
+
} else if(isNaN(result) && !allowNaN) {
|
|
152
|
+
variable.validityState = ValidityState({badInput:true,value});
|
|
153
|
+
} else if(result<this.min) {
|
|
154
|
+
variable.validityState = ValidityState({rangeUnderflow:true,value});
|
|
155
|
+
} else if(result>this.max) {
|
|
156
|
+
variable.validityState = ValidityState({rangeOverflow:true,value});
|
|
157
|
+
} else if((result % this.step)!==0) {
|
|
158
|
+
variable.validityState = ValidityState({rangeUnderflow:true,value});
|
|
159
|
+
} else {
|
|
160
|
+
variable.validityState = ValidityState({valid:true});
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return this.whenInvalid(variable);
|
|
165
|
+
}
|
|
166
|
+
const number = ({coerce=false,required = false,whenInvalid = ifInvalid,min=-Infinity,max=Infinity,step = 1,allowNaN = true,...rest}) => {
|
|
167
|
+
if(typeof(coerce)!=="boolean") throw new TypeError(`coerce, ${JSON.stringify(coerce)}, must be a boolean`);
|
|
168
|
+
if(typeof(required)!=="boolean") throw new TypeError(`required, ${JSON.stringify(required)}, must be a boolean`);
|
|
169
|
+
if(typeof(whenInvalid)!=="function") throw new TypeError(`whenInvalid, ${whenInvalid}, must be a function`);
|
|
170
|
+
if(typeof(min)!=="number") throw new TypeError(`min, ${JSON.stringify(min)}, must be a number`);
|
|
171
|
+
if(typeof(max)!=="number") throw new TypeError(`max, ${JSON.stringify(max)}, must be a number`);
|
|
172
|
+
if(typeof(step)!=="number") throw new TypeError(`step, ${JSON.stringify(step)}, must be a number`);
|
|
173
|
+
if(typeof(allowNaN)!=="boolean") throw new TypeError(`step, ${JSON.stringify(allowNaN)}, must be a boolean`);
|
|
174
|
+
if(rest.default!==undefined && typeof(rest.default)!=="number") throw new TypeError(`default, ${rest.default}, must be a number`);
|
|
175
|
+
return {
|
|
176
|
+
type: "number",
|
|
177
|
+
coerce,
|
|
178
|
+
required,
|
|
179
|
+
whenInvalid,
|
|
180
|
+
min,
|
|
181
|
+
max,
|
|
182
|
+
step,
|
|
183
|
+
allowNaN,
|
|
184
|
+
...rest,
|
|
185
|
+
validate: validateNumber
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
number.validate = validateNumber;
|
|
189
|
+
number.min = -Infinity;
|
|
190
|
+
number.max = Infinity;
|
|
191
|
+
number.coerce = false;
|
|
192
|
+
number.required = false;
|
|
193
|
+
number.allwNaN = true;
|
|
194
|
+
number.step = 1;
|
|
195
|
+
|
|
196
|
+
const validateObject = function(value,variable) {
|
|
197
|
+
if(value===undefined && variable.value===undefined) {
|
|
198
|
+
return this.default;
|
|
199
|
+
}
|
|
200
|
+
if(this.required && value==null) {
|
|
201
|
+
variable.validityState = ValidityState({valueMissing: true});
|
|
202
|
+
} else {
|
|
203
|
+
const result = this.coerce ? tryParse(value) : value;
|
|
204
|
+
if(typeof(result)!=="object") {
|
|
205
|
+
variable.validityState = ValidityState({typeMismatch:true,value});
|
|
206
|
+
} else {
|
|
207
|
+
variable.validityState = ValidityState({valid:true});
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return this.whenInvalid(variable);
|
|
212
|
+
}
|
|
213
|
+
const object = ({coerce=false, required = false,whenInvalid = ifInvalid,...rest}) => {
|
|
214
|
+
if(typeof(coerce)!=="boolean") throw new TypeError(`coerce, ${JSON.stringify(coerce)}, must be a boolean`);
|
|
215
|
+
if(typeof(required)!=="boolean") throw new TypeError(`required, ${JSON.stringify(required)}, must be a boolean`);
|
|
216
|
+
if(typeof(whenInvalid)!=="function") throw new TypeError(`whenInvalid, ${whenInvalid}, must be a function`);
|
|
217
|
+
if(rest.default!==undefined && typeof(rest.default)!=="object") throw new TypeError(`default, ${rest.default}, must be of type object`);
|
|
218
|
+
return {
|
|
219
|
+
type: "object",
|
|
220
|
+
coerce,
|
|
221
|
+
required,
|
|
222
|
+
whenInvalid,
|
|
223
|
+
...rest,
|
|
224
|
+
validate: validateObject
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
object.validate = validateObject;
|
|
228
|
+
object.coerce = false;
|
|
229
|
+
object.required = false;
|
|
230
|
+
|
|
231
|
+
const validateString = function(value,variable) {
|
|
232
|
+
if(value===undefined && variable.value===undefined) {
|
|
233
|
+
return this.default;
|
|
234
|
+
}
|
|
235
|
+
if(this.required && value==null) {
|
|
236
|
+
variable.validityState = ValidityState({valueMissing: true});
|
|
237
|
+
} else {
|
|
238
|
+
const result = this.coerce ? value+"" : value;
|
|
239
|
+
if(typeof(result)!=="string") {
|
|
240
|
+
variable.validityState = ValidityState({typeMismatch:true,value});
|
|
241
|
+
} else if(result.length<this.minlength) {
|
|
242
|
+
variable.validityState = ValidityState({tooShort:true,value});
|
|
243
|
+
} else if(result.length>this.maxlength) {
|
|
244
|
+
variable.validityState = ValidityState({tooLong:true,value});
|
|
245
|
+
} else {
|
|
246
|
+
variable.validityState = ValidityState({valid:true});
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return this.whenInvalid(variable);
|
|
251
|
+
}
|
|
252
|
+
const string = ({coerce=false, required = false,whenInvalid = ifInvalid, maxlength = Infinity, minlength = 0, pattern, ...rest}) => {
|
|
253
|
+
if(typeof(coerce)!=="boolean") throw new TypeError(`coerce, ${JSON.stringify(coerce)}, must be a boolean`);
|
|
254
|
+
if(typeof(required)!=="boolean") throw new TypeError(`required, ${JSON.stringify(required)}, must be a boolean`);
|
|
255
|
+
if(typeof(whenInvalid)!=="function") throw new TypeError(`whenInvalid, ${whenInvalid}, must be a function`);
|
|
256
|
+
if(typeof(maxlength)!=="number") throw new TypeError(`maxlength, ${JSON.stringify(maxlength)}, must be a number`);
|
|
257
|
+
if(typeof(minlength)!=="number") throw new TypeError(`minlength, ${JSON.stringify(minlength)}, must be a number`);
|
|
258
|
+
if(pattern && (typeof(pattern)!=="object" || !(pattern instanceof RegExp))) throw new TypeError(`pattern, ${pattern}, must be a RegExp`);
|
|
259
|
+
if(rest.default!==undefined && typeof(rest.default)!=="string") throw new TypeError(`default, ${rest.default}, must be a string`);
|
|
260
|
+
return {
|
|
261
|
+
type: "string",
|
|
262
|
+
coerce,
|
|
263
|
+
required,
|
|
264
|
+
whenInvalid,
|
|
265
|
+
maxlength,
|
|
266
|
+
minlength,
|
|
267
|
+
...rest,
|
|
268
|
+
validate: validateString
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
string.validate = validateString;
|
|
272
|
+
string.coerce = false;
|
|
273
|
+
string.required = false;
|
|
274
|
+
string.maxlength = Infinity;
|
|
275
|
+
string.minlength = 0;
|
|
276
|
+
|
|
277
|
+
const validateSymbol = function(value,variable) {
|
|
278
|
+
if(value===undefined && variable.value===undefined) {
|
|
279
|
+
return this.default;
|
|
280
|
+
}
|
|
281
|
+
if(this.required && value==null) {
|
|
282
|
+
variable.validityState = ValidityState({valueMissing: true});
|
|
283
|
+
} else {
|
|
284
|
+
const result = !!(this.coerce && typeof(value)!=="symbol" ? Symbol(value+"") : value);
|
|
285
|
+
if(typeof(result)!=="symbol") {
|
|
286
|
+
variable.validityState = ValidityState({typeMismatch: true, value});
|
|
287
|
+
} else {
|
|
288
|
+
variable.validityState = ValidityState({valid:true});
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return this.whenInvalid(variable);
|
|
293
|
+
}
|
|
294
|
+
const symbol = ({coerce=false,required=false, whenInvalid = ifInvalid,...rest}) =>{
|
|
295
|
+
if(typeof(coerce)!=="boolean") throw new TypeError(`coerce, ${JSON.stringify(coerce)}, must be a boolean`);
|
|
296
|
+
if(typeof(required)!=="boolean") throw new TypeError(`required, ${JSON.stringify(required)}, must be a boolean`);
|
|
297
|
+
if(typeof(whenInvalid)!=="function") throw new TypeError(`whenInvalid, ${whenInvalid}, must be a function`);
|
|
298
|
+
if(rest.default!==undefined && typeof(rest.default)!=="symbol") throw new TypeError(`default, ${rest.default}, must be a symbol`);
|
|
299
|
+
return {
|
|
300
|
+
type: "symbol",
|
|
301
|
+
coerce,
|
|
302
|
+
required,
|
|
303
|
+
whenInvalid,
|
|
304
|
+
...rest,
|
|
305
|
+
validate: validateSymbol
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
symbol.validate = validateSymbol;
|
|
309
|
+
symbol.coerce = false;
|
|
310
|
+
symbol.required = false;
|
|
311
|
+
|
|
312
|
+
export {ValidityState,any,array,boolean,number,string,symbol}
|