-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(testcontainers | json): add testcontainers and jellyfish json to…
… standard (#482) * feat(testcontainers): add testcontainers to standard * fix lint * update i9n * include jellyfish json to standard * remove build info * add buildinfo to git ignore
- Loading branch information
Showing
53 changed files
with
4,003 additions
and
106 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,3 +21,6 @@ coverage | |
|
||
# turborepo | ||
.turbo | ||
|
||
# typescript | ||
tsconfig.build.tsbuildinfo |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Eslint Config | ||
|
||
`@ordzaar/eslint-config` | ||
|
||
Within your `package.json`: | ||
|
||
```json | ||
{ | ||
"eslintConfig": { | ||
"extends": ["@ordzaar"], | ||
"parserOptions": { | ||
"project": "./tsconfig.json" | ||
} | ||
} | ||
} | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
module.exports = { | ||
extends: [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"airbnb-base", | ||
"airbnb-typescript/base", | ||
"prettier", | ||
], | ||
plugins: ["simple-import-sort", "check-file", "unused-imports", "prettier"], | ||
parser: "@typescript-eslint/parser", | ||
rules: { | ||
"@typescript-eslint/no-floating-promises": "error", | ||
"no-console": "error", | ||
curly: "error", | ||
"max-classes-per-file": "off", | ||
"class-methods-use-this": "off", | ||
"no-await-in-loop": "off", | ||
// functions and classes are going to be hoisted in runtime, but don't let var be used before declaration | ||
"@typescript-eslint/no-use-before-define": ["error", { functions: false, classes: false, variables: true }], | ||
|
||
// Fix airbnb-typescript/base rule to allow leading underscores for unused vars | ||
"@typescript-eslint/naming-convention": [ | ||
"error", | ||
{ | ||
selector: "variable", | ||
format: ["camelCase", "PascalCase", "UPPER_CASE"], | ||
leadingUnderscore: "allow", | ||
}, | ||
{ | ||
selector: "function", | ||
format: ["camelCase", "PascalCase"], | ||
}, | ||
{ | ||
selector: "typeLike", | ||
format: ["PascalCase"], | ||
}, | ||
], | ||
/** | ||
* Separates out the `no-unused-vars` rule depending on it being an import statement in the AST and providing | ||
* an auto-fix rule to remove the nodes if they are imports. | ||
* With this, we can now target test files with `'unused-imports/no-unused-vars': 'off'` for testing DX. | ||
*/ | ||
"@typescript-eslint/no-unused-vars": "off", | ||
"unused-imports/no-unused-imports": "error", | ||
"unused-imports/no-unused-vars": [ | ||
"error", | ||
{ | ||
argsIgnorePattern: "^_", | ||
varsIgnorePattern: "^_", | ||
caughtErrorsIgnorePattern: "^_", | ||
}, | ||
], | ||
|
||
// import sort | ||
"sort-imports": "off", | ||
"import/order": "off", | ||
"simple-import-sort/imports": "error", | ||
"simple-import-sort/exports": "error", | ||
|
||
// To be overridden by each project | ||
"check-file/filename-naming-convention": "off", | ||
}, | ||
overrides: [ | ||
{ | ||
files: ["**/*.{test,spec,unit,i9n,e2e}.{js,ts}"], | ||
rules: { | ||
"@typescript-eslint/no-floating-promises": 0, | ||
/** | ||
* To cater for complex test scenarios, where we need to scope blocks. This allows variables to be reused, | ||
* so we don't have to create `const getObject` and `const updatedObject` for each scenario. | ||
* We can just use `const object`. | ||
*/ | ||
"no-lone-blocks": "off", | ||
|
||
/** | ||
* Separates out the `no-unused-vars` rule depending on it being an import statement in the AST and providing | ||
* an auto-fix rule to remove the nodes if they are imports. | ||
* With this, we can now target test files with `'unused-imports/no-unused-vars': 'off'` for testing DX. | ||
*/ | ||
"unused-imports/no-unused-imports": "error", | ||
"unused-imports/no-unused-vars": "off", | ||
}, | ||
}, | ||
], | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"name": "@ordzaar/eslint-config", | ||
"version": "0.0.0", | ||
"main": "index.js", | ||
"files": [ | ||
"index.js" | ||
], | ||
"dependencies": { | ||
"@ordzaar/standard-linter": "workspace:*" | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# @ordzaar/jellyfish-json | ||
|
||
`JellyfishJSON` allows parsing of JSON with `'lossless'`, `'bignumber'` and `'number'` numeric precision. | ||
|
||
- `'lossless'` uses LosslessJSON that parses numeric values as LosslessNumber. With LosslessNumber, one can perform | ||
regular numeric operations, and it will throw an error when this would result in losing information. | ||
- `'bignumber'` parse all numeric values as 'BigNumber' using bignumber.js library. | ||
- `'number'` parse all numeric values as 'Number' and precision will be loss if it exceeds IEEE-754 standard. | ||
- `'PrecisionPath'` provides path based precision mapping, specifying 'bignumber' will automatically map all Number in | ||
that path as 'bignumber'. Otherwise, it will default to number, This applies deeply. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"private": false, | ||
"name": "@ordzaar/jellyfish-json", | ||
"version": "0.0.0", | ||
"license": "MIT", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "tsc -b ./tsconfig.build.json", | ||
"test": "jest" | ||
}, | ||
"dependencies": { | ||
"@types/lossless-json": "^1.0.1", | ||
"bignumber.js": "^9.0.2", | ||
"lossless-json": "^1.0.5" | ||
}, | ||
"jest": { | ||
"displayName": "test", | ||
"preset": "@ordzaar/turbo-jest" | ||
}, | ||
"devDependencies": { | ||
"@ordzaar/turbo-jest": "workspace:*", | ||
"@ordzaar/standard-typescript": "workspace:*" | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import BigNumber from "bignumber.js"; | ||
import { LosslessNumber, parse, stringify } from "lossless-json"; | ||
import { PrecisionPath, remap } from "./remap"; | ||
|
||
export { BigNumber, LosslessNumber }; | ||
export type { PrecisionPath }; | ||
|
||
/** | ||
* Numeric precision to parse RPC payload as. | ||
* | ||
* 'lossless' uses LosslessJSON that parses numeric values as LosslessNumber. With LosslessNumber, one can perform | ||
* regular numeric operations, and it will throw an error when this would result in losing information. | ||
* | ||
* 'bignumber' parse all numeric values as 'BigNumber' using bignumber.js library. | ||
* | ||
* 'number' parse all numeric values as 'Number' and precision will be loss if it exceeds IEEE-754 standard. | ||
*/ | ||
export type Precision = "lossless" | "bignumber" | "number"; | ||
|
||
/** | ||
* Revive lossless as a type | ||
*/ | ||
function reviveLosslessAs(transformer: (string: string) => any) { | ||
return (key: string, value: any) => { | ||
if (value instanceof LosslessNumber) { | ||
return transformer(value.toString()); | ||
} | ||
|
||
return value; | ||
}; | ||
} | ||
|
||
/** | ||
* JellyfishJSON allows parsing of JSON with 'lossless', 'bignumber' and 'number' numeric precision. | ||
*/ | ||
export const JellyfishJSON = { | ||
/** | ||
* Precision parses all numeric value as the given Precision. | ||
* | ||
* PrecisionPath selectively remap each numeric value based on the mapping provided, | ||
* defaults to number if precision is not provided for the key. This works deeply. | ||
* | ||
* @param {string} text JSON string to parse into object. | ||
* @param {Precision | PrecisionPath} precision Numeric precision to parse payload as. | ||
*/ | ||
parse(text: string, precision: Precision | PrecisionPath): any { | ||
if (typeof precision === "string") { | ||
switch (precision) { | ||
case "lossless": | ||
return parse(text); | ||
|
||
case "bignumber": | ||
return parse( | ||
text, | ||
reviveLosslessAs((string) => new BigNumber(string)), | ||
); | ||
|
||
case "number": | ||
return parse( | ||
text, | ||
reviveLosslessAs((string) => Number(string)), | ||
); | ||
|
||
default: | ||
throw new Error(`JellyfishJSON.parse ${precision as string} precision is not supported`); | ||
} | ||
} | ||
|
||
const losslessObj = parse(text); | ||
return remap(losslessObj, precision); | ||
}, | ||
|
||
/** | ||
* @param {any} value object to stringify, with no risk of losing precision. | ||
*/ | ||
stringify(value: any): string { | ||
function replacer(key: string, value: any): any { | ||
if (value instanceof BigNumber) { | ||
return new LosslessNumber(value.toString()); | ||
} | ||
if (typeof value === "bigint") { | ||
return new LosslessNumber(value.toString()); | ||
} | ||
return value; | ||
} | ||
|
||
return stringify(value, replacer); | ||
}, | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { JellyfishJSON, LosslessNumber } from "../src/"; | ||
import BigNumber from "bignumber.js"; | ||
|
||
describe("parse", () => { | ||
describe("lossless", () => { | ||
/* eslint-disable @typescript-eslint/restrict-plus-operands */ | ||
it("18 digit significant should parse as lossless without precision lost", () => { | ||
const obj = JellyfishJSON.parse('{"lossless":1200000000.00000001}', "lossless"); | ||
expect(obj.lossless.toString()).toStrictEqual("1200000000.00000001"); | ||
}); | ||
|
||
it("10 digit significant should parse as lossless with math operators should not have an error", () => { | ||
const obj = JellyfishJSON.parse('{"lossless":1200000000}', "lossless"); | ||
expect((obj.lossless + 1).toString()).toStrictEqual("1200000001"); | ||
}); | ||
|
||
it("18 digit significant should parse as lossless with math operators should throw an error", () => { | ||
const obj = JellyfishJSON.parse('{"lossless":1200000000.00000001}', "lossless"); | ||
expect(() => { | ||
console.log(obj.lossless + 1); | ||
}).toThrow(/Cannot convert to number: number would be truncated \(value: 1200000000\.00000001\)/); | ||
}); | ||
/* eslint-enable @typescript-eslint/restrict-plus-operands */ | ||
}); | ||
|
||
describe("bignumber", () => { | ||
it("18 digit significant should parse as bignumber without precision lost", () => { | ||
const obj = JellyfishJSON.parse('{"bignumber":1200000000.00000001}', "bignumber"); | ||
expect(obj.bignumber.toString()).toStrictEqual("1200000000.00000001"); | ||
}); | ||
}); | ||
|
||
describe("number", () => { | ||
it("18 digit significant should parse as number with precision lost", () => { | ||
const obj = JellyfishJSON.parse('{"number":1200000000.00000001}', "number"); | ||
expect(obj.number.toString()).not.toStrictEqual("1200000000.00000001"); | ||
}); | ||
|
||
it("10 digit significant should parse as number without precision lost", () => { | ||
const obj = JellyfishJSON.parse('{"number":1200000000}', "number"); | ||
expect(obj.number.toString()).toStrictEqual("1200000000"); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("stringify", () => { | ||
it("should stringify number as json numeric", () => { | ||
const string = JellyfishJSON.stringify({ | ||
number: Number("1200000000"), | ||
}); | ||
expect(string).toStrictEqual('{"number":1200000000}'); | ||
}); | ||
|
||
it("should stringify lossless as json numeric", () => { | ||
const string = JellyfishJSON.stringify({ | ||
lossless: new LosslessNumber("1200000000.00000001"), | ||
}); | ||
expect(string).toStrictEqual('{"lossless":1200000000.00000001}'); | ||
}); | ||
|
||
it("should stringify bignumber as json number", () => { | ||
const string = JellyfishJSON.stringify({ | ||
bignumber: new BigNumber("1200000000.00000001"), | ||
}); | ||
expect(string).toStrictEqual('{"bignumber":1200000000.00000001}'); | ||
}); | ||
it("should stringify bigint as json number", () => { | ||
const string = JellyfishJSON.stringify({ | ||
bigint: BigInt("120000000000000001"), | ||
}); | ||
expect(string).toStrictEqual('{"bigint":120000000000000001}'); | ||
}); | ||
}); | ||
|
||
it("should remap object at root with precision", () => { | ||
const parsed = JellyfishJSON.parse( | ||
`{ | ||
"big": 10.4, | ||
"num": 1234 | ||
}`, | ||
{ | ||
big: "bignumber", | ||
}, | ||
); | ||
|
||
expect(parsed.big instanceof BigNumber).toStrictEqual(true); | ||
expect(parsed.num).toStrictEqual(1234); | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import BigNumber from "bignumber.js"; | ||
|
||
/** | ||
* Why JavaScript default number should not be used as it lose precision | ||
*/ | ||
describe("number will lose precision", () => { | ||
it("1200000000.00000003 should not lose precision as a number but it does", () => { | ||
/* eslint-disable no-loss-of-precision */ | ||
const dfi = 1200000000.00000003; | ||
|
||
expect(() => { | ||
expect(dfi.toString()).toStrictEqual("1200000000.00000003"); | ||
}).toThrow(); | ||
}); | ||
|
||
it("12.00000003 * 1000000 should be 12000000.03 but its not", () => { | ||
const obj = JSON.parse('{"dfi": 12.00000003}'); | ||
const dfi = obj.dfi * 1000000; | ||
|
||
expect(() => { | ||
expect(dfi).toStrictEqual(12000000.03); | ||
}).toThrow(); | ||
}); | ||
}); | ||
|
||
/** | ||
* BigNumber from 'bignumber.js' implementations will not lose precision | ||
*/ | ||
describe("BigNumber should not lose precision", () => { | ||
it("1200000000.00000003 should not lose precision", () => { | ||
const dfi = new BigNumber("1200000000.00000003"); | ||
|
||
expect(dfi.toString()).toStrictEqual("1200000000.00000003"); | ||
}); | ||
|
||
it("12.00000003 * 1000000 should be 12000000.03", () => { | ||
const obj = { dfi: new BigNumber("12.00000003") }; | ||
const dfi = obj.dfi.multipliedBy(1000000); | ||
|
||
expect(dfi.toString()).toStrictEqual("12000000.03"); | ||
}); | ||
}); |
Oops, something went wrong.