xbintsc 0.3.25 → 0.3.46
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 +39 -3
- 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/module.js +10 -0
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +24 -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.js +14 -0
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +14 -0
- 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 +73 -5
- 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/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/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 +109 -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/gc.test.d.ts +1 -0
- package/dist/tests/e2e/gc.test.js +168 -0
- package/dist/tests/e2e/gc.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/harness.d.ts +2 -0
- package/dist/tests/e2e/harness.js +1 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- 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/parser/statements.test.js +11 -0
- package/dist/tests/parser/statements.test.js.map +1 -1
- package/package.json +3 -2
- 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/dom.cpp +7 -403
- package/runtime/ext_gui/dom_api.cpp +63 -1146
- 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 +135 -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 +56 -286
- 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/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 +1 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +1 -0
- package/runtime/ext_node/dgram/dgram.c +1 -0
- package/runtime/ext_node/events/events.c +1 -0
- package/runtime/ext_node/fs/fs_ops.c +10 -25
- package/runtime/ext_node/fs/glob.c +13 -30
- package/runtime/ext_node/fs/promises.c +1 -0
- package/runtime/ext_node/http/parts/prototypes.inc +5 -0
- package/runtime/ext_node/net/parts/prototypes.inc +2 -0
- package/runtime/ext_node/process/process.c +9 -7
- package/runtime/ext_node/stream/stream.c +1 -0
- package/runtime/ext_node/util/util.c +6 -6
- package/runtime/rt.h +16 -0
- package/runtime/rt_internal.h +67 -2
- package/runtime/xt_alloc.c +442 -5
- 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_generator.c +95 -1
- package/runtime/xt_loop.c +35 -1
- package/runtime/xt_promise.c +46 -0
- package/runtime/xt_stdlib2/error.inc +1 -0
- package/runtime/xt_stdlib2/regexp-match.inc +8 -7
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_symbol.c +2 -0
- package/runtime/xt_typed_array/construction.inc +142 -0
- package/runtime/xt_typed_array/elements.inc +92 -0
- package/runtime/xt_typed_array/methods.inc +329 -0
- package/runtime/xt_typed_array.c +72 -0
- package/runtime/xt_values/number-format.inc +26 -0
- package/scripts/check-file-length.ts +85 -0
- package/src/cli/main.ts +137 -29
- package/src/codegen/generator/calls/access.ts +9 -1
- package/src/codegen/generator/module.ts +10 -0
- package/src/codegen/generator/state.ts +24 -0
- package/src/codegen/generator/tables.ts +40 -0
- package/src/driver/bundler/commonjs.ts +553 -0
- package/src/driver/bundler/graph.ts +14 -0
- package/src/driver/bundler/merge.ts +15 -0
- package/src/driver/bundler/types.ts +8 -0
- package/src/driver/compiler.ts +83 -5
- 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/parser/statements.ts +17 -4
- package/dist/tests/e2e/gui.test.d.ts +0 -12
- package/dist/tests/e2e/gui.test.js +0 -702
- package/dist/tests/e2e/gui.test.js.map +0 -1
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — CSS declaration application (value parsing and how each
|
|
3
|
+
* property maps onto `XtStyle`).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "style_internal.h"
|
|
7
|
+
|
|
8
|
+
#include <cstdlib>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
namespace xtgui {
|
|
12
|
+
|
|
13
|
+
/* -- small helpers -------------------------------------------------------- */
|
|
14
|
+
|
|
15
|
+
static void setEdge(Edges *edges, const std::string &side, Length value) {
|
|
16
|
+
if (side == "top") edges->top = value;
|
|
17
|
+
else if (side == "right") edges->right = value;
|
|
18
|
+
else if (side == "bottom") edges->bottom = value;
|
|
19
|
+
else if (side == "left") edges->left = value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static bool parseEdgeLengths(const std::string &value, Edges *edges) {
|
|
23
|
+
std::vector<std::string> parts = xt_css_split_whitespace(value);
|
|
24
|
+
if (parts.empty() || parts.size() > 4) return false;
|
|
25
|
+
Length values[4];
|
|
26
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
27
|
+
Length length = xt_css_parse_length(parts[i]);
|
|
28
|
+
if (length.unit == Unit::Invalid) {
|
|
29
|
+
std::string keyword = xt_css_lower(parts[i]);
|
|
30
|
+
if (keyword == "thin") length = {1.0f, Unit::Px};
|
|
31
|
+
else if (keyword == "medium") length = {3.0f, Unit::Px};
|
|
32
|
+
else if (keyword == "thick") length = {5.0f, Unit::Px};
|
|
33
|
+
else return false;
|
|
34
|
+
}
|
|
35
|
+
values[i] = length;
|
|
36
|
+
}
|
|
37
|
+
switch (parts.size()) {
|
|
38
|
+
case 1:
|
|
39
|
+
edges->set(values[0]);
|
|
40
|
+
break;
|
|
41
|
+
case 2:
|
|
42
|
+
edges->top = edges->bottom = values[0];
|
|
43
|
+
edges->right = edges->left = values[1];
|
|
44
|
+
break;
|
|
45
|
+
case 3:
|
|
46
|
+
edges->top = values[0];
|
|
47
|
+
edges->right = edges->left = values[1];
|
|
48
|
+
edges->bottom = values[2];
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
edges->top = values[0];
|
|
52
|
+
edges->right = values[1];
|
|
53
|
+
edges->bottom = values[2];
|
|
54
|
+
edges->left = values[3];
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static bool assignLength(Length *target, const std::string &value) {
|
|
61
|
+
Length length = xt_css_parse_length(value);
|
|
62
|
+
if (length.unit == Unit::Invalid) return false;
|
|
63
|
+
*target = length;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static bool assignColor(Color *target, bool *has, const std::string &value) {
|
|
68
|
+
Color color = xt_css_parse_color(value);
|
|
69
|
+
if (!color.valid) return false;
|
|
70
|
+
*target = color;
|
|
71
|
+
*has = true;
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
float xt_style_resolve_absolute(const Length &length, float base, float em, float root, float vw,
|
|
76
|
+
float vh) {
|
|
77
|
+
switch (length.unit) {
|
|
78
|
+
case Unit::Px:
|
|
79
|
+
case Unit::Number:
|
|
80
|
+
return length.value;
|
|
81
|
+
case Unit::Percent:
|
|
82
|
+
return base * length.value / 100.0f;
|
|
83
|
+
case Unit::Em:
|
|
84
|
+
return em * length.value;
|
|
85
|
+
case Unit::Rem:
|
|
86
|
+
return root * length.value;
|
|
87
|
+
case Unit::Vw:
|
|
88
|
+
return vw * length.value / 100.0f;
|
|
89
|
+
case Unit::Vh:
|
|
90
|
+
return vh * length.value / 100.0f;
|
|
91
|
+
default:
|
|
92
|
+
return 0.0f;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static bool parseEnum(const std::string &value, const char *const *names, int count, int *out) {
|
|
97
|
+
std::string text = xt_css_lower(xt_css_trim(value));
|
|
98
|
+
for (int i = 0; i < count; i++) {
|
|
99
|
+
if (text == names[i]) {
|
|
100
|
+
*out = i;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* -- transitions ---------------------------------------------------------- */
|
|
108
|
+
|
|
109
|
+
static bool parseTimeSeconds(const std::string &text, float *out) {
|
|
110
|
+
std::string token = xt_css_trim(text);
|
|
111
|
+
if (token.empty()) return false;
|
|
112
|
+
const char *begin = token.c_str();
|
|
113
|
+
char *end = nullptr;
|
|
114
|
+
double value = std::strtod(begin, &end);
|
|
115
|
+
if (end == begin) return false;
|
|
116
|
+
std::string unit = xt_css_lower(xt_css_trim(std::string(end)));
|
|
117
|
+
if (unit == "ms") {
|
|
118
|
+
*out = (float)(value / 1000.0);
|
|
119
|
+
} else if (unit.empty() || unit == "s") {
|
|
120
|
+
*out = (float)value;
|
|
121
|
+
} else {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static bool parseTimingFunction(const std::string &text, TimingFunction *out) {
|
|
128
|
+
std::string token = xt_css_lower(xt_css_trim(text));
|
|
129
|
+
if (token == "linear") {
|
|
130
|
+
*out = TimingFunction::Linear;
|
|
131
|
+
} else if (token == "ease") {
|
|
132
|
+
*out = TimingFunction::Ease;
|
|
133
|
+
} else if (token == "ease-in") {
|
|
134
|
+
*out = TimingFunction::EaseIn;
|
|
135
|
+
} else if (token == "ease-out") {
|
|
136
|
+
*out = TimingFunction::EaseOut;
|
|
137
|
+
} else if (token == "ease-in-out") {
|
|
138
|
+
*out = TimingFunction::EaseInOut;
|
|
139
|
+
} else {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static std::vector<std::string> splitCommas(const std::string &text) {
|
|
146
|
+
std::vector<std::string> parts;
|
|
147
|
+
size_t start = 0;
|
|
148
|
+
for (size_t i = 0; i <= text.size(); i++) {
|
|
149
|
+
if (i == text.size() || text[i] == ',') {
|
|
150
|
+
std::string part = xt_css_trim(text.substr(start, i - start));
|
|
151
|
+
if (!part.empty()) parts.push_back(part);
|
|
152
|
+
start = i + 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return parts;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static void parseTransitionShorthand(const std::string &value, std::vector<TransitionSpec> *out) {
|
|
159
|
+
out->clear();
|
|
160
|
+
for (const std::string &group : splitCommas(value)) {
|
|
161
|
+
std::vector<std::string> tokens = xt_css_split_whitespace(group);
|
|
162
|
+
if (tokens.empty()) continue;
|
|
163
|
+
TransitionSpec spec;
|
|
164
|
+
int time_seen = 0;
|
|
165
|
+
for (const std::string &token : tokens) {
|
|
166
|
+
float seconds = 0;
|
|
167
|
+
TimingFunction timing = TimingFunction::Ease;
|
|
168
|
+
if (parseTimeSeconds(token, &seconds)) {
|
|
169
|
+
if (time_seen == 0) {
|
|
170
|
+
spec.duration = seconds;
|
|
171
|
+
} else {
|
|
172
|
+
spec.delay = seconds;
|
|
173
|
+
}
|
|
174
|
+
time_seen++;
|
|
175
|
+
} else if (parseTimingFunction(token, &timing)) {
|
|
176
|
+
spec.timing = timing;
|
|
177
|
+
} else {
|
|
178
|
+
spec.property = xt_css_lower(token);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
out->push_back(spec);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* -- declaration application ---------------------------------------------- */
|
|
186
|
+
|
|
187
|
+
void xt_style_apply_declaration(XtStyle *style, const std::string &property,
|
|
188
|
+
const std::string &rawValue, const ApplyContext &context) {
|
|
189
|
+
std::string value = xt_css_trim(rawValue);
|
|
190
|
+
|
|
191
|
+
if (property == "display") {
|
|
192
|
+
static const char *const names[] = {"none", "block", "inline", "inline-block", "flex", "list-item"};
|
|
193
|
+
int index = 0;
|
|
194
|
+
if (parseEnum(value, names, 6, &index)) style->display = (Display)index;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (property == "position") {
|
|
198
|
+
static const char *const names[] = {"static", "relative", "absolute", "fixed"};
|
|
199
|
+
int index = 0;
|
|
200
|
+
if (parseEnum(value, names, 4, &index)) style->position = (Position)index;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (property == "width") { assignLength(&style->width, value); return; }
|
|
204
|
+
if (property == "height") { assignLength(&style->height, value); return; }
|
|
205
|
+
if (property == "min-width") { assignLength(&style->min_width, value); return; }
|
|
206
|
+
if (property == "min-height") { assignLength(&style->min_height, value); return; }
|
|
207
|
+
if (property == "max-width") { assignLength(&style->max_width, value); return; }
|
|
208
|
+
if (property == "max-height") { assignLength(&style->max_height, value); return; }
|
|
209
|
+
if (property == "top") { assignLength(&style->top, value); return; }
|
|
210
|
+
if (property == "right") { assignLength(&style->right, value); return; }
|
|
211
|
+
if (property == "bottom") { assignLength(&style->bottom, value); return; }
|
|
212
|
+
if (property == "left") { assignLength(&style->left, value); return; }
|
|
213
|
+
|
|
214
|
+
if (property == "margin") { parseEdgeLengths(value, &style->margin); return; }
|
|
215
|
+
if (property == "padding") { parseEdgeLengths(value, &style->padding); return; }
|
|
216
|
+
if (property == "margin-top") { setEdge(&style->margin, "top", xt_css_parse_length(value)); return; }
|
|
217
|
+
if (property == "margin-right") { setEdge(&style->margin, "right", xt_css_parse_length(value)); return; }
|
|
218
|
+
if (property == "margin-bottom") { setEdge(&style->margin, "bottom", xt_css_parse_length(value)); return; }
|
|
219
|
+
if (property == "margin-left") { setEdge(&style->margin, "left", xt_css_parse_length(value)); return; }
|
|
220
|
+
if (property == "padding-top") { setEdge(&style->padding, "top", xt_css_parse_length(value)); return; }
|
|
221
|
+
if (property == "padding-right") { setEdge(&style->padding, "right", xt_css_parse_length(value)); return; }
|
|
222
|
+
if (property == "padding-bottom") { setEdge(&style->padding, "bottom", xt_css_parse_length(value)); return; }
|
|
223
|
+
if (property == "padding-left") { setEdge(&style->padding, "left", xt_css_parse_length(value)); return; }
|
|
224
|
+
|
|
225
|
+
if (property == "border-width") { parseEdgeLengths(value, &style->border_width); return; }
|
|
226
|
+
if (property == "border-top-width") { setEdge(&style->border_width, "top", xt_css_parse_length(value)); return; }
|
|
227
|
+
if (property == "border-right-width") { setEdge(&style->border_width, "right", xt_css_parse_length(value)); return; }
|
|
228
|
+
if (property == "border-bottom-width") { setEdge(&style->border_width, "bottom", xt_css_parse_length(value)); return; }
|
|
229
|
+
if (property == "border-left-width") { setEdge(&style->border_width, "left", xt_css_parse_length(value)); return; }
|
|
230
|
+
if (property == "border-radius") {
|
|
231
|
+
Length length = xt_css_parse_length(value);
|
|
232
|
+
if (length.unit == Unit::Px || length.unit == Unit::Number) style->border_radius = length.value;
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (property == "border-style" || property == "border-top-style" || property == "border-right-style" ||
|
|
236
|
+
property == "border-bottom-style" || property == "border-left-style") {
|
|
237
|
+
static const char *const names[] = {"none", "solid", "dashed", "dotted"};
|
|
238
|
+
int index = 0;
|
|
239
|
+
if (parseEnum(value, names, 4, &index)) style->border_style = (BorderStyle)index;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (property == "border-color" || property == "border-top-color" || property == "border-right-color" ||
|
|
243
|
+
property == "border-bottom-color" || property == "border-left-color") {
|
|
244
|
+
assignColor(&style->border_color, &style->has_border_color, value);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (property == "border" || property == "border-top" || property == "border-right" ||
|
|
248
|
+
property == "border-bottom" || property == "border-left") {
|
|
249
|
+
for (const std::string &token : xt_css_split_whitespace(value)) {
|
|
250
|
+
Length length = xt_css_parse_length(token);
|
|
251
|
+
if (length.unit == Unit::Px || length.unit == Unit::Number) {
|
|
252
|
+
if (property == "border") style->border_width.set(length);
|
|
253
|
+
else setEdge(&style->border_width, property.substr(7), length);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
static const char *const names[] = {"none", "solid", "dashed", "dotted"};
|
|
257
|
+
int index = 0;
|
|
258
|
+
if (parseEnum(token, names, 4, &index)) {
|
|
259
|
+
style->border_style = (BorderStyle)index;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
Color color = xt_css_parse_color(token);
|
|
263
|
+
if (color.valid) {
|
|
264
|
+
style->border_color = color;
|
|
265
|
+
style->has_border_color = true;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (property == "color") {
|
|
272
|
+
Color color = xt_css_parse_color(value);
|
|
273
|
+
if (color.valid) style->color = color;
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (property == "background-color") { assignColor(&style->background, &style->has_background, value); return; }
|
|
277
|
+
if (property == "background") {
|
|
278
|
+
Color color = xt_css_parse_color(value);
|
|
279
|
+
if (color.valid) {
|
|
280
|
+
style->background = color;
|
|
281
|
+
style->has_background = true;
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (property == "font-size") {
|
|
287
|
+
Length length = xt_css_parse_length(value);
|
|
288
|
+
if (length.unit == Unit::Invalid) return;
|
|
289
|
+
/* `em`/`%` resolve against the *parent* font size, never the element's own
|
|
290
|
+
* (possibly UA-set) size. */
|
|
291
|
+
style->font_size = xt_style_resolve_absolute(length, context.parentFontSize, context.parentFontSize,
|
|
292
|
+
context.rootFontSize, context.viewportWidth, context.viewportHeight);
|
|
293
|
+
if (style->font_size <= 0.0f) style->font_size = 16.0f;
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (property == "font-weight") {
|
|
297
|
+
std::string text = xt_css_lower(value);
|
|
298
|
+
if (text == "normal") style->font_weight = 400;
|
|
299
|
+
else if (text == "bold") style->font_weight = 700;
|
|
300
|
+
else if (text == "lighter") style->font_weight = 100;
|
|
301
|
+
else if (text == "bolder") style->font_weight = 700;
|
|
302
|
+
else {
|
|
303
|
+
float number = 0;
|
|
304
|
+
if (xt_css_parse_number(text, &number)) style->font_weight = (int)number;
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (property == "font-family") {
|
|
309
|
+
style->font_family = value;
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (property == "font-style") {
|
|
313
|
+
style->font_style = (xt_css_lower(value) == "italic") ? FontStyle::Italic : FontStyle::Normal;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (property == "line-height") {
|
|
317
|
+
std::string text = xt_css_lower(value);
|
|
318
|
+
if (text == "normal") {
|
|
319
|
+
style->line_height = {};
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
Length length = xt_css_parse_length(text);
|
|
323
|
+
if (length.unit == Unit::Invalid) return;
|
|
324
|
+
/* Relative units are resolved in `finalizeStyle`, once the element's own
|
|
325
|
+
* font size is settled. */
|
|
326
|
+
style->line_height = length;
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (property == "text-align") {
|
|
330
|
+
std::string text = xt_css_lower(value);
|
|
331
|
+
if (text == "left" || text == "start") style->text_align = TextAlign::Start;
|
|
332
|
+
else if (text == "right" || text == "end") style->text_align = TextAlign::End;
|
|
333
|
+
else if (text == "center") style->text_align = TextAlign::Center;
|
|
334
|
+
else if (text == "justify") style->text_align = TextAlign::Justify;
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (property == "white-space") {
|
|
338
|
+
static const char *const names[] = {"normal", "nowrap", "pre", "pre-wrap", "pre-line"};
|
|
339
|
+
int index = 0;
|
|
340
|
+
if (parseEnum(value, names, 5, &index)) style->white_space = (WhiteSpace)index;
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (property == "flex-direction") {
|
|
345
|
+
static const char *const names[] = {"row", "row-reverse", "column", "column-reverse"};
|
|
346
|
+
int index = 0;
|
|
347
|
+
if (parseEnum(value, names, 4, &index)) style->flex_direction = (FlexDirection)index;
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (property == "justify-content") {
|
|
351
|
+
static const char *const names[] = {"flex-start", "flex-end", "center", "space-between",
|
|
352
|
+
"space-around", "space-evenly"};
|
|
353
|
+
int index = 0;
|
|
354
|
+
if (parseEnum(value, names, 6, &index)) style->justify_content = (JustifyContent)index;
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (property == "align-items") {
|
|
358
|
+
static const char *const names[] = {"stretch", "flex-start", "flex-end", "center", "baseline"};
|
|
359
|
+
int index = 0;
|
|
360
|
+
if (parseEnum(value, names, 5, &index)) style->align_items = (AlignItems)index;
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (property == "gap" || property == "row-gap" || property == "column-gap") {
|
|
364
|
+
assignLength(&style->gap, value);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (property == "flex-grow") {
|
|
368
|
+
float number = 0;
|
|
369
|
+
if (xt_css_parse_number(value, &number)) style->flex_grow = number;
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (property == "flex-shrink") {
|
|
373
|
+
float number = 0;
|
|
374
|
+
if (xt_css_parse_number(value, &number)) style->flex_shrink = number;
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (property == "flex-basis") { assignLength(&style->flex_basis, value); return; }
|
|
378
|
+
if (property == "flex") {
|
|
379
|
+
std::string text = xt_css_lower(value);
|
|
380
|
+
if (text == "none") {
|
|
381
|
+
style->flex_grow = 0;
|
|
382
|
+
style->flex_shrink = 0;
|
|
383
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (text == "auto") {
|
|
387
|
+
style->flex_grow = 1;
|
|
388
|
+
style->flex_shrink = 1;
|
|
389
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (text == "initial") {
|
|
393
|
+
style->flex_grow = 0;
|
|
394
|
+
style->flex_shrink = 1;
|
|
395
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
std::vector<std::string> parts = xt_css_split_whitespace(text);
|
|
399
|
+
style->flex_grow = 0;
|
|
400
|
+
style->flex_shrink = 1;
|
|
401
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
402
|
+
size_t index = 0;
|
|
403
|
+
float number = 0;
|
|
404
|
+
if (index < parts.size() && xt_css_parse_number(parts[index], &number)) {
|
|
405
|
+
style->flex_grow = number;
|
|
406
|
+
index++;
|
|
407
|
+
if (index < parts.size() && xt_css_parse_number(parts[index], &number)) {
|
|
408
|
+
style->flex_shrink = number;
|
|
409
|
+
index++;
|
|
410
|
+
}
|
|
411
|
+
if (index >= parts.size()) style->flex_basis = {0.0f, Unit::Px};
|
|
412
|
+
}
|
|
413
|
+
if (index < parts.size()) assignLength(&style->flex_basis, parts[index]);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (property == "opacity") {
|
|
418
|
+
float number = 0;
|
|
419
|
+
if (xt_css_parse_number(value, &number)) style->opacity = number < 0 ? 0 : (number > 1 ? 1 : number);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (property == "overflow" || property == "overflow-x" || property == "overflow-y") {
|
|
423
|
+
static const char *const names[] = {"visible", "hidden", "scroll", "auto"};
|
|
424
|
+
int index = 0;
|
|
425
|
+
if (parseEnum(value, names, 4, &index)) style->overflow = (Overflow)index;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (property == "z-index") {
|
|
429
|
+
float number = 0;
|
|
430
|
+
if (xt_css_parse_number(value, &number)) {
|
|
431
|
+
style->z_index = (int)number;
|
|
432
|
+
style->has_z_index = true;
|
|
433
|
+
}
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
if (property == "transition") {
|
|
437
|
+
parseTransitionShorthand(value, &style->transitions);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (property == "transition-property") {
|
|
441
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
442
|
+
style->transitions.resize(parts.size());
|
|
443
|
+
for (size_t i = 0; i < parts.size(); i++) style->transitions[i].property = xt_css_lower(parts[i]);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (property == "transition-duration" || property == "transition-delay") {
|
|
447
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
448
|
+
style->transitions.resize(parts.size());
|
|
449
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
450
|
+
float seconds = 0;
|
|
451
|
+
if (!parseTimeSeconds(parts[i], &seconds)) continue;
|
|
452
|
+
if (property == "transition-duration") style->transitions[i].duration = seconds;
|
|
453
|
+
else style->transitions[i].delay = seconds;
|
|
454
|
+
}
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (property == "transition-timing-function") {
|
|
458
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
459
|
+
style->transitions.resize(parts.size());
|
|
460
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
461
|
+
TimingFunction timing = TimingFunction::Ease;
|
|
462
|
+
if (parseTimingFunction(parts[i], &timing)) style->transitions[i].timing = timing;
|
|
463
|
+
}
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
} // namespace xtgui
|
|
@@ -434,6 +434,7 @@ static void define_getter(xt_value proto, const char *name, void *fn) {
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
xt_value xt_gui_window_proto(void) {
|
|
437
|
+
xt_gc_add_root(&g_window_proto);
|
|
437
438
|
if (XT_IS_OBJECT(g_window_proto)) return g_window_proto;
|
|
438
439
|
xt_value proto = xt_object_new();
|
|
439
440
|
define_method(proto, "setTitle", (void *)win_set_title);
|
|
@@ -316,6 +316,7 @@ xt_value xt_dgram_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
316
316
|
|
|
317
317
|
static xt_value xt_dgram_socket_proto(void) {
|
|
318
318
|
static xt_value proto = 0;
|
|
319
|
+
xt_gc_add_root(&proto);
|
|
319
320
|
if (proto) return proto;
|
|
320
321
|
proto = xt_object_new();
|
|
321
322
|
xt_node_install_emitter(proto);
|
|
@@ -267,6 +267,7 @@ xt_value xt_events_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
267
267
|
|
|
268
268
|
static xt_value xt_events_proto(void) {
|
|
269
269
|
static xt_value proto = 0;
|
|
270
|
+
xt_gc_add_root(&proto);
|
|
270
271
|
if (proto) return proto;
|
|
271
272
|
proto = xt_object_new();
|
|
272
273
|
xt_node_install_emitter(proto);
|
|
@@ -59,27 +59,18 @@ xt_value xt_node_dirent_result(const char *dir, const char *name) {
|
|
|
59
59
|
return object;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
static void xt_fs_list_push(xt_fs_list *list, xt_value value) {
|
|
69
|
-
if (list->count == list->capacity) {
|
|
70
|
-
list->capacity = list->capacity ? list->capacity * 2 : 16;
|
|
71
|
-
xt_value *grown = (xt_value *)realloc(list->items, sizeof(xt_value) * list->capacity);
|
|
72
|
-
if (!grown) return;
|
|
73
|
-
list->items = grown;
|
|
74
|
-
}
|
|
75
|
-
list->items[list->count++] = value;
|
|
76
|
-
}
|
|
62
|
+
/* Entries accumulate in an `xt_array`, not a raw `xt_value` buffer: the
|
|
63
|
+
* collector cannot see a plain malloc'd buffer, so a `Dirent` created earlier
|
|
64
|
+
* in the walk would be swept as soon as a later entry allocates (which is
|
|
65
|
+
* exactly the GC-stress failure "object has no callable method
|
|
66
|
+
* 'isDirectory'"). The array lives on the caller's stack, so the conservative
|
|
67
|
+
* stack scan keeps it, and every entry it holds, reachable. */
|
|
77
68
|
|
|
78
69
|
/* Depth-first walk used by `readdirSync(path, { recursive: true })`. `prefix`
|
|
79
70
|
is the directory path relative to `base` (empty for the root, otherwise
|
|
80
71
|
ending in `/`). */
|
|
81
72
|
static void xt_fs_readdir_into(const char *base, const char *prefix, int withFileTypes, int recursive,
|
|
82
|
-
|
|
73
|
+
xt_value list) {
|
|
83
74
|
size_t baseLength = strlen(base);
|
|
84
75
|
size_t prefixLength = strlen(prefix);
|
|
85
76
|
size_t dirSize = baseLength + prefixLength + 2;
|
|
@@ -104,7 +95,7 @@ static void xt_fs_readdir_into(const char *base, const char *prefix, int withFil
|
|
|
104
95
|
char *relative = (char *)malloc(relSize);
|
|
105
96
|
if (!relative) continue;
|
|
106
97
|
snprintf(relative, relSize, "%s%s", prefix, name);
|
|
107
|
-
|
|
98
|
+
xt_array_push(list, withFileTypes ? xt_node_dirent_result(dirPath, name) : xt_string_from_cstr(relative));
|
|
108
99
|
|
|
109
100
|
if (recursive) {
|
|
110
101
|
size_t fullSize = dirLength + nameLength + 2;
|
|
@@ -141,14 +132,8 @@ xt_value xt_node_read_dir(int32_t argc, xt_value *argv) {
|
|
|
141
132
|
int withFileTypes = XT_IS_OBJECT(options) && xt_truthy(xt_object_get_cstr(options, "withFileTypes"));
|
|
142
133
|
int recursive = XT_IS_OBJECT(options) && xt_truthy(xt_object_get_cstr(options, "recursive"));
|
|
143
134
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
list.count = 0;
|
|
147
|
-
list.capacity = 0;
|
|
148
|
-
xt_fs_readdir_into(path, "", withFileTypes, recursive, &list);
|
|
149
|
-
|
|
150
|
-
xt_value result = xt_array_new((int32_t)list.count, list.items);
|
|
151
|
-
free(list.items);
|
|
135
|
+
xt_value result = xt_array_new(0, NULL);
|
|
136
|
+
xt_fs_readdir_into(path, "", withFileTypes, recursive, result);
|
|
152
137
|
return result;
|
|
153
138
|
}
|
|
154
139
|
|
|
@@ -10,21 +10,9 @@
|
|
|
10
10
|
#include "../node_common.h"
|
|
11
11
|
#include "fs_common.h"
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
size_t capacity;
|
|
17
|
-
} xt_glob_list;
|
|
18
|
-
|
|
19
|
-
static void xt_glob_push(xt_glob_list *list, xt_value value) {
|
|
20
|
-
if (list->count == list->capacity) {
|
|
21
|
-
list->capacity = list->capacity ? list->capacity * 2 : 16;
|
|
22
|
-
xt_value *grown = (xt_value *)realloc(list->items, sizeof(xt_value) * list->capacity);
|
|
23
|
-
if (!grown) return;
|
|
24
|
-
list->items = grown;
|
|
25
|
-
}
|
|
26
|
-
list->items[list->count++] = value;
|
|
27
|
-
}
|
|
13
|
+
/* Matches accumulate in an `xt_array` rather than a raw buffer so the garbage
|
|
14
|
+
* collector can see the `Dirent`/string entries created earlier in the walk;
|
|
15
|
+
* see the same note in `fs_ops.c`. */
|
|
28
16
|
|
|
29
17
|
static char *xt_glob_join(const char *dir, const char *name) {
|
|
30
18
|
size_t dirLength = strlen(dir);
|
|
@@ -96,11 +84,11 @@ static int xt_glob_is_dir(const char *path, int follow) {
|
|
|
96
84
|
}
|
|
97
85
|
|
|
98
86
|
static void xt_glob_walk(const char *dirPath, const char *pattern, const char *resultPrefix, int withFileTypes,
|
|
99
|
-
|
|
87
|
+
xt_value list);
|
|
100
88
|
|
|
101
89
|
/* Recurse one directory level for the `**` segment. */
|
|
102
90
|
static void xt_glob_descend(const char *dirPath, const char *pattern, const char *resultPrefix, int withFileTypes,
|
|
103
|
-
|
|
91
|
+
xt_value list) {
|
|
104
92
|
xt_fs_dir dir;
|
|
105
93
|
if (!xt_fs_dir_open(&dir, dirPath)) return;
|
|
106
94
|
while (xt_fs_dir_next(&dir)) {
|
|
@@ -123,7 +111,7 @@ static void xt_glob_descend(const char *dirPath, const char *pattern, const char
|
|
|
123
111
|
}
|
|
124
112
|
|
|
125
113
|
static void xt_glob_walk(const char *dirPath, const char *pattern, const char *resultPrefix, int withFileTypes,
|
|
126
|
-
|
|
114
|
+
xt_value list) {
|
|
127
115
|
if (pattern[0] == '\0') {
|
|
128
116
|
if (resultPrefix[0] != '\0') {
|
|
129
117
|
size_t length = strlen(resultPrefix);
|
|
@@ -131,7 +119,7 @@ static void xt_glob_walk(const char *dirPath, const char *pattern, const char *r
|
|
|
131
119
|
if (!trimmed) return;
|
|
132
120
|
memcpy(trimmed, resultPrefix, length + 1);
|
|
133
121
|
while (length > 1 && trimmed[length - 1] == '/') trimmed[--length] = '\0';
|
|
134
|
-
|
|
122
|
+
xt_array_push(list, xt_string_from_cstr(trimmed));
|
|
135
123
|
free(trimmed);
|
|
136
124
|
}
|
|
137
125
|
return;
|
|
@@ -165,13 +153,13 @@ static void xt_glob_walk(const char *dirPath, const char *pattern, const char *r
|
|
|
165
153
|
char *child = xt_glob_join(dirPath, name);
|
|
166
154
|
if (!child) continue;
|
|
167
155
|
if (rest[0] == '\0') {
|
|
168
|
-
if (withFileTypes)
|
|
156
|
+
if (withFileTypes) xt_array_push(list, xt_node_dirent_result(dirPath, name));
|
|
169
157
|
else {
|
|
170
158
|
size_t size = strlen(resultPrefix) + strlen(name) + 1;
|
|
171
159
|
char *result = (char *)malloc(size);
|
|
172
160
|
if (result) {
|
|
173
161
|
snprintf(result, size, "%s%s", resultPrefix, name);
|
|
174
|
-
|
|
162
|
+
xt_array_push(list, xt_string_from_cstr(result));
|
|
175
163
|
free(result);
|
|
176
164
|
}
|
|
177
165
|
}
|
|
@@ -189,7 +177,7 @@ static void xt_glob_walk(const char *dirPath, const char *pattern, const char *r
|
|
|
189
177
|
xt_fs_dir_close(&dir);
|
|
190
178
|
}
|
|
191
179
|
|
|
192
|
-
static void xt_glob_run(const char *pattern, const char *cwd, int withFileTypes,
|
|
180
|
+
static void xt_glob_run(const char *pattern, const char *cwd, int withFileTypes, xt_value list) {
|
|
193
181
|
if (!pattern) return;
|
|
194
182
|
const char *base = cwd && cwd[0] ? cwd : ".";
|
|
195
183
|
const char *prefix = "";
|
|
@@ -209,24 +197,19 @@ xt_value xt_node_glob(int32_t argc, xt_value *argv) {
|
|
|
209
197
|
xt_value cwdValue = XT_IS_OBJECT(options) ? xt_object_get_cstr(options, "cwd") : XT_UNDEFINED;
|
|
210
198
|
if (XT_IS_STRING(cwdValue)) cwd = xt_string_data(cwdValue);
|
|
211
199
|
|
|
212
|
-
|
|
213
|
-
list.items = NULL;
|
|
214
|
-
list.count = 0;
|
|
215
|
-
list.capacity = 0;
|
|
200
|
+
xt_value result = xt_array_new(0, NULL);
|
|
216
201
|
|
|
217
202
|
xt_value patternValue = argv[0];
|
|
218
203
|
if (XT_IS_ARRAY(patternValue)) {
|
|
219
204
|
int32_t count = (int32_t)xt_to_number(xt_array_length(patternValue));
|
|
220
205
|
for (int32_t i = 0; i < count; i++) {
|
|
221
206
|
xt_value item = xt_array_get(patternValue, xt_number((double)i));
|
|
222
|
-
if (XT_IS_STRING(item)) xt_glob_run(xt_string_data(item), cwd, withFileTypes,
|
|
207
|
+
if (XT_IS_STRING(item)) xt_glob_run(xt_string_data(item), cwd, withFileTypes, result);
|
|
223
208
|
}
|
|
224
209
|
} else {
|
|
225
210
|
const char *pattern = xt_node_cstr(patternValue);
|
|
226
|
-
xt_glob_run(pattern, cwd, withFileTypes,
|
|
211
|
+
xt_glob_run(pattern, cwd, withFileTypes, result);
|
|
227
212
|
}
|
|
228
213
|
|
|
229
|
-
xt_value result = xt_array_new((int32_t)list.count, list.items);
|
|
230
|
-
free(list.items);
|
|
231
214
|
return result;
|
|
232
215
|
}
|
|
@@ -242,6 +242,7 @@ XT_FS_PROMISES_FACADE(xt_node_p_open, _)
|
|
|
242
242
|
|
|
243
243
|
xt_value xt_fs_promises(void) {
|
|
244
244
|
static xt_value cached = 0;
|
|
245
|
+
xt_gc_add_root(&cached);
|
|
245
246
|
if (XT_IS_OBJECT(cached)) return cached;
|
|
246
247
|
xt_value object = xt_object_new();
|
|
247
248
|
#define XT_FS_PROMISE_METHOD(jsName, name) \
|