quickjs 0.2.0 → 0.2.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30027c93cb2dd5dbb85d43ab40700f7ee06679a824b503bee42786a42bc5dc26
4
- data.tar.gz: 51c60a962c82bbbbaa3a3fc4202255809751848d1474f9a4e9f6b7ebe4df0277
3
+ metadata.gz: 0c2a481a2ea280bc0d4a9c7778b62035991bd08293ddef98b4824a40a6a6ccd9
4
+ data.tar.gz: a40b2f11813f2f82db4c5b9e0931199013671e0983e80566f0b6645709deece7
5
5
  SHA512:
6
- metadata.gz: e1f248cbafcc56ceba481f658aae542660ac8de6036b7fc1e9425e5f214f4f51a918a3051b82e796a075ed83726f59ba6b8dcc85e8b1c38ee1369b089ebd410a
7
- data.tar.gz: 7c7346da3a318d3ed07bfd490561ced7deda800678bda0cb23c4f2b19b84b9720191a7999a7d9a5225d91d4c2140b7fffae03f16d75b791cd4d3b746bbab50a9
6
+ metadata.gz: f509a918c4e5ff7d19bdaa8873ee62ede64cfd98e405a7ea6f4eb00a724fc79fc2cd928e2388d0f8e07dcd455834ba1f60ec2a9990b4781bd0012ec5f72a9c16
7
+ data.tar.gz: b7604b888bc62fe12f6a5b30387891108a24cf1de55e77934cabeeab20fe9ae27f494098448a32a975e9fde99cee9a9af5bdd58c258a0bafb60adc125cedf206
data/README.md CHANGED
@@ -36,7 +36,10 @@ Quickjs.eval_code('const obj = {}; obj.missingKey;') # => :undefined (Quickjs::V
36
36
  Quickjs.eval_code("Number('whatever')") #=> :NaN (Quickjs::Value::NAN)
37
37
  ```
38
38
 
39
- #### Limit resources
39
+ <details>
40
+ <summary>Options</summary>
41
+
42
+ #### Resources
40
43
 
41
44
  ```rb
42
45
  # 1GB memory limit
@@ -46,20 +49,21 @@ Quickjs.eval_code(code, { memory_limit: 1024 ** 3 })
46
49
  Quickjs.eval_code(code, { max_stack_size: 1024 ** 2 })
47
50
  ```
48
51
 
49
- #### Enable built-in modules
52
+ #### Built-in modules
53
+
54
+ To enable [std module](https://bellard.org/quickjs/quickjs.html#std-module) and [os module](https://bellard.org/quickjs/quickjs.html#os-module) selectively.
50
55
 
51
56
  ```rb
52
57
  # enable std module
53
- # https://bellard.org/quickjs/quickjs.html#std-module
54
58
  Quickjs.eval_code(code, { features: [Quickjs::MODULE_STD] })
55
59
 
56
60
  # enable os module
57
- # https://bellard.org/quickjs/quickjs.html#os-module
58
61
  Quickjs.eval_code(code, { features: [Quickjs::MODULE_OS] })
59
62
 
60
- # enable timeout features `setTimeout`, `clearTimeout`
63
+ # enable timeout features `setTimeout`, `clearTimeout` from os module specifically
61
64
  Quickjs.eval_code(code, { features: [Quickjs::FEATURES_TIMEOUT] })
62
65
  ```
66
+ </details>
63
67
 
64
68
  ### `Quickjs::VM`: Maintain a consistent VM/runtime
65
69
 
@@ -71,7 +75,10 @@ vm.eval_code('a.b = "d";')
71
75
  vm.eval_code('a.b;') #=> "d"
72
76
  ```
73
77
 
74
- #### Config VM
78
+ <details>
79
+ <summary>Config VM/runtime</summary>
80
+
81
+ #### Resources
75
82
 
76
83
  ```rb
77
84
  vm = Quickjs::VM.new(
@@ -80,41 +87,51 @@ vm = Quickjs::VM.new(
80
87
  )
81
88
  ```
82
89
 
