From 99baec3a1094258129a7e1aba061ddf04444fa94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 7 Nov 2022 14:46:01 +0100 Subject: [PATCH] modules: add back module normalizer In the normalizer, `base_name` is the full path to the module doing the import, and `name` the import itself. Thus, we want to normalize the path and make sure Windows paths use the appropriate separator. The name, however, is always given with posix style paths. --- src/modules.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/private.h | 1 + src/vm.c | 2 +- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/modules.c b/src/modules.c index ea8f6856..0203eb08 100644 --- a/src/modules.c +++ b/src/modules.c @@ -84,7 +84,7 @@ JSModuleDef *tjs_module_loader(JSContext *ctx, const char *module_name, void *op is_json = has_suffix(module_name, ".json"); - /* Support importing JSON files bcause... why not? */ + /* Support importing JSON files because... why not? */ if (is_json) dbuf_put(&dbuf, (const uint8_t *) json_tpl_start, strlen(json_tpl_start)); @@ -119,10 +119,13 @@ JSModuleDef *tjs_module_loader(JSContext *ctx, const char *module_name, void *op return m; } +#define TJS__PATHSEP_POSIX '/' #if defined(_WIN32) #define TJS__PATHSEP '\\' +#define TJS__PATHSEP_STR "\\" #else #define TJS__PATHSEP '/' +#define TJS__PATHSEP_STR "/" #endif int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, JS_BOOL use_realpath, JS_BOOL is_main) { @@ -189,4 +192,88 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, JS_BOOL use return 0; } +static inline void tjs__normalize_pathsep(char *name) { +#if defined(_WIN32) + char *p; + + for (p = name; *p; p++) { + if (p[0] == TJS__PATHSEP_POSIX) { + p[0] = TJS__PATHSEP; + } + } +#else + (void)name; +#endif +} + +char *tjs_module_normalizer(JSContext *ctx, const char *base_name, const char *name, void *opaque) { +#if 0 + printf("normalize: %s %s\n", base_name, name); +#endif + + char *filename, *p; + const char *r; + int len; + + if (name[0] != '.') { + /* if no initial dot, the module name is not modified */ + return js_strdup(ctx, name); + } + + /* Normalize base_name. This is the path to the importing module, and + * it should have the platform native path separator. + */ + tjs__normalize_pathsep(name); + + p = strrchr(base_name, TJS__PATHSEP); + if (p) + len = p - base_name; + else + len = 0; + + filename = js_malloc(ctx, len + strlen(name) + 1 + 1); + if (!filename) + return NULL; + memcpy(filename, base_name, len); + filename[len] = '\0'; + + /* we only normalize the leading '..' or '.' */ + r = name; + for (;;) { + if (r[0] == '.' && r[1] == TJS__PATHSEP_POSIX) { + r += 2; + } else if (r[0] == '.' && r[1] == '.' && r[2] == TJS__PATHSEP_POSIX) { + /* remove the last path element of filename, except if "." + or ".." */ + if (filename[0] == '\0') + break; + p = strrchr(filename, TJS__PATHSEP); + if (!p) + p = filename; + else + p++; + if (!strcmp(p, ".") || !strcmp(p, "..")) + break; + if (p > filename) + p--; + *p = '\0'; + r += 3; + } else { + break; + } + } + if (filename[0] != '\0') + strcat(filename, TJS__PATHSEP_STR); + strcat(filename, r); + + /* Re-normalize the path. The name part will have posix style paths, so + * normalize it to the platform native separator. + */ + tjs__normalize_pathsep(filename); + + return filename; +} + #undef TJS__PATHSEP +#undef TJS__PATHSEP_STR +#undef TJS__PATHSEP_POSIX diff --git a/src/private.h b/src/private.h index 4bbda205..5709d89f 100644 --- a/src/private.h +++ b/src/private.h @@ -92,6 +92,7 @@ void tjs_execute_jobs(JSContext *ctx); int tjs__load_file(JSContext *ctx, DynBuf *dbuf, const char *filename); JSModuleDef *tjs_module_loader(JSContext *ctx, const char *module_name, void *opaque); +char *tjs_module_normalizer(JSContext *ctx, const char *base_name, const char *name, void *opaque); JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, JS_BOOL use_realpath, JS_BOOL is_main); diff --git a/src/vm.c b/src/vm.c index bd2d39fd..88484681 100644 --- a/src/vm.c +++ b/src/vm.c @@ -210,7 +210,7 @@ TJSRuntime *TJS_NewRuntimeInternal(bool is_worker, TJSRunOptions *options) { qrt->stop.data = qrt; /* loader for ES modules */ - JS_SetModuleLoaderFunc(qrt->rt, NULL, tjs_module_loader, qrt); + JS_SetModuleLoaderFunc(qrt->rt, tjs_module_normalizer, tjs_module_loader, qrt); /* unhandled promise rejection tracker */ JS_SetHostPromiseRejectionTracker(qrt->rt, tjs__promise_rejection_tracker, NULL);