zero-query 0.9.8 → 1.0.0

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.
Files changed (99) hide show
  1. package/README.md +55 -31
  2. package/cli/args.js +1 -1
  3. package/cli/commands/build.js +2 -2
  4. package/cli/commands/bundle.js +15 -15
  5. package/cli/commands/create.js +41 -7
  6. package/cli/commands/dev/devtools/index.js +1 -1
  7. package/cli/commands/dev/devtools/js/core.js +14 -14
  8. package/cli/commands/dev/devtools/js/elements.js +4 -4
  9. package/cli/commands/dev/devtools/js/stats.js +1 -1
  10. package/cli/commands/dev/devtools/styles.css +2 -2
  11. package/cli/commands/dev/index.js +2 -2
  12. package/cli/commands/dev/logger.js +1 -1
  13. package/cli/commands/dev/overlay.js +21 -14
  14. package/cli/commands/dev/server.js +5 -5
  15. package/cli/commands/dev/validator.js +7 -7
  16. package/cli/commands/dev/watcher.js +6 -6
  17. package/cli/help.js +4 -2
  18. package/cli/index.js +2 -2
  19. package/cli/scaffold/default/app/app.js +17 -18
  20. package/cli/scaffold/default/app/components/about.js +9 -9
  21. package/cli/scaffold/default/app/components/api-demo.js +6 -6
  22. package/cli/scaffold/default/app/components/contact-card.js +4 -4
  23. package/cli/scaffold/default/app/components/contacts/contacts.css +2 -2
  24. package/cli/scaffold/default/app/components/contacts/contacts.html +3 -3
  25. package/cli/scaffold/default/app/components/contacts/contacts.js +11 -11
  26. package/cli/scaffold/default/app/components/counter.js +8 -8
  27. package/cli/scaffold/default/app/components/home.js +13 -13
  28. package/cli/scaffold/default/app/components/not-found.js +1 -1
  29. package/cli/scaffold/default/app/components/playground/playground.css +1 -1
  30. package/cli/scaffold/default/app/components/playground/playground.html +11 -11
  31. package/cli/scaffold/default/app/components/playground/playground.js +11 -11
  32. package/cli/scaffold/default/app/components/todos.js +8 -8
  33. package/cli/scaffold/default/app/components/toolkit/toolkit.css +1 -1
  34. package/cli/scaffold/default/app/components/toolkit/toolkit.html +4 -4
  35. package/cli/scaffold/default/app/components/toolkit/toolkit.js +7 -7
  36. package/cli/scaffold/default/app/routes.js +1 -1
  37. package/cli/scaffold/default/app/store.js +1 -1
  38. package/cli/scaffold/default/global.css +2 -2
  39. package/cli/scaffold/default/index.html +2 -2
  40. package/cli/scaffold/minimal/app/app.js +6 -7
  41. package/cli/scaffold/minimal/app/components/about.js +5 -5
  42. package/cli/scaffold/minimal/app/components/counter.js +6 -6
  43. package/cli/scaffold/minimal/app/components/home.js +8 -8
  44. package/cli/scaffold/minimal/app/components/not-found.js +1 -1
  45. package/cli/scaffold/minimal/app/routes.js +1 -1
  46. package/cli/scaffold/minimal/app/store.js +1 -1
  47. package/cli/scaffold/minimal/global.css +2 -2
  48. package/cli/scaffold/minimal/index.html +1 -1
  49. package/cli/scaffold/ssr/app/app.js +29 -0
  50. package/cli/scaffold/ssr/app/components/about.js +28 -0
  51. package/cli/scaffold/ssr/app/components/home.js +37 -0
  52. package/cli/scaffold/ssr/app/components/not-found.js +15 -0
  53. package/cli/scaffold/ssr/app/routes.js +6 -0
  54. package/cli/scaffold/ssr/global.css +113 -0
  55. package/cli/scaffold/ssr/index.html +31 -0
  56. package/cli/scaffold/ssr/package.json +8 -0
  57. package/cli/scaffold/ssr/server/index.js +118 -0
  58. package/cli/utils.js +6 -6
  59. package/dist/zquery.dist.zip +0 -0
  60. package/dist/zquery.js +565 -228
  61. package/dist/zquery.min.js +2 -2
  62. package/index.d.ts +25 -12
  63. package/index.js +11 -7
  64. package/package.json +9 -3
  65. package/src/component.js +64 -63
  66. package/src/core.js +15 -15
  67. package/src/diff.js +38 -38
  68. package/src/errors.js +72 -18
  69. package/src/expression.js +15 -17
  70. package/src/http.js +4 -4
  71. package/src/package.json +1 -0
  72. package/src/reactive.js +75 -9
  73. package/src/router.js +104 -24
  74. package/src/ssr.js +133 -39
  75. package/src/store.js +103 -21
  76. package/src/utils.js +64 -12
  77. package/tests/audit.test.js +143 -15
  78. package/tests/cli.test.js +20 -20
  79. package/tests/component.test.js +121 -121
  80. package/tests/core.test.js +56 -56
  81. package/tests/diff.test.js +42 -42
  82. package/tests/errors.test.js +425 -147
  83. package/tests/expression.test.js +58 -53
  84. package/tests/http.test.js +20 -20
  85. package/tests/reactive.test.js +185 -24
  86. package/tests/router.test.js +501 -74
  87. package/tests/ssr.test.js +444 -10
  88. package/tests/store.test.js +264 -23
  89. package/tests/utils.test.js +163 -26
  90. package/types/collection.d.ts +2 -2
  91. package/types/component.d.ts +5 -5
  92. package/types/errors.d.ts +36 -4
  93. package/types/http.d.ts +3 -3
  94. package/types/misc.d.ts +9 -9
  95. package/types/reactive.d.ts +25 -3
  96. package/types/router.d.ts +10 -6
  97. package/types/ssr.d.ts +22 -2
  98. package/types/store.d.ts +40 -5
  99. package/types/utils.d.ts +1 -1