90
+ #### Built-in modules
91
+
92
+ To enable [std module](https://bellard.org/quickjs/quickjs.html#std-module) and [os module](https://bellard.org/quickjs/quickjs.html#os-module) selectively.
93
+
83
94
  ```rb
84
95
  # enable std module
85
- # https://bellard.org/quickjs/quickjs.html#std-module
86
- vm = Quickjs::VM.new(
87
- features: [::Quickjs::MODULE_STD],
88
- )
96
+ vm = Quickjs::VM.new(features: [::Quickjs::MODULE_STD])
89
97
 
90
98
  # enable os module
91
- # https://bellard.org/quickjs/quickjs.html#os-module
92
- vm = Quickjs::VM.new(
93
- features: [::Quickjs::MODULE_OS],
94
- )
95
-
96
- # `eval_code` will be interrupted after 1 sec (default: 100 msec)
97
- vm = Quickjs::VM.new(
98
- timeout_msec: 1_000,
99
- )
99
+ vm = Quickjs::VM.new(features: [::Quickjs::MODULE_OS])
100
100
 
101
101
  # enable timeout features `setTimeout`, `clearTimeout`
102
- vm = Quickjs::VM.new(
103
- features: [::Quickjs::FEATURES_TIMEOUT],
104
- )
102
+ vm = Quickjs::VM.new(features: [::Quickjs::FEATURES_TIMEOUT])
105
103
  ```
106
104
 
107
- #### ⚡️ Import ESM from source
105
+ #### VM timeout
106
+
107
+ ```rb
108
+ # `eval_code` will be interrupted after 1 sec (default: 100 msec)
109
+ vm = Quickjs::VM.new(timeout_msec: 1_000)
110
+ ```
111
+ </details>
112
+
113
+ #### `Quickjs::VM#import`: 🔌 Import ESM from a source code
108
114
 
109
115
  ```rb
110
116
  vm = Quickjs::VM.new
117
+
118
+ # Equivalent to `import { default: aliasedDefault, member: member } from './exports.esm.js';`
111
119
  vm.import({ default: 'aliasedDefault', member: 'member' }, from: File.read('exports.esm.js'))
112
120
 
113
121
  vm.eval_code("aliasedDefault()") #=> Exported `default` of the ESM is called
114
122
  vm.eval_code("member()") #=> Exported `member` of the ESM is called
123
+
124
+ # import { member, defaultMember } from './exports.esm.js';
125
+ vm.import(['member', 'defaultMember'], from: File.read('exports.esm.js'))
126
+
127
+ # import DefaultExport from './exports.esm.js';
128
+ vm.import('DefaultExport', from: File.read('exports.esm.js'))
129
+
130
+ # import * as all from './exports.esm.js';
131
+ vm.import('* as all', from: File.read('exports.esm.js'))
115
132
  ```
116
133
 
117
- #### ⚡️ Define a global function for JS by Ruby
134
+ #### `Quickjs::VM#define_function`: 💎 Define a global function for JS by Ruby
118
135
 
119
136
  ```rb
120
137
  vm = Quickjs::VM.new
@@ -125,6 +142,20 @@ end
125
142
  vm.eval_code("greetingTo('Rick')") #=> 'Hello! Rick'
126
143
  ```
127
144
 
145
+ #### `Quickjs::VM#logs`: 💾 Capture console logs
146
+
147
+ All logs by `console.(log|info|debug|warn|error)` on VM are recorded and inspectable.
148
+
149
+ ```rb
150
+ vm = Quickjs::VM.new
151
+ vm.eval_code('console.log("log me", null)')
152
+
153
+ vm.logs #=> Array of Quickjs::VM::Log
154
+ vm.logs.last.severity #=> :info
155
+ vm.logs.last.to_s #=> 'log me null'
156
+ vm,logs.last.raw #=> ['log me', nil]
157
+ ```
158
+
128
159
  ## License
129
160
 
130
161
  Every file in `ext/quickjsrb/quickjs` is licensed under [the MIT License Copyright 2017-2021 by Fabrice Bellard and Charlie Goron](/ext/quickjsrb/quickjs/LICENSE).
@@ -34,7 +34,7 @@
34
34
  #include <time.h>
35
35
  #if defined(__APPLE__)
36
36
  #include <malloc/malloc.h>
37
- #elif defined(__linux__)
37
+ #elif defined(__linux__) || defined(__GLIBC__)
38
38
  #include <malloc.h>
39
39
  #elif defined(__FreeBSD__)
40
40
  #include <malloc_np.h>
@@ -151,7 +151,7 @@ static size_t js_trace_malloc_usable_size(const void *ptr)
151
151
  return _msize((void *)ptr);
152
152
  #elif defined(EMSCRIPTEN)
153
153
  return 0;
154
- #elif defined(__linux__)
154
+ #elif defined(__linux__) || defined(__GLIBC__)
155
155
  return malloc_usable_size((void *)ptr);
156
156
  #else
157
157
  /* change this to `return 0;` if compilation fails */
@@ -78,6 +78,10 @@ typedef sig_t sighandler_t;
78
78
  #include "list.h"
79
79
  #include "quickjs-libc.h"
80
80
 
81
+ #if !defined(PATH_MAX)
82
+ #define PATH_MAX 4096
83
+ #endif
84
+
81
85
  /* TODO:
82
86
  - add socket calls
83
87
  */
@@ -1090,7 +1094,7 @@ static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
1090
1094
  int64_t pos;
1091
1095
  if (!f)
1092
1096
  return JS_EXCEPTION;
1093
- #if defined(__linux__)
1097
+ #if defined(__linux__) || defined(__GLIBC__)
1094
1098
  pos = ftello(f);
1095
1099
  #else
1096
1100
  pos = ftell(f);
@@ -1113,7 +1117,7 @@ static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
1113
1117
  return JS_EXCEPTION;
1114
1118
  if (JS_ToInt32(ctx, &whence, argv[1]))
1115
1119
  return JS_EXCEPTION;
1116
- #if defined(__linux__)
1120
+ #if defined(__linux__) || defined(__GLIBC__)
1117
1121
  ret = fseeko(f, pos, whence);
1118
1122
  #else
1119
1123
  ret = fseek(f, pos, whence);
@@ -34,7 +34,7 @@
34
34
  #include <math.h>
35
35
  #if defined(__APPLE__)
36
36
  #include <malloc/malloc.h>
37
- #elif defined(__linux__)
37
+ #elif defined(__linux__) || defined(__GLIBC__)
38
38
  #include <malloc.h>
39
39
  #elif defined(__FreeBSD__)
40
40
  #include <malloc_np.h>
@@ -1681,7 +1681,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
1681
1681
  rt->stack_size = JS_DEFAULT_STACK_SIZE;
1682
1682
  JS_UpdateStackTop(rt);
1683
1683
 
1684
- rt->current_exception = JS_NULL;
1684
+ rt->current_exception = JS_UNINITIALIZED;
1685
1685
 
1686
1686
  return rt;
1687
1687
  fail:
@@ -1708,7 +1708,7 @@ static size_t js_def_malloc_usable_size(const void *ptr)
1708
1708
  return _msize((void *)ptr);
1709
1709
  #elif defined(EMSCRIPTEN)
1710
1710
  return 0;
1711
- #elif defined(__linux__)
1711
+ #elif defined(__linux__) || defined(__GLIBC__)
1712
1712
  return malloc_usable_size((void *)ptr);
1713
1713
  #else
1714
1714
  /* change this to `return 0;` if compilation fails */
@@ -6398,13 +6398,13 @@ JSValue JS_GetException(JSContext *ctx)
6398
6398
  JSValue val;
6399
6399
  JSRuntime *rt = ctx->rt;
6400
6400
  val = rt->current_exception;
6401
- rt->current_exception = JS_NULL;
6401
+ rt->current_exception = JS_UNINITIALIZED;
6402
6402
  return val;
6403
6403
  }
6404
6404
 
6405
6405
  JS_BOOL JS_HasException(JSContext *ctx)
6406
6406
  {
6407
- return !JS_IsNull(ctx->rt->current_exception);
6407
+ return !JS_IsUninitialized(ctx->rt->current_exception);
6408
6408
  }
6409
6409
 
6410
6410
  static void dbuf_put_leb128(DynBuf *s, uint32_t v)
@@ -15321,7 +15321,7 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
15321
15321
 
15322
15322
  if (is_exception_pending) {
15323
15323
  ex_obj = ctx->rt->current_exception;
15324
- ctx->rt->current_exception = JS_NULL;
15324
+ ctx->rt->current_exception = JS_UNINITIALIZED;
15325
15325
  res = -1;
15326
15326
  } else {
15327
15327
  ex_obj = JS_UNDEFINED;
@@ -18674,7 +18674,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
18674
18674
  JS_IteratorClose(ctx, sp[-1], TRUE);
18675
18675
  } else {
18676
18676
  *sp++ = rt->current_exception;
18677
- rt->current_exception = JS_NULL;
18677
+ rt->current_exception = JS_UNINITIALIZED;
18678
18678
  pc = b->byte_code_buf + pos;
18679
18679
  goto restart;
18680
18680
  }
@@ -46151,8 +46151,10 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
46151
46151
  if (JS_IsException(ret))
46152
46152
  return JS_EXCEPTION;
46153
46153
  res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
