vaderjs 1.7.3 → 1.7.4

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/bundler/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  useAsyncState,
8
8
  Fragment,
9
9
  } from "vaderjs";
10
- import { document } from "vaderjs/document";
10
+ import { document } from "vaderjs/document/index.ts";
11
11
  import fs from "fs";
12
12
  import ansiColors from "ansi-colors";
13
13
  import path from "path";
@@ -15,8 +15,8 @@ let path2 = require("path");
15
15
  globalThis.Fragment = Fragment;
16
16
  globalThis.window = {
17
17
  location: {
18
- hash: "",
19
- host: "",
18
+ hash: "",
19
+ host: "",
20
20
  },
21
21
  };
22
22
  globalThis.Component = Component;
@@ -29,63 +29,55 @@ globalThis.genKey = () => {
29
29
  return crypto.randomUUID();
30
30
  };
31
31
  globalThis.document = {
32
- createElement: (tag) => {},
33
- getElementById: (id) => {},
34
- querySelector: (query) => {},
32
+ createElement: (tag) => { },
33
+ getElementById: (id) => { },
34
+ querySelector: (query) => { },
35
35
  };
36
- await Bun.build({
37
- entrypoints: [process.env.ENTRYPOINT],
38
- minify: false,
39
- root: process.cwd() + "/dist/",
40
- outdir: process.cwd() + "/dist/",
36
+ try {
37
+ await Bun.build({
38
+ entrypoints: [process.env.ENTRYPOINT],
39
+ minify: false,
40
+ root: process.cwd() + "/dist/",
41
+ outdir: process.cwd() + "/dist/",
41
42
 
42
- format: "esm",
43
- ...(process.env.DEV ? { sourcemap: "inline" } : {}),
44
- external: ["*.jsx", "*.js", "*.ts"],
45
- });
43
+ format: "esm",
44
+ ...(process.env.DEV ? { sourcemap: "inline" } : {}),
45
+ external: ['*.jsx', '*.js', '*.ts']
46
+ });
47
+ } catch (error) {
48
+ console.error(error)
49
+ }
46
50
 
47
- let builtCode = fs.readFileSync(
48
- path.join(process.cwd(), "dist", process.env.filePath),
49
- "utf-8",
50
- );
51
+ let builtCode = fs.readFileSync(path.join(process.cwd(), 'dist', process.env.filePath), 'utf-8')
51
52
 
