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.
@@ -0,0 +1,218 @@
1
+ // W3C Blob and File polyfill for QuickJS
2
+ // Spec: https://www.w3.org/TR/FileAPI/
3
+
4
+ class Blob {
5
+ #bytes;
6
+ #type;
7
+
8
+ constructor(blobParts, options) {
9
+ this.#type = normalizeType(options?.type ?? "");
10
+
11
+ if (!blobParts) {
12
+ this.#bytes = new Uint8Array(0);
13
+ return;
14
+ }
15
+
16
+ if (!Array.isArray(blobParts)) {
17
+ throw new TypeError(
18
+ "Failed to construct 'Blob': The provided value cannot be converted to a sequence."
19
+ );
20
+ }
21
+
22
+ const parts = [];
23
+ let totalLength = 0;
24
+
25
+ for (const part of blobParts) {
26
+ let bytes;
27
+ if (typeof part === "string") {
28
+ bytes = encodeUTF8(part);
29
+ } else if (part instanceof ArrayBuffer) {
30
+ bytes = new Uint8Array(part);
31
+ } else if (ArrayBuffer.isView(part)) {
32
+ bytes = new Uint8Array(part.buffer, part.byteOffset, part.byteLength);
33
+ } else if (part instanceof Blob) {
34
+ bytes = part.#bytes;
35
+ } else {
36
+ bytes = encodeUTF8(String(part));
37
+ }
38
+ parts.push(bytes);
39
+ totalLength += bytes.byteLength;
40
+ }
41
+
42
+ const merged = new Uint8Array(totalLength);
43
+ let offset = 0;
44
+ for (const part of parts) {
45
+ merged.set(part, offset);
46
+ offset += part.byteLength;
47
+ }
48
+ this.#bytes = merged;
49
+ }
50
+
51
+ get size() {
52
+ return this.#bytes.byteLength;
53
+ }
54
+
55
+ get type() {
56
+ return this.#type;
57
+ }
58
+
59
+ slice(start, end, contentType) {
60
+ const size = this.size;
61
+ let relStart = start === undefined ? 0 : clampIndex(start, size);
62
+ let relEnd = end === undefined ? size : clampIndex(end, size);
63
+ const span = Math.max(relEnd - relStart, 0);
64
+
65
+ const sliced = new Blob();
66
+ sliced.#bytes = this.#bytes.slice(relStart, relStart + span);
67
+ sliced.#type = normalizeType(contentType ?? "");
68
+ return sliced;
69
+ }
70
+
71
+ text() {
72
+ return Promise.resolve(decodeUTF8(this.#bytes));
73
+ }
74
+
75
+ arrayBuffer() {
76
+ return Promise.resolve(this.#bytes.buffer.slice(this.#bytes.byteOffset, this.#bytes.byteOffset + this.#bytes.byteLength));
77
+ }
78
+
79
+ toString() {
80
+ return "[object Blob]";
81
+ }
82
+
83
+ get [Symbol.toStringTag]() {
84
+ return "Blob";
85
+ }
86
+ }
87
+
88
+ function normalizeType(type) {
89
+ // Spec: type must be lowercase ASCII without 0x20-7E exclusions
90
+ if (/[^\x20-\x7E]/.test(type)) {
91
+ return "";
92
+ }
93
+ return type.toLowerCase();
94
+ }
95
+
96
+ function clampIndex(index, size) {
97
+ if (index < 0) {
98
+ return Math.max(size + index, 0);
99
+ }
100
+ return Math.min(index, size);
101
+ }
102
+
103
+ function encodeUTF8(str) {
104
+ // Manual UTF-8 encoding for QuickJS (no TextEncoder)
105
+ const utf8 = [];
106
+ for (let i = 0; i < str.length; i++) {
107
+ let code = str.charCodeAt(i);
108
+
109
+ // Handle surrogate pairs
110
+ if (code >= 0xd800 && code <= 0xdbff && i + 1 < str.length) {
111
+ const next = str.charCodeAt(i + 1);
112
+ if (next >= 0xdc00 && next <= 0xdfff) {
113
+ code = (code - 0xd800) * 0x400 + (next - 0xdc00) + 0x10000;
114
+ i++;
115
+ }
116
+ }
117
+
118
+ if (code <= 0x7f) {
119
+ utf8.push(code);
120
+ } else if (code <= 0x7ff) {
121
+ utf8.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f));
122
+ } else if (code <= 0xffff) {
123
+ utf8.push(
124
+ 0xe0 | (code >> 12),
125
+ 0x80 | ((code >> 6) & 0x3f),
126
+ 0x80 | (code & 0x3f)
127
+ );
128
+ } else {
129
+ utf8.push(
130
+ 0xf0 | (code >> 18),
131
+ 0x80 | ((code >> 12) & 0x3f),
132
+ 0x80 | ((code >> 6) & 0x3f),
133
+ 0x80 | (code & 0x3f)
134
+ );
135
+ }
136
+ }
137
+ return new Uint8Array(utf8);
138
+ }
139
+
140
+ function decodeUTF8(bytes) {
141
+ // Manual UTF-8 decoding for QuickJS (no TextDecoder)
142
+ let str = "";
143
+ let i = 0;
144
+ while (i < bytes.length) {
145
+ let code;
146
+ const b = bytes[i];
147
+ if (b <= 0x7f) {
148
+ code = b;
149
+ i++;
150
+ } else if ((b & 0xe0) === 0xc0) {
151
+ code = ((b & 0x1f) << 6) | (bytes[i + 1] & 0x3f);
152
+ i += 2;
153
+ } else if ((b & 0xf0) === 0xe0) {
154
+ code =
155
+ ((b & 0x0f) << 12) |
156
+ ((bytes[i + 1] & 0x3f) << 6) |
157
+ (bytes[i + 2] & 0x3f);
158
+ i += 3;
159
+ } else {
160
+ code =
161
+ ((b & 0x07) << 18) |
162
+ ((bytes[i + 1] & 0x3f) << 12) |
163
+ ((bytes[i + 2] & 0x3f) << 6) |
164
+ (bytes[i + 3] & 0x3f);
165
+ i += 4;
166
+ }
167
+
168
+ if (code <= 0xffff) {
169
+ str += String.fromCharCode(code);
170
+ } else {
171
+ // Encode as surrogate pair
172
+ code -= 0x10000;
173
+ str += String.fromCharCode(0xd800 + (code >> 10), 0xdc00 + (code & 0x3ff));
174
+ }
175
+ }
176
+ return str;
177
+ }
178
+
179
+ class File extends Blob {
180
+ #name;
181
+ #lastModified;
182
+
183
+ constructor(fileBits, fileName, options) {
184
+ if (arguments.length < 2) {
185
+ throw new TypeError(
186
+ "Failed to construct 'File': 2 arguments required, but only " +
187
+ arguments.length +
188
+ " present."
189
+ );
190
+ }
191
+
192
+ super(fileBits, options);
193
+ this.#name = String(fileName);
194
+ this.#lastModified =
195
+ options?.lastModified !== undefined
196
+ ? Number(options.lastModified)
197
+ : Date.now();
198
+ }
199
+
200
+ get name() {
201
+ return this.#name;
202
+ }
203
+
204
+ get lastModified() {
205
+ return this.#lastModified;
206
+ }
207
+
208
+ toString() {
209
+ return "[object File]";
210
+ }
211
+
212
+ get [Symbol.toStringTag]() {
213
+ return "File";
214
+ }
215
+ }
216
+
217
+ globalThis.Blob = Blob;
218
+ globalThis.File = File;
@@ -0,0 +1,15 @@
1
+ // FormatJS Intl polyfills for QuickJS (no native Intl support)
2
+ // Order matters: getCanonicalLocales and Locale are deps of the others
3
+
4
+ import "@formatjs/intl-getcanonicallocales/polyfill-force.js";
5
+ import "@formatjs/intl-locale/polyfill-force.js";
6
+
7
+ import "@formatjs/intl-pluralrules/polyfill-force.js";
8
+ import "@formatjs/intl-pluralrules/locale-data/en";
9
+
10
+ import "@formatjs/intl-numberformat/polyfill-force.js";
11
+ import "@formatjs/intl-numberformat/locale-data/en";
12
+
13
+ import "@formatjs/intl-datetimeformat/polyfill-force.js";
14
+ import "@formatjs/intl-datetimeformat/locale-data/en";
15
+ import "@formatjs/intl-datetimeformat/add-all-tz.js";
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quickjs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - hmsk
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-01-30 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: json
@@ -47,6 +46,7 @@ extensions:
47
46
  extra_rdoc_files: []
48
47
  files:
49
48
  - CHANGELOG.md
49
+ - CLAUDE.md
50
50
  - LICENSE
51
51
  - README.md
52
52
  - Rakefile
@@ -78,9 +78,15 @@ files:
78
78
  - ext/quickjsrb/quickjs/unicode_gen_def.h
79
79
  - ext/quickjsrb/quickjsrb.c
80
80
  - ext/quickjsrb/quickjsrb.h
81
+ - ext/quickjsrb/vendor/polyfill-file.min.js
81
82
  - ext/quickjsrb/vendor/polyfill-intl-en.min.js
82
83
  - lib/quickjs.rb
83
84
  - lib/quickjs/version.rb
85
+ - polyfills/package-lock.json
86
+ - polyfills/package.json
87
+ - polyfills/rolldown.config.mjs
88
+ - polyfills/src/file.js
89
+ - polyfills/src/intl-en.js
84
90
  - sig/quickjs.rbs
85
91
  homepage: https://github.com/hmsk/quickjs.rb
86
92
  licenses:
@@ -89,7 +95,6 @@ metadata:
89
95
  homepage_uri: https://github.com/hmsk/quickjs.rb
90
96
  source_code_uri: https://github.com/hmsk/quickjs.rb
91
97
  changelog_uri: https://github.com/hmsk/quickjs.rb/blob/main/CHANGELOG.md
92
- post_install_message:
93
98
  rdoc_options: []
94
99
  require_paths:
95
100
  - lib
@@ -104,8 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
109
  - !ruby/object:Gem::Version
105
110
  version: '0'
106
111
  requirements: []
107
- rubygems_version: 3.5.9
108
- signing_key:
112
+ rubygems_version: 4.0.3
109
113
  specification_version: 4
110
114
  summary: Run binding of QuickJS
111
115
  test_files: []