rtjscomp 0.8.2 → 0.8.4
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.
- package/package.json +1 -1
- package/rtjscomp.js +141 -66
package/package.json
CHANGED
package/rtjscomp.js
CHANGED
|
@@ -22,9 +22,11 @@ const PATH_PUBLIC = 'public/';
|
|
|
22
22
|
const PATH_CONFIG = 'config/';
|
|
23
23
|
const PATH_DATA = 'data/';
|
|
24
24
|
const GZIP_OPTIONS = {level: 9};
|
|
25
|
+
const WATCH_OPTIONS = {persistent: true, interval: 1000};
|
|
25
26
|
const AGENT_CHECK_BOT = /bot|googlebot|crawler|spider|robot|crawling|favicon/i;
|
|
26
27
|
const AGENT_CHECK_MOBIL = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i;
|
|
27
28
|
const HTTP_LIST_REG = /,\s*/;
|
|
29
|
+
const IMPORT_REG = /import\(/g;
|
|
28
30
|
|
|
29
31
|
let log_verbose = process.argv.includes('-v');
|
|
30
32
|
let port_http = 0;
|
|
@@ -58,11 +60,34 @@ if (!Object.fromEntries) {
|
|
|
58
60
|
};
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
// workaround for bun: https://github.com/oven-sh/bun/issues/18919
|
|
64
|
+
let fs_watch = fs.watch;
|
|
65
|
+
if (typeof Bun !== 'undefined') {
|
|
66
|
+
const fs_watch_original = fs_watch;
|
|
67
|
+
const watch_callbacks = new Map;
|
|
68
|
+
fs_watch = (path, options, callback) => {
|
|
69
|
+
if (!watch_callbacks.has(path)) {
|
|
70
|
+
fs_watch_original(path, options, () => {
|
|
71
|
+
const callback = watch_callbacks.get(path);
|
|
72
|
+
if (callback) {
|
|
73
|
+
callback();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
watch_callbacks.set(path, callback);
|
|
78
|
+
return {
|
|
79
|
+
close: () => (
|
|
80
|
+
watch_callbacks.set(path, null)
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
61
86
|
// legacy, will be removed soon!
|
|
62
87
|
global.globals = rtjscomp;
|
|
63
88
|
global.actions = rtjscomp.actions;
|
|
64
89
|
global.data_load = name => {
|
|
65
|
-
log('[deprecated] load: ' + name);
|
|
90
|
+
log('[deprecated] synchronous load: ' + PATH_DATA + name);
|
|
66
91
|
try {
|
|
67
92
|
return fs.readFileSync(PATH_DATA + name, 'utf8');
|
|
68
93
|
}
|
|
@@ -71,7 +96,7 @@ global.data_load = name => {
|
|
|
71
96
|
}
|
|
72
97
|
}
|
|
73
98
|
global.data_save = (name, data) => (
|
|
74
|
-
log('[deprecated] save: ' + name),
|
|
99
|
+
log('[deprecated] synchronous save: ' + PATH_DATA + name),
|
|
75
100
|
fs.writeFileSync(PATH_DATA + name, data, 'utf8')
|
|
76
101
|
)
|
|
77
102
|
global.number_check_int = number => (
|
|
@@ -104,19 +129,43 @@ rtjscomp.data_save = (name, data) => (
|
|
|
104
129
|
)
|
|
105
130
|
)
|
|
106
131
|
|
|
132
|
+
const custom_require_paths = new Set;
|
|
107
133
|
const custom_require_cache = new Map;
|
|
134
|
+
const custom_import_cache = new Map;
|
|
108
135
|
const custom_require = path => {
|
|
109
136
|
let result = custom_require_cache.get(path);
|
|
110
137
|
if (result != null) return result;
|
|
111
138
|
|
|
139
|
+
log_verbose && log('require: ' + path);
|
|
140
|
+
const path_real = require.resolve(path, resolve_options);
|
|
141
|
+
custom_require_paths.add(path_real);
|
|
112
142
|
custom_require_cache.set(
|
|
113
143
|
path,
|
|
114
|
-
result = require(
|
|
115
|
-
|
|
144
|
+
result = require(path_real)
|
|
145
|
+
);
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
const custom_import = async path => {
|
|
149
|
+
let result = custom_import_cache.get(path);
|
|
150
|
+
if (result != null) return result;
|
|
151
|
+
|
|
152
|
+
log_verbose && log('import: ' + path);
|
|
153
|
+
custom_import_cache.set(
|
|
154
|
+
path,
|
|
155
|
+
result = await import(
|
|
156
|
+
'file://' + require.resolve(path, resolve_options)
|
|
116
157
|
)
|
|
117
158
|
);
|
|
118
159
|
return result;
|
|
119
160
|
}
|
|
161
|
+
actions.module_cache_clear = () => {
|
|
162
|
+
for (const path of custom_require_paths) {
|
|
163
|
+
delete require.cache[path];
|
|
164
|
+
}
|
|
165
|
+
custom_require_cache.clear();
|
|
166
|
+
custom_import_cache.clear();
|
|
167
|
+
}
|
|
168
|
+
const AsyncFunction = custom_import.constructor;
|
|
120
169
|
|
|
121
170
|
const services_active = new Map;
|
|
122
171
|
const services_loading = new Set;
|
|
@@ -137,21 +186,25 @@ const service_start = async path => {
|
|
|
137
186
|
handler_stop: null,
|
|
138
187
|
path,
|
|
139
188
|
stopped: false,
|
|
189
|
+
watcher: null,
|
|
140
190
|
};
|
|
141
191
|
|
|
142
|
-
await file_keep_new(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
192
|
+
service_object.watcher = await file_keep_new(
|
|
193
|
+
PATH_PUBLIC + path + '.service.js',
|
|
194
|
+
async file_content => {
|
|
195
|
+
if (file_content === null) {
|
|
196
|
+
log('[error] service file not found: ' + path);
|
|
197
|
+
return service_stop(service_object, true);
|
|
198
|
+
}
|
|
199
|
+
if (services_loading.size > 0) {
|
|
200
|
+
await Promise.all(Array.from(services_loading));
|
|
201
|
+
}
|
|
202
|
+
const start_promise = service_start_inner(path, service_object, file_content);
|
|
203
|
+
services_loading.add(start_promise);
|
|
204
|
+
await start_promise;
|
|
205
|
+
services_loading.delete(start_promise);
|
|
149
206
|
}
|
|
150
|
-
|
|
151
|
-
services_loading.add(start_promise);
|
|
152
|
-
await start_promise;
|
|
153
|
-
services_loading.delete(start_promise);
|
|
154
|
-
});
|
|
207
|
+
);
|
|
155
208
|
}
|
|
156
209
|
const service_start_inner = async (path, service_object, file_content) => {
|
|
157
210
|
if (services_active.has(path)) {
|
|
@@ -161,16 +214,23 @@ const service_start_inner = async (path, service_object, file_content) => {
|
|
|
161
214
|
log('start service: ' + path);
|
|
162
215
|
|
|
163
216
|
const start_interval = setInterval(() => {
|
|
164
|
-
log(
|
|
217
|
+
log(`[warning] ${path}: still starting`);
|
|
165
218
|
}, 1e3);
|
|
166
219
|
|
|
220
|
+
if (file_content.includes('globals.')) {
|
|
221
|
+
log(`[deprecated] ${path}: uses globals object`);
|
|
222
|
+
}
|
|
223
|
+
|
|
167
224
|
try {
|
|
168
|
-
const
|
|
169
|
-
|
|
225
|
+
const result = await (new AsyncFunction(
|
|
226
|
+
'require',
|
|
227
|
+
'custom_import',
|
|
228
|
+
`const log=a=>rtjscomp.log(${
|
|
170
229
|
JSON.stringify(path + ': ')
|
|
171
|
-
}+a);${
|
|
172
|
-
|
|
173
|
-
|
|
230
|
+
}+a);${
|
|
231
|
+
file_content.replace(IMPORT_REG, 'custom_import(') + '\n'
|
|
232
|
+
}`
|
|
233
|
+
)).call(content_object, custom_require, custom_import);
|
|
174
234
|
if (service_object.stopped) {
|
|
175
235
|
clearInterval(start_interval);
|
|
176
236
|
return;
|
|
@@ -188,7 +248,7 @@ const service_start_inner = async (path, service_object, file_content) => {
|
|
|
188
248
|
|
|
189
249
|
const handler_start = content_object.start;
|
|
190
250
|
if (handler_start) {
|
|
191
|
-
log(
|
|
251
|
+
log(`[deprecated] ${path}: has start method`);
|
|
192
252
|
delete content_object.start;
|
|
193
253
|
try {
|
|
194
254
|
await handler_start();
|
|
@@ -202,7 +262,7 @@ const service_start_inner = async (path, service_object, file_content) => {
|
|
|
202
262
|
clearInterval(start_interval);
|
|
203
263
|
|
|
204
264
|
if (content_object.stop) {
|
|
205
|
-
log(
|
|
265
|
+
log(`[deprecated] ${path}: has stop method`);
|
|
206
266
|
service_object.handler_stop = content_object.stop;
|
|
207
267
|
delete content_object.stop;
|
|
208
268
|
}
|
|
@@ -217,18 +277,19 @@ const services_shutdown = () => (
|
|
|
217
277
|
.map(service_object => service_stop(service_object, true))
|
|
218
278
|
)
|
|
219
279
|
)
|
|
220
|
-
const service_stop =
|
|
221
|
-
service_object.stopped = true
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
280
|
+
const service_stop = (service_object, forget) => (
|
|
281
|
+
service_object.stopped = true,
|
|
282
|
+
forget && service_object.watcher &&
|
|
283
|
+
service_object.watcher.close(),
|
|
284
|
+
service_stop_handler(service_object)
|
|
285
|
+
)
|
|
225
286
|
const service_stop_handler = async service_object => {
|
|
226
287
|
services_active.delete(service_object.path);
|
|
227
288
|
log('stop service: ' + service_object.path);
|
|
228
289
|
const handler_stop = service_object.handler_stop;
|
|
229
290
|
if (handler_stop) {
|
|
230
291
|
const stop_interval = setInterval(() => {
|
|
231
|
-
log(
|
|
292
|
+
log(`[warning] ${service_object.path}: still stopping`);
|
|
232
293
|
}, 1e3);
|
|
233
294
|
try {
|
|
234
295
|
service_object.handler_stop = null;
|
|
@@ -277,36 +338,34 @@ const map_generate_equ = (map, data) => {
|
|
|
277
338
|
}
|
|
278
339
|
}
|
|
279
340
|
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
)
|
|
286
|
-
|
|
287
|
-
fs.watchFile(path, (curr, prev) => {
|
|
288
|
-
if (file_compare(curr, prev, path)) {
|
|
289
|
-
fs.unwatchFile(path);
|
|
290
|
-
callback();
|
|
291
|
-
}
|
|
292
|
-
})
|
|
293
|
-
)
|
|
341
|
+
const file_watch_once = (path, callback) => {
|
|
342
|
+
const watcher = fs_watch(path, WATCH_OPTIONS, () => (
|
|
343
|
+
watcher.close(),
|
|
344
|
+
log_verbose && log('file updated: ' + path),
|
|
345
|
+
callback()
|
|
346
|
+
));
|
|
347
|
+
};
|
|
294
348
|
const file_keep_new = async (path, callback) => {
|
|
295
349
|
try {
|
|
296
350
|
const data = await fsp.readFile(path, 'utf8');
|
|
297
351
|
if (log_verbose) log('load file: ' + path);
|
|
298
352
|
await callback(data);
|
|
299
|
-
fs.watchFile(path, async (curr, prev) => {
|
|
300
|
-
if (file_compare(curr, prev, path)) {
|
|
301
|
-
await callback(
|
|
302
|
-
await fsp.readFile(path, 'utf8').catch(() => null)
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
353
|
}
|
|
307
354
|
catch (err) {
|
|
308
355
|
await callback(null);
|
|
356
|
+
return null;
|
|
309
357
|
}
|
|
358
|
+
|
|
359
|
+
let timeout = 0;
|
|
360
|
+
return fs_watch(path, WATCH_OPTIONS, () => (
|
|
361
|
+
clearTimeout(timeout),
|
|
362
|
+
timeout = setTimeout(() => (
|
|
363
|
+
log_verbose && log('file updated: ' + path),
|
|
364
|
+
fsp.readFile(path, 'utf8')
|
|
365
|
+
.catch(() => null)
|
|
366
|
+
.then(callback)
|
|
367
|
+
), 50)
|
|
368
|
+
));
|
|
310
369
|
}
|
|
311
370
|
|
|
312
371
|
let log_history = rtjscomp.log_history = [];
|
|
@@ -480,14 +539,17 @@ const request_handle = async (request, response, https) => {
|
|
|
480
539
|
if (file_stat.isDirectory()) throw 403;
|
|
481
540
|
|
|
482
541
|
if (file_dyn_enabled) { // compile file
|
|
483
|
-
const file_content =
|
|
542
|
+
const file_content = await fsp.readFile(path_real, 'utf8');
|
|
484
543
|
try {
|
|
485
544
|
if (file_content.includes('\r')) {
|
|
486
545
|
throw 'illegal line break, must be unix';
|
|
487
546
|
}
|
|
547
|
+
if (file_content.includes('globals.')) {
|
|
548
|
+
log(`[deprecated] ${path}: uses globals object`);
|
|
549
|
+
}
|
|
488
550
|
const file_content_length = file_content.length;
|
|
489
551
|
|
|
490
|
-
let code = `
|
|
552
|
+
let code = `const log=a=>rtjscomp.log(${
|
|
491
553
|
JSON.stringify(path + ': ')
|
|
492
554
|
}+a);`;
|
|
493
555
|
|
|
@@ -512,19 +574,23 @@ const request_handle = async (request, response, https) => {
|
|
|
512
574
|
// `<?`?
|
|
513
575
|
if (file_content.charCodeAt(index_start) !== 61) {
|
|
514
576
|
code += (
|
|
515
|
-
file_content
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
577
|
+
file_content
|
|
578
|
+
.substring(
|
|
579
|
+
index_start,
|
|
580
|
+
index_end
|
|
581
|
+
)
|
|
582
|
+
.replace(IMPORT_REG, 'custom_import(') +
|
|
519
583
|
';'
|
|
520
584
|
);
|
|
521
585
|
}
|
|
522
586
|
else { // `<?=`?
|
|
523
587
|
code += `output.write(''+(${
|
|
524
|
-
file_content
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
588
|
+
file_content
|
|
589
|
+
.substring(
|
|
590
|
+
++index_start,
|
|
591
|
+
index_end
|
|
592
|
+
)
|
|
593
|
+
.replace(IMPORT_REG, 'custom_import(')
|
|
528
594
|
}));`;
|
|
529
595
|
}
|
|
530
596
|
}
|
|
@@ -559,7 +625,15 @@ const request_handle = async (request, response, https) => {
|
|
|
559
625
|
}
|
|
560
626
|
|
|
561
627
|
try {
|
|
562
|
-
file_function =
|
|
628
|
+
file_function = new AsyncFunction(
|
|
629
|
+
'input',
|
|
630
|
+
'output',
|
|
631
|
+
'request',
|
|
632
|
+
'response',
|
|
633
|
+
'require',
|
|
634
|
+
'custom_import',
|
|
635
|
+
code
|
|
636
|
+
);
|
|
563
637
|
}
|
|
564
638
|
catch (err) {
|
|
565
639
|
throw err.message;
|
|
@@ -571,9 +645,9 @@ const request_handle = async (request, response, https) => {
|
|
|
571
645
|
}
|
|
572
646
|
|
|
573
647
|
file_cache_functions.set(path, file_function);
|
|
574
|
-
|
|
575
|
-
file_cache_functions.delete(path)
|
|
576
|
-
|
|
648
|
+
file_watch_once(path_real, () => (
|
|
649
|
+
file_cache_functions.delete(path)
|
|
650
|
+
));
|
|
577
651
|
}
|
|
578
652
|
}
|
|
579
653
|
|
|
@@ -706,7 +780,8 @@ const request_handle = async (request, response, https) => {
|
|
|
706
780
|
file_function_output,
|
|
707
781
|
request,
|
|
708
782
|
response,
|
|
709
|
-
custom_require
|
|
783
|
+
custom_require,
|
|
784
|
+
custom_import
|
|
710
785
|
);
|
|
711
786
|
file_function_output.end();
|
|
712
787
|
}
|