@makano/rew 1.2.5 → 1.2.6
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/lib/civet/main.js +17239 -0
- package/lib/rew/cli/cli.js +34 -5
- package/lib/rew/cli/utils.js +43 -12
- package/lib/rew/const/default.js +2 -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/export.js +1 -1
- package/lib/rew/functions/fs.js +6 -1
- package/lib/rew/functions/import.js +17 -12
- 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 +103 -34
- package/lib/rew/modules/context.js +13 -1
- package/lib/rew/modules/runtime.js +37 -20
- 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 +7 -5
- package/runtime.d.ts +718 -146
- package/jsconfig.json +0 -13
- 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
|
+
}
|