46154
- if (res < 0)
46154
+ if (res < 0) {
46155
+ JS_FreeValue(ctx, ret);
46155
46156
  return JS_EXCEPTION;
46157
+ }
46156
46158
  if (res) {
46157
46159
  if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
46158
46160
  if (!js_same_value(ctx, desc.value, ret)) {
@@ -1,79 +1,5 @@
1
1
  #include "quickjsrb.h"
2
2
 
3
- typedef struct EvalTime
4
- {
5
- clock_t limit;
6
- clock_t started_at;
7
- } EvalTime;
8
-
9
- typedef struct VMData
10
- {
11
- struct JSContext *context;
12
- VALUE defined_functions;
13
- struct EvalTime *eval_time;
14
- VALUE logs;
15
- } VMData;
16
-
17
- static void vm_free(void *ptr)
18
- {
19
- VMData *data = (VMData *)ptr;
20
- free(data->eval_time);
21
-
22
- JSRuntime *runtime = JS_GetRuntime(data->context);
23
- JS_SetInterruptHandler(runtime, NULL, NULL);
24
- js_std_free_handlers(runtime);
25
- JS_FreeContext(data->context);
26
- JS_FreeRuntime(runtime);
27
-
28
- xfree(ptr);
29
- }
30
-
31
- size_t vm_size(const void *data)
32
- {
33
- return sizeof(VMData);
34
- }
35
-
36
- static void vm_mark(void *ptr)
37
- {
38
- VMData *data = (VMData *)ptr;
39
- rb_gc_mark_movable(data->defined_functions);
40
- rb_gc_mark_movable(data->logs);
41
- }
42
-
43
- static const rb_data_type_t vm_type = {
44
- .wrap_struct_name = "quickjsvm",
45
- .function = {
46
- .dmark = vm_mark,
47
- .dfree = vm_free,
48
- .dsize = vm_size,
49
- },
50
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
51
- };
52
-
53
- static VALUE vm_alloc(VALUE r_self)
54
- {
55
- VMData *data;
56
- VALUE obj = TypedData_Make_Struct(r_self, VMData, &vm_type, data);
57
- data->defined_functions = rb_hash_new();
58
- data->logs = rb_ary_new();
59
-
60
- EvalTime *eval_time = malloc(sizeof(EvalTime));
61
- data->eval_time = eval_time;
62
-
63
- JSRuntime *runtime = JS_NewRuntime();
64
- data->context = JS_NewContext(runtime);
65
-
66
- return obj;
67
- }
68
-
69
- VALUE rb_cQuickjsVMLog, rb_cQuickjsSyntaxError, rb_cQuickjsRuntimeError, rb_cQuickjsInterruptedError, rb_cQuickjsNoAwaitError, rb_cQuickjsTypeError, rb_cQuickjsReferenceError, rb_cQuickjsRangeError, rb_cQuickjsEvalError, rb_cQuickjsURIError, rb_cQuickjsAggregateError;
70
- const char *undefinedId = "undefined";
71
- const char *nanId = "NaN";
72
-
73
- const char *featureStdId = "feature_std";
74
- const char *featureOsId = "feature_os";
75
- const char *featureOsTimeoutId = "feature_os_timeout";
76
-
77
3
  JSValue to_js_value(JSContext *ctx, VALUE r_value)
78
4
  {
79
5
  if (RTEST(rb_funcall(
@@ -168,7 +94,7 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
168
94
  {
169
95
  if (JS_VALUE_IS_NAN(j_val))
170
96
  {
171
- return ID2SYM(rb_intern(nanId));
97
+ return QUICKJSRB_SYM(nanId);
172
98
  }
173
99
  double double_res;
174
100
  JS_ToFloat64(ctx, &double_res, j_val);
@@ -191,7 +117,7 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
191
117
  if (promiseState != -1)
192
118
  {
193
119
  VALUE r_error_message = rb_str_new2("cannot translate a Promise to Ruby. await within JavaScript's end");
194
- rb_exc_raise(rb_funcall(rb_cQuickjsRuntimeError, rb_intern("new"), 2, r_error_message, Qnil));
120
+ rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
195
121
  return Qnil;
196
122
  }
197
123
 
@@ -204,17 +130,17 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
204
130
  VALUE r_str = rb_str_new2(msg);
205
131
  JS_FreeCString(ctx, msg);
206
132
 
207
- JS_FreeValue(ctx, j_global);
208
133
  JS_FreeValue(ctx, j_strigified);
209
134
  JS_FreeValue(ctx, j_stringifyFunc);
210
135
  JS_FreeValue(ctx, j_jsonClass);
136
+ JS_FreeValue(ctx, j_global);
211
137
 
212
138
  return rb_funcall(rb_const_get(rb_cClass, rb_intern("JSON")), rb_intern("parse"), 1, r_str);
213
139
  }
214
140
  case JS_TAG_NULL:
215
141
  return Qnil;
216
142
  case JS_TAG_UNDEFINED:
217
- return ID2SYM(rb_intern(undefinedId));
143
+ return QUICKJSRB_SYM(undefinedId);
218
144
  case JS_TAG_EXCEPTION:
219
145
  {
220
146
  JSValue j_exceptionVal = JS_GetException(ctx);
@@ -230,47 +156,22 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
230
156
  JS_FreeValue(ctx, j_errorClassName);
231
157
 
232
158
  VALUE r_error_class, r_error_message = rb_str_new2(errorClassMessage);
233
-
234
- if (strcmp(errorClassName, "SyntaxError") == 0)
159
+ if (is_native_error_name(errorClassName))
235
160
  {
236
- r_error_class = rb_cQuickjsSyntaxError;
237
- }
238
- else if (strcmp(errorClassName, "TypeError") == 0)
239
- {
240
- r_error_class = rb_cQuickjsTypeError;
241
- }
242
- else if (strcmp(errorClassName, "ReferenceError") == 0)
243
- {
244
- r_error_class = rb_cQuickjsReferenceError;
245
- }
246
- else if (strcmp(errorClassName, "RangeError") == 0)
247
- {
248
- r_error_class = rb_cQuickjsRangeError;
249
- }
250
- else if (strcmp(errorClassName, "EvalError") == 0)
251
- {
252
- r_error_class = rb_cQuickjsEvalError;
253
- }
254
- else if (strcmp(errorClassName, "URIError") == 0)
255
- {
256
- r_error_class = rb_cQuickjsURIError;
257
- }
258
- else if (strcmp(errorClassName, "AggregateError") == 0)
259
- {
260
- r_error_class = rb_cQuickjsAggregateError;
161
+ r_error_class = QUICKJSRB_ERROR_FOR(errorClassName);
261
162
  }
262
163
  else if (strcmp(errorClassName, "InternalError") == 0 && strstr(errorClassMessage, "interrupted") != NULL)
263
164
  {
264
- r_error_class = rb_cQuickjsInterruptedError;
165
+ r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_INTERRUPTED_ERROR);
265
166
  r_error_message = rb_str_new2("Code evaluation is interrupted by the timeout or something");
266
167
  }
267
168
  else if (strcmp(errorClassName, "Quickjs::InterruptedError") == 0)
268
169
  {
269
- r_error_class = rb_cQuickjsInterruptedError;
170
+ r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_INTERRUPTED_ERROR);
270
171
  }
271
172
  else
272
173
  {
273
- r_error_class = rb_cQuickjsRuntimeError;
174
+ r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR);
274
175
  }
275
176
  JS_FreeCString(ctx, errorClassName);
276
177
  JS_FreeCString(ctx, errorClassMessage);
@@ -285,7 +186,7 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
285
186
 
286
187
  JS_FreeCString(ctx, errorMessage);
287
188
  JS_FreeValue(ctx, j_exceptionVal);
288
- rb_exc_raise(rb_funcall(rb_cQuickjsRuntimeError, rb_intern("new"), 2, r_error_message, Qnil));
189
+ rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
289
190
  }
290
191
  return Qnil;
291
192
  }
@@ -342,8 +243,10 @@ static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, J
342
243
  const char *severity = JS_ToCString(ctx, j_severity);
343
244
  JS_FreeValue(ctx, j_severity);
344
245
 
345
- VALUE r_log = rb_funcall(rb_cQuickjsVMLog, rb_intern("new"), 0);
246
+ VALUE r_log_class = rb_const_get(rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern("VM")), rb_intern("Log"));
247
+ VALUE r_log = rb_funcall(r_log_class, rb_intern("new"), 0);
346
248
  rb_iv_set(r_log, "@severity", ID2SYM(rb_intern(severity)));
249
+ JS_FreeCString(ctx, severity);
347
250
 
348
251
  VALUE r_row = rb_ary_new();
349
252
  int i;
@@ -351,22 +254,28 @@ static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, J
351
254
  int count;
352
255
  JS_ToInt32(ctx, &count, j_length);
353
256
  JS_FreeValue(ctx, j_length);
257
+
354
258
  for (i = 0; i < count; i++)
355
259
  {
260
+ VALUE r_loghash = rb_hash_new();
356
261
  JSValue j_logged = JS_GetPropertyUint32(ctx, argv[1], i);
262
+ if (JS_VALUE_GET_NORM_TAG(j_logged) == JS_TAG_OBJECT && JS_PromiseState(ctx, j_logged) != -1)
263
+ {
264
+ rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), rb_str_new2("Promise"));
265
+ }
266
+ else
267
+ {
268
+ rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), to_rb_value(ctx, j_logged));
269
+ }
357
270
  const char *body = JS_ToCString(ctx, j_logged);
358
- VALUE r_loghash = rb_hash_new();
359
- rb_hash_aset(r_loghash, ID2SYM(rb_intern("c")), rb_str_new2(body));
360
- rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), to_rb_value(ctx, j_logged));
361
- rb_ary_push(r_row, r_loghash);
362
271
  JS_FreeValue(ctx, j_logged);
272
+ rb_hash_aset(r_loghash, ID2SYM(rb_intern("c")), rb_str_new2(body));
363
273
  JS_FreeCString(ctx, body);
