Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TypeScript types for modules #342

Closed
wants to merge 5 commits into from
Closed

Conversation

jirutka
Copy link
Contributor

@jirutka jirutka commented Oct 9, 2020

Questions:

  • What is type BufferArrayBuffer or some custom type?
  • Where should be used NjsStringLike and where string?

Patch: https://patch-diff.githubusercontent.com/raw/nginx/njs/pull/342.patch

@jirutka jirutka changed the title WIP: Add TypeScript types for modules Add TypeScript types for modules Oct 11, 2020
@jirutka
Copy link
Contributor Author

jirutka commented Oct 14, 2020

@xeioex, could you please give me some feedback and answer the questions above?

@xeioex
Copy link
Contributor

xeioex commented Oct 14, 2020

@jirutka

Sorry for delay, I plan to return to your merge request later.

What is type Buffer – ArrayBuffer or some custom type?

No, it replicates API for node.js Buffer

NjsStringLike

Basically it is a pseudotype for TS, which says that some function accepts both string and NjsByteString.

In the future, we plan to get rid of NjsByteString (as a non-standard type) in favour of Buffer.

@xeioex
Copy link
Contributor

xeioex commented Oct 14, 2020

@jirutka

Regarding the modules API, we are trying to follow the original API for them, can't we just copy the existing API description for them?

@xeioex xeioex added the docs label Oct 14, 2020
@jirutka
Copy link
Contributor Author

jirutka commented Oct 14, 2020

Thanks for the quick response!

No, it replicates API for node.js Buffer

Okay, I will update the type definitions.

Basically it is a pseudotype for TS, which says that some function accepts both string and NjsByteString.

I understand that. I just don’t know how to recognize what functions accept/return NjsByteString and what functions just plain string.

Regarding the modules API, we are trying to follow the original API for them, can't we just copy the existing API description for them?

You mean Node.js API? You don’t follow them fully, there are some minor differences (e.g. missing functions, some extra arguments not supported, limited set of encodings etc.). It’s more a subset of them. The TS types must to be accurate to be useful.

BTW, I have copied JSDoc comments from http://nginx.org/en/docs/njs/reference.html, not Node.js docs, both due to differences and to avoid potential legal issues (not sure if there are any, just to be sure).

@jirutka
Copy link
Contributor Author

jirutka commented Oct 14, 2020

No, it replicates API for node.js Buffer

Node’s Buffer has quite a large API surface – does njs support all of its (non-deprecated) methods with all arguments? What encodings does it support?

@xeioex
Copy link
Contributor

xeioex commented Oct 14, 2020

@jirutka

I just don’t know how to recognize what functions accept/return NjsByteString and what functions just plain string.

yes, that is the point of deprecation of NjsByteString type.

Currently, we basically have two types string and NjsByteString implemented in a single String.prototype.

The only difference is the way they treat characters.
NjsByteString - a character is always a single byte.
string - a character is a UTF8 codepoint (this is not the same as UTF16 from the spec, but the visible difference is pretty negligible, only rarely used surrogate pairs are affected).

String.prototype.toUTF8(), and String.prototype.fromUTF8() are used to convert in both directions.

@xeioex
Copy link
Contributor

xeioex commented Oct 14, 2020

@jirutka

Node’s Buffer has quite a large API surface – does njs support all of its (non-deprecated) methods with all arguments? What encodings does it support?

We plan to release the documentation for it by the end of this week.
Most of the (non-deprecated) methods are supported.

With the exception of: buf.keys(), buf.entries(), buf.values(), buf.readBigInt64BE() (and other BigInt methods).

The available encodings are: utf8, hex, base64, base64url.

@jirutka
Copy link
Contributor Author

jirutka commented Oct 14, 2020

BTW, I haven’t tested it yet, but it should be possible to generate TS types and HTML documentation from TSDoc comments included directly in the .c files. This would help keep implementation, types and documentation in-sync. Would you be interested in this approach?

@xeioex
Copy link
Contributor

xeioex commented Oct 14, 2020

@jirutka

It would be great if you share a working POC (using a .c file and TSDoc).

@xeioex
Copy link
Contributor

xeioex commented Oct 16, 2020

http://nginx.org/en/docs/njs/reference.html#buffer - Buffer docs.

@jirutka
Copy link
Contributor Author

jirutka commented Oct 16, 2020

Okay, I’ve just added the Buffer type to this PR.

