-
Notifications
You must be signed in to change notification settings - Fork 17
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
feat!: export object instead of default export #16
Conversation
Default exports don't work well with CommonJS and TypeScript. Hence replace the default export with an object export. BREAKING CHANGE: import of dag-cbor changed Prior to this change this module was imported as ```js import dagcbor from '@ipld/dag-cbor' ``` Now it is imported as ```js import * as dagcbor from `@ipld/dag-cbor' ```
This is a change along the lines of multiformats/js-multiformats#70. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but could you please make sure that name
and code
will get dag-cbor
and 0x71
as types as opposed to string
and number
. Comment in the diff suggests multiple ways to do it.
@@ -104,4 +104,7 @@ function decode (data) { | |||
return cborg.decode(data, decodeOptions) | |||
} | |||
|
|||
export default codec({ name, code, encode, decode }) | |||
const decoder = new Decoder(name, code, decode) | |||
const encoder = new Encoder(name, code, encode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d suggest following instead:
export const {name, code, encode, decode, encoder, decoder} = codec({ name, code, encode, decode })
That is because this would result in code
and name
getting types for corresponding literals as opposed to generalized number
and string
they get here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
annotating those at definition site is also another option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export const {name, code, encode, decode, encoder, decoder} = codec({ name, code, encode, decode })
I tried that. But it fails to build (SyntaxError: Identifier 'name' has already been declared (112:14)
). I thought it's a JS error, but now I realize it's probably a problem of our toolchain. I get:
$ npm run build
> @ipld/dag-cbor@0.0.0-dev build
> npm run build:js && npm run build:types
> @ipld/dag-cbor@0.0.0-dev build:js
> npm_config_yes=true npx ipjs@latest build --tests
parsing file:///home/vmx/src/pl/js-dag-cbor/index.js
file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:3010
var err = new SyntaxError(message);
^
SyntaxError: Identifier 'name' has already been declared (112:14)
at Parser.pp$4.raise (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:3010:13)
at Parser.pp$5.declareName (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:3084:26)
at Parser.pp$2.checkLValSimple (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1899:48)
at Parser.pp$2.checkLValPattern (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1941:10)
at Parser.pp$2.checkLValInnerPattern (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1963:10)
at Parser.pp$2.checkLValInnerPattern (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1951:10)
at Parser.pp$2.checkLValPattern (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1928:10)
at Parser.pp$1.parseVarId (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1256:8)
at Parser.pp$1.parseVar (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1238:10)
at Parser.pp$1.parseVarStatement (file:///home/vmx/.npm/_npx/ef1ca190cb7ddd1d/node_modules/acorn/dist/acorn.mjs:1104:8) {
pos: 2740,
loc: Position { line: 112, column: 14 },
raisedAt: 2787
}
So I guess annotating them is the quicker way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a JS thing, I tried with Node.js:
$ node index.js
file:///home/vmx/src/pl/js-dag-cbor/index.js:112
export const {name, code, encode, decode, encoder, decoder} = codec({ name, code, encode, decode })
^
SyntaxError: Identifier 'name' has already been declared
at Loader.moduleStrategy (node:internal/modules/esm/translators:147:18)
at async link (node:internal/modules/esm/module_job:48:21)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried that. But it fails to build (
SyntaxError: Identifier 'name' has already been declared (112:14)
). I thought it's a JS error, but now I realize it's probably a problem of our toolchain.
Ah that makes sense because we define const name
and const code
so it rejects const { name, code ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @rvagg made a change to a codec
function so that it returns encoder
and decoder
fields, with that following should work:
export const { name, code, decoder, encoder } = codec({ name: 'dag-cbor', code: 0x71, encode, decode })
@@ -104,4 +104,7 @@ function decode (data) { | |||
return cborg.decode(data, decodeOptions) | |||
} | |||
|
|||
export default codec({ name, code, encode, decode }) | |||
const decoder = new Decoder(name, code, decode) | |||
const encoder = new Encoder(name, code, encode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @rvagg made a change to a codec
function so that it returns encoder
and decoder
fields, with that following should work:
export const { name, code, decoder, encoder } = codec({ name: 'dag-cbor', code: 0x71, encode, decode })
|
||
// https://github.com/ipfs/go-ipfs/issues/3570#issuecomment-273931692 | ||
const CID_CBOR_TAG = 42 | ||
/** @type {number} */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to use actual literal type here, so TS won't generalize it to number.
/** @type {number} */ | |
/** @type {0x71} */ |
Note: This is not needed if codec({ code: 0x71, ...
is used as TS can infer that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now that's a weird annotation!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without the annotation it also isn't generalaized. @Gozala I misunderstood you, I thought you want that generalization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m pretty sure TS generalizes type of code in export const code = 0x71
to number.
it did not generalized it in original code codec({ code: 0x71, ... })
because codec
user generics.
I apologize for confusion, but I do want non generalized types as it helps with compositions allowing codecs to reject incompatible blocks at compile time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. The code (without the generalization) produces:
export const name: "dag-cbor";
export const code: 113;
which I thought is a sign that it would also use those specific types directly and not the generalized ones. The reason why I though it is that the generalized version produces:
/** @type {string} */
export const name: string;
/** @type {number} */
export const code: number;
which is clearly generalized.
@Gozala I just checked it with your proposed type annotations, it produces:
/** @type {'dag-cbor'} */
export const name: 'dag-cbor';
/** @type {0x71} */
export const code: 0x71;
Isn't that the same as the non-generalized version?
Anyway, please tell me which version, the one without any type annotion or the one with your type annotation, would be preferred and I'll push an updated version.
const code = 0x71 | ||
/** @type {string} */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** @type {string} */ | |
/** @type {'dag-cbor'} */ |
building further on this in #18 |
squashed this into #18 and published |
Default exports don't work well with CommonJS and TypeScript. Hence replace
the default export with an object export.
BREAKING CHANGE: import of dag-cbor changed
Prior to this change this module was imported as
Now it is imported as