@makano/rew 1.2.53 → 1.2.55

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.
@@ -2,9 +2,10 @@ const execOptions = {
2
2
  sharedContext: true,
3
3
  resolveExtensions: ['.coffee', { ext: '.js', options: { type: 'js' } }, { ext: '.qrew', options: { qrew: true } }],
4
4
  nativeRequire: false,
5
+ useImport: false,
5
6
  cwdAlias: '$',
6
7
  jsxPragma: 'createElement',
7
- jsx: false,
8
+ jsx: false
8
9
  };
9
10
 
10
11
  module.exports.execOptions = execOptions;
@@ -10,7 +10,7 @@ function exportsThe(item, name, context) {
10
10
 
11
11
  module.exports.pubFunction = function (context) {
12
12
  return function (name, item) {
13
- if (name && !item) {
13
+ if (name && item == null) {
14
14
  item = name;
15
15
  name = null;
16
16
  }
@@ -8,7 +8,9 @@ const jsYaml = require('js-yaml');
8
8
  const { execOptions } = require('../const/opt');
9
9
 
10
10
  const cachedFiles = [];
11
-
11
+ module.exports.cleanCache = () => {
12
+ while(cachedFiles.length) cachedFiles.pop();
13
+ };
12
14
  const lookUpInOtherApps = (fullPath) => {
13
15
  const con = conf({});
14
16
  const name = fullPath.indexOf('/') ? fullPath.split('/')[0] : fullPath;
@@ -87,7 +89,7 @@ module.exports.imp = function (runPath, context) {
87
89
  ).context.module.exports;
88
90
 
89
91
  if (ispkg) {
90
- const pkg = getPackage(filename)(context);
92
+ const pkg = getPackage(filename)(context, options);
91
93
  exports = pkg._onImport ? pkg._onImport() : pkg;
92
94
  } else if (foundCache) {
93
95
  } else if (type == 'coffee') {
@@ -1,10 +1,26 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { execOptions } = require('../const/opt');
4
+ const { wait } = require('./wait');
5
+
6
+ const cahcedRequires = {};
7
+
8
+ const doImp = (path) => wait(async () => await import(resolvedPath));
3
9
 
4
10
  module.exports.customRequire = function customRequire(modulePath, filePath) {
11
+ const pathname = modulePath;
12
+ if (modulePath.startsWith('./') || modulePath.startsWith('../') || path.isAbsolute(modulePath)) {
13
+ pathname = path.resolve(modulePath);
14
+ }
15
+ if(cahcedRequires[pathname]) {
16
+ return cahcedRequires[pathname];
17
+ }
5
18
  const resolvedPath = resolveModulePath(modulePath, filePath);
6
19
  if(!resolvedPath) throw new Error('Module '+modulePath+' not found');
7
- return require(resolvedPath);
20
+ const r = cahcedRequires[resolvedPath] ? cahcedRequires[resolvedPath] : execOptions.useImport ? doImp(resolvedPath) : require(resolvedPath);
21
+ if(!cahcedRequires[resolvedPath]) cahcedRequires[resolvedPath] = r;
22
+ if(!cahcedRequires[pathname]) cahcedRequires[pathname] = r;
23
+ return r;
8
24
  };
9
25
 
10
26
  function resolveModulePath(modulePath, filePath) {
@@ -115,18 +115,22 @@ function compileRewStuff(content, options) {
115
115
  const token = tokens[i];
116
116
  let { token: nextToken, n } = gnextToken(i, 1, tokens) || {};
117
117
 
118
- if (token.type === 'IDENTIFIER' && token.value === 'opt') {
118
+
119
+ if (token.type === 'IDENTIFIER' && token.value === 'opt.set') {
119
120
  const { token: nextNextToken } = gnextToken(i, 2, tokens) || {};
120
- if (nextNextToken && nextNextToken.value == 'jsxPragma') {
121
+ if (nextNextToken && nextNextToken.value.slice(1).slice(0, -1) == 'jsxPragma') {
121
122
  const { token: nextLastToken } = gnextToken(i, 5, tokens) || {};
122
123
  execOptions.jsxPragma = nextLastToken.value.slice(1).slice(0, -1);
123
124
  }
124
125
  }
125
126
 
126
- if (token.type === 'COMMENT' && token.value.slice(1).trim() === '@jsx') {
127
+ if (token.type === 'COMMENT' && token.value.slice(1).trim().startsWith('@jsx')) {
127
128
  options.jsx = true;
129
+ if(token.value.split('@jsx')[1].trim()){
130
+ options.jsxPragma = token.value.split('@jsx')[1].trim();
131
+ }
128
132
  }
129
-
133
+
130
134
  if (token.type === 'COMMENT' && token.value.slice(1).trim() === '@cls') {
131
135
  options.cls = true;
132
136
  }
@@ -146,7 +150,7 @@ function compileRewStuff(content, options) {
146
150
  }
147
151
 
148
152
 
149
- if (token.type === 'IDENTIFIER' && token.value === 'let') {
153
+ if (token.type === 'IDENTIFIER' && token.value === 'let' && !options.keepImports) {
150
154
  result += '`'
151
155
  hooks.push({
152
156
  index: fnextToken(i, tokens, 'OTHER', ';').ti,
@@ -154,11 +158,11 @@ function compileRewStuff(content, options) {
154
158
  });
155
159
  }
156
160
 
157
- if (token.type === 'IDENTIFIER' && token.value === 'export') {
161
+ if (token.type === 'IDENTIFIER' && token.value === 'export' && !options.keepImports) {
158
162
  token.value = 'pub';
159
163
  }
160
164
 
161
- if (token.type === 'IDENTIFIER' && token.value === 'import') {
165
+ if (token.type === 'IDENTIFIER' && token.value === 'import' && !options.keepImports) {
162
166
  // console.log(nextToken.type);
163
167
  let ind = i + n + 2;
164
168
 
@@ -224,7 +228,7 @@ function compileRewStuff(content, options) {
224
228
  nextToken &&
225
229
  nextToken.type === 'IDENTIFIER' &&
226
230
  nextToken.value &&
227
- nextToken.value !== 'undefined'
231
+ nextToken.value !== 'undefined' && !options.keepImports
228
232
  ) {
229
233
  let next = {...nextToken};
230
234
  if(next.value == 'default'){
@@ -259,13 +263,13 @@ const cpl = (module.exports.compile = function (file, options = {}) {
259
263
  let c = options.type == 'js' || options.compile == false ? file.content : compile(compileRewStuff(file.content, options), {
260
264
  ...options,
261
265
  filename: file.path,
262
- bare: false,
266
+ bare: options.bare ?? false,
263
267
  inlineMap: false,
264
- });
268
+ });2
265
269
  // console.log(c);
266
270
  if (execOptions.jsx || options.jsx) {
267
271
  c = babel.transformSync(c, {
268
- presets: [[babelReact, { pragma: execOptions.jsxPragma }]],
272
+ presets: [[babelReact, { pragma: options.jsxPragma || execOptions.jsxPragma }]],
269
273
  plugins: [],
270
274
  }).code;
271
275
  }
@@ -273,7 +277,8 @@ const cpl = (module.exports.compile = function (file, options = {}) {
273
277
  });
274
278
 
275
279
  module.exports.compileFile = function (filepath, options = {}) {
276
- const f = getFile(filepath);
280
+ const f = typeof filepath == "object" ? filepath : getFile(filepath);
281
+ if(typeof filepath == "object") filepath = filepath.path;
277
282
  let qrew = false;
278
283
 
279
284
  if(options.qrew || path.extname(filepath) == '.qrew') {
@@ -25,7 +25,7 @@ module.exports.prepareContext = function (
25
25
  imports: [],
26
26
  },
27
27
  imports: {
28
- meta: {},
28
+ meta: { url: new URL('file://'+filepath), main: isMainFile(filepath) },
29
29
  assert: options.import ?? {},
30
30
  },
31
31
  app: findAppInfo(filepath),
@@ -1,5 +1,5 @@
1
1
  const vm = require('vm');
2
- const { compileFile } = require('./compiler');
2
+ const { compileFile, compile } = require('./compiler');
3
3
  const { prepareContext } = require('./context');
4
4
  const { existsSync, readFileSync } = require('fs');
5
5
  const { CONFIG_PATH } = require('../const/config_path');
@@ -7,37 +7,36 @@ const path = require('path');
7
7
 
8
8
  const preScript = readFileSync(path.join(__dirname, '../const/pre-exec.js'), { encoding: 'utf-8' });
9
9
 
10
- const exec = (module.exports.exec = function (code, context) {
11
- return vm.runInNewContext(code, vm.createContext(context), {
10
+ const exec = (module.exports.exec = function (code, context, original = '') {
11
+ return vm.runInNewContext(code, context.do ? null : vm.createContext(context), {
12
12
  filename: context.module.filepath,
13
- lineOffset: -1 - preScript.split('\n').length,
13
+ lineOffset: (original.split('\n').length + preScript.split('\n').length) - code.split('\n').length,
14
14
  displayErrors: true,
15
15
  });
16
16
  });
17
17
 
18
18
  module.exports.runPath = function runPath(filepath, options = {}, custom_context = {}) {
19
19
  if(filepath.endsWith('.js')) options.type = 'js';
20
- let { compiled_code, file } = compileFile(filepath, options);
21
- const context = prepareContext(custom_context, options, file.path, runPath);
22
-
23
- context.module.compiled = compiled_code;
24
- context.process.exit = (int) => process.exit(int);
20
+ let { compiled_code, file } = compileFile(options.code ? { content: options.code, path: filepath } : filepath, options);
21
+ const context = options.import?.takeThisContext ? custom_context : prepareContext(custom_context, options, file.path, runPath);
22
+ // context.module.compiled = compiled_code;
23
+ // context.process.exit = (int) => process.exit(int);
25
24
 
26
25
  if(context.app){
27
26
  const p = path.join(CONFIG_PATH, context.app.config.manifest.package, 'app');
28
27
  if(existsSync(p) && context.app.path !== p){
29
28
  console.log("App with the same package name has been installed. Conflicts happened. \nTo fix this, change your app's package name or remove the app making the conflict.");
30
29
  return {
31
- context: { exports: null },
30
+ context: { module: { exports: null } },
32
31
  returns: null
33
32
  }
34
33
  }
35
34
  }
36
35
 
37
- compiled_code = preScript+compiled_code;
36
+ compiled_code = preScript+'\n'+compiled_code;
38
37
 
39
38
  return {
40
39
  context,
41
- returns: exec(compiled_code, context),
40
+ returns: exec(compiled_code, context, file.content),
42
41
  };
43
42
  };
@@ -0,0 +1,370 @@
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
+ module.exports = (context) => {
9
+
10
+ // http.createServer((req, res) => {
11
+ // res.end();
12
+ // }).listen(1400);
13
+
14
+ const imp = (file) => context.imp(file);
15
+ const Web = imp('web');
16
+
17
+ function mkReq(req) {
18
+ const url = `http://${req.headers.host}${req.url}`;
19
+ const options = {
20
+ method: req.method,
21
+ headers: req.headers,
22
+ body: req.body
23
+ };
24
+
25
+ return new Request(url, options);
26
+ }
27
+
28
+ class Server {
29
+ _server = {};
30
+ routers = {};
31
+
32
+ constructor(options){
33
+ this.options = options;
34
+ this._server = http.createServer((req, res) => {
35
+ options.handler ? options.handler(req, res) : this.handleRequest(req, res);
36
+ });
37
+ if(options.routers){
38
+ options.routers.forEach(router => router.to(this));
39
+ }
40
+ }
41
+
42
+ async handleRequest(req, res){
43
+ try {
44
+ let response = new Response();
45
+ const request = mkReq(req);
46
+ if(this.options.fetch == 'router'){
47
+ if(!Object.keys(this.options.routers).length) throw new Error('No fetch function nor routers found');
48
+ response = await this.options.routers[Object.keys(this.options.routers)[0]].fetch(request);
49
+ } else {
50
+ response = await this.options.fetch(request);
51
+ }
52
+
53
+ if(!response){
54
+ res.end('Cannot '+req.method+' '+req.url);
55
+ return;
56
+ }
57
+
58
+ response.headers.forEach((value, name) => {
59
+ res.setHeader(name, value);
60
+ });
61
+
62
+ res.writeHead(response.status);
63
+
64
+ const buffer = await response.arrayBuffer();
65
+ res.end(Buffer.from(buffer));
66
+ } catch (error) {
67
+ // Handle errors
68
+ console.error("Error:", error);
69
+ res.writeHead(500, {'Content-Type': 'text/plain'});
70
+ res.end("Internal Server Error");
71
+ }
72
+ }
73
+
74
+ get listen(){
75
+ this._server.listen(this.options.port);
76
+ return this;
77
+ }
78
+
79
+ set listen(port){
80
+ this.options.port = port;
81
+ return this;
82
+ }
83
+
84
+ port(port){
85
+ this.listen = port;
86
+ return this;
87
+ }
88
+
89
+ log(string){
90
+ console.log(string.replace(/\$([A-Za-z0-9_]+)/g, (_, name) => this.options[name] || _));
91
+ return this;
92
+ }
93
+ }
94
+
95
+ class SvrRouter {
96
+ static new(Class, options, props){
97
+ const router = Class(options);
98
+ for(let i in props) router[i] = props[i];
99
+ router.to = (server) => {
100
+ if(server instanceof Server){
101
+ server.routers[this.id] = this;
102
+ }
103
+ };
104
+ return router;
105
+ }
106
+ }
107
+
108
+ function findLayoutFiles(filePath, root, isClientSide = true, resolveExtensions = ['.coffee', '.js', '.jsx']) {
109
+ const layouts = [];
110
+ const rootDir = root;
111
+ let currentDir = path.dirname(filePath);
112
+
113
+ while (currentDir !== rootDir) {
114
+ for (const ext of resolveExtensions) {
115
+ const layoutFile = path.join(currentDir, `layout${isClientSide ? '' : '.s'}${ext}`);
116
+ if (existsSync(layoutFile)) {
117
+ layouts.push(layoutFile);
118
+ }
119
+ }
120
+ currentDir = path.dirname(currentDir);
121
+ }
122
+
123
+ for (const ext of resolveExtensions) {
124
+ const layoutFile = path.join(currentDir, `layout${isClientSide ? '' : '.s'}${ext}`);
125
+ if (existsSync(layoutFile)) {
126
+ layouts.push(layoutFile);
127
+ }
128
+ }
129
+
130
+ return layouts.reverse();
131
+ }
132
+
133
+ const defaultBundlerEntry = (file, layouts, data) => `
134
+ import * as target from "${file}";
135
+ ${layouts.map((layout, ind) => `import * as layout${ind} from "${layout}";`).join('\n')}
136
+ let page = target.render ? target.render(${JSON.stringify(data)}) : target.default ? target.default(${JSON.stringify(data)}) : null;
137
+ ${layouts.reverse().map((_, ind) => `if (layout${ind}.render) page = layout${ind}.render(${JSON.stringify(data)}, page);`).join('\n')}
138
+ `;
139
+
140
+ const defaultSsrBundlerEntry = (file, layouts, data) => `
141
+ files = "${layouts.join(',')},${file}".split(',')
142
+
143
+ renderers = []
144
+ staticRendering = false
145
+
146
+ for key, file of files
147
+ renderers.push imp file
148
+
149
+ staticRendering = true if renderers[renderers.length-1].staticRendering
150
+
151
+ render = (req, data) ->
152
+ target = renderers.pop()
153
+ page = target.render req, data
154
+ for renderer in renderers
155
+ page = renderer.render req, data, page
156
+ page
157
+
158
+ exports { render, staticRendering }
159
+ `;
160
+
161
+ function createFileRouter({
162
+ onError = () => error(404, 'Path not found'),
163
+ root = '',
164
+ basePath = '',
165
+ resolveExtensions = ['.coffee', '.js', '.jsx'],
166
+ bundlerOptions = {},
167
+ bundlerEntry = defaultBundlerEntry,
168
+ ssrBundlerEntry = defaultSsrBundlerEntry,
169
+ }) {
170
+
171
+ const lookUpFiles = ['route', 'page', 'page.s'];
172
+
173
+ const params = {};
174
+
175
+ function lookUp(pathname) {
176
+ const routeParts = pathname.split('/').filter(Boolean);
177
+ let routePath = root;
178
+
179
+ Object.keys(params).forEach(key => delete params[key]);
180
+
181
+ for (const part of routeParts) {
182
+ const dir = readdirSync(routePath);
183
+
184
+ const match = dir.find(d => d === part || d.match(/^\[.*\]$/));
185
+ if (!match) return null;
186
+
187
+ if (match.match(/^\[.*\]$/)) {
188
+ const paramName = match.slice(1, -1);
189
+ params[paramName] = part;
190
+ }
191
+
192
+ routePath = path.join(routePath, match);
193
+ }
194
+
195
+ for (const base of lookUpFiles) {
196
+ for (const ext of resolveExtensions) {
197
+ const filePath = path.join(routePath, `${base}${ext}`);
198
+ if (existsSync(filePath)) {
199
+ return filePath;
200
+ }
201
+ }
202
+ }
203
+
204
+ return null;
205
+ }
206
+
207
+ function getReqProps(req) {
208
+ return {
209
+ params: {
210
+ ...params,
211
+ ...(req.params || {})
212
+ },
213
+ query: req.query,
214
+ url: req.url,
215
+ method: req.method
216
+ }
217
+ }
218
+
219
+ const w = new Web();
220
+
221
+ async function renderPage(file, basename, req){
222
+ const page = w.create({ viewportMeta: true });
223
+ let staticRendering = false;
224
+ if(basename.endsWith('.s')){
225
+ // SSR is enabled, do only ssr
226
+ const layouts = findLayoutFiles(file, root, false);
227
+ const fileContext = runPath(file, { code: ssrBundlerEntry(file, layouts) }).context.module.exports || {};
228
+ if(typeof fileContext.render !== "function") throw new ReferenceError("Route does not export function render");
229
+ let pageContent = fileContext.render(req, { page, ...getReqProps(req) });
230
+ if(fileContext.staticRendering) staticRendering = true;
231
+ if(!w.isNode(pageContent)) throw new TypeError("Route.render does not return an element");
232
+ if(pageContent?.type?.element == 'head'){
233
+ page.root.props.children.splice(page.root.props.children.indexOf(page.head), 1);
234
+ page.head = pageContent;
235
+ page.root.add(pageContent);
236
+ } else if(pageContent?.type?.element == 'body'){
237
+ page.root.props.children.splice(page.root.props.children.indexOf(page.body), 1);
238
+ page.body = pageContent;
239
+ page.root.add(pageContent);
240
+ } else if(pageContent?.type?.element == 'html'){
241
+ page.root = pageContent;
242
+ page.body = pageContent.find('body');
243
+ page.head = pageContent.find('head');
244
+ } else {
245
+ page.add(pageContent);
246
+ }
247
+ } else {
248
+ const layouts = findLayoutFiles(file, root, true);
249
+ const scriptString = await w.bundle(path.join(root, 'bundle.js'), {
250
+ ...bundlerOptions,
251
+ code: bundlerEntry(file, layouts, getReqProps(req))
252
+ });
253
+ page.script(scriptString);
254
+ staticRendering = true;
255
+ }
256
+ return html(page.render(staticRendering));
257
+ }
258
+
259
+ async function handleRequest(req, file) {
260
+ const ext = path.extname(file);
261
+ const basename = path.basename(file, ext);
262
+
263
+ if (basename.startsWith('route')) {
264
+ const fileContext = run(file).context;
265
+ const handlers = fileContext.module.exports;
266
+ const method = req.method.toUpperCase();
267
+ if (handlers[method]) {
268
+ return await handlers[method](req, getReqProps(req));
269
+ } else {
270
+ return error(405, `Method ${method} not allowed`);
271
+ }
272
+ } else if (basename.startsWith('page')) {
273
+ return await renderPage(file, basename, req);
274
+ }
275
+ }
276
+
277
+
278
+ return async (req) => {
279
+ const url = new URL(req.url);
280
+ const pathname = basePath ? url.pathname.replace(new RegExp('^'+basePath), '') : url.pathname;
281
+ const file = lookUp(pathname);
282
+ cleanCache();
283
+
284
+ if (file) {
285
+ const response = handleRequest(req, file);
286
+ response.catch(() => onError());
287
+ return await response;
288
+ } else {
289
+ return onError();
290
+ }
291
+ };
292
+ }
293
+
294
+
295
+
296
+ class Svr {
297
+ create(options){
298
+ return new Server(options);
299
+ }
300
+
301
+ router({ id = '/', type = 'normal', ...options }){
302
+ let router;
303
+ if(type == 'default') router = SvrRouter.new(IttyRouter, {...options}, { id });
304
+ if(type == 'auto') router = SvrRouter.new(AutoRouter, {...options}, { id });
305
+ if(type == 'normal') router = SvrRouter.new(Router, {...options}, { id });
306
+
307
+ return router;
308
+ }
309
+
310
+ createResponse(format, transform, type = 'normal'){
311
+ return type == 'json' ? json(format, transform) : createResponse(format, transform);
312
+ }
313
+
314
+ html(string, options = {}){
315
+ return html(string, options);
316
+ }
317
+
318
+ json(object, options = {}){
319
+ return json(object, options);
320
+ }
321
+
322
+ jpeg(image, options = {}){
323
+ return jpeg(image, options);
324
+ }
325
+
326
+ png(image, options = {}){
327
+ return png(image, options);
328
+ }
329
+
330
+ webp(image, options = {}){
331
+ return webp(image, options);
332
+ }
333
+
334
+ text(string, options = {}){
335
+ return text(string, options);
336
+ }
337
+
338
+ status(code, options = {}){
339
+ return status(code, options);
340
+ }
341
+
342
+ cors(options = {}){
343
+ return cors(options);
344
+ }
345
+
346
+ error(status, body){
347
+ return error(status, body);
348
+ }
349
+
350
+ createFileRouter(o){
351
+ return createFileRouter(o);
352
+ }
353
+ }
354
+
355
+ class SvrResponse extends Response {}
356
+ class SvrRequest extends Request {}
357
+
358
+ Svr.prototype.Response = SvrResponse;
359
+ Svr.prototype.Request = SvrRequest;
360
+ Svr.prototype.URL = URL;
361
+ Svr.prototype.StatusError = StatusError;
362
+
363
+ Svr.prototype.withContent = withContent;
364
+ Svr.prototype.withCookies = withCookies;
365
+ Svr.prototype.withParams = withParams;
366
+
367
+ IttyRouter
368
+
369
+ return Svr;
370
+ }
@@ -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
+ })