Skip to content

Text block comments #454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

achyu-dev
Copy link
Contributor

@achyu-dev achyu-dev commented Mar 25, 2025

Added a new logic to check the commands inside nested / normal codeblocks

export function removeCodeBlocksAndQuotes(text: string): string {
  if (!text) return "";
  let filtered = text.replace(/```[\s\S]*?```/g, "");
  filtered = filtered.replace(/`[^`]+`/g, "");
  filtered = filtered.replace(/^>.*$/gm, "");
  filtered = filtered.replace(/>>>[\s\S]*?(?=\n\n|$)/g, "");
  filtered = filtered.replace(/\n{3,}/g, "\n\n").trim();
  return filtered;
}

export function isInsideCodeBlock(text: string, position: number): boolean {
  let insideSingle = false;
  let insideTriple = false;
  let i = 0;
  
  while (i < position) {
    if (text.slice(i, i + 3) === "```") {
      insideTriple = !insideTriple;
      i += 3;
    } else if (text[i] === "`" && !insideTriple) {
      insideSingle = !insideSingle;
      i++;
    } else {
      i++;
    }
  }

  return insideSingle || insideTriple;
}

Copy link

what-the-diff bot commented Mar 25, 2025

PR Summary

  • Updated Development Script in package.json
    The development script has been updated to run specific tasks instead of a general one. This creates a more streamlined and effective process for executing and testing code.

  • Exported commandsList Variable
    The commandsList has been changed from being locally accessible to globally accessible. This provides the possibility for it to be used in various parts of the program, increasing versatility and code reuse.

  • Added Command for Immutability
    A new, immutable command has been added to the commandsList. This command promises unchanged data, ensuring data integrity and accuracy at all times.

  • Introduced 'shouldProcessCommand' Function
    This new function, shouldProcessCommand, verifies if a command should be processed or not, based on its existence inside code blocks. This allows for better control and error handling during command processing.

  • Updated Command Processing Logic
    The logic for processing commands has been updated. Instead of directly checking for command existence, it now utilizes the previously mentioned shouldProcessCommand function. This offers better efficiency and command processing accuracy.

  • New Unit Tests for Command Handling
    A new test file, test/commands.test.ts, has been created that includes extensive unit tests for command handling and edge-case scenarios. These newly added tests offer better quality control and ensure optimal performance, especially in cases where commands are used within different types of code blocks and contexts.

Copy link
Member

@vcarl vcarl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, a couple of required changes before I can approve this — let's keep the PR narrowly focused on just the specific issue of command triggers in code blocks

package.json Outdated
@@ -59,7 +59,7 @@
"ts-node": "10.9.2",
"tsx": "^4.19.2",
"typescript": "^5.7.3",
"vitest": "1.6.0"
"vitest": "^1.6.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this changing?

