@makano/rew 1.3.1 → 1.3.2

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.
@@ -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.2",
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,