-
Notifications
You must be signed in to change notification settings - Fork 0
<refactor> Refactor Node to standardised object #28
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
base: main
Are you sure you want to change the base?
Conversation
Node class contains properties: - type - content - leftNode - rightNode - parent - commutative - precedence
Previously, expressionToComponentList wasn't able to use the new Node class, for a few reasons: - The Node class needs to be defined before it is accessed (see the Temporal Dead Zone https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#temporal_dead_zone_tdz) - Move Node class to a new file - Add private type and content properties, which are accessed by the Node getter and setters
- Change node type references to the enum, instead of string - Fix spelling errors
- Change references to node type to reference the enum
- Change references to node type to reference the enum
- Replace references to string literals in the function to use the NodeType and Operator enums
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request refactors the expression tree implementation to use a standardized Node class structure. Previously, nodes were created as plain JavaScript objects with inconsistent properties. The new implementation introduces enum-like classes (Operator and NodeType) and a Node class with defined properties and computed getters.
Changes:
- Introduces new
Node,Operator, andNodeTypeclasses to standardize node representation - Refactors all node creation and type checking throughout the codebase to use the new standardized objects
- Removes manual property assignment for precedence and commutativity in favor of computed getters
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
| pages/index/tree.js | New file containing Operator, NodeType, and Node class definitions with enum-like patterns and computed properties |
| pages/index/script.js | Updates all node creation and type checking to use the new Node class and enum values instead of plain objects and string literals |
| index.html | Adds script tag to include the new tree.js file before script.js |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| default: | ||
| throw `Attempted to create Operator node with non-operator content. Given: ${content}`; | ||
| break; | ||
| } |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The content setter is missing a break statement after the OPERATOR case. This causes fall-through to the FUNCTION case, which may lead to unexpected behavior. Add a break statement after line 108 to prevent fall-through.
| } | |
| } | |
| break; |
| break; | ||
| case Operator.MULTIPLICATION: | ||
| case Operator.DIVISION: | ||
| return 1; | ||
| break; | ||
| case Operator.EXPONENTIATION: | ||
| return 2; | ||
| break; | ||
| default: | ||
| throw `Node of operator type has content ${this.content}, which should not be possible.`; | ||
| } | ||
| } | ||
|
|
||
| get commutative() { | ||
| if (this.type != NodeType.OPERATOR) { | ||
| throw "Attempted to query commutativity of non-operator."; | ||
| } | ||
| switch (this.content) { | ||
| case Operator.ADDITION: | ||
| case Operator.MULTIPLICATION: | ||
| return true; | ||
| break; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The break statements after return statements are unreachable. When a return statement executes, the function exits immediately, making any subsequent break statements unnecessary and dead code.
|
|
||
| get precedence() { | ||
| if (this.type != NodeType.OPERATOR && this.type != NodeType.FUNCTION) { | ||
| throw "Attempted to access precedence of non-operator or function."; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message is thrown as a string. For consistency and better error handling, this should be thrown as an Error object: throw new Error("Attempted to access precedence of non-operator or function.");
| throw "Attempted to access precedence of non-operator or function."; | |
| throw new Error("Attempted to access precedence of non-operator or function."); |
| return 2; | ||
| break; | ||
| default: | ||
| throw `Node of operator type has content ${this.content}, which should not be possible.`; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message uses template literal syntax with backticks but is thrown as a string. For consistency and better error handling, this should be thrown as an Error object: throw new Error(Node of operator type has content ${this.content}, which should not be possible.);
| throw `Node of operator type has content ${this.content}, which should not be possible.`; | |
| throw new Error(`Node of operator type has content ${this.content}, which should not be possible.`); |
|
|
||
| get commutative() { | ||
| if (this.type != NodeType.OPERATOR) { | ||
| throw "Attempted to query commutativity of non-operator."; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message is thrown as a string. For consistency and better error handling, this should be thrown as an Error object: throw new Error("Attempted to query commutativity of non-operator.");
| break; | ||
| default: | ||
| throw `Attempted to create Operator node with non-operator content. Given: ${content}`; | ||
| break; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The break statement after the throw is unreachable. The throw statement will exit the function, making the subsequent break statement unnecessary.
| break; |
| } | ||
| set content(content) { | ||
| // TODO: Add some input validation here | ||
| switch (this.type) { |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the content setter, when this.type is checked in the switch statement (line 78), the type property may not be set yet if content is being set in the constructor before type is fully initialized. This creates a potential timing issue where the content setter relies on this.type, but the order of execution in the constructor may cause this.type to not be properly set when content is being assigned.
| switch (this.type) { | |
| const currentType = this.#_type; | |
| if (currentType === undefined) { | |
| throw 'Cannot set content before node type is set.'; | |
| } | |
| switch (currentType) { |
| default: | ||
| output += currentNode.content; | ||
| break; | ||
| output += currentNode.content; break; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spacing and formatting is inconsistent. Line 743 combines the output statement and break on a single line, while the surrounding code uses separate lines. This inconsistency reduces code readability.
| output += currentNode.content; break; | |
| output += currentNode.content; | |
| break; |
| this.#_type = NodeType.CLOSE_BRACKET; | ||
| break; | ||
| default: // Invalid type! | ||
| throw `Invalid type! Got ${type}, which is not in the type list.`; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message uses template literal syntax with backticks but is thrown using the throw statement with a string. For consistency and better error handling, this should be thrown as an Error object: throw new Error(Invalid type! Got ${type}, which is not in the type list.);
| throw `Invalid type! Got ${type}, which is not in the type list.`; | |
| throw new Error(`Invalid type! Got ${type}, which is not in the type list.`); |
| this.#_content = Operator.EXPONENTIATION; | ||
| break; | ||
| default: | ||
| throw `Attempted to create Operator node with non-operator content. Given: ${content}`; |
Copilot
AI
Jan 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message uses template literal syntax with backticks but is thrown as a string. For consistency and better error handling, this should be thrown as an Error object: throw new Error(Attempted to create Operator node with non-operator content. Given: ${content});
|
Adding some documentation as to what each property means would be beneficial. |
Previously, nodes in the expression tree had no defined structure. Hence, it was hard to tell what a node needed, and what the correct syntax was for that property.
The standard Node class contains properties:
NON-COMPUTED:
COMPUTED:
All website functions now interact with nodes using instances of this Node object.
(*) - properties type and content (when dealing with operators) have enums that define the values they can take.