Repository: TheOdinProject/odin-bot-v2
Pull request #488 (2024-01-10 13:42:04)

Bump follow-redirects from 1.15.2 to 1.15.4
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/65858205e59f1e23c9bf173348a7a7cbb8ac47f5"><code>6585820</code></a> Release version 1.15.4 of the npm package.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/7a6567e16dfa9ad18a70bfe91784c28653fbf19d"><code>7a6567e</code></a> Disallow bracketed hostnames.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/05629af696588b90d64e738bc2e809a97a5f92fc"><code>05629af</code></a> Prefer native URL instead of deprecated url.parse.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/1cba8e85fa73f563a439fe460cf028688e4358df"><code>1cba8e8</code></a> Prefer native URL instead of legacy url.resolve.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/72bc2a4229bc18dc9fbd57c60579713e6264cb92"><code>72bc2a4</code></a> Simplify _processResponse error handling.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/3d42aecdca39b144a0a2f27ea134b4cf67dd796a"><code>3d42aec</code></a> Add bracket tests.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/bcbb096b32686ecad6cd34235358ed6f2217d4f0"><code>bcbb096</code></a> Do not directly set Error properties.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/192dbe7ce671ecad813c074bffe3b3f5d3680fee"><code>192dbe7</code></a> Release version 1.15.3 of the npm package.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/bd8c81e4f32d12f28a35d265f88b1716703687c6"><code>bd8c81e</code></a> Fix resource leak on destroy.</li>
<li><a href="https://github.com/follow-redirects/follow-redirects/commit/9c728c314b06f9595dcd7f245d40731e8a27d79f"><code>9c728c3</code></a> Split linting and testing.</li>
<li>Additional commits viewable in <a href="https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=follow-redirects&package-manager=npm_and_yarn&previous-version=1.15.2&new-version=1.15.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/TheOdinProject/odin-bot-v2/network/alerts).

</details>


