Skip to content

Commit bc1f65a

Browse files
committed
feat: basic json module supports
1 parent 550e034 commit bc1f65a

2 files changed

Lines changed: 84 additions & 16 deletions

File tree

qjsextra.wasm

2.29 KB
Binary file not shown.

qjsextra/eval.c

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,7 @@ static JSValue buf_empty_error(JSContext *ctx, uint8_t *buf, bool is_file, QJSEv
6262
static JSValue load_buf(JSContext *ctx, QJSEvalOptions opts, int flags, bool eval)
6363
{
6464
bool is_file = input_is_file(opts);
65-
// bool has_filename = opts.filename && opts.filename[0] != '\0';
66-
// bool invalid_file = is_file && (!has_filename || !file_exists(opts.filename));
67-
68-
// if (invalid_file)
69-
// return JS_ThrowReferenceError(ctx, "file does not exist: %s", opts.filename);
70-
7165
size_t buf_len = 0;
72-
// char *filename;
7366
uint8_t *buf = detect_buf(ctx, &opts, &buf_len, is_file);
7467
if (buf == NULL)
7568
return buf_empty_error(ctx, buf, is_file, &opts);
@@ -93,18 +86,92 @@ static JSValue load_buf(JSContext *ctx, QJSEvalOptions opts, int flags, bool eva
9386
return module_val;
9487
}
9588

96-
// static JSValue qjs_eval_global(JSContext *ctx, QJSEvalOptions opts)
97-
// {
98-
// return load_buf(ctx, opts, opts.eval_flags, true);
99-
// }
89+
/* Create a JSON module with the parsed JSON as default export */
90+
static JSModuleDef *js_module_loader_json(JSContext *ctx, const char *module_name)
91+
{
92+
JSModuleDef *m;
93+
size_t buf_len;
94+
uint8_t *buf;
95+
JSValue json_val, func_val;
96+
97+
buf = js_load_file(ctx, &buf_len, module_name);
98+
if (!buf)
99+
{
100+
JS_ThrowReferenceError(ctx, "could not load JSON module filename '%s'", module_name);
101+
return NULL;
102+
}
103+
104+
/* Parse the JSON content */
105+
json_val = JS_ParseJSON(ctx, (char *)buf, buf_len, module_name);
106+
js_free(ctx, buf);
107+
if (JS_IsException(json_val))
108+
return NULL;
109+
110+
/* Create a synthetic module source that exports the JSON */
111+
const char *module_source_template =
112+
"const __json_data__ = %s;\n"
113+
"export default __json_data__;\n";
114+
115+
/* Convert JSON to string */
116+
JSValue json_str = JS_JSONStringify(ctx, json_val, JS_NULL, JS_NULL);
117+
if (JS_IsException(json_str))
118+
{
119+
JS_FreeValue(ctx, json_val);
120+
return NULL;
121+
}
122+
123+
const char *json_string = JS_ToCString(ctx, json_str);
124+
if (!json_string)
125+
{
126+
JS_FreeValue(ctx, json_val);
127+
JS_FreeValue(ctx, json_str);
128+
return NULL;
129+
}
100130

101-
/* Module loader with support for appending common suffixes */
131+
/* Create the module source */
132+
size_t source_len = strlen(module_source_template) + strlen(json_string) + 1;
133+
char *module_source = malloc(source_len);
134+
snprintf(module_source, source_len, module_source_template, json_string);
135+
136+
/* Compile the module */
137+
func_val = JS_Eval(ctx, module_source, strlen(module_source), module_name,
138+
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
139+
140+
/* Cleanup */
141+
free(module_source);
142+
JS_FreeCString(ctx, json_string);
143+
JS_FreeValue(ctx, json_str);
144+
JS_FreeValue(ctx, json_val);
145+
146+
if (JS_IsException(func_val))
147+
return NULL;
148+
149+
/* Set import.meta */
150+
if (js_module_set_import_meta(ctx, func_val, true, false) < 0)
151+
{
152+
JS_FreeValue(ctx, func_val);
153+
return NULL;
154+
}
155+
156+
/* Return the compiled module */
157+
m = JS_VALUE_GET_PTR(func_val);
158+
JS_FreeValue(ctx, func_val);
159+
return m;
160+
}
161+
162+
/* Module loader with support for appending common suffixes and JSON modules */
102163
JSModuleDef *QJS_ModuleLoader(JSContext *ctx, const char *module_name, void *opaque)
103164
{
104165
module_name = detect_entry_point((char *)module_name);
105166
if (!module_name)
106167
return NULL;
107168

169+
/* Check if it's a JSON module */
170+
if (js__has_suffix(module_name, ".json"))
171+
{
172+
return js_module_loader_json(ctx, module_name);
173+
}
174+
108175
JSModuleDef *mod = js_module_loader(ctx, module_name, opaque);
109176
return mod;
110177
}
@@ -258,7 +325,7 @@ unsigned char *QJS_Compile(JSContext *c, QJSEvalOptions opts, size_t *outSize)
258325
/**
259326
* Compiles code (as a module or global script) to bytecode and returns a packed uint64_t value
260327
* containing both the bytecode's memory address (high 32 bits) and length (low 32 bits).
261-
*
328+
*
262329
* Returns NULL on error.
263330
* NOTE: The caller must free both the returned uint64_t pointer and the bytecode memory it points to.
264331
*/
@@ -277,7 +344,7 @@ uint64_t *QJS_Compile2(JSContext *ctx, QJSEvalOptions opts)
277344
free(bytecode);
278345
return NULL; // Allocation failure
279346
}
280-
347+
281348
// Store the address of the bytecode in the high 32 bits and the length in the low 32 bits
282349
*result = ((uint64_t)(uintptr_t)bytecode << 32) | (uint32_t)bytecode_len;
283350
return result;
@@ -286,11 +353,12 @@ uint64_t *QJS_Compile2(JSContext *ctx, QJSEvalOptions opts)
286353
QJSEvalOptions *QJS_CreateEvalOption(void *buf, uint8_t *bytecode_buf, size_t bytecode_len, char *filename, int eval_flags)
287354
{
288355
QJSEvalOptions *opts = (QJSEvalOptions *)malloc(sizeof(QJSEvalOptions));
289-
if (opts == NULL) {
356+
if (opts == NULL)
357+
{
290358
printf("Error allocating memory for QJSEvalOptions\n");
291359
return NULL;
292360
}
293-
361+
294362
opts->buf = buf;
295363
opts->bytecode_buf = bytecode_buf;
296364
opts->bytecode_len = bytecode_len;

0 commit comments

Comments
 (0)