vaderjs 1.7.2 → 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,179 +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) => {
429
+ update: (oldElement, newElement) => {
409
430
  if (!oldElement || !newElement) return;
410
-
411
- // If nodes are the same type and can be updated
431
+
432
+ // Check if the current element needs an update
412
433
  if (this.Reconciler.shouldUpdate(oldElement, newElement)) {
413
- // Update attributes of the parent
414
- Array.from(oldElement.attributes).forEach(({ name }) => {
415
- if (!newElement.hasAttribute(name)) {
416
- oldElement.removeAttribute(name);
417
- }
418
- });
419
-
420
- Array.from(newElement.attributes).forEach(({ name, value }) => {
421
- if (oldElement.getAttribute(name) !== value) {
422
- oldElement.setAttribute(name, value);
423
- }
424
- });
425
-
426
- // Update the parent content (if text content differs)
427
- if (oldElement.childNodes.length === 1 && oldElement.firstChild.nodeType === Node.TEXT_NODE) {
428
- if (oldElement.textContent !== newElement.textContent) {
429
- oldElement.textContent = newElement.textContent;
430
- }
431
- return; // No children to reconcile if it's a text node
432
- }
433
-
434
- // Reconcile child nodes
434
+ // Update attributes
435
435
  const oldChildren = Array.from(oldElement.childNodes);
436
436
  const newChildren = Array.from(newElement.childNodes);
437
-
437
+
438
438
  const maxLength = Math.max(oldChildren.length, newChildren.length);
439
439
  for (let i = 0; i < maxLength; i++) {
440
440
  if (i >= oldChildren.length) {
441
- // Add new children
442
441
  const newChildClone = newChildren[i].cloneNode(true);
443
442
  oldElement.appendChild(newChildClone);
444
-
445
- // Transfer events for the new child
446
- const newChildEvents = this.eventRegistry.get(newChildren[i]) || [];
447
- newChildEvents.forEach(({ type, handler }) => {
448
- this.addEventListener(newChildClone, type, handler);
449
- });
443
+
444
+ // Rebind events to the new child (and its children recursively)
445
+ this.attachEventsRecursively(newChildClone, newChildren[i]);
450
446
  } else if (i >= newChildren.length) {
451
- // Remove extra old children
452
447
  oldElement.removeChild(oldChildren[i]);
453
448
  } else {
454
- // Update existing children recursively
455
449
  this.Reconciler.update(oldChildren[i], newChildren[i]);
456
450
  }
457
451
  }
458
-
459
- // Reapply events to the parent
460
- const parentEvents = this.eventRegistry.get(newElement) || [];
461
- parentEvents.forEach(({ type, handler }) => {
462
- this.addEventListener(oldElement, type, handler);
452
+
453
+ Array.from(oldElement.attributes || []).forEach(({ name }) => {
454
+ if (!newElement.hasAttribute(name)) {
455
+ oldElement.removeAttribute(name);
456
+ }
463
457
  });
464
- } else {
465
- const oldChildren = Array.from(oldElement.childNodes);
466
- const newChildren = Array.from(newElement.childNodes);
467
-
468
- const maxLength = Math.max(oldChildren.length, newChildren.length);
469
- for (let i = 0; i < maxLength; i++) {
470
- if (i >= oldChildren.length) {
471
- // Add new children
472
- const newChildClone = newChildren[i].cloneNode(true);
473
- oldElement.appendChild(newChildClone);
474
-
475
- // Transfer events for the new child
476
- const newChildEvents = this.eventRegistry.get(newChildren[i]) || [];
477
- newChildEvents.forEach(({ type, handler }) => {
478
- this.addEventListener(newChildClone, type, handler);
479
- });
480
- } else if (i >= newChildren.length) {
481
- // Remove extra old children
482
- oldElement.removeChild(oldChildren[i]);
483
- } else {
484
- // Update existing children recursively
485
- 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;
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;
486
480
  }
481
+ return;
487
482
  }
488
483
  }
489
- },
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]);
507
+ }
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
+ });
490
515
 