Patch:
diff --git a/package-lock.json b/package-lock.json
index a6d4d91..db1c7c6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4695,9 +4695,9 @@
       "dev": true
     },
     "node_modules/follow-redirects": {
-      "version": "1.15.2",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
-      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "version": "1.15.4",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
+      "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
       "funding": [
         {
           "type": "individual",
@@ -11931,9 +11931,9 @@
       "dev": true
     },
     "follow-redirects": {
-      "version": "1.15.2",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
-      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
+      "version": "1.15.4",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
+      "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw=="
     },
     "for-each": {
       "version": "0.3.3",
diff --git a/services/update-faq/update-faq.service.js b/services/update-faq/update-faq.service.js
index 7f005ad..7efe461 100644
--- a/services/update-faq/update-faq.service.js
+++ b/services/update-faq/update-faq.service.js
@@ -4,6 +4,8 @@ const config = require('../../config');
 class UpdateFAQsService {
   static EmbedDescriptionCharacterLimit = 4096;
 
+  static Delimiter = '###'
+
   static async handleInteraction(interaction) {
     let rawFAQs;
     try {
@@ -29,7 +31,7 @@ class UpdateFAQsService {
 
   static createFAQEmbeds(rawFAQs) {
     return UpdateFAQsService
-      .segments(rawFAQs, UpdateFAQsService.EmbedDescriptionCharacterLimit)
+      .segments(rawFAQs, UpdateFAQsService.EmbedDescriptionCharacterLimit, UpdateFAQsService.Delimiter)
       .map((chunk) => new EmbedBuilder().setColor('#cc9543').setDescription(chunk));
   }
 
@@ -44,11 +46,29 @@ class UpdateFAQsService {
     prev.forEach((message) => message.delete());
   }
 
-  static segments(string, length) {
-    const segments = [];
-    for (let i = 0; i < string.length; i += length) {
-      segments.push(string.substring(i, i + length));
+  static segments(string, length, delimiter, doNotPrependDelimiter) {
+    const segmentedString = string.split(delimiter)
+    const segments = []
+    let currentSection = ""
+
+    for (let i = 0; i < segmentedString.length; i += 1) {
+      let segment = segmentedString[i]
+
+      if (!doNotPrependDelimiter) {
+        segment = delimiter + segmentedString[i]
+      }
+      if (segmentedString[i] === '') {
+        // eslint-disable-next-line no-continue
+        continue
+      }
+      if ((currentSection.length + segment.length) >= length) {
+          segments.push(currentSection)
+          currentSection = segment
+      } else {
+        currentSection += segment
+      }
     }
+    segments.push(currentSection)
     return segments;
   }
 }


Test patch:
diff --git a/services/update-faq/update-faq.service.test.js b/services/update-faq/update-faq.service.test.js
index 7b25a03..0494750 100644
--- a/services/update-faq/update-faq.service.test.js
+++ b/services/update-faq/update-faq.service.test.js
@@ -5,29 +5,73 @@ jest.spyOn(discordjs, 'EmbedBuilder');
 
 describe('UpdateFAQsService', () => {
   describe('segments', () => {
-    describe('when string size is divisible by segment length', () => {
+    describe('when string size is greater than segment length', () => {
       it('segments string correctly', () => {
-        const string = 'The Odin Project';
-        const length = 2;
-        const result = UpdateFAQsService.segments(string, length);
-        expect(result).toEqual(['Th', 'e ', 'Od', 'in', ' P', 'ro', 'je', 'ct']);
+        const string = '### The Odin Project.### Your Career in Web Development starts here';
+        const delimiter = '###'
+        const length = 25;
+        const result = UpdateFAQsService.segments(string, length, delimiter);
+        expect(result).toEqual(['### The Odin Project.', '### Your Career in Web Development starts here']);
       });
     });
-    describe('when string size is not divisible by segment length', () => {
-      it('segments string correctly', () => {
-        const string = 'The Odin Project';
-        const length = 3;
-        const result = UpdateFAQsService.segments(string, length);
-        expect(result).toEqual(['The', ' Od', 'in ', 'Pro', 'jec', 't']);
+
+    describe('when segment length is greater than string length', () => {
+      it('returns a single string', () => {
+        const string = '### The Odin Project.### Your Career in Web Development starts here';
+        const delimiter = '###'
+        const length = 75;
+        const result = UpdateFAQsService.segments(string, length, delimiter);
+        expect(result).toEqual(['### The Odin Project.### Your Career in Web Development starts here']);
       });
     });
+
     describe('when string size is 0', () => {
-      it('returns empty array', () => {
+      it('returns array containing empty string', () => {
         const string = '';
         const length = 2;
         const result = UpdateFAQsService.segments(string, length);
-        expect(result).toEqual([]);
+        expect(result).toEqual([""]);
       });
     });
+
+    describe('when different delimiters are used', () => {
+      it('returns the string with the correct delimiter', () => {
+        const string = '& The Odin Project.& Your Career in Web Development starts here';
+        const delimiter = '&'
+        const length = 25;
+        const result = UpdateFAQsService.segments(string, length, delimiter);
+        expect(result).toEqual(['& The Odin Project.', '& Your Career in Web Development starts here']);
+      })
+    })
+
+    describe('when delimiters shouldn\'t be prepended', () => {
+      it('returns the string without the delimiter', () => {
+        const string = '### The Odin Project.### Your Career in Web Development starts here';
+        const delimiter = '###'
+        const length = 25;
+        const result = UpdateFAQsService.segments(string, length, delimiter, true);
+        expect(result).toEqual([' The Odin Project.', ' Your Career in Web Development starts here']);
+      })
+    })
+
+    describe('when the delimiter isn\'t present', () => {
+      it('returns the full string with the delimiter prepended', () => {
+        const string = 'The Odin Project. Your Career in Web Development starts here';
+        const delimiter = '###'
+        const length = 75;
+        const result = UpdateFAQsService.segments(string, length, delimiter);
+        expect(result).toEqual(['###The Odin Project. Your Career in Web Development starts here']);
+      })
+    })
+
+    describe('when the delimiter isn\'t present and the delimiter shouldn\t be prepended', () => {
+      it('returns the full string', () => {
+        const string = 'The Odin Project. Your Career in Web Development starts here';
+        const delimiter = '###'
+        const length = 75;
+        const result = UpdateFAQsService.segments(string, length, delimiter, true);
+        expect(result).toEqual(['The Odin Project. Your Career in Web Development starts here']);
+      })
+    })
   });
 });