neutronium 2.9.91 → 3.0.2

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
- # ⚛️ Neutronium
1
+ # ⚛️ Neutronium v3.0
2
2
 
3
3
  **Ultra-dense JavaScript framework – maximum performance, minimal overhead**
4
4
 
@@ -8,7 +8,14 @@
8
8
 
9
9
  ---
10
10
 
11
- ## 🚀 About
11
+ ## 🎉 What's new?
12
+ - ⚡ Faster compilation for complex projects
13
+ - ✨ useState, and useEffect
14
+ - ⚛️ React like syntax for easier switching
15
+
16
+ ---
17
+
18
+ ## ℹ️ About
12
19
 
13
20
  **Neutronium** is a lightweight, efficient JavaScript framework designed for building modern web applications with **React-like simplicity** but **minimal overhead**.
14
21
 
@@ -33,12 +40,16 @@
33
40
  npm i neutronium@latest -g
34
41
  ```
35
42
 
43
+ ---
44
+
36
45
  ## 🛠️ Setup
37
46
 
38
47
  ```
39
48
  neu-cli create-app my-app
40
49
  ```
41
50
 
51
+ ---
52
+
42
53
  ## Usage Example
43
54
  ```jsx
44
55
  // App.js
@@ -63,7 +74,12 @@ createApp(App).mount('body');
63
74
  ## Result:
64
75
  ![Results](https://raw.githubusercontent.com/PFMCODES/neutronium/main/results.png)
65
76
 
66
- ## Other helpful packages you might need
77
+ ---
78
+
79
+ ## NPM Packages using Neutronium
67
80
  ### [@neuhq/alert](https://www.npmjs.com/package/@neuhq/alert)
68
- ## ⚒️ In dev
69
- ### [@neuhq/router](https://www.npmjs.com/package/@neuhq/router)
81
+
82
+ ---
83
+
84
+ ## Found a bug or a problem?
85
+ ### Report [here.](https://github.com/PFMCODES/neutronium/issues/new)
package/cli/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  const { default: inquirer } = require('inquirer');
4
4
  const fs = require('fs');
@@ -12,14 +12,19 @@ const { execSync } = require('child_process');
12
12
 
13
13
  async function compileProject(projectDir = process.cwd()) {
14
14
  const distDir = path.join(projectDir, 'dist');
15
- const neutroniumPath = '../node_modules/neutronium/src/index.js';
15
+ const neutroniumPath = path.join(projectDir, 'node_modules', 'neutronium', 'src', 'index.js');
16
16
  const packageJson = JSON.parse(fs.readFileSync(path.join(projectDir, 'package.json')));
17
17
  const entry = packageJson.main || 'App.js';
18
18
 
19
19
  try {
20
20
  log('📁 Scanning project files...');
21
21
  const allFiles = fs.readdirSync(projectDir);
22
- const jsFiles = allFiles.filter(f => f.endsWith('.js') && f !== 'compiler.js' && !f.startsWith('.'));
22
+ const jsFiles = allFiles.filter(f =>
23
+ f.endsWith('.js') &&
24
+ f !== 'compiler.js' &&
25
+ !f.startsWith('.') &&
26
+ !f.startsWith('dist')
27
+ );
23
28
 
24
29
  if (fs.existsSync(path.join(projectDir, 'tsconfig.json'))) {
25
30
  try {
@@ -63,11 +68,11 @@ async function compileProject(projectDir = process.cwd()) {
63
68
 
64
69
  // Ensure _neutronium is imported
65
70
  if (!source.includes('_neutronium')) {
66
- code = `import * as _neutronium from '${neutroniumPath}';\n\n${code}`;
71
+ code = `import * as _neutronium from '${neutroniumPath.replace(/\\/g, '/')}';\n\n${code}`;
67
72
  }
68
73
 
69
- // Replace imports to local neutronium
70
- code = code.replace(/from\s+['"]neutronium['"]/g, `from '${neutroniumPath}'`);
74
+ // Replace imports to "neutronium" with local path
75
+ code = code.replace(/from\s+['"]neutronium['"]/g, `from '${neutroniumPath.replace(/\\/g, '/')}'`);
71
76
 
72
77
  writeFile(outputPath, code);
73
78
  }
@@ -87,33 +92,71 @@ async function compileProject(projectDir = process.cwd()) {
87
92
  }
88
93
  }
89
94
 
95
+ async function compileAndReturnOutput(code) {
96
+ try {
97
+ log('📁 Scanning project files...');
98
+ log(`⚙️ Babel transforming`);
99
+
100
+ code = babel.transformSync(code, {
101
+ babelrc: false,
102
+ configFile: false,
103
+ presets: [],
104
+ plugins: [[
105
+ '@babel/plugin-transform-react-jsx',
106
+ {
107
+ pragma: '_neutronium.h',
108
+ pragmaFrag: '_neutronium.Fragment',
109
+ runtime: 'classic',
110
+ }
111
+ ]]
112
+ });
113
+ code = code.code
114
+ // Ensure _neutronium is imported
115
+ if (!code.includes('_neutronium')) {
116
+ code = `import * as _neutronium from 'https://esm.sh/neutronium@3.0.2/es2022/neutronium.mjs`;
117
+ }
118
+
119
+ // Replace imports to "neutronium" with local path
120
+ code = code.replace(/from\s+['"]neutronium['"]/g, `from '${neutroniumPath.replace(/\\/g, '/')}'`);
121
+
122
+ console.log('🛠️ Generating index.html...');
123
+ const htmlContent = baseHtml(code);
124
+
125
+
126
+ log('✅ Compilation complete!');
127
+ return htmlContent;
128
+ } catch (e) {
129
+ console.error('❌ Compilation failed:', e.message);
130
+ return false;
131
+ }
132
+ }
133
+
90
134
  function compileProjectWatch(projectDir = process.cwd(), port = 3000) {
91
- // Start server first
92
135
  const server = serveProject(projectDir, port);
93
-
94
- // Do initial compilation
95
136
  compileProject(projectDir);
96
137
 
97
138
  log('👀 Watching project for changes...');
98
139
  log('✋ Press Ctrl+C to stop the development server');
99
-
140
+
100
141
  let timeout;
101
142
 
102
- // Watch files more specifically
103
- const watcher = chokidar.watch(projectDir, {
143
+ const watcher = chokidar.watch([
144
+ path.join(projectDir, '**/*.js'),
145
+ path.join(projectDir, '**/*.ts'),
146
+ path.join(projectDir, '**/*.tsx'),
147
+ ], {
104
148
  ignoreInitial: true,
105
149
  ignored: [
106
150
  '**/node_modules/**',
107
151
  '**/dist/**',
108
152
  '**/.git/**',
109
- '**/*',
110
153
  'compiler.js'
111
154
  ],
112
155
  persistent: true,
113
156
  followSymlinks: false,
114
- depth: 2,
157
+ depth: 5,
115
158
  awaitWriteFinish: {
116
- stabilityThreshold: 100,
159
+ stabilityThreshold: 300,
117
160
  pollInterval: 100
118
161
  }
119
162
  });
@@ -123,58 +166,45 @@ function compileProjectWatch(projectDir = process.cwd(), port = 3000) {
123
166
  });
124
167
 
125
168
  watcher.on('change', filePath => {
126
- // Only watch js, ts, tsx files
127
- if (!/\.(js|ts|tsx)$/.test(filePath)) {
128
- return;
129
- }
169
+ if (!/\.(js|ts|tsx)$/.test(filePath)) return;
130
170
 
131
171
  log(`🔍 Detected change in: ${path.relative(projectDir, filePath)}`);
132
-
172
+
133
173
  clearTimeout(timeout);
134
174
  timeout = setTimeout(() => {
135
175
  log('🔨 Rebuilding project...');
136
-
137
176
  try {
138
177
  const success = compileProject(projectDir);
139
- if (success) {
140
- log('✅ Rebuild successful!');
141
- // Trigger browser reload
142
- if (server && server.broadcastReload) {
143
- server.broadcastReload();
144
- log('🔄 Browser reload triggered');
145
- }
178
+ if (success && server.broadcastReload) {
179
+ server.broadcastReload();
180
+ log('🔄 Browser reload triggered');
146
181
  }
147
182
  } catch (err) {
148
183
  console.error('❌ Rebuild failed:', err.stack || err.message);
149
184
  }
150
- }, 300); // Slightly longer debounce
185
+ }, 300);
151
186
  });
152
187
 
153
188
  watcher.on('add', filePath => {
154
- if (!/\.(js|ts|tsx)$/.test(filePath)) {
155
- return;
189
+ if (/\.(js|ts|tsx)$/.test(filePath)) {
190
+ log(`📝 New file added: ${path.relative(projectDir, filePath)}`);
156
191
  }
157
- log(`📝 New file added: ${path.relative(projectDir, filePath)}`);
158
192
  });
159
193
 
160
194
  watcher.on('unlink', filePath => {
161
- if (!/\.(js|ts|tsx)$/.test(filePath)) {
162
- return;
195
+ if (/\.(js|ts|tsx)$/.test(filePath)) {
196
+ log(`🗑️ File removed: ${path.relative(projectDir, filePath)}`);
163
197
  }
164
- log(`🗑️ File removed: ${path.relative(projectDir, filePath)}`);
165
198
  });
166
199
 
167
200
  watcher.on('error', error => {
168
201
  console.error('❌ Watcher error:', error);
169
202
  });
170
203
 
171
- // Cleanup function
172
204
  const cleanup = () => {
173
205
  log('🧹 Cleaning up...');
174
206
  watcher.close();
175
- if (server) {
176
- server.close();
177
- }
207
+ if (server) server.close();
178
208
  process.exit(0);
179
209
  };
180
210
 
@@ -187,26 +217,23 @@ function compileProjectWatch(projectDir = process.cwd(), port = 3000) {
187
217
  function serveProject(projectDir = process.cwd(), port = 3000) {
188
218
  const server = http.createServer((req, res) => {
189
219
  let reqPath = req.url;
190
-
191
- // Handle root and index requests
220
+
192
221
  if (reqPath === '/' || reqPath === '/index.html') {
193
222
  reqPath = '/dist/index.html';
194
223
  }
195
-
196
- // Handle favicon requests
224
+
197
225
  if (reqPath === '/favicon.ico') {
198
226
  res.writeHead(204);
199
227
  return res.end();
200
228
  }
201
229
 
202
230
  const filePath = path.join(projectDir, reqPath);
203
-
204
- // Security check - ensure file is within project directory
231
+
205
232
  if (!filePath.startsWith(projectDir)) {
206
233
  res.writeHead(403);
207
234
  return res.end('403 Forbidden');
208
235
  }
209
-
236
+
210
237
  if (!fs.existsSync(filePath)) {
211
238
  res.writeHead(404);
212
239
  return res.end('404 Not Found');
@@ -215,8 +242,8 @@ function serveProject(projectDir = process.cwd(), port = 3000) {
215
242
  try {
216
243
  const content = fs.readFileSync(filePath);
217
244
  const mimeType = Mime.getType(filePath) || 'application/octet-stream';
218
-
219
- res.writeHead(200, {
245
+
246
+ res.writeHead(200, {
220
247
  'Content-Type': mimeType,
221
248
  'Cache-Control': 'no-cache, no-store, must-revalidate',
222
249
  'Pragma': 'no-cache',
@@ -231,14 +258,10 @@ function serveProject(projectDir = process.cwd(), port = 3000) {
231
258
  });
232
259
 
233
260
  const wss = new WebSocket.Server({ server });
234
-
235
- // Add WebSocket connection handling
261
+
236
262
  wss.on('connection', (ws) => {
237
263
  log('🔌 WebSocket client connected');
238
-
239
- ws.on('close', () => {
240
- log('🔌 WebSocket client disconnected');
241
- });
264
+ ws.on('close', () => log('🔌 WebSocket client disconnected'));
242
265
  });
243
266
 
244
267
  server.broadcastReload = () => {
@@ -252,12 +275,14 @@ function serveProject(projectDir = process.cwd(), port = 3000) {
252
275
  server.listen(port, () => {
253
276
  log(`🚀 Server running at http://localhost:${port}`);
254
277
  log(`🌐 Open your browser and navigate to: http://localhost:${port}`);
255
-
256
- // Remove the open() call completely for now to avoid hanging
257
- // User can manually open browser
258
278
  });
259
279
 
260
280
  return server;
261
281
  }
262
282
 
263
- module.exports = { compileProject, compileProjectWatch, serveProject };
283
+ module.exports = {
284
+ compileProject,
285
+ compileProjectWatch,
286
+ serveProject,
287
+ compileAndReturnOutput
288
+ };
@@ -1,4 +1,4 @@
1
- function baseHtml(appHtml, scriptName) {
1
+ function baseHtml(script) {
2
2
  return `
3
3
  <!DOCTYPE html>
4
4
  <html>
@@ -7,8 +7,7 @@ function baseHtml(appHtml, scriptName) {
7
7
  <title>Neutronium App</title>
8
8
  </head>
9
9
  <body>
10
- ${appHtml}
11
- <script type="module" src="./${scriptName}"></script>
10
+ ${script}
12
11
  <script>
13
12
  const ws = new WebSocket('ws://' + location.host);
14
13
  ws.onmessage = (msg) => {
@@ -0,0 +1,17 @@
1
+ import chokidar from 'chokidar';
2
+ import path from 'path';
3
+
4
+ const projectDir = process.cwd(); // or absolute path
5
+
6
+ const watcher = chokidar.watch(path.join(projectDir, '**/*.js'), {
7
+ ignoreInitial: true,
8
+ ignored: ['**/node_modules/**'],
9
+ awaitWriteFinish: {
10
+ stabilityThreshold: 300,
11
+ pollInterval: 100
12
+ }
13
+ });
14
+
15
+ watcher.on('all', (event, filePath) => {
16
+ console.log(`[${event}] ${filePath}`);
17
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "neutronium",
3
- "version": "2.9.91",
4
- "description": "A dense, efficient JavaScript framework for building modern web applications",
3
+ "version": "3.0.2",
4
+ "description": "Ultra-dense JavaScript framework maximum performance, minimal overhead",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
7
7
  "types": "./ts-neutronium/index.d.ts",
@@ -10,7 +10,7 @@
10
10
  ".": "./src/index.js"
11
11
  },
12
12
  "bin": {
13
- "neu-cli": "./cli/index.js"
13
+ "neu-cli": "cli/index.js"
14
14
  },
15
15
  "keywords": [
16
16
  "framework",
package/src/index.js CHANGED
@@ -3,42 +3,60 @@
3
3
  let globalState = [];
4
4
  let stateIndex = 0;
5
5
 
6
- // This will be called before rendering begins
7
- export function resetStateIndex() {
6
+ function resetStateIndex() {
8
7
  stateIndex = 0;
9
8
  }
10
9
 
11
- // Custom useState implementation
10
+ let currentEffect = null;
11
+
12
+ function useEffect(fn) {
13
+ currentEffect = fn;
14
+ fn(); // run once to collect dependencies
15
+ currentEffect = null;
16
+ }
17
+
12
18
  function useState(initialValue) {
13
19
  const index = stateIndex;
14
20
 
15
- if (globalState[index] === undefined) {
16
- globalState[index] = initialValue;
17
- }
21
+ if (!globalState[index]) {
22
+ let value = initialValue;
23
+ const subs = new Set();
18
24
 
19
- function setState(newValue) {
20
- globalState[index] = newValue;
25
+ function get() {
26
+ if (currentEffect) subs.add(currentEffect);
27
+ return value;
28
+ }
21
29
 
22
- if (typeof window.__NEUTRONIUM_RENDER_FN__ === 'function') {
23
- window.__NEUTRONIUM_RENDER_FN__(); // triggers re-render
30
+ function set(newVal) {
31
+ if (value !== newVal) {
32
+ value = newVal;
33
+ subs.forEach(fn => fn()); // re-run effects
34
+ if (typeof window.__NEUTRONIUM_RENDER_FN__ === 'function') {
35
+ window.__NEUTRONIUM_RENDER_FN__();
36
+ }
37
+ }
24
38
  }
39
+
40
+ globalState[index] = [get, set];
25
41
  }
26
42
 
43
+ const result = globalState[index];
27
44
  stateIndex++;
28
- return [globalState[index], setState];
45
+ return result;
29
46
  }
30
47
 
31
48
  function h(type, props = {}, ...children) {
49
+ props = props || {};
50
+ props.children = (props.children || []).concat(children).flat();
51
+
32
52
  if (typeof type === 'function') {
33
- // 🔧 Add children to props
34
- props = props || {};
35
- props.children = children.flat(); // ✅ critical fix
36
53
  return type(props);
37
54
  }
38
55
 
39
56
  const el = document.createElement(type);
40
57
 
41
58
  for (const [key, value] of Object.entries(props || {})) {
59
+ if (key === 'children') continue; // skip
42
60
  if (key.startsWith('on') && typeof value === 'function') {
43
61
  el.addEventListener(key.slice(2).toLowerCase(), value);
44
62
  } else if (key === 'ref' && typeof value === 'function') {
@@ -48,7 +66,7 @@ function h(type, props = {}, ...children) {
48
66
  }
49
67
  }
50
68
 
51
- children.flat().forEach(child => {
69
+ props.children.forEach(child => {
52
70
  if (typeof child === 'string' || typeof child === 'number') {
53
71
  el.appendChild(document.createTextNode(child));
54
72
  } else if (child instanceof Node) {
@@ -71,14 +89,14 @@ function createApp(component) {
71
89
  window.__NEUTRONIUM_ROOT__ = root;
72
90
 
73
91
  function render() {
74
- resetStateIndex(); // ✅ this is enough
92
+ resetStateIndex();
75
93
  const vnode = component();
76
94
  root.innerHTML = '';
77
95
  root.appendChild(vnode);
78
96
  }
79
97
 
80
- window.__NEUTRONIUM_RENDER_FN__ = render; // save render function
81
- render(); // initial render
98
+ window.__NEUTRONIUM_RENDER_FN__ = render;
99
+ render();
82
100
 
83
101
  return root;
84
102
  }
@@ -100,4 +118,4 @@ function Fragment(props = {}) {
100
118
  return frag;
101
119
  }
102
120
 
103
- export { h, createApp, Fragment, useState };
121
+ export { h, createApp, Fragment, useState,useEffect, resetStateIndex };
@@ -1,58 +1,71 @@
1
- // @types/netronium/index.d.ts
1
+ // src/index.ts
2
2
 
3
- type StateUpdater<T> = (newValue: T) => void;
4
- type Component<T = any> = (props?: T) => HTMLElement | DocumentFragment;
3
+ type EffectFn = () => void;
4
+ type Setter<T> = (value: T) => void;
5
+ type Getter<T> = () => T;
6
+ type StateTuple<T> = [Getter<T>, Setter<T>];
5
7
 
6
- let globalState: any[] = [];
8
+ let globalState: Array<StateTuple<any>> = [];
7
9
  let stateIndex = 0;
8
10
 
9
- // Reset index before each render
10
- export function resetStateIndex(): void {
11
+ function resetStateIndex(): void {
11
12
  stateIndex = 0;
12
13
  }
13
14
 
14
- // Custom useState
15
- export function useState<T>(initialValue: T): [T, StateUpdater<T>] {
16
- const currentIndex = stateIndex;
15
+ let currentEffect: EffectFn | null = null;
17
16
 
18
- if (globalState[currentIndex] === undefined) {
19
- globalState[currentIndex] = initialValue;
20
- }
21
-
22
- function setState(newValue: T): void {
23
- globalState[currentIndex] = newValue;
17
+ function useEffect(fn: EffectFn): void {
18
+ currentEffect = fn;
19
+ fn(); // run once to collect dependencies
20
+ currentEffect = null;
21
+ }
24
22
 
25
- // Re-render
26
- const root = window.__NEUTRONIUM_ROOT__ as HTMLElement | null;
27
- const renderFn = window.__NEUTRONIUM_RENDER_FN__ as (() => Node) | null;
23
+ function useState<T>(initialValue: T): StateTuple<T> {
24
+ const index = stateIndex;
25
+
26
+ if (!globalState[index]) {
27
+ let value = initialValue;
28
+ const subs = new Set<EffectFn>();
29
+
30
+ const get: Getter<T> = () => {
31
+ if (currentEffect) subs.add(currentEffect);
32
+ return value;
33
+ };
34
+
35
+ const set: Setter<T> = (newVal: T) => {
36
+ if (value !== newVal) {
37
+ value = newVal;
38
+ subs.forEach(fn => fn()); // re-run effects
39
+ if (typeof (window as any).__NEUTRONIUM_RENDER_FN__ === 'function') {
40
+ (window as any).__NEUTRONIUM_RENDER_FN__();
41
+ }
42
+ }
43
+ };
28
44
 
29
- if (root && typeof renderFn === 'function') {
30
- root.innerHTML = '';
31
- resetStateIndex();
32
- const newVNode = renderFn();
33
- root.appendChild(newVNode);
34
- }
45
+ globalState[index] = [get, set];
35
46
  }
36
47
 
48
+ const result = globalState[index] as StateTuple<T>;
37
49
  stateIndex++;
38
- return [globalState[currentIndex], setState];
50
+ return result;
39
51
  }
40
52
 
41
- // JSX-compatible hyperscript function
42
- export function h(
43
- type: string | Component,
44
- props: { [key: string]: any } = {},
45
- ...children: any[]
46
- ): HTMLElement | DocumentFragment {
53
+ type Props = {
54
+ [key: string]: any;
55
+ children?: any;
56
+ };
57
+
58
+ function h(type: string | ((props: Props) => Node), props: Props = {}, ...children: any[]): Node {
59
+ props.children = (props.children || []).concat(children).flat();
60
+
47
61
  if (typeof type === 'function') {
48
- props = props || {};
49
- props.children = children.flat();
50
62
  return type(props);
51
63
  }
52
64
 
53
65
  const el = document.createElement(type);
54
66
 
55
67
  for (const [key, value] of Object.entries(props)) {
68
+ if (key === 'children') continue;
56
69
  if (key.startsWith('on') && typeof value === 'function') {
57
70
  el.addEventListener(key.slice(2).toLowerCase(), value);
58
71
  } else if (key === 'ref' && typeof value === 'function') {
@@ -62,56 +75,68 @@ export function h(
62
75
  }
63
76
  }
64
77
 
65
- children.flat().forEach(child => {
78
+ for (const child of props.children) {
66
79
  if (typeof child === 'string' || typeof child === 'number') {
67
- el.appendChild(document.createTextNode(child));
80
+ el.appendChild(document.createTextNode(String(child)));
68
81
  } else if (child instanceof Node) {
69
82
  el.appendChild(child);
70
83
  }
71
- });
84
+ }
72
85
 
73
86
  return el;
74
87
  }
75
88
 
76
- // Mount app to DOM
77
- export function createApp(component: () => Node) {
89
+ function createApp(component: () => Node) {
78
90
  return {
79
- mount(selector: string | HTMLElement): Node | null {
80
- const root =
81
- typeof selector === 'string'
82
- ? document.querySelector(selector)
83
- : selector;
91
+ mount(selector: string | Element): Element | null {
92
+ const root = typeof selector === 'string'
93
+ ? document.querySelector(selector)
94
+ : selector;
84
95
 
85
96
  if (!root) {
86
97
  console.error(`❌ Root element '${selector}' not found`);
87
98
  return null;
88
99
  }
89
100
 
90
- window.__NEUTRONIUM_ROOT__ = root;
91
- window.__NEUTRONIUM_RENDER_FN__ = component;
101
+ (window as any).__NEUTRONIUM_ROOT__ = root;
102
+
103
+ function render() {
104
+ resetStateIndex();
105
+ const vnode = component();
106
+ root.innerHTML = '';
107
+ root.appendChild(vnode);
108
+ }
92
109
 
93
- resetStateIndex();
94
- const vnode = component();
95
- root.innerHTML = '';
96
- root.appendChild(vnode);
110
+ (window as any).__NEUTRONIUM_RENDER_FN__ = render;
111
+ render();
97
112
 
98
- return vnode;
113
+ return root;
99
114
  }
100
115
  };
101
116
  }
102
117
 
103
- // Fragment support
104
- export function Fragment(props: { children?: any[] }): DocumentFragment {
118
+ function Fragment(props: Props = {}): DocumentFragment {
105
119
  const frag = document.createDocumentFragment();
106
- const children = props.children ?? [];
120
+ const children = props.children || [];
121
+
122
+ const childArray = Array.isArray(children) ? children : [children];
107
123
 
108
- (Array.isArray(children) ? children : [children]).forEach(child => {
124
+ for (const child of childArray) {
109
125
  if (typeof child === 'string' || typeof child === 'number') {
110
- frag.appendChild(document.createTextNode(child));
126
+ frag.appendChild(document.createTextNode(String(child)));
111
127
  } else if (child instanceof Node) {
112
128
  frag.appendChild(child);
113
129
  }
114
- });
130
+ }
115
131
 
116
132
  return frag;
117
- }
133
+ }
134
+
135
+ export {
136
+ h,
137
+ createApp,
138
+ Fragment,
139
+ useState,
140
+ useEffect,
141
+ resetStateIndex
142
+ };