create-aziz-app 3.1.2 → 3.1.3
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 +658 -207
- package/bin/create-aziz-app.js +302 -302
- package/package.json +1 -1
- package/template/README.md +402 -402
- package/template/_framework/api.js +219 -219
- package/template/_framework/boot.js +33 -33
- package/template/_framework/hooks.js +367 -291
- package/template/_framework/next-response.js +128 -128
- package/template/_framework/route-match.js +145 -145
- package/template/_framework/router.js +465 -259
- package/template/_framework/runtime.js +264 -264
- package/template/app/layout.js +18 -18
- package/template/app/page.js +33 -33
- package/template/docs/01-getting-started.md +151 -151
- package/template/docs/02-project-structure.md +109 -109
- package/template/docs/03-pages-and-layouts.md +140 -140
- package/template/docs/04-routing.md +120 -120
- package/template/docs/05-hooks.md +169 -169
- package/template/docs/06-api-routes.md +210 -210
- package/template/docs/07-api-client.md +151 -151
- package/template/docs/08-styling.md +94 -94
- package/template/docs/09-imports-and-modules.md +97 -97
- package/template/docs/10-database-and-models.md +154 -154
- package/template/docs/11-authentication.md +171 -171
- package/template/docs/12-production-and-deployment.md +121 -121
- package/template/docs/13-internals.md +179 -179
- package/template/docs/README.md +67 -67
- package/template/index.html +20 -20
- package/template/package.json +16 -16
- package/template/scripts/dev-server.js +493 -381
- package/template/scripts/lib/api-router.js +525 -525
- package/template/scripts/lib/js-transform.js +213 -195
- package/template/scripts/lib/module-resolver.js +132 -132
|
@@ -1,195 +1,213 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Aziz.js — JS/JSX transform pipeline (server-side)
|
|
3
|
-
// - JSX → h() calls via @babel/standalone
|
|
4
|
-
// - Bare / @/ import rewriting to browser-servable URLs
|
|
5
|
-
// - mtime-based transform cache (big dev-server speed win)
|
|
6
|
-
// ============================================================
|
|
7
|
-
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
|
|
11
|
-
// ─── Babel loading (with fallback resolution for monorepos/tests) ───
|
|
12
|
-
let Babel = null;
|
|
13
|
-
try {
|
|
14
|
-
Babel = require('@babel/standalone');
|
|
15
|
-
} catch (e) {
|
|
16
|
-
const fallbacks = [
|
|
17
|
-
path.join(__dirname, '..', '..', 'node_modules', '@babel', 'standalone'),
|
|
18
|
-
path.join(process.cwd(), 'node_modules', '@babel', 'standalone'),
|
|
19
|
-
];
|
|
20
|
-
for (const fb of fallbacks) {
|
|
21
|
-
try { Babel = require(fb); break; } catch { /* keep looking */ }
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function hasBabel() {
|
|
26
|
-
return !!Babel;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
i++;
|
|
95
|
-
} else if (mode === '
|
|
96
|
-
if (c === '
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Aziz.js — JS/JSX transform pipeline (server-side)
|
|
3
|
+
// - JSX → h() calls via @babel/standalone
|
|
4
|
+
// - Bare / @/ import rewriting to browser-servable URLs
|
|
5
|
+
// - mtime-based transform cache (big dev-server speed win)
|
|
6
|
+
// ============================================================
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
|
|
11
|
+
// ─── Babel loading (with fallback resolution for monorepos/tests) ───
|
|
12
|
+
let Babel = null;
|
|
13
|
+
try {
|
|
14
|
+
Babel = require('@babel/standalone');
|
|
15
|
+
} catch (e) {
|
|
16
|
+
const fallbacks = [
|
|
17
|
+
path.join(__dirname, '..', '..', 'node_modules', '@babel', 'standalone'),
|
|
18
|
+
path.join(process.cwd(), 'node_modules', '@babel', 'standalone'),
|
|
19
|
+
];
|
|
20
|
+
for (const fb of fallbacks) {
|
|
21
|
+
try { Babel = require(fb); break; } catch { /* keep looking */ }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function hasBabel() {
|
|
26
|
+
return !!Babel;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Thrown whenever a module needs compiling but Babel is unavailable.
|
|
30
|
+
// Never fall back to the untransformed source: the browser cannot execute
|
|
31
|
+
// JSX, the module import rejects, and the router silently renders its
|
|
32
|
+
// built-in 404 — a missing dependency disguised as a routing bug.
|
|
33
|
+
const BABEL_MISSING_MESSAGE =
|
|
34
|
+
'@babel/standalone is not installed, so JSX cannot be compiled. ' +
|
|
35
|
+
'Run "npm install" in the project folder, then restart the dev server.';
|
|
36
|
+
|
|
37
|
+
// ─── JSX transform ───────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
function isFrameworkPath(filePath) {
|
|
40
|
+
return filePath.includes('/_framework/') || filePath.includes('\\_framework\\');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function transformJSX(code, filename) {
|
|
44
|
+
if (!Babel) throw new Error(BABEL_MISSING_MESSAGE);
|
|
45
|
+
const result = Babel.transform(code, {
|
|
46
|
+
filename,
|
|
47
|
+
presets: [
|
|
48
|
+
// runtime: 'classic' is required. Babel 8 defaults to the automatic
|
|
49
|
+
// runtime, which rejects an explicit pragma ("pragma and pragmaFrag
|
|
50
|
+
// cannot be set when runtime is automatic"). We compile to the
|
|
51
|
+
// global `h`/`Fragment` that boot.js installs, not to jsx-runtime.
|
|
52
|
+
['react', { runtime: 'classic', pragma: 'h', pragmaFrag: 'Fragment' }]
|
|
53
|
+
],
|
|
54
|
+
plugins: [],
|
|
55
|
+
sourceType: 'module',
|
|
56
|
+
});
|
|
57
|
+
return result.code;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─── Import rewriting ─────────────────────────────────────────
|
|
61
|
+
// import X from 'mongoose' → '/_modules/mongoose'
|
|
62
|
+
// import X from '@/lib/db' → '/lib/db'
|
|
63
|
+
// import X from '/absolute.js' → unchanged
|
|
64
|
+
// import('pkg') → import('/_modules/pkg')
|
|
65
|
+
//
|
|
66
|
+
// Runs on the whole module (not line-by-line) so multi-line
|
|
67
|
+
// import statements are handled correctly.
|
|
68
|
+
//
|
|
69
|
+
// Only keywords sitting in CODE position are rewritten. A `from`
|
|
70
|
+
// or `import` inside a string literal / template literal / comment
|
|
71
|
+
// is prose (e.g. documentation text in JSX) and must be left alone
|
|
72
|
+
// — rewriting it corrupts the module and the page fails to load.
|
|
73
|
+
|
|
74
|
+
// Uint8Array marking every character that is in code position
|
|
75
|
+
// (outside string literals, template literals and comments).
|
|
76
|
+
function codePositions(code) {
|
|
77
|
+
const n = code.length;
|
|
78
|
+
const isCode = new Uint8Array(n);
|
|
79
|
+
const stack = []; // '{' for blocks, 'tpl' for ${ … } in templates
|
|
80
|
+
let mode = 'code'; // code | ' | " | ` | // | /*
|
|
81
|
+
let i = 0;
|
|
82
|
+
|
|
83
|
+
while (i < n) {
|
|
84
|
+
const c = code[i];
|
|
85
|
+
|
|
86
|
+
if (mode === 'code') {
|
|
87
|
+
isCode[i] = 1;
|
|
88
|
+
if (c === '\\') { i += 2; continue; }
|
|
89
|
+
if (c === "'" || c === '"' || c === '`') mode = c;
|
|
90
|
+
else if (c === '/' && code[i + 1] === '/') mode = '//';
|
|
91
|
+
else if (c === '/' && code[i + 1] === '*') mode = '/*';
|
|
92
|
+
else if (c === '{') stack.push('{');
|
|
93
|
+
else if (c === '}') { if (stack.pop() === 'tpl') mode = '`'; }
|
|
94
|
+
i++;
|
|
95
|
+
} else if (mode === "'" || mode === '"' || mode === '`') {
|
|
96
|
+
if (c === '\\') { i += 2; continue; }
|
|
97
|
+
if (c === mode) mode = 'code';
|
|
98
|
+
else if (mode === '`' && c === '$' && code[i + 1] === '{') {
|
|
99
|
+
stack.push('tpl');
|
|
100
|
+
mode = 'code';
|
|
101
|
+
isCode[i] = 1;
|
|
102
|
+
isCode[i + 1] = 1;
|
|
103
|
+
i += 2;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
i++;
|
|
107
|
+
} else if (mode === '//') {
|
|
108
|
+
if (c === '\n') mode = 'code';
|
|
109
|
+
i++;
|
|
110
|
+
} else { // block comment
|
|
111
|
+
if (c === '*' && code[i + 1] === '/') { mode = 'code'; i += 2; continue; }
|
|
112
|
+
i++;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return isCode;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isRelativeOrAbsolute(spec) {
|
|
119
|
+
return spec.startsWith('/') ||
|
|
120
|
+
spec.startsWith('./') ||
|
|
121
|
+
spec.startsWith('../') ||
|
|
122
|
+
spec.startsWith('#') ||
|
|
123
|
+
spec.startsWith('node:') ||
|
|
124
|
+
spec.startsWith('data:') ||
|
|
125
|
+
spec.startsWith('file:') ||
|
|
126
|
+
/^https?:\/\//.test(spec);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function mapSpecifier(spec) {
|
|
130
|
+
if (isRelativeOrAbsolute(spec)) return spec;
|
|
131
|
+
if (spec.startsWith('@/')) return '/' + spec.slice(2);
|
|
132
|
+
return '/_modules/' + spec;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function rewriteImports(code) {
|
|
136
|
+
const isCode = codePositions(code);
|
|
137
|
+
|
|
138
|
+
// from 'specifier' (covers `import ... from`, `export ... from`)
|
|
139
|
+
code = code.replace(/(\bfrom\s*)(['"])([^'"\n]+)\2/g, (m, from, q, spec, offset) => {
|
|
140
|
+
if (!isCode[offset]) return m;
|
|
141
|
+
const mapped = mapSpecifier(spec);
|
|
142
|
+
return mapped === spec ? m : `${from}${q}${mapped}${q}`;
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// side-effect imports: import 'specifier';
|
|
146
|
+
// (requires the quote right after `import`, so `import(` is not matched)
|
|
147
|
+
code = code.replace(/(\bimport\s+)(['"])([^'"\n]+)\2/g, (m, kw, q, spec, offset) => {
|
|
148
|
+
if (!isCode[offset]) return m;
|
|
149
|
+
const mapped = mapSpecifier(spec);
|
|
150
|
+
return mapped === spec ? m : `${kw}${q}${mapped}${q}`;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// dynamic imports: import('specifier')
|
|
154
|
+
code = code.replace(/(\bimport\s*\(\s*)(['"])([^'"\n]+)\2(\s*\))/g, (m, pre, q, spec, post, offset) => {
|
|
155
|
+
if (!isCode[offset]) return m;
|
|
156
|
+
const mapped = mapSpecifier(spec);
|
|
157
|
+
return mapped === spec ? m : `${pre}${q}${mapped}${q}${post}`;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return code;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ─── mtime-keyed transform cache ─────────────────────────────
|
|
164
|
+
|
|
165
|
+
const cache = new Map(); // filePath → { mtimeMs, code }
|
|
166
|
+
|
|
167
|
+
function transformModule(code, filePath, mtimeMs) {
|
|
168
|
+
// Framework internals contain no JSX and only use absolute imports.
|
|
169
|
+
if (isFrameworkPath(filePath)) return code;
|
|
170
|
+
|
|
171
|
+
const hit = cache.get(filePath);
|
|
172
|
+
if (hit && hit.mtimeMs === mtimeMs) return hit.code;
|
|
173
|
+
|
|
174
|
+
let out;
|
|
175
|
+
try {
|
|
176
|
+
out = transformJSX(code, path.basename(filePath));
|
|
177
|
+
} catch (err) {
|
|
178
|
+
if (err.message === BABEL_MISSING_MESSAGE) {
|
|
179
|
+
// Startup prints an actionable banner — don't repeat it for every file.
|
|
180
|
+
out = `throw new Error(${JSON.stringify(BABEL_MISSING_MESSAGE)});`;
|
|
181
|
+
} else {
|
|
182
|
+
console.error(`❌ JSX transform error in ${filePath}:`, err.message);
|
|
183
|
+
out = `throw new Error(${JSON.stringify('JSX transform error in ' + filePath + ': ' + err.message)});`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
out = rewriteImports(out);
|
|
187
|
+
cache.set(filePath, { mtimeMs, code: out });
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function invalidate(filePath) {
|
|
192
|
+
cache.delete(filePath);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function clearCache() {
|
|
196
|
+
cache.clear();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function cacheSize() {
|
|
200
|
+
return cache.size;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
module.exports = {
|
|
204
|
+
hasBabel,
|
|
205
|
+
BABEL_MISSING_MESSAGE,
|
|
206
|
+
transformJSX,
|
|
207
|
+
rewriteImports,
|
|
208
|
+
transformModule,
|
|
209
|
+
invalidate,
|
|
210
|
+
clearCache,
|
|
211
|
+
cacheSize,
|
|
212
|
+
isFrameworkPath,
|
|
213
|
+
};
|