@achyu-dev achyu-dev marked this pull request as ready for review March 28, 2025 17:03
Comment on lines 1275 to 1285
while (i < position) {
if (text.slice(i, i + 3) === "```") {
insideTriple = !insideTriple;
i += 3;
} else if (text[i] === "`" && !insideTriple) {
insideSingle = !insideSingle;
i++;
} else {
i++;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit concerned about the way this code works — for a string of length n, it will create n substrings, which seems like a lot of CPU and memory. Since the last PR had issues with resource contention, this makes me nervous.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it's more resource intensive than I thought — it will create n substrings for every command trigger, and we have ~ 40 commands with ~ 50 triggers. So that means that a message with 150 characters will create 150 3-character substrings 50 times — I think this is a no-go the way it's written

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm okay, I will think of a better approach for this

Copy link
Contributor

@kristersd kristersd Apr 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, couldn't you use replaceAll to remove all content in-between backticks ` (other forbidden letters). Then you could compare, if the trigger name is still there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shud be possible, will try it @kristersd . thanks !!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the meantime, check the latest commit @kristersd if tats an optimal approach

@DanielFGray
Copy link
Contributor

Seems like this could be made a lot simpler utilizing a slightly more complex regex:

/!\w+(?=[^`]*(?:`[^`]*`[^`]*)*$)/

this should match !words not inside code blocks
in action: https://regex101.com/r/pm4kqS/1

@achyu-dev
Copy link
Contributor Author

Can someone help me on why these 8 test cases fail?

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 8 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should ignore command inside deeply nested triple backticks
AssertionError: expected true to be false // Object.is equality

- Expected
+ Received

- false
+ true

 ❯ test/commands.test.ts:129:63
    127|       "```\nSome random text\n```js\nconsole.log('!mdn Array.prototype.map');\n```\nMore text outside";
    128|
    129|     expect(shouldProcessCommand(mockMessage.content, "!mdn")).toBe(false);
       |                                                               ^
    130|   });
    131|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/8]⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should ignore command inside a long deeply nested code block
AssertionError: expected true to be false // Object.is equality

- Expected
+ Received

- false
+ true

 ❯ test/commands.test.ts:145:63


⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/8]⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should process command outside deeply nested backticks but ignore the inside one
AssertionError: expected false to be true // Object.is equality

- Expected
+ Received

- true
+ false

 ❯ test/commands.test.ts:177:63
    175|       "Hey everyone, I need help with JavaScript! ```js\nfunction test() {\n  console.log('!mdn Array.prototype.map');\n}\n``` But I still need info on !m…
    176|
    177|     expect(shouldProcessCommand(mockMessage.content, "!mdn")).toBe(true); // The one outside should be processed.
       |                                                               ^
    178|     expect(
    179|       shouldProcessCommand(

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/8]⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should ignore command inside multi-level text and markdown blocks
AssertionError: expected true to be false // Object.is equality

- Expected
+ Received

- false
+ true

 ❯ test/commands.test.ts:193:63
    191|       "```\nAnother block\n```js\nconsole.log('!mdn Array.prototype.map');\n```";
    192|
    193|     expect(shouldProcessCommand(mockMessage.content, "!mdn")).toBe(false);
       |                                                               ^
    194|   });
    195|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/8]⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should ignore command if inside an embedded link
AssertionError: expected true to be false // Object.is equality

- Expected
+ Received

- false
+ true

 ❯ test/commands.test.ts:247:63
    245|     mockMessage.content =
    246|       "[Click here for !mdn Array.prototype.map](https://example.com)";
    247|     expect(shouldProcessCommand(mockMessage.content, "!mdn")).toBe(false);
       |                                                               ^
    248|   });
    249|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/8]⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should ignore command inside nested code blocks
AssertionError: expected true to be false // Object.is equality

- Expected
+ Received

- false
+ true

 ❯ test/commands.test.ts:261:63
    259|     mockMessage.content =
    260|       "```\nHere is some code:\n```js\nconsole.log('!mdn Array.prototype.map');\n```";
    261|     expect(shouldProcessCommand(mockMessage.content, "!mdn")).toBe(false);
       |                                                               ^
    262|   });
    263|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/8]⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should ignore command if it's part of a quoted message
AssertionError: expected true to be false // Object.is equality

- Expected
+ Received

- false
+ true

 ❯ test/commands.test.ts:273:63
    271|   it("should ignore command if it's part of a quoted message", () => {
    272|     mockMessage.content = `> Someone said: "!mdn Array.prototype.map is useful"`;
    273|     expect(shouldProcessCommand(mockMessage.content, "!mdn")).toBe(false);
       |                                                               ^
    274|   });
    275|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/8]⎯

 FAIL  test/commands.test.ts > Discord Bot Commands > should ignore command if part is inside a code block
AssertionError: expected false to be true // Object.is equality

- Expected
+ Received

- true
+ false

 ❯ test/commands.test.ts:323:63
    321|     mockMessage.content =
    322|       "```js\nconsole.log('!mdn Array.prototype.map');\n``` !mdn Array.prototype.map";
    323|     expect(shouldProcessCommand(mockMessage.content, "!mdn")).toBe(true); // Only process the second one
       |                                                               ^
    324|   });
    325| });

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/8]⎯

 Test Files  1 failed | 5 passed (6)
      Tests  8 failed | 48 passed | 1 skipped (57)
   Start at  12:21:41
   Duration  1.40s (transform 378ms, setup 1ms, collect 1.57s, tests 504ms, environment 1ms, prepare 936ms)

@achyu-dev
Copy link
Contributor Author

Seems like this could be made a lot simpler utilizing a slightly more complex regex:

/!\w+(?=[^`]*(?:`[^`]*`[^`]*)*$)/

this should match !words not inside code blocks in action: https://regex101.com/r/pm4kqS/1

okay I added this regex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants