@makano/rew 1.1.2 → 1.1.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.
@@ -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
  });