491
- shouldUpdate: (oldElement, newElement, isChild = false) => {
516
+ },
517
+ shouldUpdate: (oldElement, newElement) => {
518
+ // Check if node types differ
492
519
  if (oldElement.nodeType !== newElement.nodeType) {
493
- return oldElement.innerHTML !== newElement.innerHTML ? { type: "innerHTML" } : true;
520
+ return true;
494
521
  }
495
- if (oldElement.nodeType === 3 && newElement.nodeType === 3) {
496
- if (oldElement.nodeValue !== newElement.nodeValue) {
497
- return true;
498
- }
522
+
523
+ // Check if text content differs
524
+ if (oldElement.nodeType === Node.TEXT_NODE) {
525
+ return oldElement.textContent !== newElement.textContent;
499
526
  }
527
+
528
+ // Check if node names differ
500
529
  if (oldElement.nodeName !== newElement.nodeName) {
501
530
  return true;
502
531
  }
532
+
533
+ // Check if child counts differ
503
534
  if (oldElement.childNodes.length !== newElement.childNodes.length) {
504
535
  return true;
505
536
  }
506
- if (newElement.attributes) {
507
- for (let i = 0; i < newElement.attributes.length; i++) {
508
- let attr = newElement.attributes[i];
509
- if (oldElement.getAttribute(attr.name) !== attr.value) {
510
- return { type: "attribute", name: attr.name, value: attr.value };
511
- }
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;
512
543
  }
513
544
  }
545
+
546
+ // If no differences found, no update needed
514
547
  return false;
515
- }
516
- };
517
-
548
+ },
549
+ }
550
+
518
551
  parseToElement = (element) => {
519
- if (!element) return document.createElement("div");
520
- // create either a element or svg element
521
- let svg = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "ellipse", "g"];
522
- let el = svg.includes(element.type) ? document.createElementNS("http://www.w3.org/2000/svg", element.type) : document.createElement(element.type);
523
- let isText = typeof element === "string" || typeof element === "number" || typeof element === "boolean";
524
- if (isText && element) {
525
- el.innerHTML = element;
526
- } else {
527
- let attributes = element.props;
528
- let children = element.children;
529
- for (let key in attributes) {
530
- if (key === "key") {
531
- el.key = attributes[key];
532
- continue;
533
- }
534
- if (key === "className") {
535
- el.setAttribute("class", attributes[key]);
536
- continue;
537
- }
538
- if (key === "style") {
539
- try {
540
- for (let styleKey in attributes[key]) {
541
- el.style[styleKey] = attributes[key][styleKey];
542
- }
543
- } catch (error) {
544
-
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];
545
580
  }
546
- continue;
547
- }
548
- if (key.startsWith("on")) {
549
- el.addEventListener(key.substring(2).toLowerCase(), attributes[key]);
550
- this.eventRegistry.set(el, [...this.eventRegistry.get(el) || [], { event: key.substring(2).toLowerCase(), handler: attributes[key] }]);
551
- this.addEventListener(el, key.substring(2).toLowerCase(), attributes[key])
552
- continue;
553
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
554
590
  el.setAttribute(key, attributes[key]);
555
591
  }
556
- if (children === undefined)
557
- return el;
558
- for (let i = 0; i < children.length; i++) {
559
- let child = children[i];
560
- if (Array.isArray(child)) {
561
- child.forEach((c) => {
562
- el.appendChild(this.parseToElement(c));
563
- });
564
- }
565
- if (typeof child === "function") {
566
- let comp = memoizeClassComponent(Component);
567
- comp.Mounted = true;
568
- comp.render = child;
569
- let el2 = comp.toElement();
570
- el2.key = comp.key;
571
- el.appendChild(el2);
572
- } else if (typeof child === "object") {
573
- el.appendChild(this.parseToElement(child));
574
- } else if (child) {
575
- let span = document.createTextNode(child)
576
- el.appendChild(span);
577
- }
578
- }
579
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
+
580
616
  return el;
581
617
  };
582
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.2",
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"