Last active
January 26, 2020 18:56
-
-
Save drsm/d950402101765c7395c36cb4051576ba to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Artem S. Povalyukhin <artem.povaluhin@gmail.com> | |
# Date 1580064983 -10800 | |
# Sun Jan 26 21:56:23 2020 +0300 | |
# Node ID 9f95590b8bcff4db23d1939bc8a684673a0c26dc | |
# Parent 7e1dda9c16c89fd99525c7ae16822e34a99dfbcf | |
Introduced fs.access and friends. | |
diff -r 7e1dda9c16c8 -r 9f95590b8bcf src/njs_fs.c | |
--- a/src/njs_fs.c Sat Jan 25 21:55:50 2020 +0300 | |
+++ b/src/njs_fs.c Sun Jan 26 21:56:23 2020 +0300 | |
@@ -596,6 +596,56 @@ njs_fs_rename_sync(njs_vm_t *vm, njs_val | |
static njs_int_t | |
+njs_fs_access(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, | |
+ njs_index_t calltype) | |
+{ | |
+ njs_int_t ret; | |
+ const char *path; | |
+ const njs_value_t *callback, *mode; | |
+ njs_fs_ioerror_t ioerror; | |
+ | |
+ ret = njs_fs_path_arg(vm, &path, njs_arg(args, nargs, 1), | |
+ &njs_str_value("path")); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return ret; | |
+ } | |
+ | |
+ mode = njs_arg(args, nargs, 2); | |
+ | |
+ if (njs_slow_path(calltype == NJS_FS_CALLBACK)) { | |
+ callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); | |
+ if (!njs_is_function(callback)) { | |
+ njs_type_error(vm, "\"callback\" must be a function"); | |
+ return NJS_ERROR; | |
+ } | |
+ if (mode == callback) { | |
+ mode = &njs_value_undefined; | |
+ } | |
+ | |
+ } else { | |
+ /* GCC complains about uninitialized callback. */ | |
+ callback = NULL; | |
+ } | |
+ | |
+ if (njs_slow_path(!njs_is_undefined(mode) && !njs_is_number(mode))) { | |
+ njs_type_error(vm, "\"mode\" must be a number"); | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ njs_fs_set_ioerr(&ioerror, 0, NULL, NULL); | |
+ | |
+ ret = access(path, njs_is_undefined(mode) ? F_OK : (int) njs_number(mode)); | |
+ if (njs_slow_path(ret != 0)) { | |
+ njs_fs_set_ioerr(&ioerror, errno, strerror(errno), "access"); | |
+ } | |
+ | |
+ njs_set_undefined(&vm->retval); | |
+ | |
+ return njs_fs_return_result(vm, &args[1], &ioerror, calltype, callback, 1); | |
+} | |
+ | |
+ | |
+static njs_int_t | |
njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data, | |
njs_fs_ioerror_t *ioerror) | |
{ | |
@@ -852,6 +902,14 @@ static const njs_object_prop_t njs_fs_p | |
{ | |
{ | |
.type = NJS_PROPERTY, | |
+ .name = njs_string("access"), | |
+ .value = njs_native_function2(njs_fs_access, 0, NJS_FS_PROMISE), | |
+ .writable = 1, | |
+ .configurable = 1, | |
+ }, | |
+ | |
+ { | |
+ .type = NJS_PROPERTY, | |
.name = njs_string("readFile"), | |
.value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_PROMISE), | |
.writable = 1, | |
@@ -893,6 +951,50 @@ njs_fs_promises(njs_vm_t *vm, njs_object | |
} | |
+static const njs_object_prop_t njs_fs_constants_properties[] = | |
+{ | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("F_OK"), | |
+ .value = njs_value(NJS_NUMBER, 0, F_OK), | |
+ .enumerable = 1, | |
+ }, | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("R_OK"), | |
+ .value = njs_value(NJS_NUMBER, 1, R_OK), | |
+ .enumerable = 1, | |
+ }, | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("W_OK"), | |
+ .value = njs_value(NJS_NUMBER, 1, W_OK), | |
+ .enumerable = 1, | |
+ }, | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("X_OK"), | |
+ .value = njs_value(NJS_NUMBER, 1, X_OK), | |
+ .enumerable = 1, | |
+ }, | |
+}; | |
+ | |
+ | |
+static const njs_object_init_t njs_fs_constants_init = { | |
+ njs_fs_constants_properties, | |
+ njs_nitems(njs_fs_constants_properties), | |
+}; | |
+ | |
+ | |
+static njs_int_t | |
+njs_fs_constants(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, | |
+ njs_value_t *unused, njs_value_t *retval) | |
+{ | |
+ return njs_object_prop_lazyinit(vm, &njs_fs_constants_init, prop, value, | |
+ retval); | |
+} | |
+ | |
+ | |
static const njs_object_prop_t njs_fs_object_properties[] = | |
{ | |
{ | |
@@ -909,6 +1011,29 @@ static const njs_object_prop_t njs_fs_o | |
}, | |
{ | |
+ .type = NJS_PROPERTY_HANDLER, | |
+ .name = njs_string("constants"), | |
+ .value = njs_prop_handler(njs_fs_constants), | |
+ .enumerable = 1, | |
+ }, | |
+ | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("access"), | |
+ .value = njs_native_function2(njs_fs_access, 0, NJS_FS_CALLBACK), | |
+ .writable = 1, | |
+ .configurable = 1, | |
+ }, | |
+ | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("accessSync"), | |
+ .value = njs_native_function2(njs_fs_access, 0, NJS_FS_DIRECT), | |
+ .writable = 1, | |
+ .configurable = 1, | |
+ }, | |
+ | |
+ { | |
.type = NJS_PROPERTY, | |
.name = njs_string("readFile"), | |
.value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_CALLBACK), | |
diff -r 7e1dda9c16c8 -r 9f95590b8bcf src/test/njs_interactive_test.c | |
--- a/src/test/njs_interactive_test.c Sat Jan 25 21:55:50 2020 +0300 | |
+++ b/src/test/njs_interactive_test.c Sun Jan 26 21:56:23 2020 +0300 | |
@@ -233,7 +233,10 @@ static njs_interactive_test_t njs_test[ | |
" at main (native)\n") }, | |
{ njs_str("var fs = require('fs');" | |
- "['readFile'," | |
+ "[" | |
+ " 'access'," | |
+ " 'accessSync'," | |
+ " 'readFile'," | |
" 'readFileSync'," | |
" 'writeFile'," | |
" 'writeFileSync'," | |
diff -r 7e1dda9c16c8 -r 9f95590b8bcf src/test/njs_unit_test.c | |
--- a/src/test/njs_unit_test.c Sat Jan 25 21:55:50 2020 +0300 | |
+++ b/src/test/njs_unit_test.c Sun Jan 26 21:56:23 2020 +0300 | |
@@ -15728,9 +15728,39 @@ static njs_unit_test_t njs_test[] = | |
".every((x) => x === true)"), | |
njs_str("true")}, | |
+ /* require('fs').access() */ | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "fs.access()"), | |
+ njs_str("TypeError: \"path\" must be a string") }, | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "fs.access('/njs_unknown_path')"), | |
+ njs_str("TypeError: \"callback\" must be a function") }, | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "fs.access('/njs_unknown_path', fs.constants.F_OK)"), | |
+ njs_str("TypeError: \"callback\" must be a function") }, | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "fs.access('/njs_unknown_path', 'fail', function () {})"), | |
+ njs_str("TypeError: \"mode\" must be a number") }, | |
+ | |
+ /* require('fs').accessSync() */ | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "fs.accessSync()"), | |
+ njs_str("TypeError: \"path\" must be a string") }, | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "fs.accessSync('/njs_unknown_path', 'fail')"), | |
+ njs_str("TypeError: \"mode\" must be a number") }, | |
+ | |
{ njs_str("var " | |
"fs = require('fs')," | |
"func = [" | |
+ "'access'," | |
+ "'accessSync'," | |
"'readFile'," | |
"'readFileSync'," | |
"'writeFile'," | |
@@ -15755,6 +15785,7 @@ static njs_unit_test_t njs_test[] = | |
{ njs_str("var " | |
"fs = require('fs').promises," | |
"func = [" | |
+ "'access'," | |
"'readFile'," | |
"'writeFile'," | |
"'appendFile'," | |
@@ -15762,6 +15793,23 @@ static njs_unit_test_t njs_test[] = | |
"func.every((x) => typeof fs[x] == 'function')"), | |
njs_str("true")}, | |
+ /* require('fs').constants */ | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "typeof fs.constants"), | |
+ njs_str("object") }, | |
+ | |
+ { njs_str("var " | |
+ "fsc = require('fs').constants," | |
+ "items = [" | |
+ "'F_OK'," | |
+ "'R_OK'," | |
+ "'W_OK'," | |
+ "'X_OK'," | |
+ "];" | |
+ "items.every((x) => typeof fsc[x] == 'number')"), | |
+ njs_str("true")}, | |
+ | |
/* require('crypto').createHash() */ | |
{ njs_str("var h = require('crypto').createHash('sha1');" | |
diff -r 7e1dda9c16c8 -r 9f95590b8bcf test/js/fs_promises_001.js | |
--- a/test/js/fs_promises_001.js Sat Jan 25 21:55:50 2020 +0300 | |
+++ b/test/js/fs_promises_001.js Sun Jan 26 21:56:23 2020 +0300 | |
@@ -15,10 +15,10 @@ Promise.resolve() | |
return fs.readFile(fname).then(fs.readFile); | |
}) | |
.then((data) => { | |
- console.log('short citcut ok', data == fname); | |
+ console.log('short circut ok', data == fname); | |
}) | |
.catch((e) => { | |
- console.log('short citcut failed', e); | |
+ console.log('short circut failed', e); | |
}) | |
.then(() => { | |
var read = fs.readFile.bind(fs, fname, 'utf8'); | |
diff -r 7e1dda9c16c8 -r 9f95590b8bcf test/js/fs_promises_002.js | |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | |
+++ b/test/js/fs_promises_002.js Sun Jan 26 21:56:23 2020 +0300 | |
@@ -0,0 +1,71 @@ | |
+var fs = require('fs'); | |
+var fsp = fs.promises; | |
+var fname = '/tmp/njs_fs_promises_002'; | |
+ | |
+var testSync = new Promise((resolve, reject) => { | |
+ var failed = false; | |
+ try { | |
+ fs.writeFileSync(fname, fname); | |
+ | |
+ fs.accessSync(fname); | |
+ fs.accessSync(fname, fs.constants.R_OK | fs.constants.W_OK); | |
+ | |
+ try { | |
+ fs.accessSync(fname + '___'); | |
+ failed = true; | |
+ } catch(e) { | |
+ failed = (e.syscall != 'access'); | |
+ // TODO: e.code != 'ENOENT' | |
+ } | |
+ resolve(failed); | |
+ } catch (e) { | |
+ reject(e); | |
+ } | |
+}); | |
+ | |
+var testCallback = new Promise((resolve, reject) => { | |
+ var failed = false; | |
+ | |
+ fs.writeFileSync(fname, fname); | |
+ | |
+ fs.access(fname, (err) => { | |
+ failed = (err !== undefined); | |
+ fs.access(fname, fs.constants.R_OK | fs.constants.W_OK, (err) => { | |
+ failed |= (err !== undefined); | |
+ fs.access(fname + '___', (err) => { | |
+ failed |= ((err === undefined) || (err.syscall != 'access')); | |
+ resolve(failed); | |
+ }); | |
+ }); | |
+ }); | |
+}); | |
+ | |
+Promise.resolve() | |
+.then(() => testSync) | |
+.then((failed) => { | |
+ console.log('testSync ok', !failed); | |
+}) | |
+.catch((e) => { | |
+ console.log('testSync failed', e); | |
+}) | |
+.then(() => testCallback) | |
+.then((failed) => { | |
+ console.log('testCallback ok', !failed); | |
+}) | |
+.catch((e) => { | |
+ console.log('testCallback failed', e); | |
+}) | |
+.then(() => { | |
+ fs.writeFileSync(fname, fname); | |
+ | |
+ return fsp.access(fname) | |
+ .then(() => fsp.access(fname, fs.constants.R_OK | fs.constants.W_OK)) | |
+ .then(() => fsp.access(fname + '___')); | |
+}) | |
+.then(() => { | |
+ console.log('testPromise failed'); | |
+}) | |
+.catch((e) => { | |
+ console.log('testPromise ok', (e.syscall == 'access') && (e.path == fname + '___')); | |
+}) | |
+; | |
diff -r 7e1dda9c16c8 -r 9f95590b8bcf test/njs_expect_test.exp | |
--- a/test/njs_expect_test.exp Sat Jan 25 21:55:50 2020 +0300 | |
+++ b/test/njs_expect_test.exp Sun Jan 26 21:56:23 2020 +0300 | |
@@ -1064,9 +1064,14 @@ PatchedPromise async done" | |
njs_run {"./test/js/fs_promises_001.js"} \ | |
"init ok true | |
-short citcut ok true | |
+short circut ok true | |
chain ok true | |
error 1 ok true | |
error 2 ok true | |
error 3 ok true | |
errors ok" | |
+ | |
+njs_run {"./test/js/fs_promises_002.js"} \ | |
+"testSync ok true | |
+testCallback ok true | |
+testPromise ok true" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Artem S. Povalyukhin <artem.povaluhin@gmail.com> | |
# Date 1579978550 -10800 | |
# Sat Jan 25 21:55:50 2020 +0300 | |
# Node ID 7e1dda9c16c89fd99525c7ae16822e34a99dfbcf | |
# Parent 2b75ee95558921179de9f53cceb63cea10de94c1 | |
Introduced fs.promises API. | |
diff -r 2b75ee955589 -r 7e1dda9c16c8 src/njs_fs.c | |
--- a/src/njs_fs.c Mon Jan 20 13:24:09 2020 +0300 | |
+++ b/src/njs_fs.c Sat Jan 25 21:55:50 2020 +0300 | |
@@ -48,7 +48,7 @@ static njs_int_t njs_fs_rename_sync(njs_ | |
static njs_int_t njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data, | |
njs_fs_ioerror_t *ioerror); | |
static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall, | |
- const char *description, njs_value_t *path, int errn, njs_value_t *retval); | |
+ const char *description, const njs_value_t *path, int errn, njs_value_t *retval); | |
static int njs_fs_flags(njs_str_t *value); | |
static mode_t njs_fs_mode(njs_value_t *value); | |
static njs_int_t njs_fs_add_event(njs_vm_t *vm, const njs_value_t *callback, | |
@@ -112,6 +112,94 @@ njs_fs_set_ioerr(njs_fs_ioerror_t *ioerr | |
static njs_int_t | |
+ngx_fs_promise_trampoline(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, | |
+ njs_index_t unused) | |
+{ | |
+ njs_value_t value; | |
+ | |
+ return njs_function_call(vm, njs_function(&args[1]), &njs_value_undefined, | |
+ &args[2], 1, &value); | |
+} | |
+ | |
+ | |
+static const njs_value_t promise_trampoline = | |
+ njs_native_function(ngx_fs_promise_trampoline, 2); | |
+ | |
+ | |
+/* | |
+ NJS_FS_DIRECT: vm->retval | ioerror | |
+ NJS_FS_CALLBACK: void, callback(ioerror [, vm->retval]) | |
+ NJS_FS_PROMISE: Promise<vm->retval | ioerror> | |
+*/ | |
+njs_inline njs_int_t | |
+njs_fs_return_result(njs_vm_t *vm, const njs_value_t *path, | |
+ const njs_fs_ioerror_t *ioerror, njs_index_t calltype, | |
+ const njs_value_t* callback, njs_bool_t is_void) | |
+{ | |
+ njs_int_t ret; | |
+ njs_bool_t is_ioerror; | |
+ njs_value_t result, promise, cb[2]; | |
+ const njs_value_t *first, *second; | |
+ | |
+ is_ioerror = (ioerror->desc != NULL); | |
+ if (njs_slow_path(is_ioerror)) { | |
+ ret = njs_fs_error(vm, ioerror->syscall, ioerror->desc, path, | |
+ ioerror->errn, &vm->retval); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return ret; | |
+ } | |
+ } | |
+ | |
+ if (njs_fast_path(calltype == NJS_FS_DIRECT)) { | |
+ return (is_ioerror) ? NJS_ERROR : NJS_OK; | |
+ } | |
+ | |
+ if (calltype == NJS_FS_PROMISE) { | |
+ result = vm->retval; | |
+ | |
+ ret = njs_vm_promise_create(vm, &promise, &cb[0]); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return ret; | |
+ } | |
+ | |
+ callback = &promise_trampoline; | |
+ first = (is_ioerror) ? &cb[1] : &cb[0]; | |
+ second = &result; | |
+ | |
+ ret = njs_fs_add_event(vm, callback, first, second); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return ret; | |
+ } | |
+ | |
+ /* njs_event.c:65 */ | |
+ vm->retval = promise; | |
+ | |
+ return NJS_OK; | |
+ } | |
+ | |
+ if (calltype == NJS_FS_CALLBACK) { | |
+ first = (is_ioerror) ? &vm->retval : &njs_value_undefined; | |
+ second = (is_ioerror) ? &njs_value_undefined | |
+ : ((is_void) ? NULL : &vm->retval); | |
+ | |
+ ret = njs_fs_add_event(vm, callback, first, second); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return ret; | |
+ } | |
+ | |
+ /* njs_event.c:65 */ | |
+ njs_set_undefined(&vm->retval); | |
+ | |
+ return NJS_OK; | |
+ } | |
+ | |
+ njs_internal_error(vm, "invalid calltype"); | |
+ | |
+ return NJS_ERROR; | |
+} | |
+ | |
+ | |
+static njs_int_t | |
njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, | |
njs_index_t calltype) | |
{ | |
@@ -124,7 +212,6 @@ njs_fs_read_file(njs_vm_t *vm, njs_value | |
const char *path; | |
struct stat sb; | |
const njs_value_t *callback, *options; | |
- njs_value_t err; | |
njs_object_prop_t *prop; | |
njs_lvlhsh_query_t lhq; | |
njs_fs_ioerror_t ioerror; | |
@@ -306,46 +393,7 @@ done: | |
(void) close(fd); | |
} | |
- if (njs_fast_path(calltype == NJS_FS_DIRECT)) { | |
- if (njs_slow_path(ioerror.desc != NULL)) { | |
- (void) njs_fs_error(vm, ioerror.syscall, ioerror.desc, | |
- &args[1], ioerror.errn, &vm->retval); | |
- return NJS_ERROR; | |
- } | |
- | |
- return NJS_OK; | |
- } | |
- | |
- if (calltype == NJS_FS_PROMISE) { | |
- njs_internal_error(vm, "promise callback is not implemented"); | |
- return NJS_ERROR; | |
- } | |
- | |
- if (calltype == NJS_FS_CALLBACK) { | |
- if (njs_slow_path(ioerror.desc)) { | |
- ret = njs_fs_error(vm, ioerror.syscall, ioerror.desc, | |
- &args[1], ioerror.errn, &err); | |
- if (njs_slow_path(ret != NJS_OK)) { | |
- return ret; | |
- } | |
- | |
- njs_set_undefined(&vm->retval); | |
- | |
- } else { | |
- njs_set_undefined(&err); | |
- } | |
- | |
- ret = njs_fs_add_event(vm, callback, &err, &vm->retval); | |
- if (njs_slow_path(ret != NJS_OK)) { | |
- return ret; | |
- } | |
- | |
- njs_set_undefined(&vm->retval); | |
- return NJS_OK; | |
- } | |
- | |
- njs_internal_error(vm, "invalid calltype"); | |
- return NJS_ERROR; | |
+ return njs_fs_return_result(vm, &args[1], &ioerror, calltype, callback, 0); | |
fail: | |
@@ -368,7 +416,7 @@ njs_fs_write_file(njs_vm_t *vm, njs_valu | |
njs_str_t data, flag, encoding; | |
njs_int_t ret; | |
const char *path; | |
- njs_value_t *mode, err; | |
+ njs_value_t *mode; | |
njs_fs_calltype_t calltype; | |
const njs_value_t *callback, *options; | |
njs_fs_ioerror_t ioerror; | |
@@ -509,45 +557,9 @@ done: | |
(void) close(fd); | |
} | |
- if (njs_fast_path(calltype == NJS_FS_DIRECT)) { | |
- if (njs_slow_path(ioerror.desc != NULL)) { | |
- (void) njs_fs_error(vm, ioerror.syscall, ioerror.desc, &args[1], | |
- ioerror.errn, &vm->retval); | |
- return NJS_ERROR; | |
- } | |
- | |
- njs_set_undefined(&vm->retval); | |
- return NJS_OK; | |
- } | |
- | |
- if (calltype == NJS_FS_PROMISE) { | |
- njs_internal_error(vm, "not implemented"); | |
- return NJS_ERROR; | |
- } | |
+ njs_set_undefined(&vm->retval); | |
- if (calltype == NJS_FS_CALLBACK) { | |
- if (ioerror.desc != NULL) { | |
- ret = njs_fs_error(vm, ioerror.syscall, ioerror.desc, &args[1], | |
- ioerror.errn, &err); | |
- if (njs_slow_path(ret != NJS_OK)) { | |
- return ret; | |
- } | |
- | |
- } else { | |
- njs_set_undefined(&err); | |
- } | |
- | |
- ret = njs_fs_add_event(vm, callback, &err, NULL); | |
- if (njs_slow_path(ret != NJS_OK)) { | |
- return ret; | |
- } | |
- | |
- njs_set_undefined(&vm->retval); | |
- return NJS_OK; | |
- } | |
- | |
- njs_internal_error(vm, "invalid calltype"); | |
- return NJS_ERROR; | |
+ return njs_fs_return_result(vm, &args[1], &ioerror, calltype, callback, 1); | |
} | |
@@ -647,7 +659,7 @@ njs_fs_fd_read(njs_vm_t *vm, int fd, njs | |
static njs_int_t | |
njs_fs_error(njs_vm_t *vm, const char *syscall, const char *description, | |
- njs_value_t *path, int errn, njs_value_t *retval) | |
+ const njs_value_t *path, int errn, njs_value_t *retval) | |
{ | |
size_t size; | |
njs_int_t ret; | |
@@ -836,6 +848,51 @@ memory_error: | |
} | |
+static const njs_object_prop_t njs_fs_promises_properties[] = | |
+{ | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("readFile"), | |
+ .value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_PROMISE), | |
+ .writable = 1, | |
+ .configurable = 1, | |
+ }, | |
+ | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("appendFile"), | |
+ .value = njs_native_function2(njs_fs_write_file, 0, | |
+ njs_fs_magic(NJS_FS_PROMISE, NJS_FS_APPEND)), | |
+ .writable = 1, | |
+ .configurable = 1, | |
+ }, | |
+ | |
+ { | |
+ .type = NJS_PROPERTY, | |
+ .name = njs_string("writeFile"), | |
+ .value = njs_native_function2(njs_fs_write_file, 0, | |
+ njs_fs_magic(NJS_FS_PROMISE, NJS_FS_TRUNC)), | |
+ .writable = 1, | |
+ .configurable = 1, | |
+ }, | |
+}; | |
+ | |
+ | |
+static const njs_object_init_t njs_fs_promises_init = { | |
+ njs_fs_promises_properties, | |
+ njs_nitems(njs_fs_promises_properties), | |
+}; | |
+ | |
+ | |
+static njs_int_t | |
+njs_fs_promises(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, | |
+ njs_value_t *unused, njs_value_t *retval) | |
+{ | |
+ return njs_object_prop_lazyinit(vm, &njs_fs_promises_init, prop, value, | |
+ retval); | |
+} | |
+ | |
+ | |
static const njs_object_prop_t njs_fs_object_properties[] = | |
{ | |
{ | |
@@ -846,6 +903,12 @@ static const njs_object_prop_t njs_fs_o | |
}, | |
{ | |
+ .type = NJS_PROPERTY_HANDLER, | |
+ .name = njs_string("promises"), | |
+ .value = njs_prop_handler(njs_fs_promises), | |
+ }, | |
+ | |
+ { | |
.type = NJS_PROPERTY, | |
.name = njs_string("readFile"), | |
.value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_CALLBACK), | |
diff -r 2b75ee955589 -r 7e1dda9c16c8 src/njs_object.h | |
--- a/src/njs_object.h Mon Jan 20 13:24:09 2020 +0300 | |
+++ b/src/njs_object.h Sat Jan 25 21:55:50 2020 +0300 | |
@@ -79,6 +79,8 @@ njs_int_t njs_object_prop_define(njs_vm_ | |
njs_int_t njs_object_prop_descriptor(njs_vm_t *vm, njs_value_t *dest, | |
njs_value_t *value, njs_value_t *setval); | |
const char *njs_prop_type_string(njs_object_prop_type_t type); | |
+njs_int_t njs_object_prop_lazyinit(njs_vm_t *vm, const njs_object_init_t* init, | |
+ const njs_object_prop_t *base, njs_value_t *value, njs_value_t *retval); | |
njs_inline njs_bool_t | |
diff -r 2b75ee955589 -r 7e1dda9c16c8 src/njs_object_prop.c | |
--- a/src/njs_object_prop.c Mon Jan 20 13:24:09 2020 +0300 | |
+++ b/src/njs_object_prop.c Sat Jan 25 21:55:50 2020 +0300 | |
@@ -826,3 +826,58 @@ njs_prop_type_string(njs_object_prop_typ | |
return "unknown"; | |
} | |
} | |
+ | |
+ | |
+njs_int_t | |
+njs_object_prop_lazyinit(njs_vm_t *vm, const njs_object_init_t* init, | |
+ const njs_object_prop_t *base, njs_value_t *value, njs_value_t *retval) | |
+{ | |
+ njs_int_t ret; | |
+ njs_object_t *object; | |
+ njs_object_prop_t *prop; | |
+ njs_lvlhsh_query_t lhq; | |
+ njs_str_t str; | |
+ | |
+ object = njs_object_alloc(vm); | |
+ if (object == NULL) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ ret = njs_object_hash_create(vm, &object->hash, init->properties, | |
+ init->items); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ prop = njs_mp_align(vm->mem_pool, sizeof(njs_value_t), | |
+ sizeof(njs_object_prop_t)); | |
+ if (njs_slow_path(prop == NULL)) { | |
+ njs_memory_error(vm); | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ *prop = *base; | |
+ | |
+ prop->type = NJS_PROPERTY; | |
+ njs_set_object(&prop->value, object); | |
+ | |
+ njs_string_get(&prop->name, &str); | |
+ | |
+ lhq.replace = 1; | |
+ lhq.pool = vm->mem_pool; | |
+ lhq.proto = &njs_object_hash_proto; | |
+ lhq.value = prop; | |
+ lhq.key = str; | |
+ lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); | |
+ | |
+ ret = njs_lvlhsh_insert(njs_object_hash(value), &lhq); | |
+ | |
+ if (njs_fast_path(ret == NJS_OK)) { | |
+ *retval = prop->value; | |
+ return NJS_OK; | |
+ } | |
+ | |
+ njs_internal_error(vm, "lvlhsh insert failed"); | |
+ | |
+ return NJS_ERROR; | |
+} | |
diff -r 2b75ee955589 -r 7e1dda9c16c8 src/test/njs_unit_test.c | |
--- a/src/test/njs_unit_test.c Mon Jan 20 13:24:09 2020 +0300 | |
+++ b/src/test/njs_unit_test.c Sat Jan 25 21:55:50 2020 +0300 | |
@@ -15746,6 +15746,22 @@ static njs_unit_test_t njs_test[] = | |
"func.map(test).every((x) => x)"), | |
njs_str("true")}, | |
+ /* require('fs').promises */ | |
+ | |
+ { njs_str("var fs = require('fs');" | |
+ "typeof fs.promises"), | |
+ njs_str("object") }, | |
+ | |
+ { njs_str("var " | |
+ "fs = require('fs').promises," | |
+ "func = [" | |
+ "'readFile'," | |
+ "'writeFile'," | |
+ "'appendFile'," | |
+ "];" | |
+ "func.every((x) => typeof fs[x] == 'function')"), | |
+ njs_str("true")}, | |
+ | |
/* require('crypto').createHash() */ | |
{ njs_str("var h = require('crypto').createHash('sha1');" | |
diff -r 2b75ee955589 -r 7e1dda9c16c8 test/js/fs_promises_001.js | |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | |
+++ b/test/js/fs_promises_001.js Sat Jan 25 21:55:50 2020 +0300 | |
@@ -0,0 +1,60 @@ | |
+var fs = require('fs').promises; | |
+var fname = '/tmp/njs_fs_promises_001'; | |
+ | |
+Promise.resolve() | |
+.then(() => { | |
+ return fs.writeFile(fname, fname); | |
+}) | |
+.then((data) => { | |
+ console.log('init ok', data === undefined); | |
+}) | |
+.catch((e) => { | |
+ console.log('init failed', e); | |
+}) | |
+.then(() => { | |
+ return fs.readFile(fname).then(fs.readFile); | |
+}) | |
+.then((data) => { | |
+ console.log('short citcut ok', data == fname); | |
+}) | |
+.catch((e) => { | |
+ console.log('short citcut failed', e); | |
+}) | |
+.then(() => { | |
+ var read = fs.readFile.bind(fs, fname, 'utf8'); | |
+ var write = fs.writeFile.bind(fs, fname); | |
+ var append = fs.appendFile.bind(fs, fname); | |
+ | |
+ return write(fname).then(read).then(append).then(read); | |
+}) | |
+.then((data) => { | |
+ console.log('chain ok', data == (fname + fname)); | |
+}) | |
+.catch((e) => { | |
+ console.log('chain failed', e); | |
+}) | |
+.then(() => { | |
+ // nodejs incompatible | |
+ try { | |
+ return fs.readFile(); | |
+ } catch (e) { | |
+ console.log('error 1 ok', e instanceof TypeError) | |
+ } | |
+ try { | |
+ return fs.writeFile(); | |
+ } catch (e) { | |
+ console.log('error 2 ok', e instanceof TypeError) | |
+ } | |
+ try { | |
+ return fs.writeFile(fname); | |
+ } catch (e) { | |
+ console.log('error 3 ok', e instanceof TypeError) | |
+ } | |
+}) | |
+.then((data) => { | |
+ console.log('errors ok'); | |
+}) | |
+.catch((e) => { | |
+ console.log('errors failed - reject on bad args'); | |
+}) | |
+; | |
diff -r 2b75ee955589 -r 7e1dda9c16c8 test/njs_expect_test.exp | |
--- a/test/njs_expect_test.exp Mon Jan 20 13:24:09 2020 +0300 | |
+++ b/test/njs_expect_test.exp Sat Jan 25 21:55:50 2020 +0300 | |
@@ -1061,3 +1061,12 @@ PatchedPromise.constructor | |
PatchedPromise.constructor | |
PatchedPromise.constructor | |
PatchedPromise async done" | |
+ | |
+njs_run {"./test/js/fs_promises_001.js"} \ | |
+"init ok true | |
+short citcut ok true | |
+chain ok true | |
+error 1 ok true | |
+error 2 ok true | |
+error 3 ok true | |
+errors ok" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment