Skip to content

Commit

Permalink
modules: add back module normalizer
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
saghul committed Nov 8, 2022
1 parent 7fd8da2 commit 99baec3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
89 changes: 88 additions & 1 deletion src/modules.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions src/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 99baec3

Please sign in to comment.