Skip to content

Commit

Permalink
fix: add error handling for excessively large integers
Browse files Browse the repository at this point in the history
Encoding or decoding values larger than Javascript's MAX_SAFE_INTEGER can cause unpredictable
behavior. This change adds error handling to the `encode` and `decode` functions to throw an error
if this value gets exceeded. API documentation updated accordingly.

See
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
for more details.

Resolves: #28
  • Loading branch information
M-Scott-Lassiter committed Apr 30, 2022
1 parent c6a0af8 commit bc725f1
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 38 deletions.
92 changes: 54 additions & 38 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,61 @@
### Table of Contents

- [AlphanumericEncoder][1]
- [dictionary][2]
- [Parameters][3]
- [Examples][4]
- [encode][5]
- [Parameters][6]
- [Examples][7]
- [decode][8]
- [Parameters][9]
- [Examples][10]
- [Examples][2]
- [dictionary][3]
- [Parameters][4]
- [Examples][5]
- [encode][6]
- [Parameters][7]
- [Examples][8]
- [decode][9]
- [Parameters][10]
- [Examples][11]

## AlphanumericEncoder

A class for encoding and decoding base 10 integers to a custom alphanumeric base representation.

### dictionary
### Examples

Set or get the current dictionary.
```javascript
// Import into a project
const AlphanumericEncoder = require('alphanumeric-encoder')
const encoder = new AlphanumericEncoder()
```

Default is the English alphabet in order: `ABCDEFGHIJKLMNOPQRSTUVWXYZ`
### dictionary

Returns or sets the current dictionary.

#### Parameters

- `newDictionary` **[string][11]** (If setting) String of unique letters and numbers, in order, for the new dictionary
- `newDictionary` **[string][12]** (If setting) String of unique letters and numbers, in order, for the new dictionary

#### Examples

```javascript
console.log(AlphanumericEncoder.dictionary) // 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const encoder = new AlphanumericEncoder()

AlphanumericEncoder.dictionary = 'ABCD'
console.log(AlphanumericEncoder.dictionary) // 'ABCD'
console.log(encoder.dictionary) // 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

encoder.dictionary = 'ABCD'
console.log(encoder.dictionary) // 'ABCD'

AlphanumericEncoder.dictionary = 'ABCDA' // Throws error because the letter 'A' is repeated
encoder.dictionary = 'ABCDA' // Throws error because the letter 'A' is repeated
```

Returns **[string][11]** (If used as getter) The current dictionary in use
Returns **[string][12]** (If used as getter) The current dictionary in use

### encode

Takes any number and converts it into a base (dictionary length) letter combo.

#### Parameters

- `integerToEncode` **[number][12]** Base 10 integer. If passed a non-integer number, decimal values are truncated.
- `integerToEncode` **[number][13]** Base 10 integer. If passed a non-integer number, decimal values are truncated.
Passing zero, negative numbers, or non-numbers will return `undefined`.
Throws an error if `integerToEncode` exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).

#### Examples

Expand All @@ -59,39 +69,44 @@ console.log(encoder.encode(733)) // 'ABE'
```

```javascript
const encoder = new AlphanumericEncoder()
encoder.dictionary = 'ABCD'
console.log(encoder.encode(5)) // 'AA'
console.log(encoder.encode(48)) // 'BCD'
console.log(encoder.encode(733)) // 'BCACA'
```

```javascript
const encoder = new AlphanumericEncoder()
encoder.dictionary = 'DCBA'
console.log(encoder.encode(5)) // 'DD'
console.log(encoder.encode(48)) // 'CBA'
console.log(encoder.encode(733)) // 'CBDBD'
```

```javascript
const encoder = new AlphanumericEncoder()
encoder.dictionary = 'ABC123'
console.log(encoder.encode(5)) // '2'
console.log(encoder.encode(48)) // 'AA3'
console.log(encoder.encode(733)) // 'CBBA'
```

Returns **[string][11]** Dictionary encoded value
```javascript
const encoder = new AlphanumericEncoder()
console.log(encoder.encode('A')) // undefined
console.log(encoder.encode(null)) // undefined
console.log(encoder.encode(undefined)) // undefined
```

Returns **[string][12]** Dictionary encoded value

### decode

Takes any string and converts it into a base 10 integer based on the defined dictionary.

#### Parameters

- `stringToDecode` **[string][11]** If passed a non-integer number, decimal values are truncated.
- `stringToDecode` **[string][12]** If passed a non-integer number, decimal values are truncated.
Passing an empty string, `null`, or `undefined` will return `undefined`.
Throws an error if the decoded integer exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).

#### Examples

Expand All @@ -103,32 +118,33 @@ console.log(encoder.decode('ANE')) // 1045
```

