-
Notifications
You must be signed in to change notification settings - Fork 257
test(NODE-4976): ensure all use of BigInt is gated by the useBigInt64 flag #558
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
test(NODE-4976): ensure all use of BigInt is gated by the useBigInt64 flag #558
Conversation
…d' of github.com:mongodb/js-bson into NODE-4976/add_tests_to_ensure_bigint_features_are_unused
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.
forgot to publish my changes yesterday
@@ -0,0 +1,20 @@ | |||
module.exports = { |
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.
Currently, all BigInt usage is guarded behind useBigInt64
, but we should use this lint rule to enforce that for the future. If we only check for literal syntax, future changes that add construction of BigInts programmatically might not be guarded behind the same flag.
Each usage of bigints, literal syntax or programatic construction, should just ignore the lint rule and explain why it's valid to ignore it in that scenario.
@@ -0,0 +1,14 @@ | |||
const { rules } = require('../index'); |
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 we should add infrastructure to test the eslint plugins during our testing runs. Maybe a npm run check:-plugins
command in the root package.json, that runs the plugin tests. These should be incorporated into our regular test runs and CI.
test/node/bigint.test.ts
Outdated
let getBigInt64Calls = 0; | ||
let setBigInt64Calls = 0; | ||
let getBigUint64Calls = 0; | ||
let setBigUint64Calls = 0; | ||
before(function () { | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const { _, exports } = loadCJSModuleBSON({ | ||
BigInt: null, | ||
DataView: class extends DataView { | ||
getBigInt64(byteOffset: number, littleEndian?: boolean): bigint { | ||
getBigInt64Calls += 1; | ||
return super.getBigInt64(byteOffset, littleEndian); | ||
} | ||
getBigUint64(byteOffset: number, littleEndian?: boolean): bigint { | ||
getBigUint64Calls += 1; | ||
return super.getBigUint64(byteOffset, littleEndian); | ||
} | ||
setBigUint64(byteOffset: number, value: bigint, littleEndian?: boolean): void { | ||
setBigUint64Calls += 1; | ||
super.setBigUint64(byteOffset, value, littleEndian); | ||
} | ||
setBigInt64(byteOffset: number, value: bigint, littleEndian?: boolean): void { | ||
setBigInt64Calls += 1; | ||
super.setBigInt64(byteOffset, value, littleEndian); | ||
} | ||
} | ||
}); |
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.
from slack: investigate using sinon
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.
Mostly minor comments, nice job. CI looks good too
package.json
Outdated
"build": "npm run build:dts && npm run build:bundle", | ||
"check:lint": "eslint -v && eslint --ext '.js,.ts' --max-warnings=0 src test && npm run build:dts && npm run check:tsd", | ||
"format": "eslint --ext '.js,.ts' src test --fix", | ||
"check:lint": "npm run build:eslint-plugin && eslint -v && eslint --ext '.js,.ts' --max-warnings=0 src test && npm run build:dts && npm run check:tsd", | ||
"format": "npm run build:eslint-plugin && eslint --ext '.js,.ts' src test --fix", | ||
"check:coverage": "nyc --check-coverage npm run check:node", | ||
"prepare": "node etc/prepare.js", |
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.
are the changes here necessary? running npm install
installs dependencies for all dependencies listed in the package.json. since the plugin is listed as a dev dependency, npm i
will install its dependencies as well.
x = BigInt.asUintN(64, 10n); | ||
x = BigInt.toString(10n); | ||
x = BigInt.valueOf(10n); | ||
x = BigInt.whatever(); |
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.
x = BigInt.whatever(); | |
x = BigInt.toLocaleString(); |
We may as well test all 5 static bigint methods if we're going to test 4.
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.
Testing for this case would be somewhat different as BigInt.toLocaleString
is an instance method and we'd have to know beforehand that the value the method is being called is a bigint.
This should be possible, but would require a refactor of the plugin to make use of ts-parser, which I could look more into.
Edit:
Just realized that this also applies to BigInt.toString
and BigInt.valueOf
. I think that for now having the check that we never instantiate a BigInt directly via the contructor or via a literal covers these cases, but as mentioned, I am also willing to look into seeing how much more difficult working with ts-parser
would be.
etc/eslint/no-bigint-usage/README.md
Outdated
@@ -0,0 +1,5 @@ | |||
# no-bigint-literals |
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.
let's update the title and description here to the new package name
@@ -86,10 +87,11 @@ | |||
}, | |||
"scripts": { | |||
"pretest": "npm run build", | |||
"test": "npm run check:node && npm run check:web", | |||
"test": "npm run check:node && npm run check:web && npm run check:web-no-bigint", |
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.
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.
The codepaths are largely the same (we mostly take a different path for Buffer
related things). I think this is sufficient. I'm mainly concerned with the core serialization / deserialization / EJSON.stringification / EJSON.parsing, which is mostly the same across Node and web.
…tic methods and constructor to eslint builtin rule
Summarizing a Slack conversation with @baileympearson: We do not need a custom lint rule to prevent the usage of the const obj = BigInt; // Unexpected use of 'BigInt' no-restricted-globals
obj.asUint64(64, obj(10)); by reporting an error on the assignment. It is also not necessary to add linting rules on the instance methods of BigInt as running out test suite with BigInt and associated APIs set to null will flag any instances where we are using BigInt functionality that would negatively affect users in restricted environments. In addition, since we prevent calls to the BigInt constructor and use of bigint literals, we should not encounter the use of instance methods outside of APIs that expect to take bigints as inputs (for example serializing a user-provided object that has a bigint field) and so should not pose a problem. For sake of completeness, the point about instance methods also applies to the use of |
src/extended_json.ts
Outdated
@@ -93,6 +93,7 @@ function deserializeValue(value: any, options: EJSONOptions = {}) { | |||
} | |||
if (in64BitRange) { | |||
if (options.useBigInt64) { | |||
// eslint-disable-next-line no-restricted-globals |
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.
One comment, one question
- Let's add a comment explaining why we're disabling the rule here. With the custom bigint plugin, it was obvious, but now that we're relying on
no-restricted-globals
, it's no longer obvious why the linter is disabled for these lines. - Related to the above - can we configure
no-restricted-globals
to always require an additional message / description of why we're ignoring the rule? It would be nice if we could enforce that when lint rules are skipped, the justification is explained.
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.
From what I'm reading so far, the only way to do this would be to write a custom rule that checks contents of comments for the eslint-disable
and eslint-disable-next-line
directives and report when they don't contain what usually is an optional description.
Relevant documentation: https://eslint.org/docs/latest/use/configure/rules#comment-descriptions
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.
small comment
Description
We would like js-bson to be usable in environments which do not support BigInt and so it is important to ensure that any use of BigInt features in the library should be gated by the
useBigInt64
flag.What is changing?
test/node/bigint.test.ts
to be skipped when BigInt is not availablepackage.json
andpackage-lock.json
to install eslint plugin.eslintrc.json
to enable eslint plugin to fail on the usage of BigInt literals and functions so that builds fail when BigInt features are used without explicitly adding aneslint-disable
comment above the line using these featuresIs there new documentation needed for these changes?
No
Double check the following
npm run lint
scripttype(NODE-xxxx)[!]: description
feat(NODE-1234)!: rewriting everything in coffeescript