274
+ rb_ary_push(r_row, r_loghash);
364
275
  }
365
276
 
366
277
  rb_iv_set(r_log, "@row", r_row);
367
278
  rb_ary_push(data->logs, r_log);
368
- JS_FreeCString(ctx, severity);
369
-
370
279
  return JS_UNDEFINED;
371
280
  }
372
281
 
@@ -408,7 +317,7 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
408
317
  JS_SetModuleLoaderFunc(runtime, NULL, js_module_loader, NULL);
409
318
  js_std_init_handlers(runtime);
410
319
 
411
- if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, ID2SYM(rb_intern(featureStdId)))))
320
+ if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureStdId))))
412
321
  {
413
322
  js_init_module_std(data->context, "std");
414
323
  const char *enableStd = "import * as std from 'std';\n"
@@ -417,7 +326,7 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
417
326
  JS_FreeValue(data->context, j_stdEval);
418
327
  }
419
328
 
420
- if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, ID2SYM(rb_intern(featureOsId)))))
329
+ if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureOsId))))
421
330
  {
422
331
  js_init_module_os(data->context, "os");
423
332
  const char *enableOs = "import * as os from 'os';\n"
@@ -425,13 +334,19 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
425
334
  JSValue j_osEval = JS_Eval(data->context, enableOs, strlen(enableOs), "<vm>", JS_EVAL_TYPE_MODULE);
426
335
  JS_FreeValue(data->context, j_osEval);
427
336
  }
428
- else if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, ID2SYM(rb_intern(featureOsTimeoutId)))))
337
+ else if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureOsTimeoutId))))
429
338
  {
430
- js_init_module_os(data->context, "_os"); // Better if this is limited just only for setTimeout and clearTimeout
431
- const char *enableTimeout = "import * as _os from '_os';\n"
432
- "globalThis.setTimeout = _os.setTimeout;\n"
433
- "globalThis.clearTimeout = _os.clearTimeout;\n";
339
+ char *filename = random_string();
340
+ js_init_module_os(data->context, filename); // Better if this is limited just only for setTimeout and clearTimeout
341
+ const char *enableTimeoutTemplate = "import * as _os from '%s';\n"
342
+ "globalThis.setTimeout = _os.setTimeout;\n"
343
+ "globalThis.clearTimeout = _os.clearTimeout;\n";
344
+ int length = snprintf(NULL, 0, enableTimeoutTemplate, filename);
345
+ char *enableTimeout = (char *)malloc(length + 1);
346
+ snprintf(enableTimeout, length + 1, enableTimeoutTemplate, filename);
347
+
434
348
  JSValue j_timeoutEval = JS_Eval(data->context, enableTimeout, strlen(enableTimeout), "<vm>", JS_EVAL_TYPE_MODULE);
349
+ free(enableTimeout);
435
350
  JS_FreeValue(data->context, j_timeoutEval);
436
351
  }
437
352
 
@@ -477,7 +392,7 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
477
392
 
478
393
  char *code = StringValueCStr(r_code);
479
394
  JSValue j_codeResult = JS_Eval(data->context, code, strlen(code), "<code>", JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_ASYNC);
480
- JSValue j_awaitedResult = js_std_await(data->context, j_codeResult);
395
+ JSValue j_awaitedResult = js_std_await(data->context, j_codeResult); // This frees j_codeResult
481
396
  JSValue j_returnedValue = JS_GetPropertyStr(data->context, j_awaitedResult, "value");
482
397
  // Do this by rescuing to_rb_value
483
398
  if (JS_VALUE_GET_NORM_TAG(j_returnedValue) == JS_TAG_OBJECT && JS_PromiseState(data->context, j_returnedValue) != -1)
@@ -485,7 +400,7 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
485
400
  JS_FreeValue(data->context, j_returnedValue);
486
401
  JS_FreeValue(data->context, j_awaitedResult);
487
402
  VALUE r_error_message = rb_str_new2("An unawaited Promise was returned to the top-level");
488
- rb_exc_raise(rb_funcall(rb_cQuickjsNoAwaitError, rb_intern("new"), 2, r_error_message, Qnil));
403
+ rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_NO_AWAIT_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
489
404
  return Qnil;
490
405
  }
491
406
  else
@@ -531,19 +446,20 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
531
446
  rb_scan_args(argc, argv, "10:", &r_import_string, &r_opts);
532
447
  if (NIL_P(r_opts))
533
448
  r_opts = rb_hash_new();
534
- VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from")));
449
+ VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from"))); // TODO: Use kwargs instead
535
450
  if (NIL_P(r_from))
536
451
  {
537
452
  VALUE r_error_message = rb_str_new2("missing import source");
538
- rb_exc_raise(rb_funcall(rb_cQuickjsRuntimeError, rb_intern("new"), 2, r_error_message, Qnil));
453
+ rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
539
454
  return Qnil;
540
455
  }
541
456
 
542
457
  VMData *data;
543
458
  TypedData_Get_Struct(r_self, VMData, &vm_type, data);
544
459
 
460
+ char *filename = random_string();
545
461
  char *source = StringValueCStr(r_from);
