Repository: algorand/js-algorand-sdk
Pull request #598 (2022-06-26 09:04:20)

Remove code that relies on node's path module
With the removal of the dependency to node's path module, there's one less thing to 'browserify'. All tests, especially the ones under client url construction, passed. I'll leave the the webpack configuration updates to you all, I guess...

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/algorand/js-algorand-sdk?pullRequest=598) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/algorand/js-algorand-sdk?pullRequest=598) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/algorand/js-algorand-sdk?pullRequest=598) it.</sub>

Patch:
diff --git a/FAQ.md b/FAQ.md
index dafc8f2..43b3108 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -33,17 +33,7 @@ With Vite, you would see:
 Uncaught ReferenceError: Buffer is not defined
 ```
 
-You will have to install `buffer` and `path-browserify` as dependencies.
-
-In `vite.config.js`, specify:
-
-```js
-resolve: {
-  alias: {
-    path: 'path-browserify';
-  }
-}
-```
+You will have to install `buffer` as dependency.
 
 In `index.html`, add the following:
 
diff --git a/package-lock.json b/package-lock.json
index 6d02ed5..99d8b43 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,8 +17,7 @@
         "js-sha512": "^0.8.0",
         "json-bigint": "^1.0.0",
         "superagent": "^6.1.0",
-        "tweetnacl": "^1.0.3",
-        "url-parse": "^1.5.1"
+        "tweetnacl": "^1.0.3"
       },
       "devDependencies": {
         "@types/json-bigint": "^1.0.0",
@@ -45,7 +44,6 @@
         "mocha": "^9.0.0",
         "mocha-lcov-reporter": "^1.3.0",
         "mock-http-server": "^1.4.3",
-        "path-browserify": "^1.0.1",
         "prettier": "2.2.1",
         "selenium-webdriver": "^4.2.0",
         "source-map-loader": "^2.0.2",
@@ -5782,12 +5780,6 @@
         "node": ">= 0.8"
       }
     },
-    "node_modules/path-browserify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
-      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
-      "dev": true
-    },
     "node_modules/path-exists": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -5997,11 +5989,6 @@
         "node": ">=0.6"
       }
     },
-    "node_modules/querystringify": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
-    },
     "node_modules/queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -6252,11 +6239,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/requires-port": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
-    },
     "node_modules/resolve": {
       "version": "1.20.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
@@ -7691,15 +7673,6 @@
         "punycode": "^2.1.0"
       }
     },
-    "node_modules/url-parse": {
-      "version": "1.5.8",
-      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.8.tgz",
-      "integrity": "sha512-9JZ5zDrn9wJoOy/t+rH00HHejbU8dq9VsOYVu272TYDrCiyVAgHKUSpPh3ruZIpv8PMVR+NXLZvfRPJv8xAcQw==",
-      "dependencies": {
-        "querystringify": "^2.1.1",
-        "requires-port": "^1.0.0"
-      }
-    },
     "node_modules/util": {
       "version": "0.12.4",
       "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz",
@@ -12757,12 +12730,6 @@
       "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
       "dev": true
     },
-    "path-browserify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
-      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
-      "dev": true
-    },
     "path-exists": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -12924,11 +12891,6 @@
       "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
       "dev": true
     },
-    "querystringify": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
-    },
     "queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -13116,11 +13078,6 @@
       "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
       "dev": true
     },
-    "requires-port": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
-    },
     "resolve": {
       "version": "1.20.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
@@ -14232,15 +14189,6 @@
         "punycode": "^2.1.0"
       }
     },
-    "url-parse": {
-      "version": "1.5.8",
-      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.8.tgz",
-      "integrity": "sha512-9JZ5zDrn9wJoOy/t+rH00HHejbU8dq9VsOYVu272TYDrCiyVAgHKUSpPh3ruZIpv8PMVR+NXLZvfRPJv8xAcQw==",
-      "requires": {
-        "querystringify": "^2.1.1",
-        "requires-port": "^1.0.0"
-      }
-    },
     "util": {
       "version": "0.12.4",
       "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz",
diff --git a/package.json b/package.json
index 85eb906..2ca9e49 100644
--- a/package.json
+++ b/package.json
@@ -25,8 +25,7 @@
     "js-sha512": "^0.8.0",
     "json-bigint": "^1.0.0",
     "superagent": "^6.1.0",
-    "tweetnacl": "^1.0.3",
-    "url-parse": "^1.5.1"
+    "tweetnacl": "^1.0.3"
   },
   "devDependencies": {
     "@types/json-bigint": "^1.0.0",
@@ -53,7 +52,6 @@
     "mocha": "^9.0.0",
     "mocha-lcov-reporter": "^1.3.0",
     "mock-http-server": "^1.4.3",
-    "path-browserify": "^1.0.1",
     "prettier": "2.2.1",
     "selenium-webdriver": "^4.2.0",
     "source-map-loader": "^2.0.2",
diff --git a/src/client/urlTokenBaseHTTPClient.ts b/src/client/urlTokenBaseHTTPClient.ts
index f54ef8b..157b8d5 100644
--- a/src/client/urlTokenBaseHTTPClient.ts
+++ b/src/client/urlTokenBaseHTTPClient.ts
@@ -1,5 +1,3 @@
-import Url from 'url-parse';
-import path from 'path';
 import * as request from 'superagent';
 import {
   BaseHTTPClient,
@@ -35,7 +33,7 @@ export type TokenHeader =
  * This is the default implementation of BaseHTTPClient.
  */
 export class URLTokenBaseHTTPClient implements BaseHTTPClient {
-  private readonly baseURL: Url;
+  private readonly baseURL: URL;
   private readonly tokenHeader: TokenHeader;
 
   constructor(
@@ -44,9 +42,15 @@ export class URLTokenBaseHTTPClient implements BaseHTTPClient {
     port?: string | number,
     private defaultHeaders: Record<string, any> = {}
   ) {
-    const baseServerURL = new Url(baseServer, {});
+    // Append a trailing slash so we can use relative paths. Without the trailing
+    // slash, the last path segment will be replaced by the relative path. See
+    // usage in `addressWithPath`.
+    const fixedBaseServer = baseServer.endsWith('/')
+      ? baseServer
+      : `${baseServer}/`;
+    const baseServerURL = new URL(fixedBaseServer);
     if (typeof port !== 'undefined') {
-      baseServerURL.set('port', port.toString());
+      baseServerURL.port = port.toString();
     }
 
     if (baseServerURL.protocol.length === 0) {
@@ -63,10 +67,15 @@ export class URLTokenBaseHTTPClient implements BaseHTTPClient {
    * @returns A URL string
    */
   private addressWithPath(relativePath: string) {
-    const address = new Url(
-      path.posix.join(this.baseURL.pathname, relativePath),
-      this.baseURL
-    );
+    let fixedRelativePath: string;
+    if (relativePath.startsWith('./')) {
+      fixedRelativePath = relativePath;
+    } else if (relativePath.startsWith('/')) {
+      fixedRelativePath = `.${relativePath}`;
+    } else {
+      fixedRelativePath = `./${relativePath}`;
+    }
+    const address = new URL(fixedRelativePath, this.baseURL);
     return address.toString();
   }
 
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index 611a78c..c504a09 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -10,7 +10,6 @@ export interface JSONOptions {
 /**
  * Parse JSON with additional options.
  * @param str - The JSON string to parse.
- * @param options - Parsing options.
  * @param options - Options object to configure how integers in
  *   this request's JSON response will be decoded. Use the `intDecoding`
  *   property with one of the following options:
@@ -28,34 +27,32 @@ export interface JSONOptions {
 export function parseJSON(str: string, options?: JSONOptions) {
   const intDecoding =
     options && options.intDecoding ? options.intDecoding : IntDecoding.DEFAULT;
-  const parsed = JSONbig.parse(str, (_, value) => {
+  return JSONbig.parse(str, (_, value) => {
     if (
       value != null &&
       typeof value === 'object' &&
       Object.getPrototypeOf(value) == null
     ) {
-      // for some reason the Objects returned by JSONbig.parse have a null prototype, so we
-      // need to fix that.
+      // JSONbig.parse objects are created with Object.create(null) and thus have a null prototype
+      // let us remedy that
       Object.setPrototypeOf(value, Object.prototype);
     }
 
     if (typeof value === 'bigint') {
+      if (intDecoding === 'safe' && value > Number.MAX_SAFE_INTEGER) {
+        throw new Error(
+          `Integer exceeds maximum safe integer: ${value.toString()}. Try parsing with a different intDecoding option.`
+        );
+      }
       if (
         intDecoding === 'bigint' ||
         (intDecoding === 'mixed' && value > Number.MAX_SAFE_INTEGER)
       ) {
         return value;
       }
-
       // JSONbig.parse converts number to BigInts if they are >= 10**15. This is smaller than
       // Number.MAX_SAFE_INTEGER, so we can convert some BigInts back to normal numbers.
-      if (intDecoding === 'default' || intDecoding === 'mixed') {
-        return Number(value);
-      }
-
-      throw new Error(
-        `Integer exceeds maximum safe integer: ${value.toString()}. Try parsing with a different intDecoding option.`
-      );
+      return Number(value);
     }
 
     if (typeof value === 'number') {
@@ -66,7 +63,6 @@ export function parseJSON(str: string, options?: JSONOptions) {
 
     return value;
   });
-  return parsed;
 }
 
 /**
diff --git a/webpack.config.js b/webpack.config.js
index 1bd1259..c22e0e4 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -16,11 +16,6 @@ module.exports = {
   resolve: {
     // Add '.ts' as resolvable extensions
     extensions: ['.ts', '.js'],
-
-    // Support `path` in the browser
-    fallback: {
-      path: require.resolve('path-browserify'),
-    },
   },
   plugins: [
     new webpack.ProvidePlugin({


Test patch:
diff --git a/tests/2.Encoding.js b/tests/2.Encoding.js
index 25d011c..57d1452 100644
--- a/tests/2.Encoding.js
+++ b/tests/2.Encoding.js
@@ -354,17 +354,18 @@ describe('encoding', () => {
     });
 
     it('should parse number', () => {
-      const input = '17';
-
-      for (const intDecoding of ['default', 'safe', 'mixed', 'bigint']) {
-        const actual = utils.parseJSON(input, { intDecoding });
-        const expected = intDecoding === 'bigint' ? 17n : 17;
-
-        assert.deepStrictEqual(
-          actual,
-          expected,
-          `Error when intDecoding = ${intDecoding}`
-        );
+      const inputs = ['17', '9007199254740991'];
+      for (const input of inputs) {
+        for (const intDecoding of ['default', 'safe', 'mixed', 'bigint']) {
+          const actual = utils.parseJSON(input, { intDecoding });
+          const expected =
+            intDecoding === 'bigint' ? BigInt(input) : Number(input);
+          assert.deepStrictEqual(
+            actual,
+            expected,
+            `Error when intDecoding = ${intDecoding}`
+          );
+        }
       }
     });