@jirutka jirutka force-pushed the types branch 3 times, most recently from cc5e787 to 2496cce Compare October 17, 2020 00:00
@jirutka
Copy link
Contributor Author

jirutka commented Oct 17, 2020

If I understand njs_buffer.c correctly, Buffer.prototype.write returns number, but all write* methods for numbers return void. However, in Node’s Buffer, all write* methods return number. Is this intentional…?

@lexborisov
Copy link
Contributor

lexborisov commented Oct 17, 2020

Hi @jirutka

This is my mistake, I will fix it soon.
Thanks for the report!

@lexborisov
Copy link
Contributor

@jirutka

Try this patch:

# HG changeset patch
# User Alexander Borisov <alexander.borisov@nginx.com>
# Date 1602919869 -10800
#      Sat Oct 17 10:31:09 2020 +0300
# Node ID b4429c95c89a1b54da3450aef85db96d0f650d23
# Parent  a82f123409b7c0c8b97417e11dffde523018ed30
Fixed returned value for Buffer.prototype.write* functions.

All Buffer.prototype.write* functions must return offset plus
the number of bytes written.

The issue was introduced in 27bb9caf186c.

diff -r a82f123409b7 -r b4429c95c89a src/njs_buffer.c
--- a/src/njs_buffer.c	Tue Oct 13 15:44:33 2020 +0300
+++ b/src/njs_buffer.c	Sat Oct 17 10:31:09 2020 +0300
@@ -1331,7 +1331,7 @@ njs_buffer_prototype_write_int(njs_vm_t 
         break;
     }
 
-    njs_set_undefined(&vm->retval);
+    njs_set_number(&vm->retval, index + size);
 
     return NJS_OK;
 }
diff -r a82f123409b7 -r b4429c95c89a src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Tue Oct 13 15:44:33 2020 +0300
+++ b/src/test/njs_unit_test.c	Sat Oct 17 10:31:09 2020 +0300
@@ -19191,7 +19191,11 @@ static njs_unit_test_t  njs_test[] =
               "        if (size > 1) { rmethod += endianness; wmethod += endianness; };"
               "        var v = 0x7abbccddeeff & (size * 8 - 1);"
               ""
-              "        buf[wgmethod](v, offset, size);"
+              "        var ret = buf[wgmethod](v, offset, size);"
+              "        if(ret !== offset + size) {"
+              "            throw Error(`${wgmethod} returned ${ret}, need ${offset + size}`);"
+              "        }"
+              ""
               "        var gv = buf[rgmethod](offset, size);"
               ""
               "        buf.fill(0);"

@jirutka jirutka force-pushed the types branch 2 times, most recently from 2443e3c to fd5c0c7 Compare October 18, 2020 17:25
src/ts/fs.d.ts Outdated Show resolved Hide resolved
src/ts/fs.d.ts Outdated Show resolved Hide resolved
@jirutka
Copy link
Contributor Author

jirutka commented Oct 18, 2020

I’ve polished it a bit and I think that it’s ready.

@jirutka jirutka force-pushed the types branch 3 times, most recently from f74ca06 to 033ce0a Compare October 18, 2020 17:56
src/ts/njs_core.d.ts Outdated Show resolved Hide resolved
src/ts/njs_core.d.ts Outdated Show resolved Hide resolved
src/ts/njs_core.d.ts Show resolved Hide resolved
@jirutka jirutka force-pushed the types branch 2 times, most recently from 372811f to 8f4fc6d Compare October 19, 2020 19:07
@drsm
Copy link
Contributor

drsm commented Oct 19, 2020

@xeioex
@jirutka

Hi!

Looks like all the paths in fs module should be of type export type PathLike = string | Buffer instead of NjsStringLike

@jirutka
Copy link
Contributor Author

jirutka commented Oct 19, 2020

I’ve fixed all the mentioned issues in the crypto and querystring modules.

It seems that NjsStringLike is used basically as in input type only (function parameters), not as the return type, right? If so, the following in the fs module should be changed too, right?

