@makano/rew 1.2.4 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/civet/main.js +17239 -0
- package/lib/rew/cli/cli.js +57 -5
- package/lib/rew/cli/log.js +5 -1
- package/lib/rew/cli/run.js +2 -2
- package/lib/rew/cli/utils.js +147 -60
- package/lib/rew/const/default.js +5 -1
- package/lib/rew/const/ext.js +5 -0
- package/lib/rew/const/opt.js +7 -2
- package/lib/rew/const/usage.js +15 -0
- package/lib/rew/functions/exec.js +2 -2
- package/lib/rew/functions/export.js +1 -1
- package/lib/rew/functions/fs.js +6 -1
- package/lib/rew/functions/id.js +2 -2
- package/lib/rew/functions/import.js +34 -13
- package/lib/rew/functions/require.js +17 -1
- package/lib/rew/functions/stdout.js +4 -0
- package/lib/rew/main.js +1 -13
- package/lib/rew/modules/compiler.js +122 -26
- package/lib/rew/modules/context.js +13 -1
- package/lib/rew/modules/runtime.js +37 -20
- package/lib/rew/pkgs/conf.js +1 -1
- package/lib/rew/pkgs/rune.js +8 -1
- package/lib/rew/pkgs/serve.js +373 -0
- package/lib/rew/pkgs/stream.js +10 -0
- package/lib/rew/pkgs/web.js +504 -0
- package/package.json +10 -5
- package/runtime.d.ts +943 -0
- package/lib/coffeescript/browser.js +0 -156
- package/lib/coffeescript/cake.js +0 -134
- package/lib/coffeescript/coffeescript.js +0 -465
- package/lib/coffeescript/command.js +0 -832
- package/lib/coffeescript/grammar.js +0 -1930
- package/lib/coffeescript/helpers.js +0 -513
- package/lib/coffeescript/index.js +0 -230
- package/lib/coffeescript/lexer.js +0 -2316
- package/lib/coffeescript/nodes.js +0 -9784
- package/lib/coffeescript/optparse.js +0 -258
- package/lib/coffeescript/parser.js +0 -20384
- package/lib/coffeescript/register.js +0 -120
- package/lib/coffeescript/repl.js +0 -328
- package/lib/coffeescript/rewriter.js +0 -1448
- package/lib/coffeescript/scope.js +0 -191
- package/lib/coffeescript/sourcemap.js +0 -244
@@ -0,0 +1,373 @@
|
|
1
|
+
const { readdirSync, existsSync } = require('fs');
|
2
|
+
const http = require('http');
|
3
|
+
const { IttyRouter, AutoRouter, Router, createResponse, cors, error, StatusError, html, json, withCookies, withContent, withParams, jpeg, png, webp, text, status } = require('itty-router');
|
4
|
+
const path = require('path');
|
5
|
+
const { run } = require('../main');
|
6
|
+
const { runPath } = require('../modules/runtime');
|
7
|
+
const { cleanCache } = require('../functions/import');
|
8
|
+
const { REW_FILE_TYPE } = require('../const/ext');
|
9
|
+
|
10
|
+
const lookUpFiles = ['route', 'page', 'page.s'];
|
11
|
+
|
12
|
+
module.exports = (context) => {
|
13
|
+
|
14
|
+
// http.createServer((req, res) => {
|
15
|
+
// res.end();
|
16
|
+
// }).listen(1400);
|
17
|
+
|
18
|
+
const imp = (file) => context.imp(file);
|
19
|
+
const Web = imp('web');
|
20
|
+
|
21
|
+
function mkReq(req) {
|
22
|
+
const url = `http://${req.headers.host}${req.url}`;
|
23
|
+
const options = {
|
24
|
+
method: req.method,
|
25
|
+
headers: req.headers,
|
26
|
+
body: req.body
|
27
|
+
};
|
28
|
+
|
29
|
+
return new Request(url, options);
|
30
|
+
}
|
31
|
+
|
32
|
+
class Server {
|
33
|
+
_server = {};
|
34
|
+
routers = {};
|
35
|
+
|
36
|
+
constructor(options){
|
37
|
+
this.options = options;
|
38
|
+
this._server = http.createServer((req, res) => {
|
39
|
+
options.handler ? options.handler(req, res) : this.handleRequest(req, res);
|
40
|
+
});
|
41
|
+
if(options.routers){
|
42
|
+
options.routers.forEach(router => router.to(this));
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
async handleRequest(req, res){
|
47
|
+
try {
|
48
|
+
let response = new Response();
|
49
|
+
const request = mkReq(req);
|
50
|
+
if(this.options.fetch == 'router'){
|
51
|
+
if(!Object.keys(this.options.routers).length) throw new Error('No fetch function nor routers found');
|
52
|
+
response = await this.options.routers[Object.keys(this.options.routers)[0]].fetch(request);
|
53
|
+
} else {
|
54
|
+
response = await this.options.fetch(request);
|
55
|
+
}
|
56
|
+
|
57
|
+
if(!response){
|
58
|
+
res.end('Cannot '+req.method+' '+req.url);
|
59
|
+
return;
|
60
|
+
}
|
61
|
+
|
62
|
+
response.headers.forEach((value, name) => {
|
63
|
+
res.setHeader(name, value);
|
64
|
+
});
|
65
|
+
|
66
|
+
res.writeHead(response.status);
|
67
|
+
|
68
|
+
const buffer = await response.arrayBuffer();
|
69
|
+
res.end(Buffer.from(buffer));
|
70
|
+
} catch (error) {
|
71
|
+
// Handle errors
|
72
|
+
console.error("Error:", error);
|
73
|
+
res.writeHead(500, {'Content-Type': 'text/plain'});
|
74
|
+
res.end("Internal Server Error");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
get listen(){
|
79
|
+
this._server.listen(this.options.port);
|
80
|
+
return this;
|
81
|
+
}
|
82
|
+
|
83
|
+
set listen(port){
|
84
|
+
this.options.port = port;
|
85
|
+
return this;
|
86
|
+
}
|
87
|
+
|
88
|
+
port(port){
|
89
|
+
this.listen = port;
|
90
|
+
return this;
|
91
|
+
}
|
92
|
+
|
93
|
+
log(string){
|
94
|
+
console.log(string.replace(/\$([A-Za-z0-9_]+)/g, (_, name) => this.options[name] || _));
|
95
|
+
return this;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
class SvrRouter {
|
100
|
+
static new(Class, options, props){
|
101
|
+
const router = Class(options);
|
102
|
+
for(let i in props) router[i] = props[i];
|
103
|
+
router.to = (server) => {
|
104
|
+
if(server instanceof Server){
|
105
|
+
server.routers[this.id] = this;
|
106
|
+
}
|
107
|
+
};
|
108
|
+
return router;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
function findLayoutFiles(filePath, root, isClientSide = true, resolveExtensions = [REW_FILE_TYPE.EXTENSION, '.coffee', '.js', '.jsx']) {
|
113
|
+
const layouts = [];
|
114
|
+
const rootDir = root;
|
115
|
+
let currentDir = path.dirname(filePath);
|
116
|
+
|
117
|
+
while (currentDir !== rootDir) {
|
118
|
+
for (const ext of resolveExtensions) {
|
119
|
+
const layoutFile = path.join(currentDir, `layout${isClientSide ? '' : '.s'}${ext}`);
|
120
|
+
if (existsSync(layoutFile)) {
|
121
|
+
layouts.push(layoutFile);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
currentDir = path.dirname(currentDir);
|
125
|
+
}
|
126
|
+
|
127
|
+
for (const ext of resolveExtensions) {
|
128
|
+
const layoutFile = path.join(currentDir, `layout${isClientSide ? '' : '.s'}${ext}`);
|
129
|
+
if (existsSync(layoutFile)) {
|
130
|
+
layouts.push(layoutFile);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
return layouts.reverse();
|
135
|
+
}
|
136
|
+
|
137
|
+
const defaultBundlerEntry = (file, layouts, data) => `
|
138
|
+
import * as target from "${file}";
|
139
|
+
${layouts.map((layout, ind) => `import * as layout${ind} from "${layout}";`).join('\n')}
|
140
|
+
let page = target.render ? target.render(${JSON.stringify(data)}) : target.default ? target.default(${JSON.stringify(data)}) : null;
|
141
|
+
${layouts.reverse().map((_, ind) => `if (layout${ind}.render) page = layout${ind}.render(${JSON.stringify(data)}, page);`).join('\n')}
|
142
|
+
`;
|
143
|
+
|
144
|
+
const defaultSsrBundlerEntry = (file, layouts, data) => `
|
145
|
+
files = "${layouts.length ? layouts.join(',')+',' : ''}${file}".split(',')
|
146
|
+
|
147
|
+
renderers = []
|
148
|
+
staticRendering = false
|
149
|
+
|
150
|
+
for key, file of files
|
151
|
+
renderers.push imp file
|
152
|
+
|
153
|
+
staticRendering = true if renderers[renderers.length-1].staticRendering
|
154
|
+
|
155
|
+
render = (req, data) ->
|
156
|
+
target = renderers.pop()
|
157
|
+
page = target.render req, data
|
158
|
+
for renderer in renderers
|
159
|
+
page = renderer.render req, data, page
|
160
|
+
page
|
161
|
+
|
162
|
+
exports { render, staticRendering }
|
163
|
+
`;
|
164
|
+
|
165
|
+
function createFileRouter({
|
166
|
+
onError = () => error(404, 'Path not found'),
|
167
|
+
root = '',
|
168
|
+
basePath = '',
|
169
|
+
resolveExtensions = [REW_FILE_TYPE.EXTENSION, '.coffee', '.js', '.jsx'],
|
170
|
+
bundlerOptions = {},
|
171
|
+
bundlerEntry = defaultBundlerEntry,
|
172
|
+
ssrBundlerEntry = defaultSsrBundlerEntry,
|
173
|
+
}) {
|
174
|
+
|
175
|
+
const params = {};
|
176
|
+
|
177
|
+
function lookUp(pathname) {
|
178
|
+
const routeParts = pathname.split('/').filter(Boolean);
|
179
|
+
let routePath = root;
|
180
|
+
|
181
|
+
|
182
|
+
Object.keys(params).forEach(key => delete params[key]);
|
183
|
+
|
184
|
+
for (const part of routeParts) {
|
185
|
+
const dir = readdirSync(routePath);
|
186
|
+
|
187
|
+
const match = dir.find(d => d === part || d.match(/^\[.*\]$/));
|
188
|
+
if (!match) return null;
|
189
|
+
|
190
|
+
if (match.match(/^\[.*\]$/)) {
|
191
|
+
const paramName = match.slice(1, -1);
|
192
|
+
params[paramName] = part;
|
193
|
+
}
|
194
|
+
|
195
|
+
routePath = path.join(routePath, match);
|
196
|
+
}
|
197
|
+
|
198
|
+
for (const base of lookUpFiles) {
|
199
|
+
for (const ext of resolveExtensions) {
|
200
|
+
const filePath = path.join(routePath, `${base}${ext}`);
|
201
|
+
if (existsSync(filePath)) {
|
202
|
+
return filePath;
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
return null;
|
208
|
+
}
|
209
|
+
|
210
|
+
function getReqProps(req) {
|
211
|
+
return {
|
212
|
+
params: {
|
213
|
+
...params,
|
214
|
+
...(req.params || {})
|
215
|
+
},
|
216
|
+
query: req.query,
|
217
|
+
url: req.url,
|
218
|
+
method: req.method
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
const w = new Web();
|
223
|
+
|
224
|
+
async function renderPage(file, basename, req){
|
225
|
+
const page = w.create({ viewportMeta: true });
|
226
|
+
let staticRendering = false;
|
227
|
+
if(basename.endsWith('.s')){
|
228
|
+
// SSR is enabled, do only ssr
|
229
|
+
const layouts = findLayoutFiles(file, root, false);
|
230
|
+
const fileContext = runPath(file, { code: ssrBundlerEntry(file, layouts) }).context.module.exports || {};
|
231
|
+
if(typeof fileContext.render !== "function") throw new ReferenceError("Route does not export function render");
|
232
|
+
let pageContent = fileContext.render(req, { page, ...getReqProps(req) });
|
233
|
+
if(fileContext.staticRendering) staticRendering = true;
|
234
|
+
if(!w.isNode(pageContent)) throw new TypeError("Route.render does not return an element");
|
235
|
+
if(pageContent?.type?.element == 'head'){
|
236
|
+
page.root.props.children.splice(page.root.props.children.indexOf(page.head), 1);
|
237
|
+
page.head = pageContent;
|
238
|
+
page.root.add(pageContent);
|
239
|
+
} else if(pageContent?.type?.element == 'body'){
|
240
|
+
page.root.props.children.splice(page.root.props.children.indexOf(page.body), 1);
|
241
|
+
page.body = pageContent;
|
242
|
+
page.root.add(pageContent);
|
243
|
+
} else if(pageContent?.type?.element == 'html'){
|
244
|
+
page.root = pageContent;
|
245
|
+
page.body = pageContent.find('body');
|
246
|
+
page.head = pageContent.find('head');
|
247
|
+
} else {
|
248
|
+
page.add(pageContent);
|
249
|
+
}
|
250
|
+
} else {
|
251
|
+
const layouts = findLayoutFiles(file, root, true);
|
252
|
+
const scriptString = await w.bundle(path.join(root, 'bundle.js'), {
|
253
|
+
...bundlerOptions,
|
254
|
+
code: bundlerEntry(file, layouts, getReqProps(req))
|
255
|
+
});
|
256
|
+
page.script(scriptString);
|
257
|
+
staticRendering = true;
|
258
|
+
}
|
259
|
+
return html(page.render(staticRendering));
|
260
|
+
}
|
261
|
+
|
262
|
+
async function handleRequest(req, file) {
|
263
|
+
const ext = path.extname(file);
|
264
|
+
const basename = path.basename(file, ext);
|
265
|
+
|
266
|
+
if (basename.startsWith('route')) {
|
267
|
+
const fileContext = run(file).context;
|
268
|
+
const handlers = fileContext.module.exports;
|
269
|
+
const method = req.method.toUpperCase();
|
270
|
+
if (handlers[method]) {
|
271
|
+
return await handlers[method](req, getReqProps(req));
|
272
|
+
} else {
|
273
|
+
return error(405, `Method ${method} not allowed`);
|
274
|
+
}
|
275
|
+
} else if (basename.startsWith('page')) {
|
276
|
+
return await renderPage(file, basename, req);
|
277
|
+
}
|
278
|
+
}
|
279
|
+
|
280
|
+
|
281
|
+
return async (req) => {
|
282
|
+
const url = new URL(req.url);
|
283
|
+
const pathname = basePath ? url.pathname.replace(new RegExp('^'+basePath), '') : url.pathname;
|
284
|
+
const file = lookUp(pathname);
|
285
|
+
cleanCache();
|
286
|
+
|
287
|
+
if (file) {
|
288
|
+
const response = handleRequest(req, file);
|
289
|
+
response.catch(() => onError());
|
290
|
+
return await response;
|
291
|
+
} else {
|
292
|
+
return onError();
|
293
|
+
}
|
294
|
+
};
|
295
|
+
}
|
296
|
+
|
297
|
+
|
298
|
+
|
299
|
+
class Svr {
|
300
|
+
create(options){
|
301
|
+
return new Server(options);
|
302
|
+
}
|
303
|
+
|
304
|
+
router({ id = '/', type = 'normal', ...options }){
|
305
|
+
let router;
|
306
|
+
if(type == 'default') router = SvrRouter.new(IttyRouter, {...options}, { id });
|
307
|
+
if(type == 'auto') router = SvrRouter.new(AutoRouter, {...options}, { id });
|
308
|
+
if(type == 'normal') router = SvrRouter.new(Router, {...options}, { id });
|
309
|
+
|
310
|
+
return router;
|
311
|
+
}
|
312
|
+
|
313
|
+
createResponse(format, transform, type = 'normal'){
|
314
|
+
return type == 'json' ? json(format, transform) : createResponse(format, transform);
|
315
|
+
}
|
316
|
+
|
317
|
+
html(string, options = {}){
|
318
|
+
return html(string, options);
|
319
|
+
}
|
320
|
+
|
321
|
+
json(object, options = {}){
|
322
|
+
return json(object, options);
|
323
|
+
}
|
324
|
+
|
325
|
+
jpeg(image, options = {}){
|
326
|
+
return jpeg(image, options);
|
327
|
+
}
|
328
|
+
|
329
|
+
png(image, options = {}){
|
330
|
+
return png(image, options);
|
331
|
+
}
|
332
|
+
|
333
|
+
webp(image, options = {}){
|
334
|
+
return webp(image, options);
|
335
|
+
}
|
336
|
+
|
337
|
+
text(string, options = {}){
|
338
|
+
return text(string, options);
|
339
|
+
}
|
340
|
+
|
341
|
+
status(code, options = {}){
|
342
|
+
return status(code, options);
|
343
|
+
}
|
344
|
+
|
345
|
+
cors(options = {}){
|
346
|
+
return cors(options);
|
347
|
+
}
|
348
|
+
|
349
|
+
error(status, body){
|
350
|
+
return error(status, body);
|
351
|
+
}
|
352
|
+
|
353
|
+
createFileRouter(o){
|
354
|
+
return createFileRouter(o);
|
355
|
+
}
|
356
|
+
}
|
357
|
+
|
358
|
+
class SvrResponse extends Response {}
|
359
|
+
class SvrRequest extends Request {}
|
360
|
+
|
361
|
+
Svr.prototype.Response = SvrResponse;
|
362
|
+
Svr.prototype.Request = SvrRequest;
|
363
|
+
Svr.prototype.URL = URL;
|
364
|
+
Svr.prototype.StatusError = StatusError;
|
365
|
+
|
366
|
+
Svr.prototype.withContent = withContent;
|
367
|
+
Svr.prototype.withCookies = withCookies;
|
368
|
+
Svr.prototype.withParams = withParams;
|
369
|
+
|
370
|
+
IttyRouter
|
371
|
+
|
372
|
+
return Svr;
|
373
|
+
}
|