```javascript
const encoder = new AlphanumericEncoder()
console.log(encoder.decode('a')) // undefined
console.log(encoder.decode(123)) // undefined
console.log(encoder.decode('A?')) // undefined
console.log(encoder.decode(null)) // undefined
console.log(encoder.decode(undefined)) // undefined
```

```javascript
const encoder = new AlphanumericEncoder()
encoder.dictionary = 'ABCD'
console.log(encoder.decode('A')) // 1
console.log(encoder.decode('AC')) // 7
console.log(encoder.decode('ADBAC')) // 551
console.log(encoder.decode('ANE')) // undefined
```

Returns **[number][12]** Positive integer representation. If one of the characters is not present in the dictionary, it will return `undefined`.
Returns **[number][13]** Positive integer representation. If one of the characters is not present in the dictionary, it will return `undefined`.

[1]: #alphanumericencoder
[2]: #dictionary
[3]: #parameters
[4]: #examples
[5]: #encode
[6]: #parameters-1
[7]: #examples-1
[8]: #decode
[9]: #parameters-2
[10]: #examples-2
[11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[2]: #examples
[3]: #dictionary
[4]: #parameters
[5]: #examples-1
[6]: #encode
[7]: #parameters-1
[8]: #examples-2
[9]: #decode
[10]: #parameters-2
[11]: #examples-3
[12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
13 changes: 13 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class AlphanumericEncoder {
*
* @param {number} integerToEncode Base 10 integer. If passed a non-integer number, decimal values are truncated.
* Passing zero, negative numbers, or non-numbers will return `undefined`.
* Throws an error if `integerToEncode` exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).
* @returns {string} Dictionary encoded value
*
* @example
Expand Down Expand Up @@ -108,6 +109,11 @@ class AlphanumericEncoder {
if (Number.isNaN(integerToEncode) || integerToEncode < 0) {
return undefined
}
if (integerToEncode > Number.MAX_SAFE_INTEGER) {
throw new Error(
'The encoding value is greater than the maximum safe integer for Javascript.'
)
}

function numToLetter(num, dictionary) {
// Takes a letter between 0 and max letter length and returns the corresponding letter
Expand Down Expand Up @@ -145,6 +151,7 @@ class AlphanumericEncoder {
*
* @param {string} stringToDecode If passed a non-integer number, decimal values are truncated.
* Passing an empty string, `null`, or `undefined` will return `undefined`.
* Throws an error if the decoded integer exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).
* @returns {number} Positive integer representation. If one of the characters is not present in the dictionary, it will return `undefined`.
* @example
* const encoder = new AlphanumericEncoder()
Expand Down Expand Up @@ -186,6 +193,12 @@ class AlphanumericEncoder {
result += index * this.dictionary.length ** (safeEncoded.length - i)
}

if (result > Number.MAX_SAFE_INTEGER) {
throw new Error(
'The decoded value is greater than the maximum safe integer for Javascript.'
)
}

return result
}
}
Expand Down

0 comments on commit bc725f1

Please sign in to comment.