@makano/rew 1.2.4 → 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.
Files changed (43) hide show
  1. package/lib/civet/main.js +17239 -0
  2. package/lib/rew/cli/cli.js +57 -5
  3. package/lib/rew/cli/log.js +5 -1
  4. package/lib/rew/cli/run.js +2 -2
  5. package/lib/rew/cli/utils.js +147 -60
  6. package/lib/rew/const/default.js +5 -1
  7. package/lib/rew/const/ext.js +5 -0
  8. package/lib/rew/const/opt.js +7 -2
  9. package/lib/rew/const/usage.js +15 -0
  10. package/lib/rew/functions/exec.js +2 -2
  11. package/lib/rew/functions/export.js +1 -1
  12. package/lib/rew/functions/fs.js +6 -1
  13. package/lib/rew/functions/id.js +2 -2
  14. package/lib/rew/functions/import.js +34 -13
  15. package/lib/rew/functions/require.js +17 -1
  16. package/lib/rew/functions/stdout.js +4 -0
  17. package/lib/rew/main.js +1 -13
  18. package/lib/rew/modules/compiler.js +122 -26
  19. package/lib/rew/modules/context.js +13 -1
  20. package/lib/rew/modules/runtime.js +37 -20
  21. package/lib/rew/pkgs/conf.js +1 -1
  22. package/lib/rew/pkgs/rune.js +8 -1
  23. package/lib/rew/pkgs/serve.js +373 -0
  24. package/lib/rew/pkgs/stream.js +10 -0
  25. package/lib/rew/pkgs/web.js +504 -0
  26. package/package.json +10 -5
  27. package/runtime.d.ts +943 -0
  28. package/lib/coffeescript/browser.js +0 -156
  29. package/lib/coffeescript/cake.js +0 -134
  30. package/lib/coffeescript/coffeescript.js +0 -465
  31. package/lib/coffeescript/command.js +0 -832
  32. package/lib/coffeescript/grammar.js +0 -1930
  33. package/lib/coffeescript/helpers.js +0 -513
  34. package/lib/coffeescript/index.js +0 -230
  35. package/lib/coffeescript/lexer.js +0 -2316
  36. package/lib/coffeescript/nodes.js +0 -9784
  37. package/lib/coffeescript/optparse.js +0 -258
  38. package/lib/coffeescript/parser.js +0 -20384
  39. package/lib/coffeescript/register.js +0 -120
  40. package/lib/coffeescript/repl.js +0 -328
  41. package/lib/coffeescript/rewriter.js +0 -1448
  42. package/lib/coffeescript/scope.js +0 -191
  43. 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
+ }
@@ -0,0 +1,10 @@
1
+ const { Readable, Writable, Transform, Duplex, pipeline, finished } = require('stream');
2
+
3
+ module.exports = (context) => ({
4
+ Readable,
5
+ Writable,
6
+ Transform,
7
+ Duplex,
8
+ pipeline,
9
+ finished
10
+ })