52
53
  function handleReplacements(code) {
53
54
  let lines = code.split("\n");
54
55
  let newLines = [];
55
56
  for (let line of lines) {
56
- let hasImport = line.includes("import");
57
- if (hasImport && line.includes("from") && !newLines.includes(line)) {
58
- try {
59
- let url = line.includes("'") ? line.split("'")[1] : line.split('"')[1];
60
- line = line.replace(
61
- url,
62
- url.replace(".jsx", ".js").replace(".tsx", ".js"),
63
- );
64
- line = line.replace(
65
- url,
66
- url.replace(".ts", ".js").replace(".tsx", ".js"),
67
- );
68
- newLines.push(line);
69
- } catch (error) {
70
- continue;
57
+ let hasImport = line.includes('import')
58
+ if (hasImport && line.includes('from') && !newLines.includes(line)) {
59
+ try {
60
+ let url = line.includes("'") ? line.split("'")[1] : line.split('"')[1]
61
+ line = line.replace(url, url.replace('.jsx', '.js').replace('.tsx', '.js'))
62
+ line = line.replace(url, url.replace('.ts', '.js').replace('.tsx', '.js'))
63
+ newLines.push(line)
64
+ } catch (error) {
65
+ continue;
66
+ }
67
+ } else {
68
+ newLines.push(line)
71
69
  }
72
- } else {
73
- newLines.push(line);
74
- }
75
70
  }
76
71
  return newLines.join("\n");
77
72
  }
78
- builtCode = handleReplacements(builtCode);
79
- fs.writeFileSync(
80
- path.join(process.cwd(), "dist", process.env.filePath),
81
- builtCode,
82
- );
73
+ builtCode = handleReplacements(builtCode)
74
+ fs.writeFileSync(path.join(process.cwd(), 'dist', process.env.filePath), builtCode)
83
75
 
84
76
  let isClass = function (element) {
85
77
  return element.toString().startsWith("class");
86
78
  };
87
79
  const generatePage = async (
88
- data = { path: process.env.INPUT, route: process.env.OUT },
80
+ data = { path: process.env.INPUT, route: process.env.OUT }
89
81
  ) => {
90
82
  const { path, route } = data;
91
83
  if (path.includes("root.js")) return;
@@ -94,61 +86,59 @@ const generatePage = async (
94
86
  let isFunction = false;
95
87
  globalThis.isServer = true;
96
88
  if (isClass(html)) {
97
- html = new html();
98
- html.Mounted = true;
99
- html = html.render();
89
+ html = new html();
90
+ html.Mounted = true;
91
+ html = html.render();
100
92
  } else {
101
- isFunction = true;
102
- let instance = new Component();
103
- html = html.bind(instance);
104
- instance.render = html;
105
- html = instance.render();
93
+ isFunction = true;
94
+ let instance = new Component();
95
+ html = html.bind(instance);
96
+ instance.render = html;
97
+ html = instance.render();
106
98
  }
107
99
 
108
100
  let h = document(html);
109
101
  if (!fs.existsSync(process.cwd() + "/dist" + path2.dirname(route))) {
110
- fs.mkdirSync(process.cwd() + "/dist" + path2.dirname(route), {
111
- recursive: true,
112
- });
102
+ fs.mkdirSync(process.cwd() + "/dist" + path2.dirname(route), {
103
+ recursive: true,
104
+ });
113
105
  }
114
106
  let headHtml = "";
115
107
  if (head) {
116
- headHtml = document(head());
108
+ headHtml = document(head());
109
+ }
110
+
111
+ if (h.includes("<head>")) {
112
+ h = h.replace("<head>", `<head>${process.env.bindes}`)
117
113
  }
118
114
 
119
115
  await Bun.write(
120
- process.cwd() + "/dist/" + route + "/index.html",
121
- `<!DOCTYPE html>
122
- <head>
123
- ${headHtml}
124
- ${process.env.bindes}
125
- <meta charset="UTF-8">
126
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
127
- </head>
128
- ${h}
129
- <script type="module">
130
- import c from '${process.env.filePath}'
131
- import {render, e} from '/src/vader/index.js'
132
- window.e = e
133
- render(c, document.body.firstChild)
134
- </script>
135
- `,
116
+ process.cwd() + "/dist/" + route + "/index.html",
117
+ `<!DOCTYPE html>
118
+ ${h}
119
+ <script type="module">
120
+ import c from '${process.env.filePath}'
121
+ import {render, e} from '/src/vader/index.js'
122
+ window.e = e
123
+ render(c, document.body.firstChild)
124
+ </script>
125
+ `
136
126
  );
137
127
  console.log(
138
- ansiColors.blue(
139
- `${process.env.filePath.replace(".ts", ".js")} - ${parseInt(
140
- process.env.size,
141
- ).toFixed(2)}kb`,
142
- ),
128
+ ansiColors.blue(
129
+ `${process.env.filePath.replace(".js", ".jsx")} - ${parseInt(
130
+ process.env.size
131
+ ).toFixed(2)}kb`
132
+ )
143
133
  );
144
134
  process.exit(0);
145
135
  };
146
136
  try {
147
137
  if (process.env.isTs == undefined && process.env.isImport) {
148
- generatePage({ path: process.env.INPUT, route: process.env.OUT });
138
+ generatePage({ path: process.env.INPUT, route: process.env.OUT })
149
139
  } else if (process.env.isTs == undefined) {
150
- generatePage({ path: process.env.INPUT, route: process.env.OUT });
140
+ generatePage({ path: process.env.INPUT, route: process.env.OUT })
151
141
  }
152
142
  } catch (error) {
153
- console.log(ansiColors.red(error));
154
- }
143
+ console.log(ansiColors.red(error))
144
+ }
package/index.ts CHANGED
@@ -124,6 +124,7 @@ globalThis.Fragment = Fragment;
124
124
  * @returns
125
125
  */
126
126
  export const e = (element, props, ...children) => {
127
+ if(!element) return ""
127
128
  let instance;
128
129
  switch (true) {
129
130
  case isClassComponent(element):
@@ -137,10 +138,11 @@ export const e = (element, props, ...children) => {
137
138
  instance.render = element;
138
139
  instance.Mounted = true;
139
140
  let firstEl = instance.render({ key: instance.key, children, ...props }, children);
140
- instance.children = children;
141
+ instance.children = children;
141
142
  if (!firstEl)
142
143
  firstEl = { type: "div", props: { key: instance.key, ...props }, children };
143
144
  firstEl.props = { key: instance.key, ...firstEl.props, ...props };
145
+
144
146
  return firstEl;
145
147
  default:
146
148
  return { type: element, props: props || {}, children: children || [] };
@@ -404,165 +406,213 @@ export class Component {
404
406
  }
405
407
  this.Reconciler.update(el, newl);
406
408
  }
409
+ attachEventsRecursively = (element, source) => {
410
+ // Rebind events for the current element
411
+ const events = this.eventRegistry.get(source) || [];
412
+ events.forEach(({ event, handler }) => {
413
+ this.addEventListener(element, event, handler);
414
+ });
415
+
416
+ // Traverse children recursively
417
+ const children = Array.from(source.childNodes || []);
418
+ const elementChildren = Array.from(element.childNodes || []);
419
+
420
+ children.forEach((child, index) => {
421
+ if (elementChildren[index]) {
422
+ this.attachEventsRecursively(elementChildren[index], child);
423
+ }
424
+ });
425
+ };
426
+
427
+
407
428
  Reconciler = {
408
- update: (oldElement, newElement) => {
409
- if (!oldElement || !newElement)
410
- return;
429
+ update: (oldElement, newElement) => {
430
+ if (!oldElement || !newElement) return;
431
+
432
+ // Check if the current element needs an update
411
433
  if (this.Reconciler.shouldUpdate(oldElement, newElement)) {
412
- console.log(oldElement, newElement)
413
- if (oldElement.attributes && Object.keys(oldElement.attributes).length > 0)
414
- Array.from(oldElement.attributes).forEach(({ name }) => {
415
- if (!newElement.hasAttribute(name)) {
416
- oldElement.removeAttribute(name);
417
- }
418
- });
419
- if (newElement.attributes && Object.keys(newElement.attributes).length > 0)
420
- Array.from(newElement.attributes).forEach(({ name, value }) => {
421
- if (oldElement.getAttribute(name) !== value) {
422
- oldElement.setAttribute(name, value);
423
- }
424
- });
425
- if (oldElement.childNodes.length === 1 && oldElement.firstChild.nodeType === Node.TEXT_NODE) {
426
- if (oldElement.textContent !== newElement.textContent) {
427
- oldElement.textContent = newElement.textContent;
428
- }
429
- return;
430
- }else if(oldElement.nodeType === Node.TEXT_NODE){
431
- if (oldElement.textContent !== newElement.textContent) {
432
- oldElement.textContent = newElement.textContent;
433
- }
434
- return;
435
- }
434
+ // Update attributes
436
435
  const oldChildren = Array.from(oldElement.childNodes);
437
436
  const newChildren = Array.from(newElement.childNodes);
437
+
438
438
  const maxLength = Math.max(oldChildren.length, newChildren.length);
439
- for (let i = 0;i < maxLength; i++) {
439
+ for (let i = 0; i < maxLength; i++) {
440
440
  if (i >= oldChildren.length) {
441
441
  const newChildClone = newChildren[i].cloneNode(true);
442
442
  oldElement.appendChild(newChildClone);
443
- const newChildEvents = this.eventRegistry.get(newChildren[i]) || [];
444
- newChildEvents.forEach(({ type, handler }) => {
445
- this.addEventListener(newChildClone, type, handler);
446
- });
443
+
444
+ // Rebind events to the new child (and its children recursively)
445
+ this.attachEventsRecursively(newChildClone, newChildren[i]);
447
446
  } else if (i >= newChildren.length) {
448
447
  oldElement.removeChild(oldChildren[i]);
449
448
  } else {
450
449
  this.Reconciler.update(oldChildren[i], newChildren[i]);
451
450
  }
452
451
  }
453
- const parentEvents = this.eventRegistry.get(newElement) || [];
454
- parentEvents.forEach(({ type, handler }) => {
455
- this.addEventListener(oldElement, type, handler);
452
+
453
+ Array.from(oldElement.attributes || []).forEach(({ name }) => {
454
+ if (!newElement.hasAttribute(name)) {
455
+ oldElement.removeAttribute(name);
456
+ }
456
457
  });
457
- } else {
458
- const oldChildren = Array.from(oldElement.childNodes);
459
- const newChildren = Array.from(newElement.childNodes);
460
- const maxLength = Math.max(oldChildren.length, newChildren.length);
461
- for (let i = 0;i < maxLength; i++) {
462
- if (i >= oldChildren.length) {
463
- const newChildClone = newChildren[i].cloneNode(true);
464
- oldElement.appendChild(newChildClone);
465
- const newChildEvents = this.eventRegistry.get(newChildren[i]) || [];
466
- newChildEvents.forEach(({ type, handler }) => {
467
- this.addEventListener(newChildClone, type, handler);
468
- });
469
- } else if (i >= newChildren.length) {
470
- oldElement.removeChild(oldChildren[i]);
471
- } else {
472
- this.Reconciler.update(oldChildren[i], newChildren[i]);
458
+
459
+ Array.from(newElement.attributes || []).forEach(({ name, value }) => {
460
+ if (oldElement.getAttribute(name) !== value) {
461
+ oldElement.setAttribute(name, value);
462
+ }
463
+ });
464
+
465
+ // Handle text node updates
466
+ if (oldElement.nodeType === Node.TEXT_NODE) {
467
+ if (oldElement.textContent !== newElement.textContent) {
468
+ oldElement.textContent = newElement.textContent;
473
469
  }
470
+ return;
471
+ }
472
+
473
+ // If the element has a single text node, update text directly
474
+ if (
475
+ oldElement.childNodes.length === 1 &&
476
+ oldElement.firstChild.nodeType === Node.TEXT_NODE
477
+ ) {
478
+ if (oldElement.textContent !== newElement.textContent) {
479
+ oldElement.textContent = newElement.textContent;
480
+ }
481
+ return;
482
+ }
483
+ }
484
+
485
+ // Process children recursively
486
+ const oldChildren = Array.from(oldElement.childNodes);
487
+ const newChildren = Array.from(newElement.childNodes);
488
+
489
+ const maxLength = Math.max(oldChildren.length, newChildren.length);
490
+
491
+ for (let i = 0; i < maxLength; i++) {
492
+ if (i >= oldChildren.length) {
493
+ // Add new child if it exists in newChildren but not in oldChildren
494
+ const newChildClone = newChildren[i].cloneNode(true);
495
+ oldElement.appendChild(newChildClone);
496
+
497
+ // Attach any event listeners
498
+ const newChildEvents = this.eventRegistry.get(newChildren[i]) || [];
499
+ newChildEvents.forEach(({ type, handler }) => {
500
+ this.addEventListener(newChildClone, type, handler);
501
+ });
502
+ } else if (i >= newChildren.length) {
503
+ // Remove child if it exists in oldChildren but not in newChildren
504
+ oldElement.removeChild(oldChildren[i]);
505
+ } else {
506
+ this.Reconciler.update(oldChildren[i], newChildren[i]);
474
507
  }
475
508
  }
509
+
510
+ // Reapply events for the current element
511
+ const parentEvents = this.eventRegistry.get(newElement) || [];
512
+ parentEvents.forEach(({ type, handler }) => {
513
+ this.addEventListener(oldElement, type, handler);
514
+ });
515
+
476
516
  },
477
- shouldUpdate: (oldElement, newElement, isChild = false) => {
517
+ shouldUpdate: (oldElement, newElement) => {
518
+ // Check if node types differ
478
519
  if (oldElement.nodeType !== newElement.nodeType) {
479
- return oldElement.innerHTML !== newElement.innerHTML ? { type: "innerHTML" } : true;
520
+ return true;
480
521
  }
481
- if (oldElement.nodeType === 3 && newElement.nodeType === 3) {
482
- if (oldElement.nodeValue !== newElement.nodeValue) {
483
- return true;
484
- }
522
+
523
+ // Check if text content differs
524
+ if (oldElement.nodeType === Node.TEXT_NODE) {
525
+ return oldElement.textContent !== newElement.textContent;
485
526
  }
527
+
528
+ // Check if node names differ
486
529
  if (oldElement.nodeName !== newElement.nodeName) {
487
530
  return true;
488
531
  }
532
+
533
+ // Check if child counts differ
489
534
  if (oldElement.childNodes.length !== newElement.childNodes.length) {
490
535
  return true;
491
536
  }
492
- if (newElement.attributes) {
493
- for (let i = 0;i < newElement.attributes.length; i++) {
494
- let attr = newElement.attributes[i];
495
- if (oldElement.getAttribute(attr.name) !== attr.value) {
496
- return { type: "attribute", name: attr.name, value: attr.value };
497
- }
537
+
538
+ // Check if attributes differ
539
+ const newAttributes = Array.from(newElement.attributes || []);
540
+ for (let { name, value } of newAttributes) {
541
+ if (oldElement.getAttribute(name) !== value) {
542
+ return true;
498
543
  }
499
544
  }
545
+
546
+ // If no differences found, no update needed
500
547
  return false;
501
- }
502
- };
503
-
548
+ },
549
+ }
550
+
504
551
  parseToElement = (element) => {
505
- if (!element) return document.createElement("div");
506
- // create either a element or svg element
507
- let svg = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "ellipse", "g"];
508
- let el = svg.includes(element.type) ? document.createElementNS("http://www.w3.org/2000/svg", element.type) : document.createElement(element.type);
509
- let isText = typeof element === "string" || typeof element === "number" || typeof element === "boolean";
510
- if (isText && element) {
511
- el.innerHTML = element;
512
- } else {
513
- let attributes = element.props;
514
- let children = element.children;
515
- for (let key in attributes) {
516
- if (key === "key") {
517
- el.key = attributes[key];
518
- continue;
519
- }
520
- if (key === "className") {
521
- el.setAttribute("class", attributes[key]);
522
- continue;
523
- }
524
- if (key === "style") {
525
- try {
526
- for (let styleKey in attributes[key]) {
527
- el.style[styleKey] = attributes[key][styleKey];
528
- }
529
- } catch (error) {
530
-
552
+ if (!element || element.nodeType) return ""
553
+
554
+ let svgTags = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "ellipse", "g"];
555
+ let isSvg = svgTags.includes(element.type);
556
+
557
+ // Create the element, using proper namespace for SVG
558
+ let el = isSvg
559
+ ? document.createElementNS("http://www.w3.org/2000/svg", element.type)
560
+ : document.createElement(element.type);
561
+
562
+ // Handle text nodes
563
+ if (typeof element === "string" || typeof element === "number" || typeof element === "boolean") {
564
+ el.textContent = element; // Safer alternative to innerHTML
565
+ return el;
566
+ }
567
+
568
+ // Set attributes
569
+ let attributes = element.props || {};
570
+ for (let key in attributes) {
571
+ if (key === "key") {
572
+ el.key = attributes[key];
573
+ } else if (key === "className") {
574
+ el.setAttribute("class", attributes[key]);
575
+ } else if (key === "style") {
576
+ let styleObject = attributes[key];
577
+ if (typeof styleObject === "object") {
578
+ for (let styleKey in styleObject) {
579
+ el.style[styleKey] = styleObject[styleKey];
531
580
  }
532
- continue;
533
- }
534
- if (key.startsWith("on")) {
535
- el.addEventListener(key.substring(2).toLowerCase(), attributes[key]);
536
- this.eventRegistry.set(el, [...this.eventRegistry.get(el) || [], { event: key.substring(2).toLowerCase(), handler: attributes[key] }]);
537
- this.addEventListener(el, key.substring(2).toLowerCase(), attributes[key])
538
- continue;
539
581
  }
582
+ } else if (key.startsWith("on")) {
583
+ // Event listeners
584
+ const eventType = key.substring(2).toLowerCase();
585
+ const handler = attributes[key];
586
+ this.eventRegistry.set(el, [...(this.eventRegistry.get(el) || []), { event: eventType, handler }]);
587
+ this.addEventListener(el, eventType, handler);
588
+ } else if (attributes[key] !== null && attributes[key] !== undefined) {
589
+ // General attributes
540
590
  el.setAttribute(key, attributes[key]);
541
591
  }
542
- if (children === undefined)
543
- return el;
544
- for (let i = 0; i < children.length; i++) {
545
- let child = children[i];
546
- if (Array.isArray(child)) {
547
- child.forEach((c) => {
548
- el.appendChild(this.parseToElement(c));
549
- });
550
- }
551
- if (typeof child === "function") {
552
- let comp = memoizeClassComponent(Component);
553
- comp.Mounted = true;
554
- comp.render = child;
555
- let el2 = comp.toElement();
556
- el2.key = comp.key;
557
- el.appendChild(el2);
558
- } else if (typeof child === "object") {
559
- el.appendChild(this.parseToElement(child));
560
- } else if (child) {
561
- let span = document.createTextNode(child)
562
- el.appendChild(span);
563
- }
564
- }
565
592
  }
593
+
594
+ // Handle children
595
+ let children = element.children || [];
596
+ children.forEach((child) => {
597
+ if (Array.isArray(child)) {
598
+ // Recursively process nested arrays
599
+ child.forEach((nestedChild) => el.appendChild(this.parseToElement(nestedChild)));
600
+ } else if (typeof child === "function") {
601
+ // Handle functional components
602
+ let component = memoizeClassComponent(Component);
603
+ component.Mounted = true;
604
+ component.render = child;
605
+ let componentElement = component.toElement();
606
+ el.appendChild(componentElement);
607
+ } else if (typeof child === "object") {
608
+ // Nested object children
609
+ el.appendChild(this.parseToElement(child));
610
+ } else if (child !== null && child !== undefined) {
611
+ // Text nodes
612
+ el.appendChild(document.createTextNode(child));
613
+ }
614
+ });
615
+
566
616
  return el;
567
617
  };
568
618
  e(element, props, ...children) {
package/main.js CHANGED
@@ -299,8 +299,7 @@ async function generateApp() {
299
299
 
300
300
  function handleFiles() {
301
301
  return new Promise(async (resolve, reject) => {
302
- try {
303
- console.log(Glob)
302
+ try {
304
303
  let glob = new Glob('public/**/*')
305
304
  for await (var i of glob.scan()) {
306
305
  let file = i
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaderjs",
3
- "version": "1.7.3",
3
+ "version": "1.7.4",
4
4
  "description": "A simple and powerful JavaScript library for building modern web applications.",
5
5
  "bin": {
6
6
  "vaderjs": "./main.js"