xbintsc 0.3.18 → 0.3.35
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/README.md +33 -0
- package/dist/src/cli/main.js +124 -30
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -1
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/state.js +20 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +6 -0
- package/dist/src/codegen/generator/tables.js +38 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/commonjs.d.ts +52 -0
- package/dist/src/driver/bundler/commonjs.js +493 -0
- package/dist/src/driver/bundler/commonjs.js.map +1 -0
- package/dist/src/driver/bundler/graph.d.ts +2 -1
- package/dist/src/driver/bundler/graph.js +32 -3
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.d.ts +2 -1
- package/dist/src/driver/bundler/merge.js +16 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +8 -0
- package/dist/src/driver/compiler.d.ts +8 -1
- package/dist/src/driver/compiler.js +75 -7
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +53 -0
- package/dist/src/driver/config.js +141 -0
- package/dist/src/driver/config.js.map +1 -0
- package/dist/src/driver/icon.d.ts +62 -0
- package/dist/src/driver/icon.js +151 -0
- package/dist/src/driver/icon.js.map +1 -0
- package/dist/src/driver/index.d.ts +4 -0
- package/dist/src/driver/index.js +4 -0
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/mac-bundle.d.ts +41 -0
- package/dist/src/driver/mac-bundle.js +123 -0
- package/dist/src/driver/mac-bundle.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +27 -0
- package/dist/src/driver/win-icon.js +80 -0
- package/dist/src/driver/win-icon.js.map +1 -0
- package/dist/src/extensions/gui/html.d.ts +25 -0
- package/dist/src/extensions/gui/html.js +203 -0
- package/dist/src/extensions/gui/html.js.map +1 -0
- package/dist/src/extensions/gui/index.js +11 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/registry.d.ts +29 -0
- package/dist/src/extensions/registry.js +14 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lexer/scanner/identifiers.js +4 -12
- package/dist/src/lexer/scanner/identifiers.js.map +1 -1
- package/dist/src/parser/statements.js +17 -4
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/tests/cli/main.test.js +46 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/bundler-resolve.test.d.ts +1 -0
- package/dist/tests/driver/bundler-resolve.test.js +230 -0
- package/dist/tests/driver/bundler-resolve.test.js.map +1 -0
- package/dist/tests/driver/config.test.d.ts +1 -0
- package/dist/tests/driver/config.test.js +124 -0
- package/dist/tests/driver/config.test.js.map +1 -0
- package/dist/tests/driver/icon.test.d.ts +1 -0
- package/dist/tests/driver/icon.test.js +421 -0
- package/dist/tests/driver/icon.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +177 -0
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/e2e/fetch.test.d.ts +12 -0
- package/dist/tests/e2e/fetch.test.js +272 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -0
- package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
- package/dist/tests/e2e/gui-dom.test.js +102 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -0
- package/dist/tests/e2e/gui-events.test.d.ts +5 -0
- package/dist/tests/e2e/gui-events.test.js +60 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +31 -0
- package/dist/tests/e2e/gui-helpers.js +74 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
- package/dist/tests/e2e/gui-layout.test.js +88 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -0
- package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
- package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
- package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
- package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
- package/dist/tests/e2e/gui-paint.test.js +111 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -0
- package/dist/tests/e2e/gui-script.test.d.ts +5 -0
- package/dist/tests/e2e/gui-script.test.js +78 -0
- package/dist/tests/e2e/gui-script.test.js.map +1 -0
- package/dist/tests/e2e/gui-style.test.d.ts +5 -0
- package/dist/tests/e2e/gui-style.test.js +175 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -0
- package/dist/tests/e2e/icon.test.d.ts +7 -0
- package/dist/tests/e2e/icon.test.js +80 -0
- package/dist/tests/e2e/icon.test.js.map +1 -0
- package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
- package/dist/tests/e2e/npm-modules.test.js +47 -1
- package/dist/tests/e2e/npm-modules.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
- package/dist/tests/extensions/gui-index.test.d.ts +1 -0
- package/dist/tests/extensions/gui-index.test.js +49 -0
- package/dist/tests/extensions/gui-index.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.d.ts +1 -0
- package/dist/tests/extensions/gui.test.js +177 -0
- package/dist/tests/extensions/gui.test.js.map +1 -0
- package/dist/tests/extensions/registry.test.js +36 -0
- package/dist/tests/extensions/registry.test.js.map +1 -1
- package/dist/tests/parser/statements.test.js +11 -0
- package/dist/tests/parser/statements.test.js.map +1 -1
- package/dist/tests/public-api.test.d.ts +1 -0
- package/dist/tests/public-api.test.js +31 -0
- package/dist/tests/public-api.test.js.map +1 -0
- package/package.json +1 -1
- package/runtime/ext_gui/css.cpp +4 -517
- package/runtime/ext_gui/css_internal.h +27 -0
- package/runtime/ext_gui/css_match.cpp +195 -0
- package/runtime/ext_gui/css_selector.cpp +207 -0
- package/runtime/ext_gui/css_sheet.cpp +129 -0
- package/runtime/ext_gui/document.cpp +90 -0
- package/runtime/ext_gui/document.h +23 -0
- package/runtime/ext_gui/dom.cpp +43 -403
- package/runtime/ext_gui/dom.h +7 -0
- package/runtime/ext_gui/dom_api.cpp +164 -0
- package/runtime/ext_gui/dom_api.h +12 -0
- package/runtime/ext_gui/dom_api_document.cpp +96 -0
- package/runtime/ext_gui/dom_api_events.cpp +123 -0
- package/runtime/ext_gui/dom_api_internal.h +135 -0
- package/runtime/ext_gui/dom_api_node.cpp +329 -0
- package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
- package/runtime/ext_gui/dom_api_proto.cpp +130 -0
- package/runtime/ext_gui/dom_api_style.cpp +192 -0
- package/runtime/ext_gui/dom_internal.h +39 -0
- package/runtime/ext_gui/dom_parse.cpp +348 -0
- package/runtime/ext_gui/dom_serialize.cpp +54 -0
- package/runtime/ext_gui/gui.cpp +61 -245
- package/runtime/ext_gui/gui_engine.h +54 -0
- package/runtime/ext_gui/gui_events.cpp +294 -0
- package/runtime/ext_gui/gui_internal.h +29 -0
- package/runtime/ext_gui/layout.cpp +6 -597
- package/runtime/ext_gui/layout_flex.cpp +200 -0
- package/runtime/ext_gui/layout_flow.cpp +191 -0
- package/runtime/ext_gui/layout_flow_internal.h +149 -0
- package/runtime/ext_gui/layout_inline.cpp +181 -0
- package/runtime/ext_gui/layout_internal.h +20 -0
- package/runtime/ext_gui/renderer.cpp +15 -679
- package/runtime/ext_gui/renderer_image.cpp +233 -0
- package/runtime/ext_gui/renderer_internal.h +112 -0
- package/runtime/ext_gui/renderer_shaders.h +108 -0
- package/runtime/ext_gui/renderer_text.cpp +342 -0
- package/runtime/ext_gui/script.cpp +63 -0
- package/runtime/ext_gui/style.cpp +12 -660
- package/runtime/ext_gui/style_internal.h +33 -0
- package/runtime/ext_gui/style_print.cpp +113 -0
- package/runtime/ext_gui/style_ua.cpp +98 -0
- package/runtime/ext_gui/style_values.cpp +468 -0
- package/runtime/ext_gui/window.cpp +60 -0
- package/runtime/rt.h +6 -0
- package/runtime/rt_internal.h +4 -0
- package/runtime/xt_builtins.c +1 -0
- package/runtime/xt_containers/access.inc +32 -1
- package/runtime/xt_fetch/buffer.inc +64 -0
- package/runtime/xt_fetch/headers.inc +312 -0
- package/runtime/xt_fetch/request.inc +386 -0
- package/runtime/xt_fetch/response.inc +107 -0
- package/runtime/xt_fetch/socket.inc +72 -0
- package/runtime/xt_fetch/url.inc +108 -0
- package/runtime/xt_fetch.c +39 -0
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_typed_array.c +614 -0
- package/src/cli/main.ts +137 -29
- package/src/codegen/generator/calls/access.ts +9 -1
- package/src/codegen/generator/state.ts +20 -0
- package/src/codegen/generator/tables.ts +40 -0
- package/src/driver/bundler/commonjs.ts +553 -0
- package/src/driver/bundler/graph.ts +35 -2
- package/src/driver/bundler/merge.ts +18 -1
- package/src/driver/bundler/types.ts +8 -0
- package/src/driver/compiler.ts +85 -7
- package/src/driver/config.ts +173 -0
- package/src/driver/icon.ts +184 -0
- package/src/driver/index.ts +30 -0
- package/src/driver/mac-bundle.ts +156 -0
- package/src/driver/win-icon.ts +96 -0
- package/src/extensions/gui/html.ts +236 -0
- package/src/extensions/gui/index.ts +11 -0
- package/src/extensions/registry.ts +39 -0
- package/src/index.ts +1 -1
- package/src/lexer/scanner/identifiers.ts +4 -11
- package/src/parser/statements.ts +17 -4
- package/dist/tests/e2e/gui.test.d.ts +0 -12
- package/dist/tests/e2e/gui.test.js +0 -493
- package/dist/tests/e2e/gui.test.js.map +0 -1
|
@@ -163,6 +163,37 @@ xt_value xt_set(xt_value target, xt_value key, xt_value value) {
|
|
|
163
163
|
return xt_array_set(target, key, value);
|
|
164
164
|
}
|
|
165
165
|
if (XT_IS_FUNCTION(target)) return xt_object_set(target, key, value);
|
|
166
|
-
if (XT_IS_OBJECT(target))
|
|
166
|
+
if (XT_IS_OBJECT(target)) {
|
|
167
|
+
/* Writes to a typed-array element are coerced to its element type. */
|
|
168
|
+
int typed = xt_typed_array_kind_of(target);
|
|
169
|
+
if (typed >= 0) {
|
|
170
|
+
if (XT_IS_STRING(key)) {
|
|
171
|
+
xt_string *k = xt_as_string(key);
|
|
172
|
+
if ((k->length == 6 && memcmp(k->data, "length", 6) == 0) ||
|
|
173
|
+
(k->length == 10 && memcmp(k->data, "byteLength", 10) == 0) ||
|
|
174
|
+
(k->length == 10 && memcmp(k->data, "byteOffset", 10) == 0)) {
|
|
175
|
+
xt_throw(xt_string_from_cstr("TypeError: Cannot assign to read only property"));
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
uint32_t index = 0;
|
|
180
|
+
int isIndex = 0;
|
|
181
|
+
if (XT_IS_NUMBER(key)) {
|
|
182
|
+
int32_t numeric = xt_to_int32(key);
|
|
183
|
+
if (numeric >= 0) {
|
|
184
|
+
index = (uint32_t)numeric;
|
|
185
|
+
isIndex = 1;
|
|
186
|
+
}
|
|
187
|
+
} else if (XT_IS_STRING(key)) {
|
|
188
|
+
isIndex = xt_key_is_array_index(xt_as_string(key), &index);
|
|
189
|
+
}
|
|
190
|
+
if (isIndex) {
|
|
191
|
+
double length = xt_to_number(xt_object_get_cstr(target, "length"));
|
|
192
|
+
if (index >= (uint32_t)length) return value; /* out-of-bounds writes are ignored */
|
|
193
|
+
return xt_object_set(target, key, xt_number(xt_typed_array_coerce(typed, xt_to_number(value))));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return xt_object_set(target, key, value);
|
|
197
|
+
}
|
|
167
198
|
return value;
|
|
168
199
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* -- growable byte buffer ------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Fetch needs to accumulate raw response bytes before the headers and body can
|
|
5
|
+
* be parsed. A small growable buffer keeps that logic in one place; it is
|
|
6
|
+
* always NUL-terminated so it can also back a JS string, but the explicit
|
|
7
|
+
* `length` is authoritative because a response body may contain NUL bytes.
|
|
8
|
+
*/
|
|
9
|
+
typedef struct {
|
|
10
|
+
char *data;
|
|
11
|
+
size_t length;
|
|
12
|
+
size_t capacity;
|
|
13
|
+
} xt_fetch_buffer;
|
|
14
|
+
|
|
15
|
+
static void xt_fetch_buffer_init(xt_fetch_buffer *buffer) {
|
|
16
|
+
buffer->data = NULL;
|
|
17
|
+
buffer->length = 0;
|
|
18
|
+
buffer->capacity = 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static void xt_fetch_buffer_free(xt_fetch_buffer *buffer) {
|
|
22
|
+
free(buffer->data);
|
|
23
|
+
buffer->data = NULL;
|
|
24
|
+
buffer->length = 0;
|
|
25
|
+
buffer->capacity = 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static void xt_fetch_buffer_append(xt_fetch_buffer *buffer, const char *data, size_t length) {
|
|
29
|
+
if (length == 0) {
|
|
30
|
+
if (!buffer->data) {
|
|
31
|
+
buffer->capacity = 1;
|
|
32
|
+
buffer->data = (char *)malloc(1);
|
|
33
|
+
if (!buffer->data) abort();
|
|
34
|
+
buffer->data[0] = '\0';
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (buffer->length + length + 1 > buffer->capacity) {
|
|
39
|
+
size_t capacity = buffer->capacity ? buffer->capacity : 256;
|
|
40
|
+
while (capacity < buffer->length + length + 1) capacity *= 2;
|
|
41
|
+
char *grown = (char *)realloc(buffer->data, capacity);
|
|
42
|
+
if (!grown) abort();
|
|
43
|
+
buffer->data = grown;
|
|
44
|
+
buffer->capacity = capacity;
|
|
45
|
+
}
|
|
46
|
+
memcpy(buffer->data + buffer->length, data, length);
|
|
47
|
+
buffer->length += length;
|
|
48
|
+
buffer->data[buffer->length] = '\0';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static void xt_fetch_buffer_append_cstr(xt_fetch_buffer *buffer, const char *text) {
|
|
52
|
+
xt_fetch_buffer_append(buffer, text, strlen(text));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* -- string helpers ------------------------------------------------------- */
|
|
56
|
+
|
|
57
|
+
static void xt_fetch_lowercase(const char *input, char *output, size_t size) {
|
|
58
|
+
size_t i = 0;
|
|
59
|
+
for (; input[i] && i + 1 < size; i++) {
|
|
60
|
+
char c = input[i];
|
|
61
|
+
output[i] = (c >= 'A' && c <= 'Z') ? (char)(c + 32) : c;
|
|
62
|
+
}
|
|
63
|
+
output[i] = '\0';
|
|
64
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/* -- Headers -------------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* A Headers object is an ordinary JS object carrying the case-insensitive
|
|
5
|
+
* header map under `__map` (lower-cased name -> value) plus a `__set-cookie`
|
|
6
|
+
* array so `getSetCookie()` can preserve duplicate cookies. Methods are stored
|
|
7
|
+
* as own closure properties, so `headers.get(...)` dispatches through the
|
|
8
|
+
* generic `xt_call_method` path with the Headers object as `this`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
static xt_value xt_headers_map(xt_value headers) {
|
|
12
|
+
xt_value map = xt_object_get_cstr(headers, "__map");
|
|
13
|
+
if (!XT_IS_OBJECT(map)) {
|
|
14
|
+
map = xt_object_new();
|
|
15
|
+
xt_object_set(headers, xt_string_from_cstr("__map"), map);
|
|
16
|
+
}
|
|
17
|
+
return map;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static xt_value xt_headers_cookies(xt_value headers) {
|
|
21
|
+
xt_value cookies = xt_object_get_cstr(headers, "__set-cookie");
|
|
22
|
+
if (!XT_IS_ARRAY(cookies)) {
|
|
23
|
+
cookies = xt_array_new(0, NULL);
|
|
24
|
+
xt_object_set(headers, xt_string_from_cstr("__set-cookie"), cookies);
|
|
25
|
+
}
|
|
26
|
+
return cookies;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static void xt_headers_append_raw(xt_value headers, const char *name, const char *value) {
|
|
30
|
+
char key[256];
|
|
31
|
+
xt_fetch_lowercase(name, key, sizeof(key));
|
|
32
|
+
if (strcmp(key, "set-cookie") == 0) {
|
|
33
|
+
xt_array_push(xt_headers_cookies(headers), xt_string_from_cstr(value));
|
|
34
|
+
}
|
|
35
|
+
xt_value map = xt_headers_map(headers);
|
|
36
|
+
xt_value keyValue = xt_string_from_cstr(key);
|
|
37
|
+
xt_value existing = xt_object_get(map, keyValue);
|
|
38
|
+
if (XT_IS_STRING(existing)) {
|
|
39
|
+
const char *previous = xt_string_data(existing);
|
|
40
|
+
size_t total = strlen(previous) + 2 + strlen(value);
|
|
41
|
+
char *joined = (char *)malloc(total + 1);
|
|
42
|
+
if (!joined) abort();
|
|
43
|
+
snprintf(joined, total + 1, "%s, %s", previous, value);
|
|
44
|
+
xt_object_set(map, keyValue, xt_string_from_cstr(joined));
|
|
45
|
+
free(joined);
|
|
46
|
+
} else {
|
|
47
|
+
xt_object_set(map, keyValue, xt_string_from_cstr(value));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static void xt_headers_set_raw(xt_value headers, const char *name, const char *value) {
|
|
52
|
+
char key[256];
|
|
53
|
+
xt_fetch_lowercase(name, key, sizeof(key));
|
|
54
|
+
if (strcmp(key, "set-cookie") == 0) {
|
|
55
|
+
xt_value cookies = xt_headers_cookies(headers);
|
|
56
|
+
xt_as_array(cookies)->length = 0;
|
|
57
|
+
xt_array_push(cookies, xt_string_from_cstr(value));
|
|
58
|
+
}
|
|
59
|
+
xt_object_set(xt_headers_map(headers), xt_string_from_cstr(key), xt_string_from_cstr(value));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static const char *xt_headers_lookup(xt_value headers, const char *name) {
|
|
63
|
+
char key[256];
|
|
64
|
+
xt_fetch_lowercase(name, key, sizeof(key));
|
|
65
|
+
xt_value value = xt_object_get(xt_headers_map(headers), xt_string_from_cstr(key));
|
|
66
|
+
return XT_IS_STRING(value) ? xt_string_data(value) : NULL;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static xt_value xt_headers_get_value(xt_value headers, const char *name) {
|
|
70
|
+
char key[256];
|
|
71
|
+
xt_fetch_lowercase(name, key, sizeof(key));
|
|
72
|
+
xt_value value = xt_object_get(xt_headers_map(headers), xt_string_from_cstr(key));
|
|
73
|
+
return value == XT_UNDEFINED ? XT_NULL : value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static void xt_fetch_set_method(xt_value object, const char *name, void *fn) {
|
|
77
|
+
xt_object_set(object, xt_string_from_cstr(name), xt_closure_new(fn, 0, NULL));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* -- Headers methods ------------------------------------------------------ */
|
|
81
|
+
|
|
82
|
+
static xt_value xt_headers_method_get(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
83
|
+
(void)env;
|
|
84
|
+
xt_value name = xt_to_string(xt_arg_at(argc, argv, 0));
|
|
85
|
+
const char *text = xt_string_data(name);
|
|
86
|
+
if (!text) return XT_NULL;
|
|
87
|
+
return xt_headers_get_value(thisValue, text);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static xt_value xt_headers_method_has(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
91
|
+
(void)env;
|
|
92
|
+
xt_value name = xt_to_string(xt_arg_at(argc, argv, 0));
|
|
93
|
+
const char *text = xt_string_data(name);
|
|
94
|
+
if (!text) return XT_FALSE;
|
|
95
|
+
return xt_headers_lookup(thisValue, text) != NULL ? XT_TRUE : XT_FALSE;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static xt_value xt_headers_method_set(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
99
|
+
(void)env;
|
|
100
|
+
const char *name = xt_string_data(xt_to_string(xt_arg_at(argc, argv, 0)));
|
|
101
|
+
const char *value = xt_string_data(xt_to_string(xt_arg_at(argc, argv, 1)));
|
|
102
|
+
if (name && value) xt_headers_set_raw(thisValue, name, value);
|
|
103
|
+
return XT_UNDEFINED;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static xt_value xt_headers_method_append(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
107
|
+
(void)env;
|
|
108
|
+
const char *name = xt_string_data(xt_to_string(xt_arg_at(argc, argv, 0)));
|
|
109
|
+
const char *value = xt_string_data(xt_to_string(xt_arg_at(argc, argv, 1)));
|
|
110
|
+
if (name && value) xt_headers_append_raw(thisValue, name, value);
|
|
111
|
+
return XT_UNDEFINED;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static xt_value xt_headers_method_delete(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
115
|
+
(void)env;
|
|
116
|
+
const char *name = xt_string_data(xt_to_string(xt_arg_at(argc, argv, 0)));
|
|
117
|
+
if (!name) return XT_UNDEFINED;
|
|
118
|
+
char key[256];
|
|
119
|
+
xt_fetch_lowercase(name, key, sizeof(key));
|
|
120
|
+
xt_delete(xt_headers_map(thisValue), xt_string_from_cstr(key));
|
|
121
|
+
return XT_UNDEFINED;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static xt_value xt_headers_method_forEach(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
125
|
+
(void)env;
|
|
126
|
+
xt_value callback = xt_arg_at(argc, argv, 0);
|
|
127
|
+
if (!XT_IS_FUNCTION(callback)) return XT_UNDEFINED;
|
|
128
|
+
xt_value thisArg = xt_arg_at(argc, argv, 1);
|
|
129
|
+
xt_value keys = xt_object_keys(xt_headers_map(thisValue));
|
|
130
|
+
int32_t count = (int32_t)xt_to_number(xt_array_length(keys));
|
|
131
|
+
for (int32_t i = 0; i < count; i++) {
|
|
132
|
+
xt_value key = xt_array_get(keys, xt_number((double)i));
|
|
133
|
+
xt_value args[3];
|
|
134
|
+
args[0] = xt_object_get(xt_headers_map(thisValue), key);
|
|
135
|
+
args[1] = key;
|
|
136
|
+
args[2] = thisValue;
|
|
137
|
+
xt_call_with_this(callback, thisArg, 3, args);
|
|
138
|
+
}
|
|
139
|
+
return XT_UNDEFINED;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static xt_value xt_headers_method_keys(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
143
|
+
(void)env;
|
|
144
|
+
(void)argc;
|
|
145
|
+
(void)argv;
|
|
146
|
+
return xt_object_keys(xt_headers_map(thisValue));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static xt_value xt_headers_method_values(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
150
|
+
(void)env;
|
|
151
|
+
(void)argc;
|
|
152
|
+
(void)argv;
|
|
153
|
+
return xt_object_values(xt_headers_map(thisValue));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static xt_value xt_headers_method_entries(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
157
|
+
(void)env;
|
|
158
|
+
(void)argc;
|
|
159
|
+
(void)argv;
|
|
160
|
+
xt_value keys = xt_object_keys(xt_headers_map(thisValue));
|
|
161
|
+
int32_t count = (int32_t)xt_to_number(xt_array_length(keys));
|
|
162
|
+
xt_value entries = xt_array_new(0, NULL);
|
|
163
|
+
for (int32_t i = 0; i < count; i++) {
|
|
164
|
+
xt_value key = xt_array_get(keys, xt_number((double)i));
|
|
165
|
+
xt_value pair[2];
|
|
166
|
+
pair[0] = key;
|
|
167
|
+
pair[1] = xt_object_get(xt_headers_map(thisValue), key);
|
|
168
|
+
xt_array_push(entries, xt_array_new(2, pair));
|
|
169
|
+
}
|
|
170
|
+
return entries;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static xt_value xt_headers_method_get_set_cookie(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
174
|
+
(void)env;
|
|
175
|
+
(void)argc;
|
|
176
|
+
(void)argv;
|
|
177
|
+
xt_value cookies = xt_object_get_cstr(thisValue, "__set-cookie");
|
|
178
|
+
return XT_IS_ARRAY(cookies) ? cookies : xt_array_new(0, NULL);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static xt_value xt_headers_method_to_string(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
182
|
+
(void)env;
|
|
183
|
+
(void)argc;
|
|
184
|
+
(void)argv;
|
|
185
|
+
xt_value keys = xt_object_keys(xt_headers_map(thisValue));
|
|
186
|
+
int32_t count = (int32_t)xt_to_number(xt_array_length(keys));
|
|
187
|
+
xt_fetch_buffer out;
|
|
188
|
+
xt_fetch_buffer_init(&out);
|
|
189
|
+
for (int32_t i = 0; i < count; i++) {
|
|
190
|
+
xt_value key = xt_array_get(keys, xt_number((double)i));
|
|
191
|
+
xt_value value = xt_object_get(xt_headers_map(thisValue), key);
|
|
192
|
+
const char *name = xt_string_data(key);
|
|
193
|
+
const char *text = xt_string_data(xt_to_string(value));
|
|
194
|
+
if (!name || !text) continue;
|
|
195
|
+
xt_fetch_buffer_append_cstr(&out, name);
|
|
196
|
+
xt_fetch_buffer_append_cstr(&out, ": ");
|
|
197
|
+
xt_fetch_buffer_append_cstr(&out, text);
|
|
198
|
+
xt_fetch_buffer_append_cstr(&out, "\r\n");
|
|
199
|
+
}
|
|
200
|
+
xt_value result = xt_string_new(out.data ? out.data : "", out.length);
|
|
201
|
+
xt_fetch_buffer_free(&out);
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* -- construction --------------------------------------------------------- */
|
|
206
|
+
|
|
207
|
+
static xt_value xt_headers_new(void) {
|
|
208
|
+
xt_value headers = xt_object_new();
|
|
209
|
+
xt_object_set(headers, xt_string_from_cstr("__map"), xt_object_new());
|
|
210
|
+
xt_fetch_set_method(headers, "get", (void *)xt_headers_method_get);
|
|
211
|
+
xt_fetch_set_method(headers, "has", (void *)xt_headers_method_has);
|
|
212
|
+
xt_fetch_set_method(headers, "set", (void *)xt_headers_method_set);
|
|
213
|
+
xt_fetch_set_method(headers, "append", (void *)xt_headers_method_append);
|
|
214
|
+
xt_fetch_set_method(headers, "delete", (void *)xt_headers_method_delete);
|
|
215
|
+
xt_fetch_set_method(headers, "forEach", (void *)xt_headers_method_forEach);
|
|
216
|
+
xt_fetch_set_method(headers, "keys", (void *)xt_headers_method_keys);
|
|
217
|
+
xt_fetch_set_method(headers, "values", (void *)xt_headers_method_values);
|
|
218
|
+
xt_fetch_set_method(headers, "entries", (void *)xt_headers_method_entries);
|
|
219
|
+
xt_fetch_set_method(headers, "getSetCookie", (void *)xt_headers_method_get_set_cookie);
|
|
220
|
+
xt_fetch_set_method(headers, "toString", (void *)xt_headers_method_to_string);
|
|
221
|
+
return headers;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Normalise a `headers` init value (plain object or Headers) into a Headers. */
|
|
225
|
+
static xt_value xt_headers_from_source(xt_value source) {
|
|
226
|
+
xt_value headers = xt_headers_new();
|
|
227
|
+
if (source == XT_UNDEFINED || source == XT_NULL) return headers;
|
|
228
|
+
if (XT_IS_ARRAY(source)) {
|
|
229
|
+
int32_t count = (int32_t)xt_to_number(xt_array_length(source));
|
|
230
|
+
for (int32_t i = 0; i < count; i++) {
|
|
231
|
+
xt_value pair = xt_array_get(source, xt_number((double)i));
|
|
232
|
+
if (!XT_IS_ARRAY(pair) || xt_to_number(xt_array_length(pair)) < 2) continue;
|
|
233
|
+
const char *name = xt_string_data(xt_to_string(xt_array_get(pair, xt_number(0))));
|
|
234
|
+
const char *text = xt_string_data(xt_to_string(xt_array_get(pair, xt_number(1))));
|
|
235
|
+
if (name && text) xt_headers_append_raw(headers, name, text);
|
|
236
|
+
}
|
|
237
|
+
return headers;
|
|
238
|
+
}
|
|
239
|
+
if (!XT_IS_OBJECT(source)) return headers;
|
|
240
|
+
|
|
241
|
+
xt_value map = xt_object_get_cstr(source, "__map");
|
|
242
|
+
if (XT_IS_OBJECT(map)) {
|
|
243
|
+
xt_value keys = xt_object_keys(map);
|
|
244
|
+
int32_t count = (int32_t)xt_to_number(xt_array_length(keys));
|
|
245
|
+
for (int32_t i = 0; i < count; i++) {
|
|
246
|
+
xt_value key = xt_array_get(keys, xt_number((double)i));
|
|
247
|
+
xt_value value = xt_object_get(map, key);
|
|
248
|
+
const char *name = xt_string_data(key);
|
|
249
|
+
const char *text = xt_string_data(xt_to_string(value));
|
|
250
|
+
if (name && text) xt_headers_append_raw(headers, name, text);
|
|
251
|
+
}
|
|
252
|
+
return headers;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
xt_value keys = xt_object_keys(source);
|
|
256
|
+
int32_t count = (int32_t)xt_to_number(xt_array_length(keys));
|
|
257
|
+
for (int32_t i = 0; i < count; i++) {
|
|
258
|
+
xt_value key = xt_array_get(keys, xt_number((double)i));
|
|
259
|
+
const char *name = xt_string_data(key);
|
|
260
|
+
if (!name || strncmp(name, "__", 2) == 0) continue;
|
|
261
|
+
xt_value value = xt_object_get(source, key);
|
|
262
|
+
if (XT_IS_FUNCTION(value)) continue;
|
|
263
|
+
if (XT_IS_ARRAY(value)) {
|
|
264
|
+
xt_value items = value;
|
|
265
|
+
int32_t itemCount = (int32_t)xt_to_number(xt_array_length(items));
|
|
266
|
+
for (int32_t j = 0; j < itemCount; j++) {
|
|
267
|
+
const char *text = xt_string_data(xt_to_string(xt_array_get(items, xt_number((double)j))));
|
|
268
|
+
if (text) xt_headers_append_raw(headers, name, text);
|
|
269
|
+
}
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const char *text = xt_string_data(xt_to_string(value));
|
|
273
|
+
if (text) xt_headers_append_raw(headers, name, text);
|
|
274
|
+
}
|
|
275
|
+
return headers;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* -- wire parsing --------------------------------------------------------- */
|
|
279
|
+
|
|
280
|
+
/** Parse the header block `[start, start+length)` (status line already read). */
|
|
281
|
+
static void xt_headers_parse_block(xt_value headers, const char *start, size_t length) {
|
|
282
|
+
size_t i = 0;
|
|
283
|
+
while (i < length) {
|
|
284
|
+
size_t lineEnd = i;
|
|
285
|
+
while (lineEnd + 1 < length && !(start[lineEnd] == '\r' && start[lineEnd + 1] == '\n')) lineEnd++;
|
|
286
|
+
if (lineEnd + 1 >= length) break;
|
|
287
|
+
const char *colon = (const char *)memchr(start + i, ':', lineEnd - i);
|
|
288
|
+
if (colon) {
|
|
289
|
+
const char *name = start + i;
|
|
290
|
+
const char *nameEnd = colon;
|
|
291
|
+
while (nameEnd > name && (nameEnd[-1] == ' ' || nameEnd[-1] == '\t')) nameEnd--;
|
|
292
|
+
const char *value = colon + 1;
|
|
293
|
+
while (value < start + lineEnd && (*value == ' ' || *value == '\t')) value++;
|
|
294
|
+
const char *valueEnd = start + lineEnd;
|
|
295
|
+
while (valueEnd > value && (valueEnd[-1] == ' ' || valueEnd[-1] == '\t')) valueEnd--;
|
|
296
|
+
if (nameEnd > name) {
|
|
297
|
+
char nameBuffer[256];
|
|
298
|
+
size_t nameLength = (size_t)(nameEnd - name);
|
|
299
|
+
if (nameLength >= sizeof(nameBuffer)) nameLength = sizeof(nameBuffer) - 1;
|
|
300
|
+
memcpy(nameBuffer, name, nameLength);
|
|
301
|
+
nameBuffer[nameLength] = '\0';
|
|
302
|
+
char valueBuffer[8192];
|
|
303
|
+
size_t valueLength = (size_t)(valueEnd - value);
|
|
304
|
+
if (valueLength >= sizeof(valueBuffer)) valueLength = sizeof(valueBuffer) - 1;
|
|
305
|
+
memcpy(valueBuffer, value, valueLength);
|
|
306
|
+
valueBuffer[valueLength] = '\0';
|
|
307
|
+
xt_headers_append_raw(headers, nameBuffer, valueBuffer);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
i = lineEnd + 2;
|
|
311
|
+
}
|
|
312
|
+
}
|