546
- JSValue func = JS_Eval(data->context, source, strlen(source), "mmmodule", JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
462
+ JSValue func = JS_Eval(data->context, source, strlen(source), filename, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
547
463
  js_module_set_import_meta(data->context, func, TRUE, FALSE);
548
464
  JS_FreeValue(data->context, func);
549
465
 
@@ -557,11 +473,11 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
557
473
  VALUE r_globalize = rb_ary_entry(r_import_settings, 1);
558
474
  char *globalize = StringValueCStr(r_globalize);
559
475
 
560
- const char *importAndGlobalizeModule = "import %s from 'mmmodule';\n"
476
+ const char *importAndGlobalizeModule = "import %s from '%s';\n"
561
477
  "%s\n";
562
- int length = snprintf(NULL, 0, importAndGlobalizeModule, import_name, globalize);
478
+ int length = snprintf(NULL, 0, importAndGlobalizeModule, import_name, filename, globalize);
563
479
  char *result = (char *)malloc(length + 1);
564
- snprintf(result, length + 1, importAndGlobalizeModule, import_name, globalize);
480
+ snprintf(result, length + 1, importAndGlobalizeModule, import_name, filename, globalize);
565
481
 
566
482
  JSValue j_codeResult = JS_Eval(data->context, result, strlen(result), "<vm>", JS_EVAL_TYPE_MODULE);
567
483
  free(result);
@@ -570,7 +486,7 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
570
486
  return Qtrue;
571
487
  }
572
488
 
573
- static VALUE vm_m_getLogs(VALUE r_self)
489
+ static VALUE vm_m_logs(VALUE r_self)
574
490
  {
575
491
  VMData *data;
576
492
  TypedData_Get_Struct(r_self, VMData, &vm_type, data);
@@ -578,77 +494,21 @@ static VALUE vm_m_getLogs(VALUE r_self)
578
494
  return data->logs;
579
495
  }
580
496
 
581
- static VALUE pick_raw(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
582
- {
583
- return rb_hash_aref(block_arg, ID2SYM(rb_intern("raw")));
584
- }
585
-
586
- static VALUE vm_m_raw(VALUE r_self)
587
- {
588
- VALUE row = rb_iv_get(r_self, "@row");
589
- VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, pick_raw, Qnil);
590
-
591
- return r_ary;
592
- }
593
-
594
- static VALUE pick_c(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
595
- {
596
- return rb_hash_aref(block_arg, ID2SYM(rb_intern("c")));
597
- }
598
-
599
- static VALUE vm_m_to_s(VALUE r_self)
600
- {
601
- VALUE row = rb_iv_get(r_self, "@row");
602
- VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, pick_c, Qnil);
603
-
604
- return rb_funcall(r_ary, rb_intern("join"), 1, rb_str_new2(" "));
605
- }
606
-
607
- VALUE vm_m_initialize_quickjs_error(VALUE self, VALUE r_message, VALUE r_js_name)
608
- {
609
- rb_call_super(1, &r_message);
610
- rb_iv_set(self, "@js_name", r_js_name);
611
-
612
- return self;
613
- }
614
-
615
497
  RUBY_FUNC_EXPORTED void Init_quickjsrb(void)
616
498
  {
617
- VALUE rb_mQuickjs = rb_define_module("Quickjs");
618
- rb_define_const(rb_mQuickjs, "MODULE_STD", ID2SYM(rb_intern(featureStdId)));
619
- rb_define_const(rb_mQuickjs, "MODULE_OS", ID2SYM(rb_intern(featureOsId)));
620
- rb_define_const(rb_mQuickjs, "FEATURES_TIMEOUT", ID2SYM(rb_intern(featureOsTimeoutId)));
621
-
622
- VALUE rb_cQuickjsValue = rb_define_class_under(rb_mQuickjs, "Value", rb_cObject);
623
- rb_define_const(rb_cQuickjsValue, "UNDEFINED", ID2SYM(rb_intern(undefinedId)));
624
- rb_define_const(rb_cQuickjsValue, "NAN", ID2SYM(rb_intern(nanId)));
625
-
626
- VALUE rb_cQuickjsVM = rb_define_class_under(rb_mQuickjs, "VM", rb_cObject);
627
- rb_define_alloc_func(rb_cQuickjsVM, vm_alloc);
628
- rb_define_method(rb_cQuickjsVM, "initialize", vm_m_initialize, -1);
629
- rb_define_method(rb_cQuickjsVM, "eval_code", vm_m_evalCode, 1);
630
- rb_define_method(rb_cQuickjsVM, "define_function", vm_m_defineGlobalFunction, 1);
631
- rb_define_method(rb_cQuickjsVM, "import", vm_m_import, -1);
632
- rb_define_method(rb_cQuickjsVM, "logs", vm_m_getLogs, 0);
633
-
634
- rb_cQuickjsVMLog = rb_define_class_under(rb_cQuickjsVM, "Log", rb_cObject);
635
- rb_define_attr(rb_cQuickjsVMLog, "severity", 1, 0);
636
- rb_define_method(rb_cQuickjsVMLog, "raw", vm_m_raw, 0);
637
- rb_define_method(rb_cQuickjsVMLog, "to_s", vm_m_to_s, 0);
638
- rb_define_method(rb_cQuickjsVMLog, "inspect", vm_m_to_s, 0);
639
-
640
- rb_cQuickjsRuntimeError = rb_define_class_under(rb_mQuickjs, "RuntimeError", rb_eRuntimeError);
641
- rb_define_method(rb_cQuickjsRuntimeError, "initialize", vm_m_initialize_quickjs_error, 2);
642
- rb_define_attr(rb_cQuickjsRuntimeError, "js_name", 1, 0);
643
-
644
- rb_cQuickjsSyntaxError = rb_define_class_under(rb_mQuickjs, "SyntaxError", rb_cQuickjsRuntimeError);
645
- rb_cQuickjsTypeError = rb_define_class_under(rb_mQuickjs, "TypeError", rb_cQuickjsRuntimeError);
646
- rb_cQuickjsRangeError = rb_define_class_under(rb_mQuickjs, "RangeError", rb_cQuickjsRuntimeError);
647
- rb_cQuickjsReferenceError = rb_define_class_under(rb_mQuickjs, "ReferenceError", rb_cQuickjsRuntimeError);
648
- rb_cQuickjsURIError = rb_define_class_under(rb_mQuickjs, "URIError", rb_cQuickjsRuntimeError);
649
- rb_cQuickjsEvalError = rb_define_class_under(rb_mQuickjs, "EvalError", rb_cQuickjsRuntimeError);
650
- rb_cQuickjsAggregateError = rb_define_class_under(rb_mQuickjs, "AggregateError", rb_cQuickjsRuntimeError);
651
-
652
- rb_cQuickjsInterruptedError = rb_define_class_under(rb_mQuickjs, "InterruptedError", rb_cQuickjsRuntimeError);
653
- rb_cQuickjsNoAwaitError = rb_define_class_under(rb_mQuickjs, "NoAwaitError", rb_cQuickjsRuntimeError);
499
+ rb_require("json");
500
+ rb_require("securerandom");
501
+
502
+ VALUE r_module_quickjs = rb_define_module("Quickjs");
503
+ r_define_constants(r_module_quickjs);
504
+ r_define_exception_classes(r_module_quickjs);
505
+
506
+ VALUE r_class_vm = rb_define_class_under(r_module_quickjs, "VM", rb_cObject);
507
+ rb_define_alloc_func(r_class_vm, vm_alloc);
508
+ rb_define_method(r_class_vm, "initialize", vm_m_initialize, -1);
509
+ rb_define_method(r_class_vm, "eval_code", vm_m_evalCode, 1);
510
+ rb_define_method(r_class_vm, "define_function", vm_m_defineGlobalFunction, 1);
511
+ rb_define_method(r_class_vm, "import", vm_m_import, -1);
512
+ rb_define_method(r_class_vm, "logs", vm_m_logs, 0);
513
+ r_define_log_class(r_class_vm);
654
514
  }
@@ -12,4 +12,205 @@
12
12
  #include <string.h>
13
13
  #include <time.h>
14
14
 
15
+ const char *featureStdId = "feature_std";
16
+ const char *featureOsId = "feature_os";
17
+ const char *featureOsTimeoutId = "feature_os_timeout";
18
+
19
+ const char *undefinedId = "undefined";
20
+ const char *nanId = "NaN";
21
+
22
+ const char *native_errors[] = {
23
+ "SyntaxError",
24
+ "TypeError",
25
+ "ReferenceError",
26
+ "RangeError",
27
+ "EvalError",
28
+ "URIError",
29
+ "AggregateError"};
30
+
31
+ #define QUICKJSRB_SYM(id) \
32
+ (VALUE) { ID2SYM(rb_intern(id)) }
33
+
34
+ // VM data structure
35
+
36
+ typedef struct EvalTime
37
+ {
38
+ clock_t limit;
39
+ clock_t started_at;
40
+ } EvalTime;
41
+
42
+ typedef struct VMData
43
+ {
44
+ struct JSContext *context;
45
+ VALUE defined_functions;
46
+ struct EvalTime *eval_time;
47
+ VALUE logs;
48
+ } VMData;
49
+
50
+ static void vm_free(void *ptr)
51
+ {
52
+ VMData *data = (VMData *)ptr;
53
+ free(data->eval_time);
54
+
55
+ JSRuntime *runtime = JS_GetRuntime(data->context);
56
+ JS_SetInterruptHandler(runtime, NULL, NULL);
57
+ js_std_free_handlers(runtime);
58
+ JS_FreeContext(data->context);
59
+ JS_FreeRuntime(runtime);
60
+
61
+ xfree(ptr);
62
+ }
63
+
64
+ size_t vm_size(const void *data)
65
+ {
66
+ return sizeof(VMData);
67
+ }
68
+
69
+ static void vm_mark(void *ptr)
70
+ {
71
+ VMData *data = (VMData *)ptr;
72
+ rb_gc_mark_movable(data->defined_functions);
73
+ rb_gc_mark_movable(data->logs);
74
+ }
75
+
76
+ static const rb_data_type_t vm_type = {
77
+ .wrap_struct_name = "quickjsvm",
78
+ .function = {
79
+ .dmark = vm_mark,
80
+ .dfree = vm_free,
81
+ .dsize = vm_size,
82
+ },
83
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
84
+ };
85
+
86
+ static VALUE vm_alloc(VALUE r_self)
87
+ {
88
+ VMData *data;
89
+ VALUE obj = TypedData_Make_Struct(r_self, VMData, &vm_type, data);
90
+ data->defined_functions = rb_hash_new();
91
+ data->logs = rb_ary_new();
92
+
93
+ EvalTime *eval_time = malloc(sizeof(EvalTime));
94
+ data->eval_time = eval_time;
95
+
96
+ JSRuntime *runtime = JS_NewRuntime();
97
+ data->context = JS_NewContext(runtime);
98
+
99
+ return obj;
100
+ }
101
+
102
+ // Utils
103
+
104
+ static char *random_string()
105
+ {
106
+ VALUE r_rand = rb_funcall(
107
+ rb_const_get(rb_cClass, rb_intern("SecureRandom")),
108
+ rb_intern("alphanumeric"),
109
+ 1,
110
+ INT2NUM(12));
111
+ return StringValueCStr(r_rand);
112
+ }
113
+
114
+ static bool is_native_error_name(const char *error_name)
115
+ {
116
+ bool is_native_error = false;
117
+ int numStrings = sizeof(native_errors) / sizeof(native_errors[0]);
118
+ for (int i = 0; i < numStrings; i++)
119
+ {
120
+ if (strcmp(native_errors[i], error_name) == 0)
121
+ {
122
+ is_native_error = true;
123
+ break;
124
+ }
125
+ }
126
+ return is_native_error;
127
+ }
128
+
129
+ // Constants
130
+
131
+ static void r_define_constants(VALUE r_parent_class)
132
+ {
133
+ rb_define_const(r_parent_class, "MODULE_STD", QUICKJSRB_SYM(featureStdId));
134
+ rb_define_const(r_parent_class, "MODULE_OS", QUICKJSRB_SYM(featureOsId));
135
+ rb_define_const(r_parent_class, "FEATURES_TIMEOUT", QUICKJSRB_SYM(featureOsTimeoutId));
136
+
137
+ VALUE rb_cQuickjsValue = rb_define_class_under(r_parent_class, "Value", rb_cObject);
138
+ rb_define_const(rb_cQuickjsValue, "UNDEFINED", QUICKJSRB_SYM(undefinedId));
139
+ rb_define_const(rb_cQuickjsValue, "NAN", QUICKJSRB_SYM(nanId));
140
+ }
141
+
142
+ // Log class
143
+
144
+ static VALUE r_proc_pick_raw(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
145
+ {
146
+ return rb_hash_aref(block_arg, ID2SYM(rb_intern("raw")));
147
+ }
148
+
149
+ static VALUE r_log_m_raw(VALUE r_self)
150
+ {
151
+ VALUE row = rb_iv_get(r_self, "@row");
152
+ VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, r_proc_pick_raw, Qnil);
153
+
154
+ return r_ary;
155
+ }
156
+
157
+ static VALUE r_proc_pick_c(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
158
+ {
159
+ return rb_hash_aref(block_arg, ID2SYM(rb_intern("c")));
160
+ }
161
+
162
+ static VALUE r_log_m_to_s(VALUE r_self)
163
+ {
164
+ VALUE row = rb_iv_get(r_self, "@row");
165
+ VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, r_proc_pick_c, Qnil);
166
+
167
+ return rb_funcall(r_ary, rb_intern("join"), 1, rb_str_new2(" "));
168
+ }
169
+
170
+ static VALUE r_define_log_class(VALUE r_parent_class)
171
+ {
172
+ VALUE r_log_class = rb_define_class_under(r_parent_class, "Log", rb_cObject);
173
+ rb_define_attr(r_log_class, "severity", 1, 0);
174
+ rb_define_method(r_log_class, "raw", r_log_m_raw, 0);
175
+ rb_define_method(r_log_class, "to_s", r_log_m_to_s, 0);
176
+ rb_define_method(r_log_class, "inspect", r_log_m_to_s, 0);
177
+
178
+ return r_log_class;
179
+ }
180
+
181
+ // Exceptions
182
+
183
+ #define QUICKJSRB_ROOT_RUNTIME_ERROR "RuntimeError"
184
+ #define QUICKJSRB_INTERRUPTED_ERROR "InterruptedError"
185
+ #define QUICKJSRB_NO_AWAIT_ERROR "NoAwaitError"
186
+
187
+ #define QUICKJSRB_ERROR_FOR(name) \
188
+ (VALUE) { rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern(name)) }
189
+
190
+ VALUE vm_m_initialize_quickjs_error(VALUE self, VALUE r_message, VALUE r_js_name)
191
+ {
192
+ rb_call_super(1, &r_message);
193
+ rb_iv_set(self, "@js_name", r_js_name);
194
+
195
+ return self;
196
+ }
197
+
198
+ static void r_define_exception_classes(VALUE r_parent_class)
199
+ {
200
+ VALUE r_runtime_error = rb_define_class_under(r_parent_class, QUICKJSRB_ROOT_RUNTIME_ERROR, rb_eRuntimeError);
201
+ rb_define_method(r_runtime_error, "initialize", vm_m_initialize_quickjs_error, 2);
202
+ rb_define_attr(r_runtime_error, "js_name", 1, 0);
203
+
204
+ // JS native errors
205
+ int numStrings = sizeof(native_errors) / sizeof(native_errors[0]);
206
+ for (int i = 0; i < numStrings; i++)
207
+ {
208
+ rb_define_class_under(r_parent_class, native_errors[i], r_runtime_error);
209
+ }
210
+
211
+ // quickjsrb specific errors
212
+ rb_define_class_under(r_parent_class, QUICKJSRB_INTERRUPTED_ERROR, r_runtime_error);
213
+ rb_define_class_under(r_parent_class, QUICKJSRB_NO_AWAIT_ERROR, r_runtime_error);
214
+ }
215
+
15
216
  #endif /* QUICKJSRB_H */
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quickjs
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
data/lib/quickjs.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "timeout"
4
- require "json"
5
4
  require_relative "quickjs/version"
