@makano/rew 1.1.2 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,17 +14,18 @@ const lookUpInOtherApps = (fullPath) => {
14
14
  const name = fullPath.indexOf('/') ? fullPath.split('/')[0] : fullPath;
15
15
  let dpath = fullPath.indexOf('/') ? fullPath.split('/')[1] : '';
16
16
  let ppath = path.join(con.CONFIG_PATH, name, 'app');
17
- if(!existsSync(ppath)) return null;
18
- if(!dpath){
17
+ if (!existsSync(ppath)) return null;
18
+ if (!dpath) {
19
19
  dpath = jsYaml.load(readFileSync(path.join(ppath, 'app.yaml'), 'utf-8')).entry;
20
20
  }
21
21
  ppath = path.join(ppath, dpath);
22
- if(existsSync(ppath)) return ppath;
22
+ if (existsSync(ppath)) return ppath;
23
23
  else return null;
24
24
  }
25
25
 
26
26
  module.exports.imp = function (runPath, context) {
27
27
  return function (filename, options = {}) {
28
+ if (!options) options = {};
28
29
  let type = options.type || "coffee";
29
30
  let exports,
30
31
  ispkg = findPackage(filename);
@@ -35,24 +36,24 @@ module.exports.imp = function (runPath, context) {
35
36
 
36
37
  const lookUp = () => {
37
38
  const otherPath = lookUpInOtherApps(filename);
38
- if(!otherPath) throw new Error('Module "'+filename+'" not found');
39
+ if (!otherPath) throw new Error('Module "' + filename + '" not found');
39
40
  else filepath = otherPath;
40
41
  }
41
42
 
42
43
  const foundCache = cachedFiles.find(f => f.filepath == filepath);
43
44
 
44
- if(!ispkg && foundCache){
45
+ if (!ispkg && foundCache) {
45
46
  exports = foundCache.exports;
46
47
  }
47
48
 
48
- if(!ispkg && !existsSync(filepath)){
49
- if(Array.isArray(execOptions.resolveExtensions) && execOptions.resolveExtensions.length){
50
- const resolve = execOptions.resolveExtensions.find(ext => typeof ext == "string" ? existsSync(filepath+ext) : existsSync(filepath+(ext.ext || '')));
51
- if(resolve) {
49
+ if (!ispkg && !existsSync(filepath)) {
50
+ if (Array.isArray(execOptions.resolveExtensions) && execOptions.resolveExtensions.length) {
51
+ const resolve = execOptions.resolveExtensions.find(ext => typeof ext == "string" ? existsSync(filepath + ext) : existsSync(filepath + (ext.ext || '')));
52
+ if (resolve) {
52
53
  filepath += typeof resolve == "string" ? resolve : resolve.ext;
53
- if(typeof resolve == "object" && resolve.options){
54
- if(resolve.options.type) type = resolve.options.type;
55
- for(let i in resolve.options) options[i] = resolve.options[i];
54
+ if (typeof resolve == "object" && resolve.options) {
55
+ if (resolve.options.type) type = resolve.options.type;
56
+ for (let i in resolve.options) options[i] = resolve.options[i];
56
57
  }
57
58
  } else lookUp();
58
59
  } else lookUp();
@@ -60,16 +61,24 @@ module.exports.imp = function (runPath, context) {
60
61
 
61
62
  const exec = (coptions = {}) => runPath(
62
63
  filepath,
63
- { ...options, useContext: execOptions.sharedContext == false ? false : true, ...coptions },
64
- execOptions.sharedContext == false ? {} : context,
64
+ {
65
+ import: options,
66
+ main: false,
67
+ useContext: execOptions.sharedContext == false ? false : !(options.context && options.context == 'new'),
68
+ ...coptions,
69
+ as: options.as == 'main' ? context.module.main ? 'main' : 'parent' : options.as == 'parent' ? 'parent' : 'child',
70
+ fromMain: context.module.main
71
+ },
72
+ execOptions.sharedContext == false ? {} :
73
+ options.context && options.context == 'new' ? {} : context,
65
74
  ).context.module.exports;
66
75
 
67
76
  if (ispkg) {
68
77
  exports = getPackage(filename)(context);
69
- } else if(foundCache) {
70
-
78
+ } else if (foundCache) {
79
+
71
80
  } else if (type == "coffee") {
72
- exports = exec({ });
81
+ exports = exec({});
73
82
  } else if (type == "js") {
74
83
  exports = exec({ compile: false });
75
84
  } else if (type == "yaml" || type == "json" || type == "text") {
@@ -95,8 +104,8 @@ module.exports.imp = function (runPath, context) {
95
104
  }
96
105
  }
97
106
 
98
- if(!ispkg) context.module.imports.push(filepath);
99
- if(!ispkg) cachedFiles.push({ filepath, exports });
107
+ if (!ispkg) context.module.imports.push(filepath);
108
+ if (!ispkg) cachedFiles.push({ filepath, exports });
100
109
 
101
110
  return exports;
102
111
  };
@@ -15,17 +15,21 @@ function getType(value){
15
15
  return typeof value === 'object' ? Array.isArray(value) ? 'array' : typeof value : typeof value;
16
16
  }
17
17
 
18
- function typedef(value) {
18
+ function typedef(value, strict = false) {
19
19
  return {
20
+ strict,
20
21
  defaultValue: value,
21
22
  class: typeof value == 'function' ? value : typeof value === 'object' && value !== null && !Array.isArray(value) ? value.constructor : _defaultConstructors[getType(value)],
22
23
  type: getType(value),
23
24
  isConstucted: typeof value === 'object' && value !== null && !Array.isArray(value),
24
- isEmpty: typeof value == "object" ? !Object.keys(value).length : typeof value == "string" ? value == "" : true
25
+ isEmpty: typeof value == "object" ? !Object.keys(value).length : typeof value == "string" ? value == "" : typeof value !== "function"
25
26
  };
26
27
  }
27
28
 
28
29
  function typeis(obj, typeDef) {
30
+ // Resolve Type
31
+ if(typeof typeDef == "function" && typeDef.type) typeDef = typeDef.type;
32
+
29
33
  if (typeDef.isConstucted && typeDef.class && !(obj instanceof typeDef.class)) {
30
34
  return false;
31
35
  }
@@ -41,7 +45,9 @@ function typeis(obj, typeDef) {
41
45
  if(!typeDef.isEmpty) {
42
46
  if(typeDef.type == 'object'){
43
47
  for (const key in typeDef.defaultValue) {
44
- const propTypeDef = typeDef.defaultValue[key];
48
+ let propTypeDef = typeDef.defaultValue[key];
49
+ // Resolve type
50
+ if(typeof propTypeDef == "function" && propTypeDef.type) propTypeDef = propTypeDef.type;
45
51
 
46
52
  if (typeof propTypeDef === 'object') {
47
53
  if (!typeis(obj[key], propTypeDef)) {
@@ -51,8 +57,13 @@ function typeis(obj, typeDef) {
51
57
  return false;
52
58
  }
53
59
  }
60
+ if(typeDef.strict) {
61
+ if(Object.keys(obj).some(key => !Object.keys(typeDef.defaultValue).includes(key))) return false;
62
+ }
54
63
  } else if(typeDef.type == 'string'){
55
64
  return typeDef.defaultValue == obj;
65
+ } else if(typeDef.type == 'function'){
66
+ return typeDef.defaultValue == obj;
56
67
  }
57
68
  }
58
69
 
@@ -70,24 +81,29 @@ function typei(child, parent) {
70
81
  function int(str){
71
82
  return parseInt(str);
72
83
  }
84
+ int.type = typedef(1)
73
85
 
74
86
  function float(str){
75
87
  return parseFloat(str);
76
88
  }
89
+ float.type = typedef(1.0)
77
90
 
78
91
  function num(str){
79
92
  return Number(str);
80
93
  }
94
+ num.type = typedef(1)
81
95
 
82
96
  function str(str){
83
97
  return str ? str.toString() : "";
84
98
  }
99
+ str.type = typedef('')
85
100
 
86
101
  function bool(value){
87
102
  return typeof value == 'string' ? (
88
103
  value == 'true' ? true : false
89
104
  ) : value !== null && value !== undefined;
90
105
  }
106
+ bool.type = typedef(true)
91
107
 
92
108
  module.exports = {
93
109
  typex,
@@ -189,10 +189,20 @@ window.recieveMessage = (data) => {
189
189
  } catch (e) {
190
190
  log(e.toString());
191
191
  }
192
- }
192
+ } else if(edata.action == 'message') {
193
+ window.dispatchEvent(new CustomEvent('message', {
194
+ detail: edata.data
195
+ }));
196
+ }
193
197
  };
194
198
 
195
199
  window.addEventListener('load', () => {
196
- window.exec(window.execContext);
200
+ window.exec({
201
+ ...window.execContext,
202
+ window,
203
+ log,
204
+ send: (data) => sendData({ action: 'message', data }),
205
+ onRecieve: (cb) => window.addEventListener('message', (e) => cb(e.detail || {}))
206
+ });
197
207
  log('SETUP::READY');
198
208
  });
@@ -1,8 +1,197 @@
1
1
  const { compile } = require("../../coffeescript/coffeescript");
2
+ const { execOptions } = require("../const/opt");
2
3
  const { getFile } = require("./fs");
4
+ const babel = require('@babel/core');
5
+ const babelReact = require('@babel/preset-react');
6
+
7
+ function tokenizeCoffeeScript(code) {
8
+ const tokens = [];
9
+ let currentToken = '';
10
+
11
+ for (let i = 0; i < code.length; i++) {
12
+ const char = code[i];
13
+ const nextChar = code[i + 1];
14
+
15
+ if (char === '#') {
16
+ // Comment
17
+ tokens.push({ type: 'COMMENT', value: char + code.substring(i + 1).split('\n')[0]+'\n' });
18
+ i = code.indexOf('\n', i);
19
+ } else if (char === '"' || char === "'") {
20
+ // String
21
+ let string = char;
22
+ let escaped = false;
23
+ i++;
24
+ while (i < code.length && (code[i] !== char || escaped)) {
25
+ string += code[i];
26
+ if (code[i] === '\\' && !escaped) {
27
+ escaped = true;
28
+ } else {
29
+ escaped = false;
30
+ }
31
+ i++;
32
+ }
33
+ string += char; // Include closing quote
34
+ tokens.push({ type: 'STRING', value: string });
35
+ } else if (char === '/' && (nextChar === '/' || nextChar === '*')) {
36
+ // Regular expression
37
+ let regex = char;
38
+ i++;
39
+ while (i < code.length && (code[i] !== '/' || regex.endsWith('\\'))) {
40
+ regex += code[i];
41
+ i++;
42
+ }
43
+ regex += '/';
44
+ tokens.push({ type: 'REGEX', value: regex });
45
+ } else if (/\s/.test(char)) {
46
+ // Whitespace
47
+ if(tokens[tokens.length-1]?.type == 'WHITESPACE'
48
+ && tokens[tokens.length-1].value[0] == char
49
+ ){
50
+ tokens[tokens.length-1].value += char;
51
+ } else {
52
+ tokens.push({ type: 'WHITESPACE', value: char });
53
+ }
54
+ } else if (/[a-zA-Z_$]/.test(char)) {
55
+ // Identifier
56
+ let identifier = char;
57
+ i++;
58
+ while (i < code.length && /[a-zA-Z0-9_$]/.test(code[i])) {
59
+ identifier += code[i];
60
+ i++;
61
+ }
62
+ tokens.push({ type: 'IDENTIFIER', value: identifier });
63
+ i--; // Move back one character to recheck
64
+ } else {
65
+ // Other characters
66
+ tokens.push({ type: 'OTHER', value: char });
67
+ }
68
+ }
69
+
70
+ return tokens;
71
+ }
72
+
73
+ const gnextToken = (i, n, tokens) => {
74
+ return tokens[i + n] ? tokens[i + n].type == 'WHITESPACE' ? gnextToken(i, n + 1, tokens) : { nextToken: tokens[i + n], n } : null;
75
+ }
76
+
77
+ const fnextToken = (i, tokens, type, value) => {
78
+ return tokens.map((t, ind) => { t.ti = ind; return t }).slice(i, tokens.length - 1).map((t, ind) => { t.ri = ind; t.index = ind - i; return t }).find(t => t.type == type && (value ? t.value == value : true));
79
+ }
80
+
81
+ function compileRewStuff(content, options) {
82
+ const tokens = tokenizeCoffeeScript(content);
83
+ let result = '';
84
+
85
+ let hooks = [];
86
+
87
+ for (let i = 0; i < tokens.length; i++) {
88
+ const token = tokens[i];
89
+ let { nextToken, n } = gnextToken(i, 1, tokens) || {};
90
+
91
+ if (token.type === 'IDENTIFIER' && token.value === 'opt') {
92
+ const { nextToken: nextNextToken } = gnextToken(i, 2, tokens) || {};
93
+ if(nextNextToken && nextNextToken.value == 'jsxPragma'){
94
+ const { nextToken: nextLastToken } = gnextToken(i, 5, tokens) || {};
95
+ execOptions.jsxPragma = nextLastToken.value.slice(1).slice(0, -1);
96
+ }
97
+ }
98
+
99
+ if (token.type === 'COMMENT' && token.value.slice(1).trim() === '@jsx') {
100
+ options.jsx = true;
101
+ }
102
+
103
+ if (token.type === 'IDENTIFIER' && token.value === 'import') {
104
+ // console.log(nextToken.type);
105
+ let ind = i + n + 2;
106
+
107
+ let defaultName;
108
+ if (nextToken.type === 'STRING') {
109
+ result += `inc ${nextToken.value}`;
110
+ i += n;
111
+ } else if (nextToken.value === '{') {
112
+ const closingBraceToken = fnextToken(ind, tokens, 'OTHER', '}');
113
+ const nameToken = fnextToken(ind, tokens, 'STRING');
114
+ if (closingBraceToken) {
115
+ const exportsTokens = tokens.slice(ind, closingBraceToken.ti);
116
+ const exports = exportsTokens.filter(t => t.type === 'IDENTIFIER').map(t => t.value).join(', ');
117
+ result += `{ ${exports} } = inc ${nameToken.value}`;
118
+ i = nameToken.ti;
119
+ }
120
+ } else if (nextToken.value === '*') {
121
+ const asToken = fnextToken(ind, tokens, 'IDENTIFIER', 'as');
122
+ const nameToken = fnextToken(asToken.ri, tokens, 'STRING');
123
+ if (asToken) {
124
+ const nextToken = fnextToken(asToken.ti + 1, tokens, 'IDENTIFIER');
125
+ defaultName = nextToken.value;
126
+ result += `${defaultName} = inc ${nameToken.value}`;
127
+ i = ind + 6;
128
+ }
129
+ } else if(nextToken) {
130
+ const nameToken = fnextToken(ind, tokens, 'STRING');
131
+ defaultName = nextToken.value;
132
+ let { nextToken: nextNextToken, n: n2 } = gnextToken(i + 2, 1, tokens) || {};
133
+ if(nextNextToken?.type == 'OTHER' && nextNextToken?.value == ','){
134
+ const closingBraceToken = fnextToken(ind, tokens, 'OTHER', '}');
135
+ if(closingBraceToken){
136
+ const exportsTokens = tokens.slice(ind, closingBraceToken.ti);
137
+ const exports = exportsTokens.filter(t => t.type === 'IDENTIFIER').map(t => t.value).join(', ');
138
+ result += `{ default: ${defaultName}, ${exports} } = inc ${nameToken?.value || ""}`;
139
+ i = closingBraceToken.ti + 4;
140
+ }
141
+ } else {
142
+ result += `{ default: ${defaultName} } = inc ${nameToken?.value || ""}`;
143
+ i = ind + 2;
144
+ }
145
+
146
+ }
147
+
148
+ const nextLastToken = fnextToken(i, tokens, 'IDENTIFIER');
149
+
150
+ if(nextLastToken?.value == 'assert'){
151
+ result += ', ';
152
+ i += 3;
153
+ }
154
+
155
+ continue;
156
+ }
157
+
158
+
159
+ if (token.type === 'IDENTIFIER' && token.value === 'pub' &&
160
+ nextToken && nextToken.type === 'IDENTIFIER' &&
161
+ nextToken.value && nextToken.value !== 'undefined') {
162
+
163
+ hooks.push({
164
+ index: i + 1,
165
+ value: `"${nextToken.value}", `
166
+ });
167
+ }
168
+
169
+ result += token.value;
170
+ if (hooks.length) {
171
+ hooks.forEach((hook, ind) => {
172
+ if (i == hook.index) {
173
+ result += hook.value;
174
+ hooks.splice(ind, 1);
175
+ }
176
+ });
177
+ }
178
+ }
179
+
180
+ // console.log(result)
181
+
182
+ return result;
183
+ }
184
+
3
185
 
4
186
  const cpl = (module.exports.compile = function (file, options = {}) {
5
- return compile(file.content, options);
187
+ let c = compile(compileRewStuff(file.content, options), { ...options, filename: file.path, bare: false, inlineMap: false });
188
+ if(options.jsx) {
189
+ c = babel.transformSync(c, {
190
+ presets: [[babelReact, { pragma: execOptions.jsxPragma }]],
191
+ plugins: []
192
+ }).code;
193
+ }
194
+ return c;
6
195
  });
7
196
 
8
197
  module.exports.compileFile = function (filepath, options = {}) {
@@ -1,37 +1,46 @@
1
1
  const defaultContext = require("../const/default");
2
2
  const { execOptions } = require("../const/opt");
3
3
  const emitter = require("../functions/emitter");
4
- const { exportsFunction } = require("../functions/export");
4
+ const { exportsFunction, pubFunction } = require("../functions/export");
5
5
  const { imp } = require("../functions/import");
6
6
  const { customRequire } = require("../functions/require");
7
7
  const fsLib = require('../functions/fs');
8
8
  const pathLib = require('../functions/path');
9
+ const execLib = require('../functions/exec');
9
10
 
11
+ let mainFile = "";
12
+ const isMainFile = filepath => filepath == mainFile;
10
13
  module.exports.prepareContext = function (
11
14
  custom_context,
12
15
  options,
13
16
  filepath = "",
14
17
  runPath = () => {},
15
18
  ) {
19
+ if(mainFile == "") mainFile = filepath;
16
20
  let context = {
17
21
  module: {
18
22
  exports: null,
19
- options,
20
23
  filepath,
24
+ main: isMainFile(filepath),
21
25
  imports: []
22
26
  },
23
- ...fsLib(filepath)
27
+ imports: {
28
+ meta: {},
29
+ assert: options.import ?? {}
30
+ },
31
+ ...fsLib(filepath),
24
32
  };
25
33
  if (options.useContext) {
26
34
  context = {
27
- ...context,
28
35
  ...custom_context,
36
+ ...context
29
37
  };
30
38
  } else {
31
39
  context = {
32
40
  ...context,
33
41
  ...defaultContext,
34
42
  ...pathLib(filepath),
43
+ ...execLib(filepath),
35
44
  require: (package) => {
36
45
  try {
37
46
  return execOptions.nativeRequire || package.startsWith('node:') ? require(package.startsWith('node:') ? package.split('node:')[1] : package) : customRequire(package, filepath);
@@ -39,26 +48,43 @@ module.exports.prepareContext = function (
39
48
  throw new Error("Module "+package+" not found");
40
49
  }
41
50
  },
42
- opt: {
43
- set: (key, value) => execOptions[key] = value,
44
- get: (key) => execOptions[key],
45
- push: (key, value) => execOptions[key]?.push(value),
46
- pop: (key) => execOptions[key]?.pop()
47
- },
48
51
  ...custom_context,
49
52
  };
50
- context.imp = imp(runPath, context);
51
- context.exports = exportsFunction(context);
52
53
  }
53
- if (!context.global) context.global = context;
54
54
  if (!context.process)
55
55
  context.process = {
56
56
  argv: process.argv,
57
- target: emitter(),
57
+ target: {
58
+ on: (event, listener) => process.on(event, listener),
59
+ off: (event, listener) => process.off(event, listener),
60
+ emit: (event, code) => process.emit(event, code)
61
+ },
58
62
  env: process.env,
59
63
  cwd: () => process.cwd(),
60
64
  arch: process.arch
61
65
  };
62
- // console.log(custom_context);
66
+
67
+ context.global = context;
68
+ context.imports.assert = options.import ?? {};
69
+ context.imp = imp(runPath, context);
70
+ context.inc = (package, asserts) => {
71
+ try{
72
+ if(package.startsWith('node:') || package.startsWith('pkg:')) throw new Error('');
73
+ return context.imp(package, asserts);
74
+ } catch(e) {
75
+ return context.require(package.startsWith('pkg:') ? package.split('pkg:')[1] : package);
76
+ }
77
+ };
78
+ context.pub = pubFunction(context);
79
+ context.exports = exportsFunction(context);
80
+
81
+ if(context.module.main || (options.fromMain == true && options.as == 'main')){
82
+ context.opt = {
83
+ set: (key, value) => execOptions[key] = value,
84
+ get: (key) => execOptions[key],
85
+ push: (key, value) => execOptions[key]?.push(value),
86
+ pop: (key) => execOptions[key]?.pop()
87
+ };
88
+ } else delete context.opt
63
89
  return context;
64
90
  };
@@ -3,7 +3,11 @@ const { compileFile } = require("./compiler");
3
3
  const { prepareContext } = require("./context");
4
4
 
5
5
  const exec = (module.exports.exec = function (code, context) {
6
- return vm.runInNewContext(code, vm.createContext(context));
6
+ return vm.runInNewContext(code, vm.createContext(context), {
7
+ filename: context.module.filepath,
8
+ lineOffset: 0,
9
+ displayErrors: true
10
+ });
7
11
  });
8
12
 
9
13
  module.exports.runPath = function runPath(
@@ -22,7 +22,7 @@ parentPort.on('message', (data) => {
22
22
  exec(`(${workerData.cb}).call({ process }, context)`, { print: (...a) => console.log(...a), process: {
23
23
  on: (e, cb) => { target.on(e, cb) },
24
24
  off: (e) => { target.off(e) },
25
- emit: (e) => { parentPort.postMessage({ type: 'event', event: e, data }) },
25
+ emit: (e, data) => { parentPort.postMessage({ type: 'event', event: e, data }) },
26
26
  exit: (code) => process.exit(code),
27
27
  finish: (data) => {
28
28
  parentPort.postMessage({ type: 'result', result: data });
@@ -161,11 +161,17 @@ module.exports.uiClasses = (context, options, send, recieve, hook, rmHook) => {
161
161
  // }
162
162
  // }, false);
163
163
 
164
+ const Transmitter = {
165
+ send: (data) => send({ action: 'message', data }),
166
+ recieve: (cb) => recieve((data) => cb(data.data))
167
+ }
168
+
164
169
  return {
165
170
  Widget: RewWidget,
166
171
  Text: RewTextWidget,
167
172
  WidgetOptions: RemWidgetOptions,
168
173
  findElement,
169
- StyleSheet: StyleSheet
174
+ StyleSheet: StyleSheet,
175
+ Transmitter
170
176
  }
171
177
  }
@@ -44,7 +44,10 @@ module.exports = (context) => ({
44
44
  stop();
45
45
  });
46
46
 
47
+ let exiting = false;
48
+
47
49
  worker.on('exit', (code) => {
50
+ if(exiting) return;
48
51
  stop();
49
52
  if (code !== 0) {
50
53
  throw new Error(`Worker stopped with exit code ${code}`);
@@ -57,7 +60,8 @@ module.exports = (context) => ({
57
60
  on: (e, cb) => listener.on(e, cb),
58
61
  off: (e, cb) => listener.off(e, cb),
59
62
  emit: (e, data) => worker?.postMessage({ type: 'event', event: e, data }),
60
- get: () => dataResult.wait()
63
+ get: () => dataResult.wait(),
64
+ stop: () => { exiting = true; stop(); }
61
65
  };
62
66
  }
63
67
  };
@@ -1,7 +1,5 @@
1
1
  const path = require("path");
2
2
  const { spawn, exec } = require("child_process");
3
- const WebSocket = require("ws");
4
- const http = require("http");
5
3
  const fs = require("fs");
6
4
  const { uiClasses } = require("./modules/ui/classes");
7
5
  const { generateRandomID } = require("../functions/id");
@@ -26,7 +24,7 @@ const defaultOptions = {
26
24
  onExit: () => process.exit(),
27
25
  style: '',
28
26
  stylePath: THEME_PATH,
29
- exec: () => {},
27
+ exec: () => { },
30
28
  execContext: {}
31
29
  };
32
30
 
@@ -44,18 +42,22 @@ module.exports = (context) => ({
44
42
 
45
43
  options.runId = runId;
46
44
 
47
- if(fs.existsSync(options.stylePath)) options.style = fs.readFileSync(options.stylePath, { encoding: 'utf-8' }) + '\n' + options.style;
45
+ if (fs.existsSync(options.stylePath)) options.style = fs.readFileSync(options.stylePath, { encoding: 'utf-8' }) + '\n' + options.style;
48
46
 
49
- options.style = ' */\n'+options.style+'\n/* ';
47
+ options.style = ' */\n' + options.style + '\n/* ';
50
48
 
51
49
  const HTML = replaceString(HTML_STRING, options);
52
50
  const JS = replaceString(JS_STRING, options);
53
51
 
52
+ /**
53
+ * Queue for future writes
54
+ * @type {string[]}
55
+ * */
54
56
  const queue = [];
55
57
 
56
58
  const send = (data) => {
57
59
  const content = fs.readFileSync(tmpFile, { encoding: 'utf-8' });
58
- if(content) {
60
+ if (content) {
59
61
  queue.push(data);
60
62
  } else {
61
63
  fs.writeFileSync(tmpFile, typeof data !== "string" ? JSON.stringify(data) : data);
@@ -77,20 +79,18 @@ module.exports = (context) => ({
77
79
  output: process.stdout
78
80
  });
79
81
 
80
- rl.question('', () => {});
82
+ rl.question('', () => { });
81
83
 
82
84
  fs.writeFileSync(tmpFile, '');
83
85
 
84
86
  fs.watch(tmpFile, { encoding: 'utf-8' })
85
- .on('change', () => {
86
- if(queue.length){
87
- send(queue.pop());
88
- }
89
- });
90
-
91
- const p = spawn(BIN_PATH, [runId]);
87
+ .on('change', () => {
88
+ if (queue.length) {
89
+ send(queue.pop());
90
+ }
91
+ });
92
92
 
93
-
93
+ const p = spawn(options.bin || BIN_PATH, [runId]);
94
94
 
95
95
  p.on("close", (code) => {
96
96
  rl.close();
@@ -103,12 +103,12 @@ module.exports = (context) => ({
103
103
  });
104
104
 
105
105
  g_emitter.on('recieve', (edata) => {
106
- if(edata.action.startsWith('hook:')){
106
+ if (edata.action.startsWith('hook:')) {
107
107
  const hook = hookedSocketListeners[edata.data.rid];
108
108
  const type = edata.action.split('hook:')[1];
109
- if(hook && hook.type == type) {
109
+ if (hook && hook.type == type) {
110
110
  hookedSocketListeners[edata.data.rid].cb(edata.data.object);
111
- if(hook.once) delete hookedSocketListeners[edata.data.rid];
111
+ if (hook.once) delete hookedSocketListeners[edata.data.rid];
112
112
  }
113
113
  }
114
114
  });
@@ -119,7 +119,7 @@ module.exports = (context) => ({
119
119
  const d = data.toString().split("RESPONSE::")[1];
120
120
  const jd = JSON.parse(d);
121
121
  recieve(jd);
122
- } else if(data.toString().trim().endsWith('SETUP::READY')) {
122
+ } else if (data.toString().trim().endsWith('SETUP::READY')) {
123
123
  console.log('READY');
124
124
  r(uiClasses(context, options, sendEvent, (cb) => {
125
125
  g_emitter.on('recieve', cb);
@@ -128,15 +128,15 @@ module.exports = (context) => ({
128
128
  }, (rid) => { // Remove hook
129
129
  delete hookedSocketListeners[rid];
130
130
  }));
131
- } else if(data.toString().endsWith('SETUP::HTML')) {
132
- send({action: 'JS2', data: JS, isSetup: true});
133
- } else if(data.toString() == 'INIT::READY') {
134
- send({action: 'HTML', data: HTML});
131
+ } else if (data.toString().endsWith('SETUP::HTML')) {
132
+ send({ action: 'JS2', data: JS, isSetup: true });
133
+ } else if (data.toString() == 'INIT::READY') {
134
+ send({ action: 'HTML', data: HTML });
135
135
  } else {
136
136
  console.log(data.toString());
137
137
  }
138
138
  });
139
-
139
+
140
140
  p.stderr.on("data", (data) => {
141
141
  console.error(data.toString());
142
142
  });