vaderjs 1.3.3-alpha-19 → 1.3.3-alpha-21

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/runtime/vader.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  window.params = {};
3
3
  window.Vader = {
4
- version: "1.3.2",
4
+ version: "1.3.3",
5
5
  };
6
6
 
7
7
  let errors = {
@@ -43,16 +43,13 @@ let hasran = [];
43
43
  let states = {};
44
44
  let mounts = [];
45
45
  export const strictMount = (key, callback) => {
46
- let interval = setInterval(() => {
47
- if(mounts.find(mount => mount.key === key)
48
- && !hasran.includes(callback.toString())
49
- ){
46
+ let timer = setInterval(() => {
47
+ if (document.querySelector('[key="' + key + '"]')) {
48
+ console.log('mounted')
49
+ clearInterval(timer);
50
50
  callback();
51
- clearInterval(interval)
52
-
53
- hasran.push(callback.toString());
54
- }
55
- },0);
51
+ }
52
+ }, 120);
56
53
  };
57
54
 
58
55
  window.delegate = (event) => {
@@ -167,9 +164,81 @@ export class Component {
167
164
  window.listeners = [];
168
165
  this.functionMap = new Map();
169
166
  this.freeMemoryFromFunctions();
167
+ this.checkIFMounted();
170
168
  this.memoizes = []
169
+
170
+
171
+
171
172
  this.children = []
173
+
174
+
175
+ /**
176
+ * Parent of the current component.
177
+ * @type {Component}
178
+ */
179
+ this.parentNode = {}
180
+
181
+ /**
182
+ * Request object.
183
+ */
184
+ this.request = {
185
+ /**
186
+ * @type {string}
187
+ * @description The headers for the current route
188
+ */
189
+ headers:{},
190
+ /**
191
+ * @type {string}
192
+ * @description The method for the current route
193
+ */
194
+ method: "GET",
195
+ /**
196
+ * @type {string}
197
+ * @description params for the given route /:id/:name etc
198
+ */
199
+ params: {},
200
+ /**
201
+ * @type {string}
202
+ * @description path: current route path
203
+ */
204
+ path: "",
205
+ /**
206
+ * @type {string}
207
+ * @description query: query object for the current route ?name=hello -> {name: 'hello'}
208
+ */
209
+ query: {},
210
+ },
211
+ /**
212
+ * @type {string}
213
+ * @description The response object for the current route
214
+ */
215
+ this.response = {
216
+ /**
217
+ * @method json
218
+ * @description This method allows you to send json data to the client
219
+ * @param {*} data
220
+ */
221
+ json: (data) => {},
222
+ /**
223
+ * @method send
224
+ * @description This method allows you to send text data to the client
225
+ * @param {*} data
226
+ */
227
+ send: (data) => {},
228
+ /**
229
+ * @method redirect
230
+ * @description This method allows you to redirect the client to a new route
231
+ * @param {*} path
232
+ */
233
+ redirect: (path) => {},
234
+ /**
235
+ * @method render
236
+ * @description render a new component to the client
237
+ * @param {*} Component
238
+ */
239
+ render: async (Component) => {},
172
240
  }
241
+ }
173
242
 
174
243
  createComponent(/**@type {Component}**/component, props, children) {
175
244
 
@@ -179,13 +248,16 @@ export class Component {
179
248
  if(!props.key){
180
249
  throw new Error('new components must have a key')
181
250
  }
182
- let comp = new component();
183
-
251
+ let comp = new component(props);
252
+ if(this.components[props.key]){
253
+ return this.components[props.key]
254
+ }
184
255
  comp['props'] = props;
185
256
  comp.children = children;
186
257
  comp.props.children = children.join('')
187
258
  comp.parentNode = this;
188
259
  comp.key = props.key || null;
260
+
189
261
  this.components[props.key] = comp
190
262
  this.children.push(comp)
191
263
  return this.components[props.key]
@@ -202,6 +274,7 @@ export class Component {
202
274
  }
203
275
 
204
276
  let comp = this.components[component.key];
277
+
205
278
  let h = comp.render()
206
279
 
207
280
  if(h && h.split('>,').length > 1){
@@ -227,28 +300,75 @@ export class Component {
227
300
  * Hydrates the component by updating the HTML content if it has changed.
228
301
  * @private
229
302
  */
230
- hydrate() {
231
- if (this.key) {
232
-
233
- const el = document.querySelector(`[key="${this.key}"]`);
234
303
 
235
-
236
- if (el) {
237
-
238
-
239
- // Render the new HTML content
240
- const newHtml = this.render();
241
- // Compare the new HTML with the cached content
242
- if (newHtml !== this.currentHtml) {
243
- // Update the HTML only if it has changed
244
- el.innerHTML = newHtml;
245
-
246
- // Update the cached HTML content
247
- this.currentHtml = newHtml;
304
+ domDifference(oldDom, newDom) {
305
+ let diff = [];
306
+
307
+ for (let i = 0; i < oldDom.length; i++) {
308
+ let oldEl = oldDom[i];
309
+ let newEl = newDom[i];
310
+
311
+ if (oldEl && newEl && !oldEl.isEqualNode(newEl)) {
312
+ diff.push({
313
+ type: 'replace',
314
+ old: oldEl,
315
+ new: newEl.cloneNode(true),
316
+ });
317
+ }
318
+ }
319
+
320
+ return diff;
321
+ }
322
+
323
+ updateChangedElements(diff) {
324
+ diff.forEach((change) => {
325
+ switch (change.type) {
326
+ case 'replace':
327
+ change.old.parentNode.replaceChild(change.new, change.old);
328
+ break;
329
+ case 'remove':
330
+ change.old.remove();
331
+ break;
332
+ case 'add':
333
+ change.old.appendChild(change.new.cloneNode(true));
334
+ break;
335
+ default:
336
+ break;
337
+ }
338
+ });
339
+ }
340
+
341
+ hydrate(hook) {
342
+ if (this.key) {
343
+ if (hook) {
344
+ let newDom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
345
+
346
+ let oldElements = document.body.querySelectorAll(`[ref="${hook}"]`);
347
+ let newElements = newDom.querySelectorAll(`[ref="${hook}"]`);
348
+ let diff = this.domDifference(oldElements, newElements);
349
+ this.updateChangedElements(diff);
350
+ } else {
351
+ const targetElement = document.querySelector(`[key="${this.key}"]`);
352
+ if (targetElement) {
353
+ targetElement.innerHTML = this.render();
354
+ } else {
355
+ console.error('Target element not found.');
248
356
  }
249
357
  }
250
358
  }
251
359
  }
360
+
361
+
362
+
363
+ patch(oldElements, newElements) {
364
+ const diff = this.domDifference(oldElements, newElements);
365
+
366
+ this.updateChangedElements(diff);
367
+ }
368
+
369
+
370
+
371
+
252
372
 
253
373
  /**
254
374
  * Handles an object by parsing it as JSON and evaluating it.
@@ -266,7 +386,7 @@ export class Component {
266
386
  }
267
387
 
268
388
  /**
269
- * Frees memory from functions that have not been used for a certain period of time.
389
+ * Frees memory from functions that have not been used for a certain period of time.c
270
390
  * @private
271
391
  */
272
392
  freeMemoryFromFunctions() {
@@ -286,24 +406,53 @@ export class Component {
286
406
  * @param {string} ref - The reference.
287
407
  * @returns {string} - A valid inline JS function call.
288
408
  */
289
- bind(funcData,jsx,ref, params) {
409
+ bind(funcData,jsx,ref, paramNames, ...params) {
410
+
290
411
 
291
- console.log(jsx)
292
412
  const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
293
413
 
294
- var dynamicFunction = (params) => {
295
- let func = new Function(`return (async () => {
296
- ${funcData}
297
- })()`);
298
- func = func.bind(this);
299
- func(params);
414
+ var dynamicFunction = async (...params) => {
415
+
416
+ // Replace double commas with a single comma
417
+
418
+
419
+ // Turn params into a destructured object
420
+ let paramObject = {};
421
+ params = params[0]
422
+
423
+ paramNames = paramNames.replace(/,,/g, ',');
424
+ let newparamnames = paramNames.replaceAll(',,', ',')
425
+ params.forEach((param, index) => {
426
+ if(param && Object.keys(param).includes('detail')){
427
+ param = param['detail']['target']['event']
428
+ params[index] = param
429
+ }
430
+ });
431
+ // Remove trailing commas
432
+ paramNames.endsWith(',') ? paramNames = paramNames.slice(0, -1) : null;
433
+ console.log(paramNames)
434
+
435
+ params.forEach((param, index) => {
436
+ paramObject[newparamnames.split(',')[index]] = param;
437
+ });
438
+
439
+ paramNames = paramNames.replace(',,', ',');
440
+ let func = new Function(`${paramNames}`, `
441
+ return (async (${paramNames}) => {
442
+ ${funcData}
443
+ })(${Object.keys(paramObject).join(',')})
444
+ `);
445
+
446
+ // Bind and execute the function with the provided parameters
447
+ await func.bind(this)(...Object.values(paramObject));
300
448
  };
449
+
301
450
 
302
451
  dynamicFunction = dynamicFunction.bind(this);
303
452
  if (!this.functionMap.has(name)) {
304
453
  document.addEventListener(`call_${name}`, (e) => {
305
454
 
306
- dynamicFunction();
455
+ dynamicFunction(params);
307
456
  this.functionMap.set(e.detail.name, {
308
457
  lastUsed: Date.now(),
309
458
  });
@@ -325,13 +474,15 @@ export class Component {
325
474
  // Return a valid inline js function call
326
475
  return jsx ? dynamicFunction : `
327
476
  ((event) => {
328
- event.target.setAttribute('data-ref', '${ref}}');
477
+ event.target.setAttribute('data-ref', '${ref}');
329
478
  let reference = event.target.getAttribute('data-ref');
330
479
  event.target.eventData = event;
480
+
331
481
  let domquery = queryRef(reference);
332
- domquery.eventData = event;
333
- domquery.eventData.detail.target = domquery;
334
- call('${name}', {event:domquery.eventData}, '${params}')
482
+
483
+ domquery.eventData = event;
484
+ domquery.eventData.target = domquery;
485
+ call('${name}', {event:domquery.eventData}, '${paramNames}')
335
486
  })(event)
336
487
  `;
337
488
  }
@@ -389,25 +540,45 @@ export class Component {
389
540
  }
390
541
 
391
542
  /**
392
- * Uses state to dynamically update the component.
393
- * @method useState
394
- * @param {string} [key=null] - The auto-generated key.
395
- * @param {*} initialState - The initial state.
396
- * @param {Component.render} [func=null] - The render function.
397
- * @returns {Array} - An array containing the state value and the setter function.
398
- */
399
- useState(key = null, initialState) {
400
- if (!this.state[key]) {
401
- this.state[key] = initialState;
402
- }
403
- const getValue = () => this.state[key];
404
- const set = (newValue) => {
405
- this.state[key] = newValue;
406
- this.hydrate();
407
- };
408
- return [getValue, set];
543
+ * useState hook.
544
+ *
545
+ * @template T
546
+ * @param {string} key - The key for the state property.
547
+ * @param {T} initialState - The initial state value.
548
+ * @returns {[() => T, (newValue: T, hook: Function) => void]} - A tuple with getter and setter functions.
549
+ */
550
+ useState(key, initialState) {
551
+ if (!this.state[key]) {
552
+ this.state[key] = initialState;
409
553
  }
410
554
 
555
+ /**
556
+ * Get the current state value.
557
+ *
558
+ * @returns {T} The current state value.
559
+ */
560
+ let updatedValue = () => this.state[key];
561
+
562
+ const getValue = updatedValue();
563
+
564
+ /**
565
+ * Set a new value for the state.
566
+ *
567
+ * @param {T} newValue - The new value to set.
568
+ * @param {Function} hook - The hook to hydrate after setting the value.
569
+ */
570
+ const set = (newValue, hook) => {
571
+ this.state[key] = newValue;
572
+ this.hydrate(hook);
573
+ };
574
+
575
+
576
+
577
+ return [this.state[key], set];
578
+ }
579
+
580
+
581
+
411
582
  useRef(key = null, initialState) {
412
583
  if (!this.state[key]) {
413
584
  this.state[key] = initialState;
@@ -417,9 +588,11 @@ export class Component {
417
588
  this.state[key] = newValue;
418
589
  this.hydrate();
419
590
  };
591
+
592
+
420
593
  return {
421
- bind: key,
422
- current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
594
+ bind: key + this.key,
595
+ current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
423
596
  }
424
597
  }
425
598
 
@@ -443,7 +616,7 @@ export class Component {
443
616
  * @private
444
617
  */
445
618
  checkIFMounted() {
446
- if (this.mounted) return;
619
+ if (this.mounted || !this.key) return;
447
620
  let timer = setInterval(() => {
448
621
  if (document.querySelector('[key="' + this.key + '"]')) {
449
622
  clearInterval(timer);
@@ -513,19 +686,49 @@ export const require = async (path, noresolve = false) => {
513
686
 
514
687
 
515
688
  window.require = require;
689
+ /**
690
+ * useState hook.
691
+ *
692
+ * @param {string} key - The key for the state property.
693
+ * @param {*} initialState - The initial state value.
694
+ * @returns {[*]} - A tuple with the current state value and a setter function.
695
+ */
696
+ export const useState = (key, initialState) => {
697
+ if (!states[key]) {
698
+ states[key] = initialState;
699
+ }
700
+
701
+ /**
702
+ * Get the current state value.
703
+ *
704
+ * @returns {*} The current state value.
705
+ */
706
+ let updatedValue = () => states[key];
707
+
708
+ /**
709
+ * Set a new value for the state.
710
+ *
711
+ * @param {*} newValue - The new value to set.
712
+ * @param {Function} hook - The hook to hydrate after setting the value.
713
+ */
714
+ const set = (newValue, hook) => {
715
+ states[key] = newValue;
716
+ this.hydrate(hook);
717
+ };
718
+
719
+ return [states[key], set];
720
+ };
721
+
722
+
516
723
 
517
724
  /**
518
- * @method useState - type
519
- * @param {*} initialState
725
+ * @method useReducer
726
+ * @param {*} initialState
727
+ * @param {*} reducer
520
728
  * @returns {Array} [value, set]
521
- * @description Allows you to use state to dynamically update your component
522
729
  */
523
- export const useState = (initialState) => {
524
- let value = initialState;
525
- if (key && !states[key]) {
526
- this.states[key] = initialState;
527
- }
528
- return [value, (newValue) => {}];
730
+ export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
731
+ return [initialState, (newValue) => {}];
529
732
  };
530
733
 
531
734
  const constants = {};
@@ -539,12 +742,34 @@ export const constant = (value) => {
539
742
  return constants[key];
540
743
  };
541
744
 
745
+ /**
746
+ * useRef hook.
747
+ *
748
+ * @param {*} initialState - The initial state value for the ref.
749
+ * @returns {{ current: *, bind: string }} - An object containing the current value and a bind string.
750
+ */
751
+ export const useRef = (initialState) => {
752
+ return {
753
+ /**
754
+ * @description The current value of the ref.
755
+
756
+ */
757
+ current: initialState,
758
+ /**
759
+ * @description A unique string that can be used to bind the ref to an element.
760
+ */
761
+ bind: '',
762
+ };
763
+ };
764
+
542
765
  export default {
543
766
  Component,
544
767
  require,
545
768
  invoke,
546
769
  mem,
547
770
  constant,
771
+ useRef,
772
+ useReducer,
548
773
  useState,
549
774
  strictMount,
550
775
  stylis,
package/vader.js CHANGED
@@ -39,8 +39,7 @@ function Compiler(func) {
39
39
  )
40
40
  ) {
41
41
  return;
42
- }
43
- let code = string;
42
+ }
44
43
 
45
44
  let name = func.split(" ")[1].split("(")[0].trim();
46
45
 
@@ -159,7 +158,7 @@ function Compiler(func) {
159
158
  let params = hasParams
160
159
  ? line.split("(")[1].split(")")[0].trim()
161
160
  : null;
162
-
161
+
163
162
  if (
164
163
  functionparams.length > 0 &&
165
164
  functionparams.find((p) => p.name == name)
@@ -188,7 +187,7 @@ function Compiler(func) {
188
187
  newvalue = newvalue.replace(
189
188
  hasParams ? `${name}(${params})` : name,
190
189
  `this.callFunction(\${${replacement}}, ${isJSXComponent ? true : false
191
- }, event,${params || null})`
190
+ }, event, \${JSON.stringify(${params || null})})`
192
191
  );
193
192
  }
194
193
  }
@@ -215,14 +214,19 @@ function Compiler(func) {
215
214
 
216
215
 
217
216
  let otherdata = {};
217
+
218
218
  params ? (otherdata["params"] = params) : null;
219
219
  otherdata["jsx"] = isJSXComponent;
220
220
  otherdata["ref"] = ref;
221
221
 
222
222
  newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
223
223
 
224
+ // turn params into param1, param2, param3
224
225
 
225
- let newatribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', ${params || null})}"`
226
+
227
+ let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
228
+
229
+ let newatribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', "${paramString}", ${params || null})}"`
226
230
 
227
231
 
228
232
  attribute[attributeName] = {
@@ -258,7 +262,10 @@ function Compiler(func) {
258
262
  otherdata["ref"] = ref;
259
263
  // since js is all in one line split it
260
264
  newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
261
- let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', ${params || null})}"`
265
+ // param1, param2, param3
266
+ let length = params ? params.split(' ').length : 0;
267
+ let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
268
+ let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', "${paramString}", ${params || null})}"`
262
269
  newattribute = newattribute.replace(/\s+/g, " ")
263
270
  string = string.replace(old, newattribute);
264
271
  }
@@ -295,6 +302,7 @@ function Compiler(func) {
295
302
  let contents = "";
296
303
  let updatedContents = "";
297
304
  outerReturn.forEach((returnStatement) => {
305
+
298
306
  let lines = returnStatement.split("\n");
299
307
 
300
308
  for (let i = 0; i < lines.length; i++) {
@@ -303,7 +311,7 @@ function Compiler(func) {
303
311
  continue;
304
312
  }
305
313
  contents += line + "\n";
306
- }
314
+ }
307
315
 
308
316
  // Remove trailing ']'
309
317
  contents = contents.trim().replace(/\]$/, "");
@@ -321,19 +329,19 @@ function Compiler(func) {
321
329
 
322
330
  let value = attributes[key];
323
331
  let oldvalue = value;
324
- if (value && !value.new) {
325
- if (value && value.includes("{")) {
332
+ if (value && !value.new) {
333
+ if (value && value.includes("={")) {
326
334
  value = value.replace("=", "");
327
335
  value == "undefined" ? (value = '"') : (value = value);
328
336
  key == 'style' ? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
329
337
 
330
338
 
331
339
  value = `="\$${value}",`;
332
- string = string.replaceAll(oldvalue, value);
340
+ string = string.replace(oldvalue, value);
333
341
 
334
- } else if (value && value.includes("`")) {
342
+ } else if (value && value.includes("={`")) {
335
343
  value = value.replace("=", "");
336
-
344
+
337
345
  value = `"\$${value}",`;
338
346
  string = string.replace(oldvalue, value);
339
347
 
@@ -405,16 +413,15 @@ function Compiler(func) {
405
413
  let setKey = line.split("=")[0].split(",")[1].trim().replace("]", "");
406
414
 
407
415
  key = key.replace("[", "").replace(",", "");
408
- let value = line
409
- .split("=")[1]
410
- .split("useState")[1]
411
- .split("(")[1]
412
- .split(")")[0]
413
- .trim();
414
- let newState = `${type} [${key}, ${setKey}] = this.useState('${key}', ${value})
415
- this.${key} = ${key}
416
- this.${setKey} = ${setKey}
416
+ let value = line.split("=")[1].split("useState(")[1]
417
+ let regex = /useState\((.*)\)/gs
418
+ value = value.match(regex) ? value.match(regex)[0].split("useState(")[1].split(")")[0].trim() : value
419
+
420
+
421
+ let newState = `${type} [${key}, ${setKey}] = this.useState('${key}', ${value}
422
+
417
423
  `;
424
+
418
425
 
419
426
  // get setkey calls and replace with this.setKey
420
427
  string.split("\n").forEach((line) => {
@@ -429,18 +436,16 @@ function Compiler(func) {
429
436
  }
430
437
  });
431
438
  string = string.replace(line, newState);
432
- } else if (line.includes("useRef")) {
439
+ } else if (line.includes("useRef") && !line.includes("import")) {
433
440
  line = line.trim();
434
441
  // let ref = useRef(null)
435
442
  let type = line.split(" ")[0];
436
443
  let key = line.split("=")[0].split(" ")[1].trim();
437
- let value = line
438
- .split("=")[1]
439
- .split("useRef")[1]
440
- .split("(")[1]
441
- .split(")")[0]
442
- .trim();
443
- let newState = `${type} ${key} = this.useRef('${key}', ${value})`;
444
+ let value = line.split("=")[1].split("useRef(")[1]
445
+
446
+ let regex = /useState\((.*)\)/gs
447
+ value = value.match(regex) ? value.match(regex)[0].split("useRef(")[1].split(")")[0].trim() : value
448
+ let newState = `${type} ${key} = this.useRef('${key}', ${value}`;
444
449
 
445
450
  string = string.replace(line, newState);
446
451
  }
@@ -475,6 +480,12 @@ function Compiler(func) {
475
480
  return array;
476
481
  };
477
482
 
483
+ // replaceall comments ${/* */} with ''
484
+ string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
485
+
486
+ string = string.replaceAll('../src', './src')
487
+
488
+
478
489
  // capture <Component />, <Component></Component>, and <Component>content</Component>
479
490
 
480
491
  // Example usage
@@ -495,7 +506,7 @@ function Compiler(func) {
495
506
 
496
507
  let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
497
508
  let props = component.split(`<${name}`)[1].split(">")[0].trim()
498
- console.log(props)
509
+
499
510
 
500
511
  let savedname = name;
501
512
  let children = props
@@ -551,6 +562,7 @@ function Compiler(func) {
551
562
  // remove trailing ,
552
563
  .replace(/,\s*$/, "")
553
564
  props = props.replace(/:('[^']*'|"[^"]*")/g, ':$1,');
565
+ props = props.replaceAll(',,', ',')
554
566
 
555
567
 
556
568
 
@@ -724,9 +736,7 @@ async function Build() {
724
736
  });
725
737
 
726
738
  }
727
-
728
739
 
729
- console.log(`Compilation completed`)
730
740
  globalThis.isBuilding = false
731
741
  }
732
742
  import { watch } from "fs";
@@ -735,7 +745,9 @@ switch (true) {
735
745
  case process.argv.includes('--watch'):
736
746
 
737
747
  console.log(`
738
- Vader.js v1.3.3
748
+ Vader.js v1.3.3
749
+ - Watching for changes in ./pages
750
+ - Watching for changes in ./src
739
751
  `)
740
752
  Build()
741
753