lightview 1.6.3-b → 1.6.4-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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # lightview v1.6.3b (BETA)
1
+ # lightview v1.6.4b (BETA)
2
2
 
3
3
  Small, simple, powerful web UI and micro front end creation ...
4
4
 
package/jest.config.json CHANGED
@@ -9,4 +9,4 @@
9
9
  "globalSetup": "jest-environment-puppeteer/setup",
10
10
  "globalTeardown": "jest-environment-puppeteer/teardown",
11
11
  "testEnvironment": "jest-environment-puppeteer"
12
- }
12
+ }
package/lightview.js CHANGED
@@ -241,10 +241,13 @@ const {observe} = (() => {
241
241
  const variable = target[property],
242
242
  {type, value, shared, exported, constant, reactive, remote} = variable;
243
243
  if (constant) throw new TypeError(`${property}:${type} is a constant`);
244
- newValue = type.validate ? type.validate(newValue,target[property]) : coerce(newValue,type);
244
+ if(newValue!=null || type.required) newValue = type.validate ? type.validate(newValue,target[property]) : coerce(newValue,type);
245
245
  const newtype = typeof (newValue),
246
246
  typetype = typeof (type);
247
- if (newValue == null || type === "any" || (newtype === type && typetype==="string") || (typetype === "function" && (newValue && newtype === "object" && newValue instanceof type) || variable.validityState?.valid)) {
247
+ if ((newValue == null && !type.required) ||
248
+ type === "any" ||
249
+ (newtype === type && typetype==="string") ||
250
+ (typetype === "function" && !type.validate && (newValue && newtype === "object" && newValue instanceof type) || variable.validityState?.valid)) {
248
251
  if (value !== newValue) {
249
252
  event.oldValue = value;
250
253
  target[property].value = reactive ? Reactor(newValue) : newValue; // do first to prevent loops
@@ -260,7 +263,7 @@ const {observe} = (() => {
260
263
  if (typetype === "function" && newValue && newtype === "object") {
261
264
  throw new TypeError(`Can't assign instance of '${newValue.constructor.name}' to variable '${property}:${type.name.replace("bound ", "")}'`)
262
265
  }
263
- throw new TypeError(`Can't assign '${typeof (newValue)} ${newtype === "string" ? '"' + newValue + '"' : newValue}' to variable '${property}:${typetype === "function" ? type.name.replace("bound ", "") : type}'`)
266
+ throw new TypeError(`Can't assign '${typeof (newValue)} ${newtype === "string" ? '"' + newValue + '"' : newValue}' to variable '${property}:${typetype === "function" ? type.name.replace("bound ", "") : type} ${type.required ? "required" : ""}'`)
264
267
  },
265
268
  keys() {
266
269
  return [...Object.keys(vars)];
@@ -339,7 +342,7 @@ const {observe} = (() => {
339
342
  }
340
343
  return nodes;
341
344
  }
342
- const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
345
+
343
346
  const resolveNodeOrText = (node, component, safe) => {
344
347
  const type = typeof (node),
345
348
  template = type === "string" ? node.trim() : node.template;
@@ -782,7 +785,7 @@ const {observe} = (() => {
782
785
  variable.remote = remote;
783
786
  remote.handleRemote({variable, config:remote.config, reactive,component:this});
784
787
  }
785
- if(type.validate) type.validate(variable.value,variable);
788
+ if(type.validate && variable.value!==undefined) type.validate(variable.value,variable);
786
789
  });
787
790
  }
788
791
  return Object.entries(this.vars)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightview",
3
- "version": "1.6.3b",
3
+ "version": "1.6.4b",
4
4
  "description": "Small, simple, powerful web UI and micro front end creation ... Great ideas from Svelte, React, Vue and Riot combined.",
5
5
  "main": "lightview.js",
6
6
  "scripts": {
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Extended</title>
6
+ <script src="../lightview.js?as=x-body"></script>
7
+ </head>
8
+ <body>
9
+ <script type="lightview/module">
10
+ const {array,boolean,number,object,string} = await import("../types.js");
11
+
12
+ self.variables({strictarray:array},{set:[]});
13
+ self.variables({strictboolean:boolean},{set:true});
14
+ self.variables({strictnumber:number},{set:0});
15
+ self.variables({strictobject:object},{set:{}});
16
+ self.variables({strictstring:string},{set:"test"});
17
+
18
+
19
+ self.variables({requiredarray:array({required:true})});
20
+ self.variables({requiredboolean:boolean({required:true})});
21
+ self.variables({requirednumber:number({required:true})});
22
+ self.variables({requiredobject:object({required:true})});
23
+ self.variables({requiredstring:string({required:true})});
24
+
25
+ //self.setVariableValue("requirednumber",null);
26
+
27
+ </script>
28
+ </body>
29
+ </html>
@@ -0,0 +1,270 @@
1
+ import 'expect-puppeteer';
2
+ function reviver(property,value) {
3
+ if(value==="@-Infinity") return -Infinity;
4
+ if(value==="@Infinity") return Infinity;
5
+ if(value==="@NaN") return NaN;
6
+ return value;
7
+ }
8
+
9
+ describe('Lightview - Variables', () => {
10
+ beforeAll(async () => {
11
+ await page.goto('http://localhost:8080/test/extended.html');
12
+ });
13
+
14
+ test('should be titled "Extended"', async () => {
15
+ await expect(page.title()).resolves.toMatch('Extended');
16
+ });
17
+
18
+ test('strictarray - should be array', async () => {
19
+ const result = await page.evaluate(() => {
20
+ return document.body.getVariableValue("strictarray")
21
+ });
22
+ expect(Array.isArray(result)).toBe(true);
23
+ });
24
+
25
+ test('strictarray - should set', async () => {
26
+ const result = await page.evaluate(() => {
27
+ try {
28
+ document.body.setVariableValue("strictarray",[]);
29
+ } catch(e) {
30
+ return e;
31
+ }
32
+ return document.body.getVariableValue("strictarray")
33
+ });
34
+ expect(Array.isArray(result)).toBe(true);
35
+ });
36
+
37
+ test('strictarray - should allow null', async () => {
38
+ const result = await page.evaluate(() => {
39
+ try {
40
+ document.body.setVariableValue("strictarray",undefined);
41
+ document.body.setVariableValue("strictarray",null);
42
+ } catch(e) {
43
+ return e;
44
+ }
45
+ return document.body.getVariableValue("strictarray")
46
+ });
47
+ expect(result).toBe(null);
48
+ });
49
+
50
+ test('strictarray - should throw', async () => {
51
+ const result = await page.evaluate(() => {
52
+ try {
53
+ document.body.setVariableValue("strictarray","false");
54
+ } catch(e) {
55
+ return e.message;
56
+ }
57
+ return document.body.getVariableValue("strictarray");
58
+ });
59
+ const {name,validityState} = JSON.parse(result,reviver);
60
+ expect(name).toBe("strictarray");
61
+ expect(validityState.typeMismatch).toBe(true);
62
+ expect(validityState.value).toBe("false");
63
+ });
64
+
65
+ test('strictboolean - should be boolean', async () => {
66
+ const result = await page.evaluate(() => {
67
+ return document.body.getVariableValue("strictboolean")
68
+ });
69
+ expect(result).toBe(true);
70
+ });
71
+
72
+ test('strictboolean - should set', async () => {
73
+ const result = await page.evaluate(() => {
74
+ try {
75
+ document.body.setVariableValue("strictboolean",false);
76
+ } catch(e) {
77
+ return e.message;
78
+ }
79
+ return document.body.getVariableValue("strictboolean")
80
+ });
81
+ expect(result).toBe(false);
82
+ });
83
+
84
+ test('strictboolean - should allow null', async () => {
85
+ const result = await page.evaluate(() => {
86
+ try {
87
+ document.body.setVariableValue("strictboolean",undefined);
88
+ document.body.setVariableValue("strictboolean",null);
89
+ } catch(e) {
90
+ return e.message;
91
+ }
92
+ return document.body.getVariableValue("strictboolean")
93
+ });
94
+ expect(result).toBe(null);
95
+ });
96
+
97
+ test('strictboolean - should throw', async () => {
98
+ const result = await page.evaluate(() => {
99
+ try {
100
+ document.body.setVariableValue("strictboolean","true");
101
+ } catch(e) {
102
+ return e.message;
103
+ }
104
+ return document.body.getVariableValue("strictboolean");
105
+ });
106
+ const {name,validityState} = JSON.parse(result,reviver);
107
+ expect(name).toBe("strictboolean");
108
+ expect(validityState.typeMismatch).toBe(true);
109
+ expect(validityState.value).toBe("true");
110
+ });
111
+
112
+ test('strictnumber - should be number', async () => {
113
+ const result = await page.evaluate(() => {
114
+ return document.body.getVariableValue("strictnumber")
115
+ });
116
+ expect(result).toBe(0);
117
+ });
118
+
119
+ test('strictnumber - should set', async () => {
120
+ const result = await page.evaluate(() => {
121
+ try {
122
+ document.body.setVariableValue("strictnumber",1);
123
+ } catch(e) {
124
+ return e.message;
125
+ }
126
+ return document.body.getVariableValue("strictnumber")
127
+ });
128
+ expect(result).toBe(1);
129
+ });
130
+
131
+ test('strictnumber - should allow null', async () => {
132
+ const result = await page.evaluate(() => {
133
+ try {
134
+ document.body.setVariableValue("strictnumber",undefined);
135
+ document.body.setVariableValue("strictnumber",null);
136
+ } catch(e) {
137
+ return e.message;
138
+ }
139
+ return document.body.getVariableValue("strictnumber")
140
+ });
141
+ expect(result).toBe(null);
142
+ });
143
+
144
+ test('strictnumber - should throw', async () => {
145
+ const result = await page.evaluate(() => {
146
+ try {
147
+ document.body.setVariableValue("strictnumber","0");
148
+ } catch(e) {
149
+ return e.message;
150
+ }
151
+ return document.body.getVariableValue("strictnumber");
152
+ });
153
+ const {name,validityState} = JSON.parse(result,reviver);
154
+ expect(name).toBe("strictnumber");
155
+ expect(validityState.typeMismatch).toBe(true);
156
+ expect(validityState.value).toBe("0");
157
+ });
158
+
159
+ test('strictobject - should be object', async () => {
160
+ const result = await page.evaluate(() => {
161
+ return document.body.getVariableValue("strictobject")
162
+ });
163
+ expect(typeof(result)).toBe("object");
164
+ expect(Object.keys(result).length).toBe(0);
165
+ });
166
+
167
+ test('strictobject - should set', async () => {
168
+ const result = await page.evaluate(() => {
169
+ try {
170
+ document.body.setVariableValue("strictobject", {test:"test"});
171
+ } catch(e) {
172
+ return e.message;
173
+ }
174
+ return document.body.getVariableValue("strictobject")
175
+ });
176
+ expect(typeof(result)).toBe("object");
177
+ expect(Object.keys(result).length).toBe(1);
178
+ expect(result.test).toBe("test");
179
+ });
180
+
181
+ test('strictobject - should allow null', async () => {
182
+ const result = await page.evaluate(() => {
183
+ try {
184
+ document.body.setVariableValue("strictobject",undefined);
185
+ document.body.setVariableValue("strictobject",null);
186
+ } catch(e) {
187
+ return e.message;
188
+ }
189
+ return document.body.getVariableValue("strictobject")
190
+ });
191
+ expect(result).toBe(null);
192
+ });
193
+
194
+ test('strictobject - should throw', async () => {
195
+ const result = await page.evaluate(() => {
196
+ try {
197
+ document.body.setVariableValue("strictobject","false");
198
+ } catch(e) {
199
+ return e.message;
200
+ }
201
+ return document.body.getVariableValue("strictobject");
202
+ });
203
+ const {name,validityState} = JSON.parse(result,reviver);
204
+ expect(name).toBe("strictobject");
205
+ expect(validityState.typeMismatch).toBe(true);
206
+ expect(validityState.value).toBe("false");
207
+ });
208
+
209
+ test('strictstring - should be string', async () => {
210
+ const result = await page.evaluate(() => {
211
+ return document.body.getVariableValue("strictstring")
212
+ });
213
+ expect(result).toBe("test");
214
+ });
215
+
216
+ test('strictstring - should set', async () => {
217
+ const result = await page.evaluate(() => {
218
+ try {
219
+ document.body.setVariableValue("strictstring","anothertest");
220
+ } catch(e) {
221
+ return e.message;
222
+ }
223
+ return document.body.getVariableValue("strictstring")
224
+ });
225
+ expect(result).toBe("anothertest");
226
+ });
227
+
228
+ test('strictstring - should allow null', async () => {
229
+ const result = await page.evaluate(() => {
230
+ try {
231
+ document.body.setVariableValue("strictstring",undefined);
232
+ document.body.setVariableValue("strictstring",null);
233
+ } catch(e) {
234
+ return e.message;
235
+ }
236
+ return document.body.getVariableValue("strictstring")
237
+ });
238
+ expect(result).toBe(null);
239
+ });
240
+
241
+ test('strictstring - should throw', async () => {
242
+ const result = await page.evaluate(() => {
243
+ try {
244
+ document.body.setVariableValue("strictstring",0);
245
+ } catch(e) {
246
+ return e.message;
247
+ }
248
+ return document.body.getVariableValue("strictstring");
249
+ });
250
+ const {name,validityState} = JSON.parse(result,reviver);
251
+ expect(name).toBe("strictstring");
252
+ expect(validityState.typeMismatch).toBe(true);
253
+ expect(validityState.value).toBe(0);
254
+ });
255
+
256
+ test('requirednumber - should throw and not allow null', async () => {
257
+ const result = await page.evaluate(() => {
258
+ try {
259
+ document.body.setVariableValue("requirednumber",null);
260
+ } catch(e) {
261
+ return e.message;
262
+ }
263
+ return document.body.getVariableValue("requirednumber")
264
+ });
265
+ const {name,validityState} = JSON.parse(result,reviver);
266
+ expect(name).toBe("requirednumber");
267
+ expect(validityState.valueMissing).toBe(true);
268
+ //expect(validityState.value).toBe(null);
269
+ });
270
+ })
package/types.js CHANGED
@@ -1,3 +1,23 @@
1
+ const toJSON = (value) => {
2
+ if([-Infinity,Infinity].includes(value)) return `@${value}`;
3
+ if(typeof(value)==="number" && isNaN(value)) return "@NaN";
4
+ if(value && typeof(value)==="object") {
5
+ return Object.entries(value)
6
+ .reduce((json,[key,value]) => {
7
+ if(value && typeof(value)==="object" && value.toJSON) value = value.toJSON();
8
+ json[key] = toJSON(value);
9
+ return json;
10
+ },Array.isArray(value) ? [] : {})
11
+ }
12
+ return value;
13
+ };
14
+ function reviver(property,value) {
15
+ if(value==="@-Infinity") return -Infinity;
16
+ if(value==="@Infinity") return Infinity;
17
+ if(value==="@NaN") return NaN;
18
+ return value;
19
+ }
20
+
1
21
  function ValidityState(options) {
2
22
  if(!this || !(this instanceof ValidityState)) return new ValidityState(options);
3
23
  Object.assign(this,{
@@ -15,9 +35,17 @@ function ValidityState(options) {
15
35
  },options);
16
36
  }
17
37
 
38
+ function DataType(options) {
39
+ if(!this || !(this instanceof DataType)) return new DataType(options);
40
+ Object.assign(this,options);
41
+ }
42
+ DataType.prototype.toJSON = function() {
43
+ return toJSON(this);
44
+ }
45
+
18
46
  const tryParse = (value) => {
19
47
  try {
20
- return JSON.parse(value+"")
48
+ return JSON.parse(value+"",reviver)
21
49
  } catch(e) {
22
50
 
23
51
  }
@@ -25,7 +53,7 @@ const tryParse = (value) => {
25
53
 
26
54
  const ifInvalid = (variable) => {
27
55
  variable.validityState.type = typeof(variable.type)==="string" ? variable.type : variable.type.type;
28
- throw new TypeError(JSON.stringify(variable));
56
+ throw new TypeError(JSON.stringify(DataType(variable)));
29
57
  // or could return existing value variable.value
30
58
  // or could return nothing
31
59
  }
@@ -99,6 +127,7 @@ const array = ({coerce=false, required = false,whenInvalid = ifInvalid,maxlength
99
127
  }
100
128
  }
101
129
  array.validate = validateArray;
130
+ array.whenInvalid = ifInvalid;
102
131
  array.coerce = false;
103
132
  array.required = false;
104
133
 
@@ -110,7 +139,7 @@ const validateBoolean = function(value,variable) {
110
139
  if(this.required && value==null) {
111
140
  variable.validityState = ValidityState({valueMissing: true});
112
141
  } else {
113
- const result = !!(this.coerce ? tryParse(value) : value);
142
+ const result = this.coerce ? tryParse(value) : value;
114
143
  if(typeof(result)!=="boolean") {
115
144
  variable.validityState = ValidityState({typeMismatch: true, value});
116
145
  } else {
@@ -135,6 +164,7 @@ const boolean = ({coerce=false,required=false, whenInvalid = ifInvalid,...rest})
135
164
  }
136
165
  }
137
166
  boolean.validate = validateBoolean;
167
+ boolean.whenInvalid = ifInvalid;
138
168
  boolean.coerce = false;
139
169
  boolean.required = false;
140
170
 
@@ -186,11 +216,12 @@ const number = ({coerce=false,required = false,whenInvalid = ifInvalid,min=-Infi
186
216
  }
187
217
  }
188
218
  number.validate = validateNumber;
219
+ number.whenInvalid = ifInvalid;
189
220
  number.min = -Infinity;
190
221
  number.max = Infinity;
191
222
  number.coerce = false;
192
223
  number.required = false;
193
- number.allwNaN = true;
224
+ number.allowNaN = true;
194
225
  number.step = 1;
195
226
 
196
227
  const validateObject = function(value,variable) {
@@ -225,6 +256,7 @@ const object = ({coerce=false, required = false,whenInvalid = ifInvalid,...rest}
225
256
  }
226
257
  }
227
258
  object.validate = validateObject;
259
+ object.whenInvalid = ifInvalid;
228
260
  object.coerce = false;
229
261
  object.required = false;
230
262
 
@@ -269,6 +301,7 @@ const string = ({coerce=false, required = false,whenInvalid = ifInvalid, maxleng
269
301
  }
270
302
  }
271
303
  string.validate = validateString;
304
+ string.whenInvalid = ifInvalid;
272
305
  string.coerce = false;
273
306
  string.required = false;
274
307
  string.maxlength = Infinity;
@@ -306,6 +339,7 @@ const symbol = ({coerce=false,required=false, whenInvalid = ifInvalid,...rest})
306
339
  }
307
340
  }
308
341
  symbol.validate = validateSymbol;
342
+ symbol.whenInvalid = ifInvalid;
309
343
  symbol.coerce = false;
310
344
  symbol.required = false;
311
345
 
@@ -442,4 +476,4 @@ const remote = (config) => {
442
476
  }
443
477
  }
444
478
 
445
- export {ValidityState,any,array,boolean,number,string,symbol,remote}
479
+ export {ValidityState,any,array,boolean,number,object,string,symbol,remote,reviver}