Skip to content

Instantly share code, notes, and snippets.

@drsm
Last active January 26, 2020 18:56
Show Gist options
  • Save drsm/d950402101765c7395c36cb4051576ba to your computer and use it in GitHub Desktop.
Save drsm/d950402101765c7395c36cb4051576ba to your computer and use it in GitHub Desktop.
# 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"
# 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