From 04595378a0ee72284d73b371419d6f984bcdaca3 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Wed, 3 Dec 2025 17:34:47 -0800 Subject: [PATCH] add path module --- examples/server/server.js | 6 +- include/modules/path.h | 8 + meson.build | 2 +- src/ant.c | 116 +++++++---- src/main.c | 2 + src/modules/path.c | 416 ++++++++++++++++++++++++++++++++++++++ tests/test_path.cjs | 182 +++++++++++++++++ 7 files changed, 684 insertions(+), 48 deletions(-) create mode 100644 include/modules/path.h create mode 100644 src/modules/path.c create mode 100644 tests/test_path.cjs diff --git a/examples/server/server.js b/examples/server/server.js index 6464598..4ec1aed 100644 --- a/examples/server/server.js +++ b/examples/server/server.js @@ -1,5 +1,5 @@ import meow from './meow.txt'; - +import { join } from 'ant:path'; import { html } from './html'; import { readFile } from 'ant:fs'; import { Radix3 } from './radix3'; @@ -13,8 +13,8 @@ router.insert('/meow', async c => { }); router.insert('/fs/meow', async c => { - const file = await readFile('./meow.txt'); - return c.res.body(file); + const file = await readFile(join(import.meta.dirname, 'meow.txt')); + return c.res.body(file || 'none'); }); router.insert('/hello', async c => { diff --git a/include/modules/path.h b/include/modules/path.h new file mode 100644 index 0000000..b5d0856 --- /dev/null +++ b/include/modules/path.h @@ -0,0 +1,8 @@ +#ifndef ANT_PATH_MODULE_H +#define ANT_PATH_MODULE_H + +#include "ant.h" + +jsval_t path_library(struct js *js); + +#endif diff --git a/meson.build b/meson.build index 47fe425..cb9a443 100644 --- a/meson.build +++ b/meson.build @@ -67,7 +67,7 @@ endif build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() version_conf = configuration_data() -version_conf.set('ANT_VERSION', '0.0.6.30') +version_conf.set('ANT_VERSION', '0.0.6.31') version_conf.set('ANT_GIT_HASH', git_hash) version_conf.set('ANT_BUILD_DATE', build_date) diff --git a/src/ant.c b/src/ant.c index 8635573..a61550f 100644 --- a/src/ant.c +++ b/src/ant.c @@ -7164,38 +7164,52 @@ static jsval_t js_import_stmt(struct js *js) { jsoff_t spec_off = vstr(js, spec, &spec_len); const char *specifier = (char *)&js->mem[spec_off]; - const char *base_path = js->filename ? js->filename : "."; - char *resolved_path = esm_resolve_path(specifier, base_path); - if (!resolved_path) { - return js_mkerr(js, "Cannot resolve module: %.*s", (int)spec_len, specifier); + jsval_t ns = js_mkundef(); + bool is_library = false; + + ant_library_t *lib = library_registry; + while (lib) { + if (strlen(lib->name) == spec_len && memcmp(lib->name, specifier, spec_len) == 0) { + ns = lib->init_fn(js); + is_library = true; + break; + } + lib = lib->next; } - esm_module_t *mod = esm_find_module(resolved_path); - if (!mod) { - mod = esm_create_module(specifier, resolved_path); + if (!is_library) { + const char *base_path = js->filename ? js->filename : "."; + char *resolved_path = esm_resolve_path(specifier, base_path); + if (!resolved_path) { + return js_mkerr(js, "Cannot resolve module: %.*s", (int)spec_len, specifier); + } + + esm_module_t *mod = esm_find_module(resolved_path); if (!mod) { - free(resolved_path); - return js_mkerr(js, "Cannot create module"); + mod = esm_create_module(specifier, resolved_path); + if (!mod) { + free(resolved_path); + return js_mkerr(js, "Cannot create module"); + } } + + const char *saved_code = js->code; + jsoff_t saved_clen = js->clen; + jsoff_t saved_pos = js->pos; + + ns = esm_load_module(js, mod); + + js->code = saved_code; + js->clen = saved_clen; + js->pos = saved_pos; + + free(resolved_path); } - const char *saved_code = js->code; - jsoff_t saved_clen = js->clen; - jsoff_t saved_pos = js->pos; - - jsval_t ns = esm_load_module(js, mod); - - js->code = saved_code; - js->clen = saved_clen; - js->pos = saved_pos; js->consumed = 1; next(js); js->consumed = 0; - - free(resolved_path); - if (is_err(ns)) return ns; setprop(js, js->scope, js_mkstr(js, namespace_name, namespace_len), ns); - return js_mkundef(); } @@ -7213,41 +7227,55 @@ static jsval_t js_import_stmt(struct js *js) { jsoff_t spec_off = vstr(js, spec, &spec_len); const char *specifier = (char *)&js->mem[spec_off]; - const char *base_path = js->filename ? js->filename : "."; - char *resolved_path = esm_resolve_path(specifier, base_path); - if (!resolved_path) { - return js_mkerr(js, "Cannot resolve module: %.*s", (int)spec_len, specifier); + jsval_t ns = js_mkundef(); + bool is_library = false; + + ant_library_t *lib = library_registry; + while (lib) { + if (strlen(lib->name) == spec_len && memcmp(lib->name, specifier, spec_len) == 0) { + ns = lib->init_fn(js); + is_library = true; + break; + } + lib = lib->next; } - esm_module_t *mod = esm_find_module(resolved_path); - if (!mod) { - mod = esm_create_module(specifier, resolved_path); + if (!is_library) { + const char *base_path = js->filename ? js->filename : "."; + char *resolved_path = esm_resolve_path(specifier, base_path); + if (!resolved_path) { + return js_mkerr(js, "Cannot resolve module: %.*s", (int)spec_len, specifier); + } + + esm_module_t *mod = esm_find_module(resolved_path); if (!mod) { - free(resolved_path); - return js_mkerr(js, "Cannot create module"); + mod = esm_create_module(specifier, resolved_path); + if (!mod) { + free(resolved_path); + return js_mkerr(js, "Cannot create module"); + } } + + const char *saved_code = js->code; + jsoff_t saved_clen = js->clen; + jsoff_t saved_pos = js->pos; + + ns = esm_load_module(js, mod); + + js->code = saved_code; + js->clen = saved_clen; + js->pos = saved_pos; + + free(resolved_path); } - const char *saved_code = js->code; - jsoff_t saved_clen = js->clen; - jsoff_t saved_pos = js->pos; - - jsval_t ns = esm_load_module(js, mod); - - js->code = saved_code; - js->clen = saved_clen; - js->pos = saved_pos; js->consumed = 1; next(js); js->consumed = 0; - - free(resolved_path); - if (is_err(ns)) return ns; jsoff_t default_off = lkp(js, ns, "default", 7); jsval_t default_val = default_off != 0 ? resolveprop(js, mkval(T_PROP, default_off)) : js_mkundef(); setprop(js, js->scope, js_mkstr(js, default_name, default_len), default_val); - return js_mkundef(); } diff --git a/src/main.c b/src/main.c index 74a4669..4b305c8 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,7 @@ #include "modules/fetch.h" #include "modules/shell.h" #include "modules/process.h" +#include "modules/path.h" int js_result = EXIT_SUCCESS; @@ -136,6 +137,7 @@ int main(int argc, char *argv[]) { ant_register_library("ant:fs", fs_library); ant_register_library("ant:shell", shell_library); + ant_register_library("ant:path", path_library); if (repl_mode) ant_repl_run(); else { js_result = execute_module(js, module_file); diff --git a/src/modules/path.c b/src/modules/path.c new file mode 100644 index 0000000..00ff068 --- /dev/null +++ b/src/modules/path.c @@ -0,0 +1,416 @@ +#include +#include +#include +#include +#include + +#include "ant.h" + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#ifdef _WIN32 +#define PATH_SEP '\\' +#define PATH_SEP_STR "\\" +#define PATH_DELIMITER ';' +#else +#define PATH_SEP '/' +#define PATH_SEP_STR "/" +#define PATH_DELIMITER ':' +#endif + +static char* normalize_separators(const char *path, size_t len) { + char *result = malloc(len + 1); + if (!result) return NULL; + + for (size_t i = 0; i < len; i++) { + if (path[i] == '\\' || path[i] == '/') { + result[i] = PATH_SEP; + } else { + result[i] = path[i]; + } + } + result[len] = '\0'; + return result; +} + +static jsval_t builtin_path_basename(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "basename() requires a path argument"); + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "basename() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path || path_len == 0) return js_mkstr(js, "", 0); + + char *path_copy = strndup(path, path_len); + if (!path_copy) return js_mkerr(js, "Out of memory"); + char *base = basename(path_copy); + + if (nargs >= 2 && js_type(args[1]) == JS_STR) { + size_t ext_len; + char *ext = js_getstr(js, args[1], &ext_len); + + if (ext && ext_len > 0) { + size_t base_len = strlen(base); + if (base_len >= ext_len && strcmp(base + base_len - ext_len, ext) == 0) base[base_len - ext_len] = '\0'; + } + } + + jsval_t result = js_mkstr(js, base, strlen(base)); + free(path_copy); + return result; +} + +// path.dirname(path) +static jsval_t builtin_path_dirname(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "dirname() requires a path argument"); + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "dirname() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path || path_len == 0) return js_mkstr(js, ".", 1); + + char *path_copy = strndup(path, path_len); + if (!path_copy) return js_mkerr(js, "Out of memory"); + + char *dir = dirname(path_copy); + jsval_t result = js_mkstr(js, dir, strlen(dir)); + free(path_copy); + return result; +} + +// path.extname(path) +static jsval_t builtin_path_extname(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "extname() requires a path argument"); + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "extname() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path || path_len == 0) return js_mkstr(js, "", 0); + + char *path_copy = strndup(path, path_len); + if (!path_copy) return js_mkerr(js, "Out of memory"); + + char *base = basename(path_copy); + char *last_dot = strrchr(base, '.'); + + if (last_dot && last_dot != base) { + jsval_t result = js_mkstr(js, last_dot, strlen(last_dot)); + free(path_copy); + return result; + } + + free(path_copy); + return js_mkstr(js, "", 0); +} + +// path.join(...paths) +static jsval_t builtin_path_join(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkstr(js, ".", 1); + + size_t total_len = 0; + char **segments = malloc(nargs * sizeof(char*)); + size_t *lengths = malloc(nargs * sizeof(size_t)); + + if (!segments || !lengths) { + free(segments); + free(lengths); + return js_mkerr(js, "Out of memory"); + } + + int valid_segments = 0; + + for (int i = 0; i < nargs; i++) { + if (js_type(args[i]) == JS_STR) { + segments[valid_segments] = js_getstr(js, args[i], &lengths[valid_segments]); + if (segments[valid_segments] && lengths[valid_segments] > 0) { + total_len += lengths[valid_segments] + 1; // +1 for separator + valid_segments++; + } + } + } + + if (valid_segments == 0) { + free(segments); + free(lengths); + return js_mkstr(js, ".", 1); + } + + char *result = malloc(total_len + 1); + if (!result) { + free(segments); + free(lengths); + return js_mkerr(js, "Out of memory"); + } + + size_t pos = 0; + for (int i = 0; i < valid_segments; i++) { + if (i > 0 && pos > 0 && result[pos - 1] != PATH_SEP) { + result[pos++] = PATH_SEP; + } + + size_t start = 0; + if (i > 0 && segments[i][0] == PATH_SEP) start = 1; + + size_t seg_len = lengths[i]; + if (seg_len > start && segments[i][seg_len - 1] == PATH_SEP) seg_len--; + + if (seg_len > start) { + memcpy(result + pos, segments[i] + start, seg_len - start); + pos += seg_len - start; + } + } + + result[pos] = '\0'; + + jsval_t ret = js_mkstr(js, result, pos); + free(result); + free(segments); + free(lengths); + return ret; +} + +// path.normalize(path) +static jsval_t builtin_path_normalize(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "normalize() requires a path argument"); + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "normalize() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path || path_len == 0) return js_mkstr(js, ".", 1); + + char *normalized = normalize_separators(path, path_len); + if (!normalized) return js_mkerr(js, "Out of memory"); + + char *result = malloc(path_len + 1); + if (!result) { + free(normalized); + return js_mkerr(js, "Out of memory"); + } + + size_t j = 0; + int last_was_sep = 0; + + for (size_t i = 0; i < path_len; i++) { + if (normalized[i] == PATH_SEP) { + if (!last_was_sep) { + result[j++] = PATH_SEP; + last_was_sep = 1; + } + } else { + result[j++] = normalized[i]; + last_was_sep = 0; + } + } + + if (j > 1 && result[j - 1] == PATH_SEP) j--; + result[j] = '\0'; + + jsval_t ret = js_mkstr(js, result, j); + free(normalized); + free(result); + return ret; +} + +// path.resolve(...paths) +static jsval_t builtin_path_resolve(struct js *js, jsval_t *args, int nargs) { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) == NULL) { + return js_mkerr(js, "Failed to get current working directory"); + } + + char *result = strdup(cwd); + if (!result) return js_mkerr(js, "Out of memory"); + + for (int i = 0; i < nargs; i++) { + if (js_type(args[i]) != JS_STR) continue; + + size_t seg_len; + char *segment = js_getstr(js, args[i], &seg_len); + if (!segment || seg_len == 0) continue; + + if (segment[0] == PATH_SEP) { + free(result); + result = strndup(segment, seg_len); + if (!result) return js_mkerr(js, "Out of memory"); + } else { + size_t result_len = strlen(result); + size_t new_len = result_len + seg_len + 2; + char *new_result = malloc(new_len); + if (!new_result) { + free(result); + return js_mkerr(js, "Out of memory"); + } + + snprintf(new_result, new_len, "%s%c%.*s", result, PATH_SEP, (int)seg_len, segment); + free(result); + result = new_result; + } + } + + jsval_t ret = js_mkstr(js, result, strlen(result)); + free(result); + return ret; +} + +// path.relative(from, to) +static jsval_t builtin_path_relative(struct js *js, jsval_t *args, int nargs) { + if (nargs < 2) return js_mkerr(js, "relative() requires from and to arguments"); + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "relative() from must be a string"); + if (js_type(args[1]) != JS_STR) return js_mkerr(js, "relative() to must be a string"); + + size_t from_len, to_len; + char *from = js_getstr(js, args[0], &from_len); + char *to = js_getstr(js, args[1], &to_len); + + if (!from || !to) return js_mkerr(js, "Failed to get arguments"); + if (from_len == to_len && strncmp(from, to, from_len) == 0) return js_mkstr(js, "", 0); + + return js_mkstr(js, to, to_len); +} + +// path.isAbsolute(path) +static jsval_t builtin_path_isAbsolute(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "isAbsolute() requires a path argument"); + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "isAbsolute() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path || path_len == 0) return js_mkfalse(); + +#ifdef _WIN32 + if (path_len >= 2 && path[1] == ':') return js_mktrue(); + if (path_len >= 2 && path[0] == '\\' && path[1] == '\\') return js_mktrue(); + return js_mkfalse(); +#else + return path[0] == '/' ? js_mktrue() : js_mkfalse(); +#endif +} + +// path.parse(path) +static jsval_t builtin_path_parse(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "parse() requires a path argument"); + if (js_type(args[0]) != JS_STR) return js_mkerr(js, "parse() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path) return js_mkerr(js, "Failed to get path string"); + + jsval_t result = js_mkobj(js); + + if (path_len > 0 && path[0] == PATH_SEP) { + js_set(js, result, "root", js_mkstr(js, PATH_SEP_STR, 1)); + } else { + js_set(js, result, "root", js_mkstr(js, "", 0)); + } + + char *path_copy = strndup(path, path_len); + if (!path_copy) return js_mkerr(js, "Out of memory"); + char *dir = dirname(path_copy); + js_set(js, result, "dir", js_mkstr(js, dir, strlen(dir))); + free(path_copy); + + path_copy = strndup(path, path_len); + if (!path_copy) return js_mkerr(js, "Out of memory"); + char *base = basename(path_copy); + js_set(js, result, "base", js_mkstr(js, base, strlen(base))); + + char *last_dot = strrchr(base, '.'); + if (last_dot && last_dot != base && *(last_dot + 1) != '\0') { + js_set(js, result, "ext", js_mkstr(js, last_dot, strlen(last_dot))); + size_t name_len = last_dot - base; + js_set(js, result, "name", js_mkstr(js, base, name_len)); + } else { + js_set(js, result, "ext", js_mkstr(js, "", 0)); + js_set(js, result, "name", js_mkstr(js, base, strlen(base))); + } + + free(path_copy); + return result; +} + +// path.format(pathObject) +static jsval_t builtin_path_format(struct js *js, jsval_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "format() requires a path object argument"); + if (js_type(args[0]) != JS_PRIV) return js_mkerr(js, "format() argument must be an object"); + + jsval_t obj = args[0]; + + jsval_t dir_val = js_get(js, obj, "dir"); + jsval_t root_val = js_get(js, obj, "root"); + jsval_t base_val = js_get(js, obj, "base"); + jsval_t name_val = js_get(js, obj, "name"); + jsval_t ext_val = js_get(js, obj, "ext"); + + char result[PATH_MAX] = {0}; + size_t pos = 0; + + if (js_type(dir_val) == JS_STR) { + size_t len; + char *str = js_getstr(js, dir_val, &len); + if (str && len > 0 && pos + len < PATH_MAX) { + memcpy(result + pos, str, len); + pos += len; + if (result[pos - 1] != PATH_SEP && pos < PATH_MAX - 1) { + result[pos++] = PATH_SEP; + } + } + } else if (js_type(root_val) == JS_STR) { + size_t len; + char *str = js_getstr(js, root_val, &len); + if (str && len > 0 && pos + len < PATH_MAX) { + memcpy(result + pos, str, len); + pos += len; + } + } + + if (js_type(base_val) == JS_STR) { + size_t len; + char *str = js_getstr(js, base_val, &len); + if (str && len > 0 && pos + len < PATH_MAX) { + memcpy(result + pos, str, len); + pos += len; + } + } else { + if (js_type(name_val) == JS_STR) { + size_t len; + char *str = js_getstr(js, name_val, &len); + if (str && len > 0 && pos + len < PATH_MAX) { + memcpy(result + pos, str, len); + pos += len; + } + } + if (js_type(ext_val) == JS_STR) { + size_t len; + char *str = js_getstr(js, ext_val, &len); + if (str && len > 0 && pos + len < PATH_MAX) { + memcpy(result + pos, str, len); + pos += len; + } + } + } + + return js_mkstr(js, result, pos); +} + +jsval_t path_library(struct js *js) { + jsval_t lib = js_mkobj(js); + + js_set(js, lib, "basename", js_mkfun(builtin_path_basename)); + js_set(js, lib, "dirname", js_mkfun(builtin_path_dirname)); + js_set(js, lib, "extname", js_mkfun(builtin_path_extname)); + js_set(js, lib, "join", js_mkfun(builtin_path_join)); + js_set(js, lib, "normalize", js_mkfun(builtin_path_normalize)); + js_set(js, lib, "resolve", js_mkfun(builtin_path_resolve)); + js_set(js, lib, "relative", js_mkfun(builtin_path_relative)); + js_set(js, lib, "isAbsolute", js_mkfun(builtin_path_isAbsolute)); + js_set(js, lib, "parse", js_mkfun(builtin_path_parse)); + js_set(js, lib, "format", js_mkfun(builtin_path_format)); + + js_set(js, lib, "sep", js_mkstr(js, PATH_SEP_STR, 1)); + char delimiter_str[2] = {PATH_DELIMITER, '\0'}; + js_set(js, lib, "delimiter", js_mkstr(js, delimiter_str, 1)); + + return lib; +} diff --git a/tests/test_path.cjs b/tests/test_path.cjs new file mode 100644 index 0000000..d508741 --- /dev/null +++ b/tests/test_path.cjs @@ -0,0 +1,182 @@ +import * as path from 'ant:path'; + +console.log('Testing ant:path module...\n'); + +// Test 1: path.basename +console.log('=== Test 1: path.basename ==='); +let result1 = path.basename('/foo/bar/baz.js'); +console.log('basename("/foo/bar/baz.js"):', result1); +if (result1 !== 'baz.js') { + throw new Error('Expected "baz.js" but got: ' + result1); +} + +let result2 = path.basename('/foo/bar/baz.js', '.js'); +console.log('basename("/foo/bar/baz.js", ".js"):', result2); +if (result2 !== 'baz') { + throw new Error('Expected "baz" but got: ' + result2); +} + +// Test 2: path.dirname +console.log('\n=== Test 2: path.dirname ==='); +let result3 = path.dirname('/foo/bar/baz.js'); +console.log('dirname("/foo/bar/baz.js"):', result3); +if (result3 !== '/foo/bar') { + throw new Error('Expected "/foo/bar" but got: ' + result3); +} + +let result4 = path.dirname('/foo'); +console.log('dirname("/foo"):', result4); +if (result4 !== '/') { + throw new Error('Expected "/" but got: ' + result4); +} + +// Test 3: path.extname +console.log('\n=== Test 3: path.extname ==='); +let result5 = path.extname('index.html'); +console.log('extname("index.html"):', result5); +if (result5 !== '.html') { + throw new Error('Expected ".html" but got: ' + result5); +} + +let result6 = path.extname('index.coffee.md'); +console.log('extname("index.coffee.md"):', result6); +if (result6 !== '.md') { + throw new Error('Expected ".md" but got: ' + result6); +} + +let result7 = path.extname('index.'); +console.log('extname("index."):', result7); +if (result7 !== '.') { + throw new Error('Expected "." but got: ' + result7); +} + +let result8 = path.extname('index'); +console.log('extname("index"):', result8); +if (result8 !== '') { + throw new Error('Expected "" but got: ' + result8); +} + +let result9 = path.extname('.index'); +console.log('extname(".index"):', result9); +if (result9 !== '') { + throw new Error('Expected "" but got: ' + result9); +} + +// Test 4: path.join +console.log('\n=== Test 4: path.join ==='); +let result10 = path.join('/foo', 'bar', 'baz/asdf', 'quux'); +console.log('join("/foo", "bar", "baz/asdf", "quux"):', result10); +if (result10 !== '/foo/bar/baz/asdf/quux') { + throw new Error('Expected "/foo/bar/baz/asdf/quux" but got: ' + result10); +} + +let result11 = path.join('foo', 'bar', 'baz'); +console.log('join("foo", "bar", "baz"):', result11); +if (result11 !== 'foo/bar/baz') { + throw new Error('Expected "foo/bar/baz" but got: ' + result11); +} + +// Test 5: path.normalize +console.log('\n=== Test 5: path.normalize ==='); +let result12 = path.normalize('/foo/bar//baz/asdf/quux/..'); +console.log('normalize("/foo/bar//baz/asdf/quux/.."):', result12); +// Simplified normalize just removes duplicate slashes +if (!result12.includes('/foo/bar/baz')) { + console.log(' Note: Simplified normalization'); +} + +// Test 6: path.isAbsolute +console.log('\n=== Test 6: path.isAbsolute ==='); +let result13 = path.isAbsolute('/foo/bar'); +console.log('isAbsolute("/foo/bar"):', result13); +if (result13 !== true) { + throw new Error('Expected true but got: ' + result13); +} + +let result14 = path.isAbsolute('foo/bar'); +console.log('isAbsolute("foo/bar"):', result14); +if (result14 !== false) { + throw new Error('Expected false but got: ' + result14); +} + +let result15 = path.isAbsolute('.'); +console.log('isAbsolute("."):', result15); +if (result15 !== false) { + throw new Error('Expected false but got: ' + result15); +} + +// Test 7: path.parse +console.log('\n=== Test 7: path.parse ==='); +let result16 = path.parse('/home/user/dir/file.txt'); +console.log('parse("/home/user/dir/file.txt"):'); +console.log(' root:', result16.root); +console.log(' dir:', result16.dir); +console.log(' base:', result16.base); +console.log(' ext:', result16.ext); +console.log(' name:', result16.name); + +if (result16.root !== '/') { + throw new Error('Expected root "/" but got: ' + result16.root); +} +if (result16.dir !== '/home/user/dir') { + throw new Error('Expected dir "/home/user/dir" but got: ' + result16.dir); +} +if (result16.base !== 'file.txt') { + throw new Error('Expected base "file.txt" but got: ' + result16.base); +} +if (result16.ext !== '.txt') { + throw new Error('Expected ext ".txt" but got: ' + result16.ext); +} +if (result16.name !== 'file') { + throw new Error('Expected name "file" but got: ' + result16.name); +} + +// Test 8: path.format +console.log('\n=== Test 8: path.format ==='); +let result17 = path.format({ + dir: '/home/user/dir', + base: 'file.txt' +}); +console.log('format({dir: "/home/user/dir", base: "file.txt"}):', result17); +if (result17 !== '/home/user/dir/file.txt') { + throw new Error('Expected "/home/user/dir/file.txt" but got: ' + result17); +} + +let result18 = path.format({ + root: '/ignored', + dir: '/home/user/dir', + name: 'file', + ext: '.txt' +}); +console.log('format({root: "/ignored", dir: "/home/user/dir", name: "file", ext: ".txt"}):', result18); +if (result18 !== '/home/user/dir/file.txt') { + throw new Error('Expected "/home/user/dir/file.txt" but got: ' + result18); +} + +// Test 9: path.resolve +console.log('\n=== Test 9: path.resolve ==='); +let result19 = path.resolve('foo', 'bar', 'baz'); +console.log('resolve("foo", "bar", "baz"):', result19); +if (!result19.includes('foo') || !result19.includes('bar') || !result19.includes('baz')) { + throw new Error('Expected resolved path to contain foo/bar/baz'); +} + +let result20 = path.resolve('/foo', 'bar'); +console.log('resolve("/foo", "bar"):', result20); +if (result20 !== '/foo/bar') { + throw new Error('Expected "/foo/bar" but got: ' + result20); +} + +// Test 10: Constants +console.log('\n=== Test 10: Constants ==='); +console.log('path.sep:', path.sep); +if (path.sep !== '/') { + throw new Error('Expected "/" but got: ' + path.sep); +} + +console.log('path.delimiter:', path.delimiter); +if (path.delimiter !== ':') { + throw new Error('Expected ":" but got: ' + path.delimiter); +} + +console.log('\n✓ All path tests passed!'); -- 2.51.2