6
5
  require_relative "quickjs/quickjsrb"
7
6
 
@@ -23,15 +22,30 @@ module Quickjs
23
22
  end
24
23
  module_function :_with_timeout
25
24
 
26
- def _build_import(mappings)
27
- imports, aliases = mappings.to_a.map do |imp|
28
- ["#{imp[0]} as #{imp[1]}", imp[1].to_s]
29
- end.transpose
25
+ def _build_import(imported)
26
+ code_define_global = ->(name) { "globalThis['#{name}'] = #{name};" }
27
+ case imported
28
+ in String if matched = imported.match(/\* as (.+)/)
29
+ [imported, code_define_global.call(matched[1])]
30
+ in String
31
+ [imported, code_define_global.call(imported)]
32
+ in [*all] if all.all? {|e| e.is_a? String }
33
+ [
34
+ imported.join(', ').yield_self{|s| '{ %s }' % s },
35
+ imported.map(&code_define_global).join("\n")
36
+ ]
37
+ in { ** }
38
+ imports, aliases = imported.to_a.map do |imp|
39
+ ["#{imp[0]} as #{imp[1]}", imp[1].to_s]
40
+ end.transpose
30
41
 
31
- [
32
- imports.join(", ").yield_self{|s| '{ %s }' % s },
33
- aliases.map {|name| "globalThis['#{name}'] = #{name};"}.join("\n")
34
- ]
42
+ [
43
+ imports.join(', ').yield_self{|s| '{ %s }' % s },
44
+ aliases.map(&code_define_global).join("\n")
45
+ ]
46
+ else
47
+ raise 'Unsupported importing style'
48
+ end
35
49
  end
36
50
  module_function :_build_import
37
51
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quickjs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - hmsk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-14 00:00:00.000000000 Z
11
+ date: 2024-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: securerandom
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  description: A native wrapper to run QuickJS in Ruby
28
42
  email:
29
43
  - k.hamasaki@gmail.com