diff --git a/packages/ripple-address-codec/.eslintrc.js b/packages/ripple-address-codec/.eslintrc.js index 81d98811..715a66b0 100644 --- a/packages/ripple-address-codec/.eslintrc.js +++ b/packages/ripple-address-codec/.eslintrc.js @@ -5,7 +5,7 @@ module.exports = { parserOptions: { // Enable linting rules with type information from our tsconfig tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], + project: ['./tsconfig.eslint.json'], sourceType: 'module', // Allow the use of imports / ES modules diff --git a/packages/ripple-address-codec/jest.config.js b/packages/ripple-address-codec/jest.config.js index 70d1971d..5a02b5b5 100644 --- a/packages/ripple-address-codec/jest.config.js +++ b/packages/ripple-address-codec/jest.config.js @@ -3,5 +3,6 @@ const base = require('../../jest.config.base.js') module.exports = { ...base, + roots: [...base.roots, '/test'], displayName: 'ripple-address-codec', } diff --git a/packages/ripple-address-codec/package.json b/packages/ripple-address-codec/package.json index cc65865d..1876a991 100644 --- a/packages/ripple-address-codec/package.json +++ b/packages/ripple-address-codec/package.json @@ -26,10 +26,10 @@ "prepublish": "tsc -b", "prepublishOnly": "tslint -b ./ && jest", "scripts": { - "build": "tsc -b", - "test": "jest --verbose false --silent=false ./src/*.test.js", + "build": "tsc --build tsconfig.build.json", + "test": "jest --verbose false --silent=false ./test/*.test.ts", "lint": "eslint . --ext .ts", - "clean": "rm -rf ./dist && rm -rf tsconfig.tsbuildinfo" + "clean": "rm -rf ./dist && rm -rf ./coverage && rm -rf tsconfig.tsbuildinfo" }, "prettier": "@xrplf/prettier-config", "engines": { diff --git a/packages/ripple-address-codec/src/index.test.js b/packages/ripple-address-codec/test/index.test.ts similarity index 92% rename from packages/ripple-address-codec/src/index.test.js rename to packages/ripple-address-codec/test/index.test.ts index a26c5762..57d5c506 100644 --- a/packages/ripple-address-codec/src/index.test.js +++ b/packages/ripple-address-codec/test/index.test.ts @@ -1,11 +1,22 @@ -const { +import { classicAddressToXAddress, xAddressToClassicAddress, isValidXAddress, encodeXAddress, -} = require('./index') +} from '../src' -const testCases = [ +interface AddressTestCase { + // classicAddress + [0]: string + // tag + [1]: false | number + // mainnetAddress + [2]: string + // testnetAddress + [3]: string +} + +const testCases: AddressTestCase[] = [ [ 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59', false, @@ -144,10 +155,9 @@ const testCases = [ const MAX_32_BIT_UNSIGNED_INT = 4294967295 const network = isTestAddress ? ' (test)' : ' (main)' - for (const i in testCases) { - const testCase = testCases[i] + testCases.forEach((testCase) => { const classicAddress = testCase[0] - const tag = testCase[1] !== false ? testCase[1] : false + const tag = testCase[1] === false ? false : testCase[1] const xAddress = isTestAddress ? testCase[3] : testCase[2] test(`Converts ${classicAddress}${ tag ? `:${tag}` : '' @@ -163,7 +173,7 @@ const testCases = [ }) expect(isValidXAddress(xAddress)).toBe(true) }) - } + }) { const classicAddress = 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf' @@ -196,9 +206,14 @@ const testCases = [ ] highAndLowAccounts.forEach((accountId) => { - const testCases = [false, 0, 1, MAX_32_BIT_UNSIGNED_INT] - testCases.forEach((t) => { - const tag = t | false + const tagTestCases: Array = [ + false, + 0, + 1, + MAX_32_BIT_UNSIGNED_INT, + ] + tagTestCases.forEach((testCase) => { + const tag = testCase || false const xAddress = encodeXAddress(accountId, tag, isTestAddress) test(`Encoding ${accountId.toString('hex')}${ tag ? `:${tag}` : '' @@ -253,6 +268,7 @@ test(`isValidXAddress returns false for invalid X-address`, () => { test(`Converts X7AcgcsBL6XDcUb... to r9cZA1mLK5R5A... and tag: false`, () => { const classicAddress = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59' + // eslint-disable-next-line @typescript-eslint/naming-convention -- tag can be false or a number const tag = false const xAddress = 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ' const isTestAddress = false diff --git a/packages/ripple-address-codec/src/utils.test.js b/packages/ripple-address-codec/test/utils.test.ts similarity index 86% rename from packages/ripple-address-codec/src/utils.test.js rename to packages/ripple-address-codec/test/utils.test.ts index f14e9084..dfac224f 100644 --- a/packages/ripple-address-codec/src/utils.test.js +++ b/packages/ripple-address-codec/test/utils.test.ts @@ -1,4 +1,4 @@ -const {seqEqual, concatArgs} = require('./utils') +import { seqEqual, concatArgs } from '../src/utils' test('two sequences are equal', () => { expect(seqEqual([1, 2, 3], [1, 2, 3])).toBe(true) @@ -28,7 +28,9 @@ test('plain numbers are concatenated', () => { }) test('a variety of values are concatenated', () => { - expect(concatArgs(1, [2, 3], Buffer.from([4,5]), new Uint8Array([6, 7]))).toStrictEqual([1,2,3,4,5,6,7]) + expect( + concatArgs(1, [2, 3], Buffer.from([4, 5]), new Uint8Array([6, 7])), + ).toStrictEqual([1, 2, 3, 4, 5, 6, 7]) }) test('a single value is returned as an array', () => { diff --git a/packages/ripple-address-codec/src/xrp-codec.test.js b/packages/ripple-address-codec/test/xrp-codec.test.ts similarity index 74% rename from packages/ripple-address-codec/src/xrp-codec.test.js rename to packages/ripple-address-codec/test/xrp-codec.test.ts index e1211c3f..c70123e7 100644 --- a/packages/ripple-address-codec/src/xrp-codec.test.js +++ b/packages/ripple-address-codec/test/xrp-codec.test.ts @@ -1,22 +1,39 @@ -const api = require('./xrp-codec') +import { + codec, + decodeAccountID, + decodeAccountPublic, + decodeNodePublic, + decodeSeed, + encodeAccountID, + encodeAccountPublic, + encodeNodePublic, + encodeSeed, + isValidClassicAddress, +} from '../src' -function toHex(bytes) { +function toHex(bytes: Buffer): string { return Buffer.from(bytes).toString('hex').toUpperCase() } -function toBytes(hex) { +function toBytes(hex: string): Buffer { return Buffer.from(hex, 'hex') } /** * Create a test case for encoding data and a test case for decoding data. * - * @param encoder Encoder function to test - * @param decoder Decoder function to test - * @param base58 Base58-encoded string to decode - * @param hex Hexadecimal representation of expected decoded data + * @param encoder - Encoder function to test + * @param decoder - Decoder function to test + * @param base58 - Base58-encoded string to decode + * @param hex - Hexadecimal representation of expected decoded data */ -function makeEncodeDecodeTest(encoder, decoder, base58, hex) { +// eslint-disable-next-line max-params -- needs them +function makeEncodeDecodeTest( + encoder: (val: Buffer) => string, + decoder: (val: string) => Buffer, + base58: string, + hex: string, +): void { test(`can translate between ${hex} and ${base58}`, function () { const actual = encoder(toBytes(hex)) expect(actual).toBe(base58) @@ -28,70 +45,66 @@ function makeEncodeDecodeTest(encoder, decoder, base58, hex) { } makeEncodeDecodeTest( - api.encodeAccountID, - api.decodeAccountID, + encodeAccountID, + decodeAccountID, 'rJrRMgiRgrU6hDF4pgu5DXQdWyPbY35ErN', 'BA8E78626EE42C41B46D46C3048DF3A1C3C87072', ) makeEncodeDecodeTest( - api.encodeNodePublic, - api.decodeNodePublic, + encodeNodePublic, + decodeNodePublic, 'n9MXXueo837zYH36DvMc13BwHcqtfAWNJY5czWVbp7uYTj7x17TH', '0388E5BA87A000CB807240DF8C848EB0B5FFA5C8E5A521BC8E105C0F0A44217828', ) makeEncodeDecodeTest( - api.encodeAccountPublic, - api.decodeAccountPublic, + encodeAccountPublic, + decodeAccountPublic, 'aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3', '023693F15967AE357D0327974AD46FE3C127113B1110D6044FD41E723689F81CC6', ) test('can decode arbitrary seeds', function () { - const decoded = api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2') + const decoded = decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2') expect(toHex(decoded.bytes)).toBe('4C3A1D213FBDFB14C7C28D609469B341') expect(decoded.type).toBe('ed25519') - const decoded2 = api.decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL') + const decoded2 = decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL') expect(toHex(decoded2.bytes)).toBe('CF2DE378FBDD7E2EE87D486DFB5A7BFF') expect(decoded2.type).toBe('secp256k1') }) test('can pass a type as second arg to encodeSeed', function () { const edSeed = 'sEdTM1uX8pu2do5XvTnutH6HsouMaM2' - const decoded = api.decodeSeed(edSeed) + const decoded = decodeSeed(edSeed) const type = 'ed25519' expect(toHex(decoded.bytes)).toBe('4C3A1D213FBDFB14C7C28D609469B341') expect(decoded.type).toBe(type) - expect(api.encodeSeed(decoded.bytes, type)).toBe(edSeed) + expect(encodeSeed(decoded.bytes, type)).toBe(edSeed) }) test('isValidClassicAddress - secp256k1 address valid', function () { - expect(api.isValidClassicAddress('rU6K7V3Po4snVhBBaU29sesqs2qTQJWDw1')).toBe( - true, - ) + expect(isValidClassicAddress('rU6K7V3Po4snVhBBaU29sesqs2qTQJWDw1')).toBe(true) }) test('isValidClassicAddress - ed25519 address valid', function () { - expect(api.isValidClassicAddress('rLUEXYuLiQptky37CqLcm9USQpPiz5rkpD')).toBe( - true, - ) + expect(isValidClassicAddress('rLUEXYuLiQptky37CqLcm9USQpPiz5rkpD')).toBe(true) }) test('isValidClassicAddress - invalid', function () { - expect(api.isValidClassicAddress('rU6K7V3Po4snVhBBaU29sesqs2qTQJWDw2')).toBe( + expect(isValidClassicAddress('rU6K7V3Po4snVhBBaU29sesqs2qTQJWDw2')).toBe( false, ) }) test('isValidClassicAddress - empty', function () { - expect(api.isValidClassicAddress('')).toBe(false) + expect(isValidClassicAddress('')).toBe(false) }) describe('encodeSeed', function () { it('encodes a secp256k1 seed', function () { - const result = api.encodeSeed( + const result = encodeSeed( Buffer.from('CF2DE378FBDD7E2EE87D486DFB5A7BFF', 'hex'), 'secp256k1', ) @@ -99,7 +112,7 @@ describe('encodeSeed', function () { }) it('encodes low secp256k1 seed', function () { - const result = api.encodeSeed( + const result = encodeSeed( Buffer.from('00000000000000000000000000000000', 'hex'), 'secp256k1', ) @@ -107,7 +120,7 @@ describe('encodeSeed', function () { }) it('encodes high secp256k1 seed', function () { - const result = api.encodeSeed( + const result = encodeSeed( Buffer.from('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 'hex'), 'secp256k1', ) @@ -115,7 +128,7 @@ describe('encodeSeed', function () { }) it('encodes an ed25519 seed', function () { - const result = api.encodeSeed( + const result = encodeSeed( Buffer.from('4C3A1D213FBDFB14C7C28D609469B341', 'hex'), 'ed25519', ) @@ -123,7 +136,7 @@ describe('encodeSeed', function () { }) it('encodes low ed25519 seed', function () { - const result = api.encodeSeed( + const result = encodeSeed( Buffer.from('00000000000000000000000000000000', 'hex'), 'ed25519', ) @@ -131,7 +144,7 @@ describe('encodeSeed', function () { }) it('encodes high ed25519 seed', function () { - const result = api.encodeSeed( + const result = encodeSeed( Buffer.from('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 'hex'), 'ed25519', ) @@ -140,7 +153,7 @@ describe('encodeSeed', function () { test('attempting to encode a seed with less than 16 bytes of entropy throws', function () { expect(() => { - api.encodeSeed( + encodeSeed( Buffer.from('CF2DE378FBDD7E2EE87D486DFB5A7B', 'hex'), 'secp256k1', ) @@ -149,7 +162,7 @@ describe('encodeSeed', function () { test('attempting to encode a seed with more than 16 bytes of entropy throws', function () { expect(() => { - api.encodeSeed( + encodeSeed( Buffer.from('CF2DE378FBDD7E2EE87D486DFB5A7BFFFF', 'hex'), 'secp256k1', ) @@ -159,13 +172,13 @@ describe('encodeSeed', function () { describe('decodeSeed', function () { it('can decode an Ed25519 seed', function () { - const decoded = api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2') + const decoded = decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2') expect(toHex(decoded.bytes)).toBe('4C3A1D213FBDFB14C7C28D609469B341') expect(decoded.type).toBe('ed25519') }) it('can decode a secp256k1 seed', function () { - const decoded = api.decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL') + const decoded = decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL') expect(toHex(decoded.bytes)).toBe('CF2DE378FBDD7E2EE87D486DFB5A7BFF') expect(decoded.type).toBe('secp256k1') }) @@ -173,7 +186,7 @@ describe('decodeSeed', function () { describe('encodeAccountID', function () { it('can encode an AccountID', function () { - const encoded = api.encodeAccountID( + const encoded = encodeAccountID( Buffer.from('BA8E78626EE42C41B46D46C3048DF3A1C3C87072', 'hex'), ) expect(encoded).toBe('rJrRMgiRgrU6hDF4pgu5DXQdWyPbY35ErN') @@ -181,7 +194,7 @@ describe('encodeAccountID', function () { test('unexpected length should throw', function () { expect(() => { - api.encodeAccountID(Buffer.from('ABCDEF', 'hex')) + encodeAccountID(Buffer.from('ABCDEF', 'hex')) }).toThrow( 'unexpected_payload_length: bytes.length does not match expectedLength', ) @@ -190,7 +203,7 @@ describe('encodeAccountID', function () { describe('decodeNodePublic', function () { it('can decode a NodePublic', function () { - const decoded = api.decodeNodePublic( + const decoded = decodeNodePublic( 'n9MXXueo837zYH36DvMc13BwHcqtfAWNJY5czWVbp7uYTj7x17TH', ) expect(toHex(decoded)).toBe( @@ -201,7 +214,7 @@ describe('decodeNodePublic', function () { test('encodes 123456789 with version byte of 0', () => { expect( - api.codec.encode(Buffer.from('123456789'), { + codec.encode(Buffer.from('123456789'), { versions: [0], expectedLength: 9, }), @@ -210,7 +223,7 @@ test('encodes 123456789 with version byte of 0', () => { test('multiple versions with no expected length should throw', () => { expect(() => { - api.codec.decode('rnaC7gW34M77Kneb78s', { + codec.decode('rnaC7gW34M77Kneb78s', { versions: [0, 1], }) }).toThrow( @@ -220,7 +233,7 @@ test('multiple versions with no expected length should throw', () => { test('attempting to decode data with length < 5 should throw', () => { expect(() => { - api.codec.decode('1234', { + codec.decode('1234', { versions: [0], }) }).toThrow('invalid_input_size: decoded data must have length >= 5') @@ -228,7 +241,7 @@ test('attempting to decode data with length < 5 should throw', () => { test('attempting to decode data with unexpected version should throw', () => { expect(() => { - api.codec.decode('rnaC7gW34M77Kneb78s', { + codec.decode('rnaC7gW34M77Kneb78s', { versions: [2], }) }).toThrow( @@ -238,7 +251,7 @@ test('attempting to decode data with unexpected version should throw', () => { test('invalid checksum should throw', () => { expect(() => { - api.codec.decode('123456789', { + codec.decode('123456789', { versions: [0, 1], }) }).toThrow('checksum_invalid') @@ -246,7 +259,7 @@ test('invalid checksum should throw', () => { test('empty payload should throw', () => { expect(() => { - api.codec.decode('', { + codec.decode('', { versions: [0, 1], }) }).toThrow('invalid_input_size: decoded data must have length >= 5') @@ -254,7 +267,7 @@ test('empty payload should throw', () => { test('decode data', () => { expect( - api.codec.decode('rnaC7gW34M77Kneb78s', { + codec.decode('rnaC7gW34M77Kneb78s', { versions: [0], }), ).toStrictEqual({ @@ -266,7 +279,7 @@ test('decode data', () => { test('decode data with expected length', function () { expect( - api.codec.decode('rnaC7gW34M77Kneb78s', { + codec.decode('rnaC7gW34M77Kneb78s', { versions: [0], expectedLength: 9, }), @@ -279,7 +292,7 @@ test('decode data with expected length', function () { test('decode data with wrong expected length should throw', function () { expect(() => { - api.codec.decode('rnaC7gW34M77Kneb78s', { + codec.decode('rnaC7gW34M77Kneb78s', { versions: [0], expectedLength: 8, }) @@ -287,7 +300,7 @@ test('decode data with wrong expected length should throw', function () { 'version_invalid: version bytes do not match any of the provided version(s)', ) expect(() => { - api.codec.decode('rnaC7gW34M77Kneb78s', { + codec.decode('rnaC7gW34M77Kneb78s', { versions: [0], expectedLength: 10, }) diff --git a/packages/ripple-address-codec/tsconfig.build.json b/packages/ripple-address-codec/tsconfig.build.json new file mode 100644 index 00000000..7f59b80d --- /dev/null +++ b/packages/ripple-address-codec/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + }, + "include": ["./src/**/*.ts", "./src/**/*.json"] +} diff --git a/packages/ripple-address-codec/tsconfig.eslint.json b/packages/ripple-address-codec/tsconfig.eslint.json index 0b4edec6..16dc56bd 100644 --- a/packages/ripple-address-codec/tsconfig.eslint.json +++ b/packages/ripple-address-codec/tsconfig.eslint.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "include": ["src/**/*.ts", "src/*.test.ts"] + "include": ["src/**/*.ts", "test/*.test.ts"] } diff --git a/packages/ripple-address-codec/tsconfig.json b/packages/ripple-address-codec/tsconfig.json index 941f61aa..520f2f7a 100644 --- a/packages/ripple-address-codec/tsconfig.json +++ b/packages/ripple-address-codec/tsconfig.json @@ -5,7 +5,6 @@ "lib": [ "es2017" ], - "rootDir": "./src", "outDir": "./dist", "noUnusedLocals": true, "noUnusedParameters": true,