@makano/rew 1.3.1 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,24 +27,21 @@ function tokenizeCoffeeScript(code) {
27
27
  const nextNextChar = code[i + 2];
28
28
 
29
29
  if (char === '#') {
30
- // Comment
31
30
  const commentEnd = code.indexOf('\n', i);
32
31
  const comment = code.substring(i, commentEnd < 0 ? code.length : commentEnd + 1);
33
32
  tokens.push({ type: 'COMMENT', value: comment });
34
33
  i += comment.length - 1;
35
34
  } else if (char === '"' && nextChar === '"' && nextNextChar === '"') {
36
- // Triple-quoted string
37
35
  let string = '"""';
38
36
  i += 3;
39
37
  while (i < code.length && !(code[i] === '"' && code[i + 1] === '"' && code[i + 2] === '"')) {
40
38
  string += code[i];
41
39
  i++;
42
40
  }
43
- string += '"""'; // Include closing triple quotes
41
+ string += '"""';
44
42
  tokens.push({ type: 'TRIPLE_STRING', value: string });
45
- i += 2; // Skip past the closing triple quotes
43
+ i += 2;
46
44
  } else if (char === '"' || char === "'") {
47
- // Single or double-quoted string
48
45
  let string = char;
49
46
  let escaped = false;
50
47
  i++;
@@ -57,10 +54,9 @@ function tokenizeCoffeeScript(code) {
57
54
  }
58
55
  i++;
59
56
  }
60
- string += char; // Include closing quote
57
+ string += char;
61
58
  tokens.push({ type: 'STRING', value: string });
62
59
  } else if (char === '/' && nextChar !== ' ' && nextChar !== '/' && nextChar !== '*' && prevChar !== '<') {
63
- // Regular expression
64
60
  let regex = char;
65
61
  i++;
66
62
  while (i < code.length && (code[i] !== '/' || regex.endsWith('\\'))) {
@@ -70,14 +66,12 @@ function tokenizeCoffeeScript(code) {
70
66
  regex += '/';
71
67
  tokens.push({ type: 'REGEX', value: regex });
72
68
  } else if (/\s/.test(char)) {
73
- // Whitespace
74
69
  if (tokens[tokens.length - 1]?.type === 'WHITESPACE') {
75
70
  tokens[tokens.length - 1].value += char;
76
71
  } else {
77
72
  tokens.push({ type: 'WHITESPACE', value: char });
78
73
  }
79
74
  } else if (/[a-zA-Z_$@]/.test(char)) {
80
- // Identifier
81
75
  let identifier = char;
82
76
  i++;
83
77
  while (i < code.length && /[a-zA-Z0-9_$]/.test(code[i])) {
@@ -85,18 +79,17 @@ function tokenizeCoffeeScript(code) {
85
79
  i++;
86
80
  }
87
81
  tokens.push({ type: 'IDENTIFIER', value: identifier });
88
- i--; // Move back one character to recheck
89
- } else if (/[a-f0-9.n]/.test(char)) {
82
+ i--;
83
+ } else if (/[a-f0-9.xn]/.test(char)) {
90
84
  let num = char;
91
85
  i++;
92
- while (i < code.length && /[a-f0-9.n]/.test(code[i])) {
86
+ while (i < code.length && /[a-f0-9.nx]/.test(code[i])) {
93
87
  num += code[i];
94
88
  i++;
95
89
  }
96
90
  tokens.push({ type: 'NUMBER', value: num });
97
- i--; // Move back one character to recheck
91
+ i--;
98
92
  } else {
99
- // Other characters
100
93
  tokens.push({ type: 'OTHER', value: char });
101
94
  }
102
95
  i++;
@@ -397,7 +390,7 @@ function compileRewStuff(content, options) {
397
390
  }
398
391
 
399
392
 
400
- if (token.type === 'IDENTIFIER' && token.value === 'export' && !options.keepImports) {
393
+ if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && token.value === 'export' && !options.keepImports) {
401
394
  token.value = 'pub';
402
395
  straceLog('EXPORT() => TRANSLATING TO pub');
403
396
  }
@@ -421,7 +414,7 @@ function compileRewStuff(content, options) {
421
414
  }
422
415
  }
423
416
 
424
- if (token.type === 'IDENTIFIER' && token.value === 'using' && !options.disableUse) {
417
+ if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && token.value === 'using' && !options.disableUse) {
425
418
  straceLog('USING()');
426
419
  const next = nextToken.value;
427
420
  if(next in USING_DEFAULT) {
@@ -448,7 +441,7 @@ function compileRewStuff(content, options) {
448
441
  }
449
442
  }
450
443
 
451
- if (token.type === 'IDENTIFIER' && token.value === 'import' && !options.keepImports) {
444
+ if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && token.value === 'import' && !options.keepImports) {
452
445
  // console.log(nextToken.type);
453
446
  straceLog('IMPORT()');
454
447
  straceLog('==> WARN: SLOWS DOWN COMPILATION');
@@ -539,7 +532,7 @@ function compileRewStuff(content, options) {
539
532
  continue;
540
533
  }
541
534
 
542
- if (token.type === 'IDENTIFIER' && (token.value === 'imp' || token.value === 'inc')) {
535
+ if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && (token.value === 'imp' || token.value === 'inc')) {
543
536
  straceLog('IMP() Detected');
544
537
  let { token: t1 } = gnextToken(i, 1, tokens) || {};
545
538
  let { token: t2 } = gnextToken(i, 2, tokens) || {};
@@ -559,6 +552,7 @@ function compileRewStuff(content, options) {
559
552
  }
560
553
 
561
554
  if (
555
+ tokens[i-1]?.value !== '.' &&
562
556
  token.type === 'IDENTIFIER' &&
563
557
  token.value === 'pub' &&
564
558
  nextToken &&
@@ -166,9 +166,9 @@ module.exports = (context) => {
166
166
 
167
167
  render = (req, data) ->
168
168
  target = renderers.pop()
169
- page = target.render req, data
169
+ page = target.render.call @, req, data
170
170
  for renderer in renderers
171
- page = renderer.render req, data, page
171
+ page = renderer.render.call @, req, data, page
172
172
  page
173
173
 
174
174
  exports { render, staticRendering }
@@ -241,7 +241,8 @@ module.exports = (context) => {
241
241
  const layouts = findLayoutFiles(file, root, false);
242
242
  const fileContext = runPath(file, { code: ssrBundlerEntry(file, layouts) }).context.module.exports || {};
243
243
  if(typeof fileContext.render !== "function") throw new ReferenceError("Route does not export function render");
244
- let pageContent = fileContext.render(req, { page, ...getReqProps(req) });
244
+ const props = { page, ...getReqProps(req) };
245
+ let pageContent = fileContext.render.call(props, req, props);
245
246
  if(fileContext.staticRendering) staticRendering = true;
246
247
  if(!w.isNode(pageContent)) throw new TypeError("Route.render does not return an element");
247
248
  if(pageContent?.type?.element == 'head'){
@@ -245,6 +245,95 @@ function renderToString(element, js = false) {
245
245
  return js ? js === 'raw' ? eltJSON : JSON.stringify(eltJSON) : element instanceof TextNode ? `${type.text}` : `<${type.element}${propsString}>${selfClosingElements.has(type.element) ? '' : childrenHTML}${selfClosingElements.has(type.element) ? '' : `</${type.element}>`}`;
246
246
  }
247
247
 
248
+ function createStyles(styles) {
249
+ let css = "";
250
+ const variables = {};
251
+ const mixins = {};
252
+
253
+ const parseValue = (v, self, name, vars) => {
254
+ const vs = {...variables, ...vars, name, ...Object.fromEntries(Object.entries(self).map(i => ['prop_'+i[0], i[1]]))};
255
+ return v.startsWith('@v') ? vs[v.split('@v')[1].trim()] : v
256
+ .toString()
257
+ .replace(/\$([A-Za-z0-9-_]+)/g, (_, name) => (vs)[name])
258
+ }
259
+
260
+ const declectProp = (value, name, selector, start, parent, self, vars = {}) => {
261
+ let prop = `${name}: `;
262
+ self.__parent = parent;
263
+ if (typeof value == 'object') {
264
+ prop += parseValue(value.default || 'unset', self, name, vars) + ';';
265
+ prop += '}\n';
266
+ for (let state in value) {
267
+ if (state == 'default') continue;
268
+ else if (state.startsWith('@media')) {
269
+ prop += `${state} { ${start} ${name}: ${parseValue(value[state], self, name, vars)}; } }\n`
270
+ } else if (state.startsWith(':')) {
271
+ prop += `${selector}${state} { ${name}: ${parseValue(value[state], self, name, vars)}; }\n`
272
+ }
273
+ }
274
+ prop += start;
275
+ } else {
276
+ let v = parseValue(value, self, name, vars);
277
+ if(typeof v == 'object') return declectProp(v, name, selector, start, parent, self, vars);
278
+ prop += v + ';';
279
+ }
280
+ return prop;
281
+ }
282
+
283
+ const declectNames = (names, $name, parent, values = {}) => {
284
+ const start = $name ? $name + ' {' : '';
285
+ let nameStyles = start;
286
+ for (let name in names) {
287
+ let selector = name.replace(/,/g, ', &').replace(/&/g, $name || '');
288
+ if (name == '@variables') {
289
+ for (let i in names[name]) {
290
+ variables[i] = names[name][i];
291
+ }
292
+ } else if (name.startsWith('@mixin')) {
293
+ const mame = name.split('@mixin')[1].trim();
294
+ const mname = mame.split('(')[0];
295
+ const args = mame.replace(mname, '').slice(1, -1);
296
+ mixins[mname] = {
297
+ args: args.split(','),
298
+ value: names[name]
299
+ }
300
+ } else if (name.startsWith('@keyframes')) {
301
+ nameStyles += $name ? '' : name + '{';
302
+
303
+ for(let keyFrame in names[name]){
304
+ nameStyles += declectNames(names[name][keyFrame], keyFrame, names[name], values);
305
+ }
306
+
307
+ if(!$name) nameStyles += '}\n';
308
+ } else if ($name) {
309
+ if (name.startsWith('&')) {
310
+ nameStyles += '}\n';
311
+ nameStyles += declectNames(names[name], selector, names, values);
312
+ nameStyles += start;
313
+ } else if(name.startsWith('@include')) {
314
+ const mame = names[name];
315
+ const mname = mame.split('(')[0];
316
+ const args = mame.replace(mname, '').slice(1, -1).split(',');
317
+ if(mixins[mname]){
318
+ nameStyles += declectNames(mixins[mname].value, selector, names, {...values, ...Object.fromEntries(mixins[mname].args.map((n, i) => [n, args[i]]))}).trim().replace('@include ', '').slice(1, -1);
319
+ }
320
+ } else {
321
+ nameStyles += declectProp(names[name], name, $name, start, parent || styles, names, values);
322
+ }
323
+ } else {
324
+ nameStyles += declectNames(names[name], selector, names, values);
325
+ }
326
+ }
327
+ if ($name) nameStyles += '}\n';
328
+ return nameStyles;
329
+ }
330
+
331
+ css += declectNames(styles);
332
+
333
+ return css.replace(/(.+) \{\}/g, '');
334
+ }
335
+
336
+
248
337
  class Page extends Node {
249
338
  constructor() {
250
339
  super();
@@ -270,6 +359,8 @@ class Page extends Node {
270
359
  style(styleString) {
271
360
  if (typeof styleString == "object" && styleString.href)
272
361
  return this.head.add(createElement('link', { href: styleString.href, rel: 'stylesheet' }));
362
+ else if(typeof styleString == "object")
363
+ return this.head.add(createElement('style', null, createTextNode(createStyles(styleString))))
273
364
  else
274
365
  return this.head.add(createElement('style', null, createTextNode(styleString)));
275
366
  }
@@ -301,13 +392,17 @@ class Page extends Node {
301
392
  ${State}
302
393
  const states = [];
303
394
 
395
+ function styleAttribute(value, el){
396
+ for(let i in value){
397
+ const v = value[i];
398
+ el.style.setProperty(i, value[i]);
399
+ }
400
+ }
401
+
304
402
  function setAttribute(el, key, value){
305
403
  let defVal = value;
306
404
  if(key == 'style'){
307
- for(let i in value){
308
- const v = value[i];
309
- el.style.setProperty(i, value[i]);
310
- }
405
+ styleAttribute(value, el);
311
406
  return;
312
407
  } else if(key.startsWith('on')){
313
408
  if(!el.listeners) el.listeners = [];
@@ -453,12 +548,21 @@ module.exports = (context, importOptions) => {
453
548
  createElement(...args) {
454
549
  return createElement(...args);
455
550
  }
551
+ createStyles(...args){
552
+ return createStyles(...args);
553
+ }
456
554
  state(value) {
457
555
  return new State(value);
458
556
  }
459
557
  invokeState(states, callback){
460
558
  const statesMapped = states.map(i => i instanceof State ? `getState('${i.id}')` : (typeof i == "function" ? i.toString() : JSON.stringify(i)));
461
- return `((${callback})(event, ...[${statesMapped}]))`;
559
+ return `((${callback})(typof event !== "undefined" ? event : null, ...[${statesMapped}]))`;
560
+ }
561
+ async bundleCode(code, options){
562
+ return Web.prototype.bundle(generateRandomID(), {
563
+ ...options,
564
+ code
565
+ });
462
566
  }
463
567
  async bundle(filepath, options = {}) {
464
568
  const virtualModuleId = `virtual:${filepath}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makano/rew",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "A simple coffescript runtime and app manager",
5
5
  "main": "main.js",
6
6
  "directories": {
package/runtime.d.ts CHANGED
@@ -500,6 +500,7 @@ declare namespace Rew {
500
500
  add(...children: nodable[]): typeof this.body;
501
501
 
502
502
  script(script: string): ReturnType<typeof this.add>;
503
+ style(style: string | Record<string, any>): ReturnType<typeof this.add>;
503
504
 
504
505
  serializeState(): string;
505
506
 
@@ -522,11 +523,13 @@ declare namespace Rew {
522
523
 
523
524
  createText(text: string): Node;
524
525
  createElement(...args: any[]): ElementNode;
526
+ createStyles(styles: Record<string, any>): string;
525
527
 
526
528
  state(value): ModuleWebState | any;
527
529
  // @ts-ignore
528
530
  invokeState(states: State[], callback: CallableFunction): any;
529
531
 
532
+ bundleCode(code: string, options?: Record<string, any>): string;
530
533
  bundle(filePath: string, options?: Record<string, any>): string;
531
534
  }
532
535
 
@@ -1006,16 +1009,16 @@ declare namespace Rew {
1006
1009
  group(...group: any[]): { g: T, with: (props: any) => { g: T, [key: string]: any }, [key: string]: any }
1007
1010
  }
1008
1011
 
1009
- declare const std = {
1010
- curl: curl,
1011
- int: int,
1012
- str: str,
1013
- bool: bool,
1014
- float: float,
1015
- num: num,
1016
- typeis: typeis,
1017
- typex: typex,
1018
- typei: typei,
1012
+ declare const std: {
1013
+ curl: typeof curl,
1014
+ int: typeof int,
1015
+ str: typeof str,
1016
+ bool: typeof bool,
1017
+ float: typeof float,
1018
+ num: typeof num,
1019
+ typeis: typeof typeis,
1020
+ typex: typeof typex,
1021
+ typei: typeof typei,
1019
1022
 
1020
1023
  prototype: {
1021
1024
  void: () => void 0,