@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,504 @@
1
+
2
+ const emitter = require("../functions/emitter");
3
+ const { compile } = require("../modules/compiler");
4
+ const { wait } = require("../functions/wait");
5
+ const { generateRandomID } = require("../functions/id");
6
+ const { REW_FILE_TYPE } = require("../const/ext");
7
+
8
+
9
+ const selfClosingElements = new Set([
10
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'source', 'track', 'wbr'
11
+ ]);
12
+
13
+ class Node { }
14
+
15
+ class State {
16
+ _target = emitter();
17
+ id = generateRandomID();
18
+ constructor(value) {
19
+ this._value = value;
20
+ }
21
+ get value() {
22
+ return this._value;
23
+ }
24
+ set value(value) {
25
+ const oldValue = this._value;
26
+ this._value = value;
27
+ this._target.emit('change', { old: oldValue, new: this._value })
28
+ }
29
+
30
+ set(value){
31
+ this.value = value;
32
+ return this;
33
+ }
34
+
35
+ subscribe(renderCallback) {
36
+ this._target.on('change', renderCallback);
37
+ }
38
+ }
39
+
40
+ const nodeType = (name) => class extends Node {
41
+ [name] = "";
42
+ constructor(value) {
43
+ super();
44
+ this[name] = value;
45
+ }
46
+ }
47
+
48
+ const node = (typeNode) => class extends Node {
49
+ constructor(value) {
50
+ super();
51
+ if (!value.type instanceof typeNode) throw new TypeError('Node does not match it\'s type');
52
+ for (let i in value) this[i] = value[i];
53
+
54
+ this.props.children.forEach(child => parentify(child, this));
55
+ }
56
+ parent = null;
57
+ _target = emitter();
58
+ find(prop, value = null) {
59
+ return findChild(this, prop, value, true);
60
+ }
61
+ add(...children) {
62
+ for (let child of children) addChildren(this, child);
63
+ return this;
64
+ }
65
+ remove() {
66
+ this.parent?.children.splice(this.parent.children.indexOf(this), 1);
67
+ return this;
68
+ }
69
+ setProp(key, val) {
70
+ if (key == 'children') return;
71
+ this.props[key] = val;
72
+ return this;
73
+ }
74
+ render() {
75
+ renderToString(this, true);
76
+ this._target.emit('render', () => { });
77
+ return this;
78
+ }
79
+ }
80
+
81
+
82
+ class TextTypeNode extends nodeType('text') { };
83
+ class TextNode extends node(TextTypeNode) { };
84
+ function createTextNode(text) {
85
+ let t = text instanceof State ? text.value : text;
86
+ const node = new TextNode({
87
+ type: new TextTypeNode(t),
88
+ props: {
89
+ children: []
90
+ }
91
+ });
92
+ if (text instanceof State) {
93
+ node.props.children.push(text);
94
+ text.subscribe(() => node.parent?.render());
95
+ node.states = {
96
+ ':text': text
97
+ };
98
+ }
99
+ return node;
100
+ }
101
+
102
+ class ElementTypeNode extends nodeType('element') { };
103
+ class ElementNode extends node(ElementTypeNode) { };
104
+ function createElement(type, props, ...children) {
105
+ const flattenChildren = (childrenArray) =>
106
+ childrenArray.flatMap(child => Array.isArray(child) ? flattenChildren(child) : child).map(child => {
107
+ if (typeof child !== 'object') return createTextNode(child.toString());
108
+
109
+ if (child instanceof State) {
110
+ const textNode = createTextNode(child);
111
+ child.subscribe(() => {
112
+ textNode.parent?.render();
113
+ });
114
+ return textNode;
115
+ }
116
+
117
+ return child;
118
+ });
119
+
120
+ if (type instanceof State) {
121
+ return createTextNode(child);
122
+ }
123
+
124
+ if (typeof type === 'function') {
125
+ return type({ ...props, children: flattenChildren(children) })
126
+ }
127
+
128
+ const newChildren = flattenChildren(children);
129
+
130
+
131
+ const resolvedProps = {};
132
+ const attributeStates = {};
133
+ for (const key in props) {
134
+ if (props[key] instanceof State) {
135
+ resolvedProps[key] = props[key].value;
136
+ props[key].subscribe(() => {
137
+ if (props[key].value !== resolvedProps[key]) {
138
+ resolvedProps[key] = props[key].value;
139
+ if (elementInstance) elementInstance.render();
140
+ }
141
+ });
142
+ attributeStates[key] = props[key];
143
+ } else {
144
+ resolvedProps[key] = props[key];
145
+ }
146
+ }
147
+
148
+
149
+ return new ElementNode({
150
+ type: new ElementTypeNode(type),
151
+ props: {
152
+ ...resolvedProps,
153
+ children: newChildren
154
+ },
155
+ states: attributeStates
156
+ });
157
+ }
158
+
159
+ function parentify(child, parent) {
160
+ child.parent = parent;
161
+ }
162
+
163
+ function addChildren(nest, child) {
164
+ nest.props.children.push(child);
165
+ parentify(child, nest);
166
+ }
167
+
168
+ function findChild(nest, prop, value, recurse = false) {
169
+ let child = nest.props.children.find(element => element instanceof State ? false : value ? element.props[prop] == value : element.type.element == prop);
170
+ if (recurse && !child) return nest.props.children.find(element => element instanceof State ? false : findChild(element, prop, value, recurse));
171
+ return child;
172
+ }
173
+
174
+ function cloneNest(node) {
175
+ const clonedNode = new ElementNode({
176
+ type: node.type,
177
+ props: { ...node.props },
178
+ });
179
+
180
+ clonedNode.props.children = node.props.children.map(child => {
181
+ if (child instanceof ElementNode) {
182
+ return cloneNest(child);
183
+ } else if (child instanceof TextNode) {
184
+ return new TextNode({ type: child.type, props: { ...child.props } });
185
+ } else {
186
+ return child;
187
+ }
188
+ });
189
+
190
+ return clonedNode;
191
+ }
192
+
193
+ function assessKey(key){
194
+ if(key.startsWith('on')) return key.toLowerCase();
195
+ return key;
196
+ }
197
+
198
+ function assessValue(value, key){
199
+ if(key.startsWith('on')) return value = `(${value})()`;
200
+ return value;
201
+ }
202
+
203
+ function renderToString(element, js = false) {
204
+ if (typeof element === 'string') {
205
+ return element
206
+ }
207
+
208
+ const { type, props = {} } = element
209
+
210
+ if (typeof type === 'function') {
211
+ return renderToString(type(props))
212
+ }
213
+
214
+ const children = element instanceof TextNode ? [] : props?.children || []
215
+ const childrenParsed = Array.isArray(children) ? children.map((c) => renderToString(c, js ? 'raw' : false)) : renderToString(children, js ? 'raw' : false)
216
+ const childrenHTML = Array.isArray(childrenParsed) ? childrenParsed.join('') : childrenParsed;
217
+
218
+ const propsString = Object.entries(props)
219
+ .filter(([key]) => key !== 'children')
220
+ .map(([key, value]) => ` ${assessKey(key)}="${assessValue(value, key)}"`)
221
+ .join('')
222
+
223
+ const eltJSON = {
224
+ ...element,
225
+ nodeType: element instanceof TextNode ? 'text' : 'element',
226
+ props: {
227
+ ...props,
228
+ children: childrenParsed,
229
+ },
230
+ states: element.states || {}
231
+ };
232
+ for(let i in eltJSON.props) {
233
+ if(typeof eltJSON.props[i] == "function"){
234
+ eltJSON.props[assessKey(i)] = assessValue(eltJSON.props[i].toString(), i);
235
+ }
236
+ }
237
+ delete eltJSON.parent;
238
+ delete eltJSON._target;
239
+
240
+ 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}>`}`;
241
+ }
242
+
243
+ class Page extends Node {
244
+ constructor() {
245
+ super();
246
+ }
247
+ /** @type{ElementNode} */
248
+ root = null;
249
+ /** @type{ElementNode} */
250
+ head = null;
251
+ /** @type{ElementNode} */
252
+ body = null;
253
+ find(key, value = null) {
254
+ return this.root.find(key, value);
255
+ }
256
+ add(...children) {
257
+ return this.body.add(...children);
258
+ }
259
+ script(scriptString) {
260
+ if (typeof scriptString == "object" && scriptString.src)
261
+ return this.add(createElement('script', { src: scriptString.src }));
262
+ else
263
+ return this.add(createElement('script', null, createTextNode(scriptString)));
264
+ }
265
+ style(styleString) {
266
+ if (typeof styleString == "object" && styleString.href)
267
+ return this.head.add(createElement('link', { href: styleString.href, rel: 'stylesheet' }));
268
+ else
269
+ return this.head.add(createElement('style', null, createTextNode(styleString)));
270
+ }
271
+ link(rel, href){
272
+ return this.head.add(createElement('link', { href, rel }));
273
+ }
274
+ serializeState() {
275
+ const states = {};
276
+ function extractStates(node) {
277
+ if (node instanceof ElementNode) {
278
+ if (node.props && node.props.children) {
279
+ node.props.children.forEach(child => extractStates(child));
280
+ }
281
+ }
282
+ if(node.states){
283
+ for(let i in node.states) states[node.states[i].id] = node.states[i];
284
+ }
285
+ }
286
+ extractStates(this.root);
287
+ this.initialState = states;
288
+ return JSON.stringify(states);
289
+ }
290
+ render(staticRender = false) {
291
+ return staticRender ? renderToString(this.root) : `<script>
292
+ const __INITIAL_STATE__ = ${this.serializeState()};
293
+ const DOMObject = ${renderToString(this.root, true)};
294
+ const generateRandomID = ${generateRandomID}
295
+ const emitter = ${emitter}
296
+ ${State}
297
+ const states = [];
298
+
299
+ function setAttribute(el, key, value){
300
+ let defVal = value;
301
+ if(key == 'style'){
302
+ for(let i in value){
303
+ const v = value[i];
304
+ el.style.setProperty(i, value[i]);
305
+ }
306
+ return;
307
+ } else if(key.startsWith('on')){
308
+ el.addEventListener(key.replace('on', '').toLowerCase(), (event) => {
309
+ new Function('event', value).call(event.target, event);
310
+ });
311
+ return;
312
+ }
313
+ el.setAttribute(key, defVal);
314
+ }
315
+
316
+ function rehydrate() {
317
+ const initialState = __INITIAL_STATE__;
318
+
319
+ function updateDOM(node, state) {
320
+ const elt = node.DOMELEMENT ? node.DOMELEMENT : node.nodeType == 'text' ? document.createTextNode(node.type.text) : document.createElement(node.type.element);
321
+ node.DOMELEMENT = elt;
322
+
323
+ if (node.nodeType == 'text') {
324
+ if(node.states?.[':text']){
325
+ const state = node.states[':text'];
326
+ if(state) elt.textContent = getState(state.id)?.value || state._value;
327
+ }
328
+ } else if (node.nodeType !== 'text' && node.props.children) {
329
+ const nodeState = node.states || {};
330
+ node.props.children.forEach(child => {
331
+ child.parent = node;
332
+ updateDOM(child, state);
333
+ });
334
+ Object.keys(node.props).forEach(key => {
335
+ if (key !== 'children') {
336
+ if(key in nodeState){
337
+ setAttribute(elt, key, getState(nodeState[key].id)?.value ?? nodeState[key]._value);
338
+ } else setAttribute(elt, key, node.props[key]);
339
+ }
340
+ });
341
+ if('data-only-if' in node.props){
342
+ if(elt.getAttribute('data-only-if') == 'true'){
343
+ elt.hidden = false;
344
+ } else {
345
+ elt.hidden = true;
346
+ }
347
+ }
348
+ }
349
+ if(node.parent && !elt.parentNode){
350
+ node.parent.DOMELEMENT.appendChild(elt);
351
+ }
352
+ return node;
353
+ }
354
+
355
+ function createState(inState, val, key){
356
+ const state = new State(inState._value);
357
+ state.id = inState.id;
358
+ states.push(state);
359
+ state.subscribe(() => updateDOM(DOMObject, { [key]: Array.isArray(val) ? [...val.filter(i => i.id !== state.id), state] : state }));
360
+ }
361
+
362
+ Object.keys(initialState).forEach(key => {
363
+ if(Array.isArray(initialState[key])) initialState[key].forEach((i) => createState(i, initialState[key], key));
364
+ else createState(initialState[key], initialState[key], key);
365
+ });
366
+
367
+ document.body.parentNode.remove();
368
+ document.appendChild(updateDOM(DOMObject, initialState).DOMELEMENT);
369
+ }
370
+ window.getState = (id) => states.find(s => s.id == id);
371
+ if (document.readyState === 'loading') {
372
+ document.addEventListener('DOMContentLoaded', rehydrate);
373
+ } else {
374
+ rehydrate();
375
+ }
376
+ </script>`;
377
+ }
378
+
379
+ toString() {
380
+ return this.render();
381
+ }
382
+
383
+ clone(){
384
+ const page = new Page();
385
+ page.root = cloneNest(this.root);
386
+ page.body = page.root.find('body');
387
+ page.head = page.root.find('head');
388
+ page.body.parent = page.root;
389
+ page.head.parent = page.root;
390
+ return page;
391
+ }
392
+ }
393
+ function createPage(options) {
394
+ const page = new Page;
395
+ const root = createElement('html');
396
+ page.root = root;
397
+
398
+ const head = createElement('head');
399
+ page.head = head;
400
+
401
+ if (options.viewportMeta) {
402
+ head
403
+ .add(createElement('meta', { charset: 'UTF-8' }))
404
+ .add(createElement('meta', { name: 'viewport', content: typeof options.viewportMeta == 'string' ? options.basicMeta : 'width=device-width, initial-scale=1.0' }));
405
+ }
406
+
407
+ const title = createElement('title', null, 'Document');
408
+
409
+ if (options.title) title.props.children = [createTextNode(options.title)];
410
+
411
+ if (options.title !== false) {
412
+ head.add(title);
413
+ page.title = title;
414
+ }
415
+
416
+ const body = createElement('body');
417
+ page.body = body;
418
+
419
+ root.add(head);
420
+ root.add(body);
421
+
422
+ return page;
423
+ }
424
+
425
+ module.exports = (context, importOptions) => {
426
+
427
+ const { build } = wait(async () => await import('vite'));
428
+
429
+ class Web {
430
+ create(options) {
431
+ return createPage(options);
432
+ }
433
+ isNode(node) {
434
+ return node instanceof Node;
435
+ }
436
+ isTextNode(node) {
437
+ return node instanceof TextNode;
438
+ }
439
+ isElementNode(node) {
440
+ return node instanceof ElementNode;
441
+ }
442
+ createText(text) {
443
+ return createTextNode(text);
444
+ }
445
+ createElement(...args) {
446
+ return createElement(...args);
447
+ }
448
+ state(value) {
449
+ return new State(value);
450
+ }
451
+ invokeState(states, callback){
452
+ const statesMapped = states.map(i => i instanceof State ? `getState('${i.id}')` : JSON.stringify(i));
453
+ return `((${callback})(event, ...[${statesMapped}]))`;
454
+ }
455
+ async bundle(filepath, options = {}) {
456
+ const virtualModuleId = `virtual:${filepath}`;
457
+ const result = await build({
458
+ build: {
459
+ rollupOptions: {
460
+ input: options.code ? virtualModuleId : filepath,
461
+ output: {
462
+ format: 'iife', // Immediately Invoked Function Expression for the browser
463
+ entryFileNames: '[name].js',
464
+ },
465
+ },
466
+ write: false, // Do not write to file system, get the output as string
467
+ },
468
+ logLevel: 'silent',
469
+ plugins: [
470
+ (function rew() {
471
+ return {
472
+ name: 'rew',
473
+ resolveId(id) {
474
+ if (options.code && id === virtualModuleId) {
475
+ return virtualModuleId;
476
+ }
477
+ return null;
478
+ },
479
+ load(id) {
480
+ if (options.code && id === virtualModuleId) {
481
+ return options.code;
482
+ }
483
+ return null;
484
+ },
485
+ async transform(code, id) {
486
+ if (id.endsWith(REW_FILE_TYPE.EXTENSION) || id.endsWith('.coffee')) {
487
+ const result = compile({ content: code, path: filepath }, { jsx: true, async: true, keepImports: true });
488
+ return {
489
+ code: await result,
490
+ map: null,
491
+ };
492
+ }
493
+ },
494
+ };
495
+ })(),
496
+ ...(options.plugins ?? [])
497
+ ],
498
+ });
499
+ return result.output[0].code;
500
+ }
501
+ }
502
+
503
+ return importOptions.instance ? new Web : Web;
504
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makano/rew",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "A simple coffescript runtime and app manager",
5
5
  "main": "main.js",
6
6
  "directories": {
@@ -11,6 +11,8 @@
11
11
  },
12
12
  "files": [
13
13
  "lib/",
14
+ "runtime.d.ts",
15
+ "jsconfig.json",
14
16
  "main.js",
15
17
  "README.md"
16
18
  ],
@@ -30,6 +32,10 @@
30
32
  "license": "ISC",
31
33
  "dependencies": {
32
34
  "@babel/core": "^7.24.6",
35
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
36
+ "@babel/plugin-proposal-decorators": "^7.24.7",
37
+ "@babel/plugin-transform-class-static-block": "^7.24.7",
38
+ "@babel/preset-env": "^7.24.7",
33
39
  "@babel/preset-react": "^7.24.6",
34
40
  "@babel/preset-typescript": "^7.24.7",
35
41
  "axios": "^1.7.2",
@@ -37,14 +43,13 @@
37
43
  "chokidar": "^3.6.0",
38
44
  "colors": "^1.4.0",
39
45
  "deasync": "^0.1.30",
46
+ "itty-router": "^5.0.17",
40
47
  "js-yaml": "^4.1.0",
48
+ "loading-cli": "^1.1.2",
41
49
  "tiny-msgpack": "^2.2.0",
42
50
  "uuid": "^9.0.1",
51
+ "vite": "^5.2.13",
43
52
  "vm": "^0.1.0",
44
53
  "yargs": "^17.7.2"
45
- },
46
- "devDependencies": {
47
- "pkg": "^5.8.1",
48
- "vitepress": "^1.2.2"
49
54
  }
50
55
  }