@@ -0,0 +1,15 @@
1
+ // not-found.js - 404 fallback component
2
+
3
+ export const notFound = {
4
+ render() {
5
+ return `
6
+ <div class="page-header" style="text-align:center; margin-top:4rem;">
7
+ <h1>404</h1>
8
+ <p class="subtitle">Page not found.</p>
9
+ <p style="margin-top:1rem;">
10
+ <a href="/" style="color:var(--accent);">← Home</a>
11
+ </p>
12
+ </div>
13
+ `;
14
+ }
15
+ };
@@ -0,0 +1,6 @@
1
+ // routes.js - Route definitions (shared between client and server)
2
+
3
+ export const routes = [
4
+ { path: '/', component: 'home-page' },
5
+ { path: '/about', component: 'about-page' },
6
+ ];
@@ -0,0 +1,113 @@
1
+ /* global.css - SSR Scaffold Styles */
2
+
3
+ *, *::before, *::after {
4
+ box-sizing: border-box;
5
+ margin: 0;
6
+ padding: 0;
7
+ }
8
+
9
+ :root {
10
+ --bg: #0f0f0f;
11
+ --surface: #1a1a2e;
12
+ --text: #e0e0e0;
13
+ --muted: #888;
14
+ --accent: #00d4ff;
15
+ --accent-hover: #00b8d9;
16
+ --radius: 8px;
17
+ --gap: 1.5rem;
18
+ }
19
+
20
+ body {
21
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
22
+ background: var(--bg);
23
+ color: var(--text);
24
+ line-height: 1.6;
25
+ min-height: 100vh;
26
+ }
27
+
28
+ /* -- Navbar -- */
29
+ .navbar {
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: space-between;
33
+ padding: 1rem 2rem;
34
+ background: var(--surface);
35
+ border-bottom: 1px solid rgba(255,255,255,0.06);
36
+ }
37
+
38
+ .brand {
39
+ font-weight: 700;
40
+ font-size: 1.2rem;
41
+ color: var(--accent);
42
+ }
43
+
44
+ .nav-links { display: flex; gap: 1rem; }
45
+
46
+ .nav-link {
47
+ color: var(--muted);
48
+ text-decoration: none;
49
+ padding: 0.4rem 0.8rem;
50
+ border-radius: var(--radius);
51
+ transition: color 0.2s, background 0.2s;
52
+ }
53
+ .nav-link:hover, .nav-link.active {
54
+ color: var(--accent);
55
+ background: rgba(0, 212, 255, 0.08);
56
+ }
57
+
58
+ /* -- Main content -- */
59
+ z-outlet {
60
+ max-width: 800px;
61
+ margin: 2rem auto;
62
+ padding: 0 1.5rem;
63
+ }
64
+
65
+ [z-cloak] { display: none !important; }
66
+
67
+ .page-header {
68
+ margin-bottom: var(--gap);
69
+ }
70
+ .page-header h1 {
71
+ font-size: 2rem;
72
+ margin-bottom: 0.5rem;
73
+ }
74
+ .page-header .subtitle {
75
+ color: var(--muted);
76
+ }
77
+
78
+ .card {
79
+ background: var(--surface);
80
+ border: 1px solid rgba(255,255,255,0.06);
81
+ border-radius: var(--radius);
82
+ padding: 1.5rem;
83
+ margin-bottom: var(--gap);
84
+ }
85
+ .card h3 {
86
+ margin-bottom: 0.75rem;
87
+ color: var(--accent);
88
+ }
89
+ .card code {
90
+ background: rgba(255,255,255,0.06);
91
+ padding: 0.15em 0.4em;
92
+ border-radius: 4px;
93
+ font-size: 0.9em;
94
+ }
95
+
96
+ .badge {
97
+ display: inline-block;
98
+ padding: 2px 8px;
99
+ border-radius: 4px;
100
+ font-size: 0.8em;
101
+ font-weight: 600;
102
+ }
103
+ .badge-ssr { background: rgba(0,212,255,0.15); color: var(--accent); }
104
+ .badge-csr { background: rgba(255,165,0,0.15); color: #ffa500; }
105
+
106
+ /* -- Footer -- */
107
+ .footer {
108
+ text-align: center;
109
+ padding: 2rem;
110
+ color: var(--muted);
111
+ border-top: 1px solid rgba(255,255,255,0.06);
112
+ margin-top: 3rem;
113
+ }
@@ -0,0 +1,31 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{NAME}}</title>
7
+ <base href="/">
8
+ <link rel="stylesheet" href="global.css">
9
+ <script src="zquery.min.js"></script>
10
+ <script type="module" src="app/app.js"></script>
11
+ </head>
12
+ <body>
13
+
14
+ <!-- Navigation -->
15
+ <nav class="navbar">
16
+ <span class="brand">⚡ {{NAME}}</span>
17
+ <div class="nav-links">
18
+ <a z-link="/" class="nav-link">Home</a>
19
+ <a z-link="/about" class="nav-link">About</a>
20
+ </div>
21
+ </nav>
22
+
23
+ <!-- Main content - SSR output is injected here by the server -->
24
+ <z-outlet z-cloak></z-outlet>
25
+
26
+ <footer class="footer">
27
+ <small>Built with zQuery · SSR Scaffold</small>
28
+ </footer>
29
+
30
+ </body>
31
+ </html>
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "{{NAME}}",
3
+ "private": true,
4
+ "type": "module",
5
+ "dependencies": {
6
+ "zero-query": "latest"
7
+ }
8
+ }
@@ -0,0 +1,118 @@
1
+ // server/index.js - SSR HTTP server
2
+ //
3
+ // Renders routes to HTML with zQuery SSR and serves them over HTTP.
4
+ // Components are imported from app/components/ - the same definitions
5
+ // the client uses.
6
+ //
7
+ // Usage:
8
+ // node server/index.js
9
+ // PORT=8080 node server/index.js
10
+
11
+ import { createServer } from 'node:http';
12
+ import { readFile } from 'node:fs/promises';
13
+ import { join, extname, resolve } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { createSSRApp } from 'zero-query/ssr';
16
+
17
+ // Shared component definitions - same ones the client registers
18
+ import { homePage } from '../app/components/home.js';
19
+ import { aboutPage } from '../app/components/about.js';
20
+ import { notFound } from '../app/components/not-found.js';
21
+ import { routes } from '../app/routes.js';
22
+
23
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
24
+ const ROOT = join(__dirname, '..');
25
+ const PORT = parseInt(process.env.PORT || '3000', 10);
26
+
27
+ // --- SSR app ----------------------------------------------------------------
28
+
29
+ const app = createSSRApp();
30
+ app.component('home-page', homePage);
31
+ app.component('about-page', aboutPage);
32
+ app.component('not-found', notFound);
33
+
34
+ // --- Route matching ---------------------------------------------------------
35
+
36
+ function matchRoute(pathname) {
37
+ const route = routes.find(r => r.path === pathname);
38
+ return route ? route.component : 'not-found';
39
+ }
40
+
41
+ // --- Render a full HTML page ------------------------------------------------
42
+
43
+ async function render(pathname) {
44
+ const component = matchRoute(pathname);
45
+ const body = await app.renderToString(component);
46
+
47
+ return `<!DOCTYPE html>
48
+ <html lang="en">
49
+ <head>
50
+ <meta charset="UTF-8">
51
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
52
+ <title>{{NAME}}</title>
53
+ <link rel="stylesheet" href="/global.css">
54
+ </head>
55
+ <body>
56
+ <nav class="navbar">
57
+ <span class="brand">⚡ {{NAME}}</span>
58
+ <div class="nav-links">
59
+ ${routes.map(r =>
60
+ ` <a href="${r.path}" class="nav-link${r.path === pathname ? ' active' : ''}">${
61
+ r.path === '/' ? 'Home' : r.path.slice(1)[0].toUpperCase() + r.path.slice(2)
62
+ }</a>`).join('\n')}
63
+ </div>
64
+ </nav>
65
+ <z-outlet>${body}</z-outlet>
66
+ <footer class="footer"><small>Built with zQuery · SSR</small></footer>
67
+ </body>
68
+ </html>`;
69
+ }
70
+
71
+ // --- Static files -----------------------------------------------------------
72
+
73
+ const MIME = {
74
+ '.css': 'text/css', '.js': 'text/javascript', '.json': 'application/json',
75
+ '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml',
76
+ '.ico': 'image/x-icon', '.woff2': 'font/woff2',
77
+ };
78
+
79
+ async function serveStatic(res, pathname) {
80
+ const ext = extname(pathname);
81
+ if (!MIME[ext]) return false;
82
+
83
+ const filePath = join(ROOT, pathname);
84
+ if (!resolve(filePath).startsWith(resolve(ROOT))) return false;
85
+
86
+ try {
87
+ const data = await readFile(filePath);
88
+ res.writeHead(200, { 'Content-Type': MIME[ext] });
89
+ res.end(data);
90
+ return true;
91
+ } catch { return false; }
92
+ }
93
+
94
+ // --- HTTP server ------------------------------------------------------------
95
+
96
+ createServer(async (req, res) => {
97
+ const { pathname } = new URL(req.url, `http://localhost:${PORT}`);
98
+
99
+ // Static assets (CSS, images, etc.)
100
+ if (pathname !== '/' && await serveStatic(res, pathname)) return;
101
+
102
+ // SSR route
103
+ try {
104
+ const html = await render(pathname);
105
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
106
+ res.end(html);
107
+ } catch (err) {
108
+ console.error('SSR error:', err);
109
+ if (!res.headersSent) {
110
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
111
+ }
112
+ res.end('Internal Server Error');
113
+ }
114
+ }).listen(PORT, () => {
115
+ console.log(`\n ⚡ SSR server → http://localhost:${PORT}\n`);
116
+ routes.forEach(r => console.log(` ${r.path.padEnd(10)} → ${r.component}`));
117
+ console.log(` * → not-found\n`);
118
+ });
package/cli/utils.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * cli/utils.js shared utility functions
2
+ * cli/utils.js - shared utility functions
3
3
  *
4
4
  * Context-aware comment stripping, quick minification, size formatting,
5
5
  * and recursive directory copying. These are consumed by both the
@@ -12,7 +12,7 @@ const fs = require('fs');
12
12
  const path = require('path');
13
13
 
14
14
  // ---------------------------------------------------------------------------
15
- // _copyTemplateLiteral copy a template literal verbatim, tracking ${…}
15
+ // _copyTemplateLiteral - copy a template literal verbatim, tracking ${…}
16
16
  // nesting so that `//` inside template text isn't mistaken for a comment.
17
17
  // ---------------------------------------------------------------------------
18
18
 
@@ -49,7 +49,7 @@ function _copyTemplateLiteral(code, start) {
49
49
  }
50
50
 
51
51
  // ---------------------------------------------------------------------------
52
- // stripComments context-aware, skips strings / templates / regex
52
+ // stripComments - context-aware, skips strings / templates / regex
53
53
  // ---------------------------------------------------------------------------
54
54
 
55
55
  function stripComments(code) {
@@ -127,7 +127,7 @@ function stripComments(code) {
127
127
  }
128
128
 
129
129
  // ---------------------------------------------------------------------------
130
- // minify single-pass minification
130
+ // minify - single-pass minification
131
131
  // Strips comments, collapses whitespace to the minimum required,
132
132
  // and preserves string / template-literal / regex content verbatim.
133
133
  // ---------------------------------------------------------------------------
@@ -251,7 +251,7 @@ function _isRegexCtx(out) {
251
251
  }
252
252
 
253
253
  // ---------------------------------------------------------------------------
254
- // sizeKB human-readable file size
254
+ // sizeKB - human-readable file size
255
255
  // ---------------------------------------------------------------------------
256
256
 
257
257
  function sizeKB(buf) {
@@ -259,7 +259,7 @@ function sizeKB(buf) {
259
259
  }
260
260
 
261
261
  // ---------------------------------------------------------------------------
262
- // copyDirSync recursive directory copy
262
+ // copyDirSync - recursive directory copy
263
263
  // ---------------------------------------------------------------------------
264
264
 
265
265
  function copyDirSync(src, dest) {
Binary file