@makano/rew 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. package/lib/civet/main.js +17239 -0
  2. package/lib/rew/cli/cli.js +34 -5
  3. package/lib/rew/cli/utils.js +43 -12
  4. package/lib/rew/const/default.js +2 -1
  5. package/lib/rew/const/ext.js +5 -0
  6. package/lib/rew/const/opt.js +7 -2
  7. package/lib/rew/const/usage.js +15 -0
  8. package/lib/rew/functions/export.js +1 -1
  9. package/lib/rew/functions/fs.js +6 -1
  10. package/lib/rew/functions/import.js +17 -12
  11. package/lib/rew/functions/require.js +17 -1
  12. package/lib/rew/functions/stdout.js +4 -0
  13. package/lib/rew/main.js +1 -13
  14. package/lib/rew/modules/compiler.js +103 -34
  15. package/lib/rew/modules/context.js +13 -1
  16. package/lib/rew/modules/runtime.js +37 -20
  17. package/lib/rew/pkgs/serve.js +373 -0
  18. package/lib/rew/pkgs/stream.js +10 -0
  19. package/lib/rew/pkgs/web.js +504 -0
  20. package/package.json +7 -5
  21. package/runtime.d.ts +718 -146
  22. package/jsconfig.json +0 -13
  23. package/lib/coffeescript/browser.js +0 -156
  24. package/lib/coffeescript/cake.js +0 -134
  25. package/lib/coffeescript/coffeescript.js +0 -465
  26. package/lib/coffeescript/command.js +0 -832
  27. package/lib/coffeescript/grammar.js +0 -1930
  28. package/lib/coffeescript/helpers.js +0 -513
  29. package/lib/coffeescript/index.js +0 -230
  30. package/lib/coffeescript/lexer.js +0 -2316
  31. package/lib/coffeescript/nodes.js +0 -9784
  32. package/lib/coffeescript/optparse.js +0 -258
  33. package/lib/coffeescript/parser.js +0 -20384
  34. package/lib/coffeescript/register.js +0 -120
  35. package/lib/coffeescript/repl.js +0 -328
  36. package/lib/coffeescript/rewriter.js +0 -1448
  37. package/lib/coffeescript/scope.js +0 -191
  38. 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.5",
3
+ "version": "1.2.6",
4
4
  "description": "A simple coffescript runtime and app manager",
5
5
  "main": "main.js",
6
6
  "directories": {
@@ -32,6 +32,10 @@
32
32
  "license": "ISC",
33
33
  "dependencies": {
34
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",
35
39
  "@babel/preset-react": "^7.24.6",
36
40
  "@babel/preset-typescript": "^7.24.7",
37
41
  "axios": "^1.7.2",
@@ -39,15 +43,13 @@
39
43
  "chokidar": "^3.6.0",
40
44
  "colors": "^1.4.0",
41
45
  "deasync": "^0.1.30",
46
+ "itty-router": "^5.0.17",
42
47
  "js-yaml": "^4.1.0",
43
48
  "loading-cli": "^1.1.2",
44
49
  "tiny-msgpack": "^2.2.0",
45
50
  "uuid": "^9.0.1",
51
+ "vite": "^5.2.13",
46
52
  "vm": "^0.1.0",
47
53
  "yargs": "^17.7.2"
48
- },
49
- "devDependencies": {
50
- "pkg": "^5.8.1",
51
- "vitepress": "^1.2.2"
52
54
  }
53
55
  }