quickjs 0.11.1 → 0.12.0
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 +4 -4
- data/CLAUDE.md +62 -0
- data/README.md +7 -1
- data/Rakefile +53 -1
- data/ext/quickjsrb/extconf.rb +7 -1
- data/ext/quickjsrb/quickjsrb.c +28 -7
- data/ext/quickjsrb/quickjsrb.h +18 -2
- data/ext/quickjsrb/vendor/polyfill-file.min.js +1 -0
- data/ext/quickjsrb/vendor/polyfill-intl-en.min.js +10 -9
- data/lib/quickjs/version.rb +1 -1
- data/polyfills/package-lock.json +465 -0
- data/polyfills/package.json +18 -0
- data/polyfills/rolldown.config.mjs +20 -0
- data/polyfills/src/file.js +218 -0
- data/polyfills/src/intl-en.js +15 -0
- metadata +10 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 64bdf2de37fc8ac24b7acec74dd724226f732a4acbef401d579b9b46e12c86f1
|
|
4
|
+
data.tar.gz: 4d76617466a380a038de3684495dc38eacb29be11002b3d6b1536c2c6caf0d80
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0fcf3bde7047e39038983326a6d867430e4e5fc63ac65bc6823c44df4222904a8bef385abd12bcadcca5213c9610198a08cdf4f12bc949dc2f7613509a8e46fc
|
|
7
|
+
data.tar.gz: af03f93832d2400cbb1418c764fbdaca5b1a51fd232462731b404a897851ff60cb3437c745ab2c03e36a7a5219c3618751075649b1cdc2e9935689b4e218ccf7
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
quickjs.rb is a Ruby gem wrapping QuickJS (a lightweight JavaScript interpreter) via a C extension. It lets Ruby programs evaluate JavaScript code without a full Node.js runtime.
|
|
8
|
+
|
|
9
|
+
## Build & Test Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bundle exec rake # Full cycle: clobber → compile → test
|
|
13
|
+
bundle exec rake compile # Compile C extension only
|
|
14
|
+
bundle exec rake test # Run all tests
|
|
15
|
+
bundle exec ruby -Itest:lib test/quickjs_test.rb # Run single test file
|
|
16
|
+
bundle exec ruby -Itest:lib test/quickjs_test.rb -n test_name # Run single test
|
|
17
|
+
rake polyfills:build # Rebuild Intl polyfill bundle (requires npm)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
QuickJS source lives as a git submodule under `ext/quickjsrb/quickjs/` — clone with `--recurse-submodules`.
|
|
21
|
+
|
|
22
|
+
## Design Principles
|
|
23
|
+
|
|
24
|
+
- **Never modify QuickJS core** — the engine is a git submodule; all customization is implemented externally in our C extension or Ruby layer
|
|
25
|
+
- **Prefer Ruby over C** — don't rush to write C code; use Ruby where it provides better extendability and maintainability
|
|
26
|
+
- **Security-conscious C layer** — avoid adding flexible C-level features that introduce security risks; expose QuickJS's own options as-is rather than inventing new attack surface
|
|
27
|
+
- **Keep the default footprint small** — don't increase bundle size or add JavaScript overhead (e.g. polyfills) by default; additional capabilities should be opt-in via feature flags
|
|
28
|
+
|
|
29
|
+
## Architecture
|
|
30
|
+
|
|
31
|
+
**C Extension** (`ext/quickjsrb/`):
|
|
32
|
+
- `quickjsrb.c` / `quickjsrb.h` — Core extension: creates QuickJS runtime/context, handles Ruby↔JS value conversion, timeout interrupts, and Ruby function bridging into JS
|
|
33
|
+
- Value conversion uses JSON serialization for complex types (objects/arrays); direct conversion for primitives
|
|
34
|
+
- `VMData` struct holds the JS context, defined Ruby functions, timeout state, console logs, and error references
|
|
35
|
+
- Ruby GC integration via `vm_mark`, `vm_free`, `vm_compact` callbacks
|
|
36
|
+
|
|
37
|
+
**Ruby layer** (`lib/quickjs/`):
|
|
38
|
+
- `Quickjs::VM` — Persistent JS runtime with `eval_code`, `import`, `define_function`
|
|
39
|
+
- `Quickjs.eval_code` — Convenience method for one-shot evaluation
|
|
40
|
+
- Exception hierarchy maps JS error types (SyntaxError, TypeError, etc.) to Ruby classes under `Quickjs::`
|
|
41
|
+
- Special values: `Quickjs::Value::UNDEFINED` and `Quickjs::Value::NAN` represent JS undefined/NaN
|
|
42
|
+
|
|
43
|
+
**Feature flags** (passed to `VM.new` via `features:` array):
|
|
44
|
+
- `:feature_std`, `:feature_os` — QuickJS std/os modules
|
|
45
|
+
- `:feature_timeout` — setTimeout/setInterval via CRuby threads
|
|
46
|
+
- `:feature_polyfill_intl` — Intl API polyfill (DateTimeFormat, NumberFormat, PluralRules, Locale)
|
|
47
|
+
|
|
48
|
+
**Polyfills** (`polyfills/`):
|
|
49
|
+
- Built from FormatJS packages via rolldown, output minified JS embedded as C source
|
|
50
|
+
- Polyfill version must match gem version (enforced during `rake release`)
|
|
51
|
+
|
|
52
|
+
## Testing
|
|
53
|
+
|
|
54
|
+
Tests use minitest with `describe`/`it` blocks. Key test files:
|
|
55
|
+
- `test/quickjs_test.rb` — Main test suite (value conversion, errors, VM features, ESM imports, function definitions)
|
|
56
|
+
- `test/quickjs_polyfill_test.rb` — Intl polyfill tests
|
|
57
|
+
|
|
58
|
+
## Build Notes
|
|
59
|
+
|
|
60
|
+
- `extconf.rb` compiles with `-DNDEBUG` to avoid conflicts with Ruby 4.0 GC assertions
|
|
61
|
+
- Symbol visibility is hidden by default (`-fvisibility=hidden`)
|
|
62
|
+
- CI matrix: Ruby 3.2/3.3/3.4/4.0 × Ubuntu/macOS
|
data/README.md
CHANGED
|
@@ -63,6 +63,9 @@ vm = Quickjs.eval_code(features: [::Quickjs::FEATURE_TIMEOUT])
|
|
|
63
63
|
|
|
64
64
|
# Inject the polyfill of Intl
|
|
65
65
|
vm = Quickjs.eval_code(features: [::Quickjs::POLYFILL_INTL])
|
|
66
|
+
|
|
67
|
+
# Inject the polyfill of Blob and File (W3C File API)
|
|
68
|
+
vm = Quickjs.eval_code(features: [::Quickjs::POLYFILL_FILE])
|
|
66
69
|
```
|
|
67
70
|
|
|
68
71
|
</details>
|
|
@@ -103,6 +106,9 @@ vm = Quickjs::VM.new(features: [::Quickjs::FEATURE_TIMEOUT])
|
|
|
103
106
|
|
|
104
107
|
# Inject the polyfill of Intl
|
|
105
108
|
vm = Quickjs::VM.new(features: [::Quickjs::POLYFILL_INTL])
|
|
109
|
+
|
|
110
|
+
# Inject the polyfill of Blob and File (W3C File API)
|
|
111
|
+
vm = Quickjs::VM.new(features: [::Quickjs::POLYFILL_FILE])
|
|
106
112
|
```
|
|
107
113
|
|
|
108
114
|
#### VM timeout
|
|
@@ -163,7 +169,7 @@ vm.logs.last.raw #=> ['log me', nil]
|
|
|
163
169
|
|
|
164
170
|
- `ext/quickjsrb/quickjs`
|
|
165
171
|
- [MIT License Copyright (c) 2017-2021 by Fabrice Bellard and Charlie Gordon](https://github.com/bellard/quickjs/blob/6e2e68fd0896957f92eb6c242a2e048c1ef3cae0/LICENSE).
|
|
166
|
-
- `ext/quickjsrb/vendor/polyfill-intl-en.min.js` (bundled and minified)
|
|
172
|
+
- `ext/quickjsrb/vendor/polyfill-intl-en.min.js` ([bundled and minified from `polyfills/`](https://github.com/hmsk/quickjs.rb/tree/main/polyfills))
|
|
167
173
|
- MIT License Copyright (c) 2023 FormatJS
|
|
168
174
|
- [@formatjs/intl-getcanonicallocales](https://github.com/formatjs/formatjs/blob/main/packages/intl-getcanonicallocales/LICENSE.md)
|
|
169
175
|
- [@formatjs/intl-locale](https://github.com/formatjs/formatjs/blob/main/packages/intl-locale/LICENSE.md)
|
data/Rakefile
CHANGED
|
@@ -11,7 +11,7 @@ end
|
|
|
11
11
|
|
|
12
12
|
require 'rake/extensiontask'
|
|
13
13
|
|
|
14
|
-
task build: :compile
|
|
14
|
+
task build: [:compile, 'polyfills:version:warn']
|
|
15
15
|
|
|
16
16
|
GEMSPEC = Gem::Specification.load('quickjs.gemspec')
|
|
17
17
|
|
|
@@ -19,4 +19,56 @@ Rake::ExtensionTask.new('quickjsrb', GEMSPEC) do |ext|
|
|
|
19
19
|
ext.lib_dir = 'lib/quickjs'
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
def check_polyfill_version!
|
|
23
|
+
require 'json'
|
|
24
|
+
require_relative 'lib/quickjs/version'
|
|
25
|
+
|
|
26
|
+
package = JSON.parse(File.read(File.expand_path('polyfills/package.json', __dir__)))
|
|
27
|
+
return if package['version'] == Quickjs::VERSION
|
|
28
|
+
|
|
29
|
+
yield package['version'], Quickjs::VERSION
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
namespace :polyfills do
|
|
33
|
+
desc 'Build polyfill bundles with rolldown and recompile'
|
|
34
|
+
task build: :clobber do
|
|
35
|
+
require 'json'
|
|
36
|
+
require_relative 'lib/quickjs/version'
|
|
37
|
+
|
|
38
|
+
polyfills_dir = File.expand_path('polyfills', __dir__)
|
|
39
|
+
package_json_path = File.join(polyfills_dir, 'package.json')
|
|
40
|
+
package = JSON.parse(File.read(package_json_path))
|
|
41
|
+
old_version = package['version']
|
|
42
|
+
package['version'] = Quickjs::VERSION
|
|
43
|
+
File.write(package_json_path, "#{JSON.pretty_generate(package)}\n")
|
|
44
|
+
if old_version != Quickjs::VERSION
|
|
45
|
+
warn "\n⚠️ polyfills/package.json version was #{old_version}, updated to #{Quickjs::VERSION}\n\n"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
Dir.chdir(polyfills_dir) do
|
|
49
|
+
sh 'npm install' unless File.exist?('node_modules/.package-lock.json') &&
|
|
50
|
+
File.mtime('node_modules/.package-lock.json') >= File.mtime('package.json')
|
|
51
|
+
sh 'npx rolldown -c rolldown.config.mjs'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
Rake::Task[:compile].invoke
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
namespace :version do
|
|
58
|
+
task :check do
|
|
59
|
+
check_polyfill_version! do |pkg_v, gem_v|
|
|
60
|
+
abort "polyfills/package.json version (#{pkg_v}) does not match gem version (#{gem_v}). Run `rake polyfills:build` first."
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
task :warn do
|
|
65
|
+
check_polyfill_version! do |pkg_v, gem_v|
|
|
66
|
+
warn "⚠️ polyfills/package.json version (#{pkg_v}) does not match gem version (#{gem_v}). Run `rake polyfills:build` to sync."
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
task 'release:guard_clean' => 'polyfills:version:check'
|
|
73
|
+
|
|
22
74
|
task default: %i[clobber compile test]
|
data/ext/quickjsrb/extconf.rb
CHANGED
|
@@ -12,6 +12,7 @@ $srcs = [
|
|
|
12
12
|
'quickjs.c',
|
|
13
13
|
'quickjs-libc.c',
|
|
14
14
|
'polyfill-intl-en.min.c',
|
|
15
|
+
'polyfill-file.min.c',
|
|
15
16
|
'quickjsrb.c',
|
|
16
17
|
]
|
|
17
18
|
|
|
@@ -37,7 +38,8 @@ else
|
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
append_cflags('-fwrapv')
|
|
40
|
-
|
|
41
|
+
# NDEBUG: suppress QuickJS debug assertions that conflict with Ruby 4.0 GC
|
|
42
|
+
$CFLAGS << ' ' << '-D_GNU_SOURCE -DCONFIG_VERSION=\"2024-02-14\" -DNDEBUG'
|
|
41
43
|
|
|
42
44
|
abort('could not find quickjs.h') unless find_header('quickjs.h')
|
|
43
45
|
abort('could not find cutils.h') unless find_header('cutils.h')
|
|
@@ -60,6 +62,10 @@ polyfill-intl-en.min.js:
|
|
|
60
62
|
$(COPY) $(srcdir)/vendor/$@ $@
|
|
61
63
|
polyfill-intl-en.min.c: ./qjsc polyfill-intl-en.min.js
|
|
62
64
|
./qjsc $(POLYFILL_OPTS) -c -M polyfill/intl-en.so,intlen -m -o $@ polyfill-intl-en.min.js
|
|
65
|
+
polyfill-file.min.js:
|
|
66
|
+
$(COPY) $(srcdir)/vendor/$@ $@
|
|
67
|
+
polyfill-file.min.c: ./qjsc polyfill-file.min.js
|
|
68
|
+
./qjsc -fno-string-normalize -fno-eval -fno-proxy -fno-module-loader -c -M polyfill/file.so,file -m -o $@ polyfill-file.min.js
|
|
63
69
|
COMPILE_POLYFILL
|
|
64
70
|
conf
|
|
65
71
|
end
|
data/ext/quickjsrb/quickjsrb.c
CHANGED
|
@@ -8,6 +8,10 @@ JSValue j_error_from_ruby_error(JSContext *ctx, VALUE r_error)
|
|
|
8
8
|
int objectId = NUM2INT(r_object_id);
|
|
9
9
|
JS_SetPropertyStr(ctx, j_error, "rb_object_id", JS_NewInt32(ctx, objectId));
|
|
10
10
|
|
|
11
|
+
// Keep the error alive in VMData to prevent GC before find_ruby_error retrieves it
|
|
12
|
+
VMData *data = JS_GetContextOpaque(ctx);
|
|
13
|
+
rb_hash_aset(data->alive_errors, r_object_id, r_error);
|
|
14
|
+
|
|
11
15
|
VALUE r_exception_message = rb_funcall(r_error, rb_intern("message"), 0);
|
|
12
16
|
const char *errorMessage = StringValueCStr(r_exception_message);
|
|
13
17
|
JS_SetPropertyStr(ctx, j_error, "message", JS_NewString(ctx, errorMessage));
|
|
@@ -89,8 +93,11 @@ VALUE find_ruby_error(JSContext *ctx, JSValue j_error)
|
|
|
89
93
|
JS_FreeValue(ctx, j_errorOriginalRubyObjectId);
|
|
90
94
|
if (errorOriginalRubyObjectId > 0)
|
|
91
95
|
{
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
VMData *data = JS_GetContextOpaque(ctx);
|
|
97
|
+
VALUE r_key = INT2NUM(errorOriginalRubyObjectId);
|
|
98
|
+
VALUE r_error = rb_hash_aref(data->alive_errors, r_key);
|
|
99
|
+
rb_hash_delete(data->alive_errors, r_key);
|
|
100
|
+
return r_error;
|
|
94
101
|
}
|
|
95
102
|
}
|
|
96
103
|
else
|
|
@@ -329,7 +336,7 @@ static JSValue js_quickjsrb_call_global(JSContext *ctx, JSValueConst _this, int
|
|
|
329
336
|
JS_FreeValue(ctx, j_v);
|
|
330
337
|
}
|
|
331
338
|
rb_ary_push(r_call_args, r_argv);
|
|
332
|
-
rb_ary_push(r_call_args, ULONG2NUM(data->eval_time->
|
|
339
|
+
rb_ary_push(r_call_args, ULONG2NUM(data->eval_time->limit_ms));
|
|
333
340
|
|
|
334
341
|
int sadnessHappened;
|
|
335
342
|
|
|
@@ -507,7 +514,7 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
|
507
514
|
VMData *data;
|
|
508
515
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
|
509
516
|
|
|
510
|
-
data->eval_time->
|
|
517
|
+
data->eval_time->limit_ms = (int64_t)NUM2UINT(r_timeout_msec);
|
|
511
518
|
JS_SetContextOpaque(data->context, data);
|
|
512
519
|
JSRuntime *runtime = JS_GetRuntime(data->context);
|
|
513
520
|
|
|
@@ -554,6 +561,13 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
|
554
561
|
JS_FreeValue(data->context, j_polyfillIntlResult);
|
|
555
562
|
}
|
|
556
563
|
|
|
564
|
+
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featurePolyfillFileId))))
|
|
565
|
+
{
|
|
566
|
+
JSValue j_polyfillFileObject = JS_ReadObject(data->context, &qjsc_polyfill_file_min, qjsc_polyfill_file_min_size, JS_READ_OBJ_BYTECODE);
|
|
567
|
+
JSValue j_polyfillFileResult = JS_EvalFunction(data->context, j_polyfillFileObject);
|
|
568
|
+
JS_FreeValue(data->context, j_polyfillFileResult);
|
|
569
|
+
}
|
|
570
|
+
|
|
557
571
|
JSValue j_console = JS_NewObject(data->context);
|
|
558
572
|
JS_SetPropertyStr(
|
|
559
573
|
data->context, j_console, "log",
|
|
@@ -580,7 +594,11 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
|
580
594
|
static int interrupt_handler(JSRuntime *runtime, void *opaque)
|
|
581
595
|
{
|
|
582
596
|
EvalTime *eval_time = opaque;
|
|
583
|
-
|
|
597
|
+
struct timespec now;
|
|
598
|
+
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
599
|
+
int64_t elapsed_ms = (int64_t)(now.tv_sec - eval_time->started_at.tv_sec) * 1000
|
|
600
|
+
+ (now.tv_nsec - eval_time->started_at.tv_nsec) / 1000000;
|
|
601
|
+
return elapsed_ms >= eval_time->limit_ms ? 1 : 0;
|
|
584
602
|
}
|
|
585
603
|
|
|
586
604
|
static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
@@ -594,7 +612,7 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
|
594
612
|
rb_raise(rb_eTypeError, "JavaScript code must be a String, got %s", StringValueCStr(r_code_class));
|
|
595
613
|
}
|
|
596
614
|
|
|
597
|
-
data->eval_time->started_at
|
|
615
|
+
clock_gettime(CLOCK_MONOTONIC, &data->eval_time->started_at);
|
|
598
616
|
JS_SetInterruptHandler(JS_GetRuntime(data->context), interrupt_handler, data->eval_time);
|
|
599
617
|
|
|
600
618
|
char *code = StringValueCStr(r_code);
|
|
@@ -612,9 +630,12 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
|
612
630
|
}
|
|
613
631
|
else
|
|
614
632
|
{
|
|
633
|
+
// Free j_awaitedResult before to_rb_value because to_rb_value may
|
|
634
|
+
// raise (longjmp) for JS exceptions, which would skip any cleanup
|
|
635
|
+
// after it and leak JS GC objects.
|
|
636
|
+
JS_FreeValue(data->context, j_awaitedResult);
|
|
615
637
|
VALUE result = to_rb_value(data->context, j_returnedValue);
|
|
616
638
|
JS_FreeValue(data->context, j_returnedValue);
|
|
617
|
-
JS_FreeValue(data->context, j_awaitedResult);
|
|
618
639
|
return result;
|
|
619
640
|
}
|
|
620
641
|
}
|
data/ext/quickjsrb/quickjsrb.h
CHANGED
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
extern const uint32_t qjsc_polyfill_intl_en_min_size;
|
|
16
16
|
extern const uint8_t qjsc_polyfill_intl_en_min;
|
|
17
|
+
extern const uint32_t qjsc_polyfill_file_min_size;
|
|
18
|
+
extern const uint8_t qjsc_polyfill_file_min;
|
|
17
19
|
|
|
18
20
|
const char *featureStdId = "feature_std";
|
|
19
21
|
const char *featureOsId = "feature_os";
|
|
20
22
|
const char *featureTimeoutId = "feature_timeout";
|
|
21
23
|
const char *featurePolyfillIntlId = "feature_polyfill_intl";
|
|
24
|
+
const char *featurePolyfillFileId = "feature_polyfill_file";
|
|
22
25
|
|
|
23
26
|
const char *undefinedId = "undefined";
|
|
24
27
|
const char *nanId = "NaN";
|
|
@@ -39,8 +42,8 @@ const char *native_errors[] = {
|
|
|
39
42
|
|
|
40
43
|
typedef struct EvalTime
|
|
41
44
|
{
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
int64_t limit_ms;
|
|
46
|
+
struct timespec started_at;
|
|
44
47
|
} EvalTime;
|
|
45
48
|
|
|
46
49
|
typedef struct VMData
|
|
@@ -49,6 +52,7 @@ typedef struct VMData
|
|
|
49
52
|
VALUE defined_functions;
|
|
50
53
|
struct EvalTime *eval_time;
|
|
51
54
|
VALUE logs;
|
|
55
|
+
VALUE alive_errors;
|
|
52
56
|
} VMData;
|
|
53
57
|
|
|
54
58
|
static void vm_free(void *ptr)
|
|
@@ -75,6 +79,15 @@ static void vm_mark(void *ptr)
|
|
|
75
79
|
VMData *data = (VMData *)ptr;
|
|
76
80
|
rb_gc_mark_movable(data->defined_functions);
|
|
77
81
|
rb_gc_mark_movable(data->logs);
|
|
82
|
+
rb_gc_mark_movable(data->alive_errors);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static void vm_compact(void *ptr)
|
|
86
|
+
{
|
|
87
|
+
VMData *data = (VMData *)ptr;
|
|
88
|
+
data->defined_functions = rb_gc_location(data->defined_functions);
|
|
89
|
+
data->logs = rb_gc_location(data->logs);
|
|
90
|
+
data->alive_errors = rb_gc_location(data->alive_errors);
|
|
78
91
|
}
|
|
79
92
|
|
|
80
93
|
static const rb_data_type_t vm_type = {
|
|
@@ -83,6 +96,7 @@ static const rb_data_type_t vm_type = {
|
|
|
83
96
|
.dmark = vm_mark,
|
|
84
97
|
.dfree = vm_free,
|
|
85
98
|
.dsize = vm_size,
|
|
99
|
+
.dcompact = vm_compact,
|
|
86
100
|
},
|
|
87
101
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
88
102
|
};
|
|
@@ -93,6 +107,7 @@ static VALUE vm_alloc(VALUE r_self)
|
|
|
93
107
|
VALUE obj = TypedData_Make_Struct(r_self, VMData, &vm_type, data);
|
|
94
108
|
data->defined_functions = rb_hash_new();
|
|
95
109
|
data->logs = rb_ary_new();
|
|
110
|
+
data->alive_errors = rb_hash_new();
|
|
96
111
|
|
|
97
112
|
EvalTime *eval_time = malloc(sizeof(EvalTime));
|
|
98
113
|
data->eval_time = eval_time;
|
|
@@ -138,6 +153,7 @@ static void r_define_constants(VALUE r_parent_class)
|
|
|
138
153
|
rb_define_const(r_parent_class, "MODULE_OS", QUICKJSRB_SYM(featureOsId));
|
|
139
154
|
rb_define_const(r_parent_class, "FEATURE_TIMEOUT", QUICKJSRB_SYM(featureTimeoutId));
|
|
140
155
|
rb_define_const(r_parent_class, "POLYFILL_INTL", QUICKJSRB_SYM(featurePolyfillIntlId));
|
|
156
|
+
rb_define_const(r_parent_class, "POLYFILL_FILE", QUICKJSRB_SYM(featurePolyfillFileId));
|
|
141
157
|
|
|
142
158
|
VALUE rb_cQuickjsValue = rb_define_class_under(r_parent_class, "Value", rb_cObject);
|
|
143
159
|
rb_define_const(rb_cQuickjsValue, "UNDEFINED", QUICKJSRB_SYM(undefinedId));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){var e=class e{#e;#t;constructor(n,i){if(this.#t=t(i?.type??``),!n){this.#e=new Uint8Array;return}if(!Array.isArray(n))throw TypeError(`Failed to construct 'Blob': The provided value cannot be converted to a sequence.`);let a=[],o=0;for(let t of n){let n;n=typeof t==`string`?r(t):t instanceof ArrayBuffer?new Uint8Array(t):ArrayBuffer.isView(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):t instanceof e?t.#e:r(String(t)),a.push(n),o+=n.byteLength}let s=new Uint8Array(o),c=0;for(let e of a)s.set(e,c),c+=e.byteLength;this.#e=s}get size(){return this.#e.byteLength}get type(){return this.#t}slice(r,i,a){let o=this.size,s=r===void 0?0:n(r,o),c=i===void 0?o:n(i,o),l=Math.max(c-s,0),u=new e;return u.#e=this.#e.slice(s,s+l),u.#t=t(a??``),u}text(){return Promise.resolve(i(this.#e))}arrayBuffer(){return Promise.resolve(this.#e.buffer.slice(this.#e.byteOffset,this.#e.byteOffset+this.#e.byteLength))}toString(){return`[object Blob]`}get[Symbol.toStringTag](){return`Blob`}};function t(e){return/[^\x20-\x7E]/.test(e)?``:e.toLowerCase()}function n(e,t){return e<0?Math.max(t+e,0):Math.min(e,t)}function r(e){let t=[];for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);if(r>=55296&&r<=56319&&n+1<e.length){let t=e.charCodeAt(n+1);t>=56320&&t<=57343&&(r=(r-55296)*1024+(t-56320)+65536,n++)}r<=127?t.push(r):r<=2047?t.push(192|r>>6,128|r&63):r<=65535?t.push(224|r>>12,128|r>>6&63,128|r&63):t.push(240|r>>18,128|r>>12&63,128|r>>6&63,128|r&63)}return new Uint8Array(t)}function i(e){let t=``,n=0;for(;n<e.length;){let r,i=e[n];i<=127?(r=i,n++):(i&224)==192?(r=(i&31)<<6|e[n+1]&63,n+=2):(i&240)==224?(r=(i&15)<<12|(e[n+1]&63)<<6|e[n+2]&63,n+=3):(r=(i&7)<<18|(e[n+1]&63)<<12|(e[n+2]&63)<<6|e[n+3]&63,n+=4),r<=65535?t+=String.fromCharCode(r):(r-=65536,t+=String.fromCharCode(55296+(r>>10),56320+(r&1023)))}return t}var a=class extends e{#e;#t;constructor(e,t,n){if(arguments.length<2)throw TypeError(`Failed to construct 'File': 2 arguments required, but only `+arguments.length+` present.`);super(e,n),this.#e=String(t),this.#t=n?.lastModified===void 0?Date.now():Number(n.lastModified)}get name(){return this.#e}get lastModified(){return this.#t}toString(){return`[object File]`}get[Symbol.toStringTag](){return`File`}};globalThis.Blob=e,globalThis.File=a})();
|