- readFileSync(path: NjsStringLike, options: { encoding?: FileEncoding; flag?: OpenMode; } | FileEncoding): NjsStringLike;
+ readFileSync(path: NjsStringLike, options: { encoding?: FileEncoding; flag?: OpenMode; } | FileEncoding): string;
- readdirSync(path: NjsStringLike, options?: { encoding?: "utf8"; withFileTypes?: false; } | "utf8"): NjsStringLike[];
+ readdirSync(path: NjsStringLike, options?: { encoding?: "utf8"; withFileTypes?: false; } | "utf8"): string[];
- realpathSync(path: NjsStringLike, options?: { encoding?: "utf8" } | "utf8"): NjsStringLike;
+ realpathSync(path: NjsStringLike, options?: { encoding?: "utf8" } | "utf8"): string;
- readFile(path: NjsStringLike, options: { encoding?: FileEncoding; flag?: OpenMode; } | FileEncoding): Promise<NjsStringLike>;
+ readFile(path: NjsStringLike, options: { encoding?: FileEncoding; flag?: OpenMode; } | FileEncoding): Promise<string>;
- readdir(path: NjsStringLike, options?: { encoding?: "utf8"; withFileTypes?: false; } | "utf8"): Promise<NjsStringLike[]>;
+ readdir(path: NjsStringLike, options?: { encoding?: "utf8"; withFileTypes?: false; } | "utf8"): Promise<string[]>;
- realpath(path: NjsStringLike, options?: { encoding?: "utf8" } | "utf8"): Promise<NjsStringLike>;
+ realpath(path: NjsStringLike, options?: { encoding?: "utf8" } | "utf8"): Promise<string>;

I’ve also changed Buffer module to extend Uint8Array (as in Node.js) and accept Uint8Array instead of Buffer (its subtype) in relevant functions, after I’ve noticed in njs shell that it really behaves in the same way as in Node regarding Uint8Array.

@xeioex
Copy link
Contributor

xeioex commented Oct 19, 2020

It seems that NjsStringLike is used basically as in input type only (function parameters), not as the return type, right?

@jirutka yes, since 0.4.4 "fs" method ensures that ordinary string are returned (as a part of the plan to eliminate NjsByteString).

But, still NjsByteString can be created with deprecated method String.bytesFrom() (will be removed in the future).

Created according to http://nginx.org/en/docs/njs/reference.html.

Signed-off-by: Jakub Jirutka <jakub@jirutka.cz>
@jirutka
Copy link
Contributor Author

jirutka commented Oct 19, 2020

Okay, updated: all the path parameters accept PathLike (PathLike = string | Buffer), functions don’t return NjsStringLike, but string, NjsStringLike is used only for the input data parameters.

I’ve also tagged String.bytesFrom() as @deprecated.

src/ts/fs.d.ts Outdated Show resolved Hide resolved
Created according to http://nginx.org/en/docs/njs/reference.html.

Signed-off-by: Jakub Jirutka <jakub@jirutka.cz>
Created according to http://nginx.org/en/docs/njs/reference.html.

Signed-off-by: Jakub Jirutka <jakub@jirutka.cz>
Created according to http://nginx.org/en/docs/njs/reference.html.

Signed-off-by: Jakub Jirutka <jakub@jirutka.cz>
@@ -66,7 +66,7 @@ interface NginxStreamVariables {
readonly 'time_iso8601'?: NjsByteString;
readonly 'time_local'?: NjsByteString;

[prop: string]: NjsByteString;
[prop: string]: NjsByteString | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jirutka Can you share the exact code snippet that causes the issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it’s part of #344:

git clone -b njs-types-pkg git@github.com:jirutka/njs.git
cd njs/ts
npm install
npm test

The problem is that you’re running tsc with the defaults – backward compatible settings that are very lax and shouldn’t be used for any new projects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for mixing this commit into this PR, I should have created a new PR for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m gonna move this commit into #344 and close this PR, ’cause it has been already merged, except this one.

@xeioex
Copy link
Contributor

xeioex commented Oct 20, 2020

@jirutka BTW, is there a proper way to reference internal types like Hash? https://github.com/nginx/njs/blob/master/test/ts/test.ts#L87

Something like:

var h:Hash;

h = crypto.createHash('sha1');

@jirutka
Copy link
Contributor Author

jirutka commented Oct 20, 2020

@jirutka BTW, is there a proper way to reference internal types like Hash? https://github.com/nginx/njs/blob/master/test/ts/test.ts#L87

Something like:

var h:Hash;

h = crypto.createHash('sha1');

Well, Hash is exported, so it’s not an internal type, you can just import it:

import crypto, { Hash } from 'crypto'

const h: Hash = crypto.createHash('sha1')

TypeScript will automatically remove named imports of types from the generated ES2015 code.

@jirutka
Copy link
Contributor Author

jirutka commented Oct 22, 2020

Merged in 993e7a8, 20c02d0, ef46a05, e246283, fb7ba09.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants