-
Notifications
You must be signed in to change notification settings - Fork 0
Sprint 2 #2
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
📝 WalkthroughWalkthroughThis PR contains fixes to debug scripts addressing property access and iteration patterns, implementations of utility functions with comprehensive test coverage, and a .gitignore update. The debug fixes correct how object properties are accessed, while the implement and interpret modules provide complete working versions of array/object processing utilities. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~18 minutes 🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
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.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In `@Sprint-2/implement/contains.test.js`:
- Around line 43-45: The test passes an array to contains without a property and
asserts false while the comment allows either false or an error; make the
behavior deterministic: either (A) if contains should validate input types,
update the test to expect an error using expect(() => contains(["a",1,"b"],
"someProp")).toThrow() and add a test for arrays without property if needed, or
(B) if contains should simply return false for non-plain-object first args,
change the test to include a property argument (e.g., contains(["a",1], "prop"))
and assert toEqual(false); update the test to match whichever behavior you
implement for the contains function.
- Around line 23-25: Test is calling contains with only an object but acceptance
criteria require both an object and a property name; update the test to pass a
property (e.g., expect(contains({}, "someKey")).toEqual(false)) or, if you
intend to test missing-argument behavior, rename the test to clarify it's
verifying that contains(obj) returns false when property is omitted and ensure
the implementation of contains handles undefined property by returning false;
reference the contains function and the test case in contains.test.js when
making the change.
In `@Sprint-2/implement/querystring.js`:
- Around line 9-10: The current code decodes the whole 'pair' (decodedPair =
decodeURIComponent(pair)) before splitting, which can mis-handle encoded
delimiters; instead split the raw 'pair' into [key, value] using the existing
split (pair.split(/=(.*)/s)) first, then individually decodeURIComponent the
resulting key and value variables (handling absent value as empty string), and
replace usages of decodedPair with decoded key/value so encoded '=' or '&' in
either component aren't interpreted as delimiters.
In `@Sprint-2/implement/tally.js`:
- Line 6: The loop currently uses an undeclared implicit global variable `char`
in `for (char of arrayOfItems)` and a misleading name; change it to a properly
declared loop variable (e.g., `for (const item of arrayOfItems)` or `for (let
item of arrayOfItems)`) and update references inside the loop to use `item`
instead of `char`, keeping `arrayOfItems` and `object` as-is so the tally logic
remains `object[item] = (object[item] || 0) + 1`.
- Line 2: The assignment "object = {}" creates an implicit global; change it to
an explicit local binding (e.g., use "const" or "let") and/or rename the
variable to avoid colliding with built-ins (replace the "object = {}" occurrence
with something like "const tally = {}" or "let obj = {}"); also consider adding
"use strict"; at the top of tally.js to enforce errors on accidental globals.
🧹 Nitpick comments (6)
Sprint-2/debug/recipe.js (1)
17-19: The iteration works, but what do you thinkfor...inactually iterates over?When you use
for...inon an array, you're iterating over the indices (as strings: "0", "1", "2"...), not the values themselves — which is why you needrecipe.ingredients[ingredientIndex]to get the actual item.Have you explored
for...of? It iterates directly over the values, which would let you write something like:for (const ingredient of recipe.ingredients) { console.log(ingredient); }What advantages might this have for readability and reducing the chance of bugs?
.gitignore (1)
2-4: I notice there might be some redundancy here — what do you think?Looking at lines 2 and 4, you have both
.DS_Storeand**/.DS_Store. The**/.DS_Storepattern is actually more comprehensive since it matches.DS_Storefiles in any subdirectory. Would you consider whether the simpler.DS_Storeon line 2 is still needed, or could you consolidate these into just the glob pattern?🧹 Optional cleanup
node_modules -.DS_Store .vscode **/.DS_Store prepSprint-2/implement/lookup.js (1)
3-5: Have you consideredfor...ofhere?I notice you're using
for...into iterate over the array. While this works,for...inis typically designed for iterating over object properties, and when used on arrays it gives you the indices as strings rather than the elements directly.How might the code look if you used
for...ofwith destructuring instead? It could make the intent clearer and avoid the need for index-based access.♻️ Suggested approach using for...of with destructuring
function createLookup(array) { const countryCurrencyObject = {}; - for (const index in array) { - countryCurrencyObject[array[index][0]] = array[index][1] - }; - return countryCurrencyObject -}; + for (const [country, currency] of array) { + countryCurrencyObject[country] = currency; + } + return countryCurrencyObject; +}Sprint-2/implement/lookup.test.js (1)
12-31: What if we simplified these tests?I see you're testing
Object.keys()andObject.values()separately to verify the structure. This works, but it relies on object property order being preserved. Have you thought about whether a single test comparing the entire object might be clearer and more robust?test("creates a lookup object from country-currency pairs", () => { expect(createLookup([["US", "USD"], ["CA", "CAD"]])).toEqual({ US: "USD", CA: "CAD", }); });Also, what edge cases might be worth considering? For example:
- What should happen with an empty array?
- What about duplicate country codes — should the last one win?
Sprint-2/implement/tally.test.js (1)
22-22: Quick thought on the describe block namingThe describe name reads like a requirement: "Given a function called tally, return an object containing the count for each unique item". Typically, describe blocks name the unit being tested (like
"tally"or"tally function"), while the individual test names describe specific behaviors.How might reorganizing this improve readability when test output is displayed?
🧹 Optional naming adjustment
-describe("Given a function called tally, return an object containing the count for each unique item", () => { +describe("tally", () => {Sprint-2/interpret/invert.js (1)
40-45: Consider a prototype‑less target object to avoid key collisions.I’ve noticed you’re assigning arbitrary values as keys; if a value is
"__proto__"or"constructor", it can collide with object prototypes. How could you make the target immune to that? UsingObject.create(null)is a simple fix.♻️ Proposed refactor
function invert(obj) { - const invertedObj = {}; + const invertedObj = Object.create(null); for (const [key, value] of Object.entries(obj)) { invertedObj[value] = key; }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
.gitignoreSprint-2/debug/address.jsSprint-2/debug/author.jsSprint-2/debug/recipe.jsSprint-2/implement/contains.jsSprint-2/implement/contains.test.jsSprint-2/implement/lookup.jsSprint-2/implement/lookup.test.jsSprint-2/implement/querystring.jsSprint-2/implement/querystring.test.jsSprint-2/implement/tally.jsSprint-2/implement/tally.test.jsSprint-2/interpret/invert.jsSprint-2/interpret/invert.test.js
🧰 Additional context used
🧬 Code graph analysis (4)
Sprint-2/implement/contains.js (1)
Sprint-2/implement/contains.test.js (1)
contains(1-1)
Sprint-2/implement/lookup.js (2)
Sprint-2/implement/lookup.test.js (1)
createLookup(1-1)Sprint-1/refactor/includes.js (1)
index(4-4)
Sprint-2/interpret/invert.js (2)
Sprint-2/interpret/invert.test.js (1)
invert(1-1)Sprint-2/implement/querystring.js (1)
key(10-10)
Sprint-2/implement/tally.js (1)
Sprint-2/implement/tally.test.js (1)
tally(1-1)
🔇 Additional comments (6)
Sprint-2/debug/address.js (1)
2-4: Nice work identifying the root cause!Your explanation is spot on — objects aren't accessed by numeric index like arrays. I see you've used bracket notation
address["houseNumber"]. Have you considered when you might prefer dot notation (address.houseNumber) versus bracket notation? Both work here, but dot notation is often cleaner when you know the key name at write-time.Also applies to: 17-17
Sprint-2/debug/author.js (1)
16-18: Excellent fix!You've correctly identified that
for...inis the right tool for iterating over object properties. Notice how this contrasts with arrays — herefor...ingives you the keys, and you use bracket notation to get the corresponding values.This is a great example of understanding when to use
for...in(objects) versusfor...of(iterables like arrays). Well done!Sprint-2/implement/contains.js (1)
1-3: Solid implementation! Have you thought about what happens with edge cases?Your approach with
Object.keys(object).includes(property)works well. A couple of things to consider:
What happens if someone passes
nullorundefinedas the object? Try it out and see!Did you know JavaScript has a built-in way to check for property existence? Have you looked into
Object.hasOwn(object, property)orobject.hasOwnProperty(property)? How might these differ from your current approach, especially regarding inherited properties?These are good explorations for deepening your understanding of JavaScript objects.
Sprint-2/implement/querystring.test.js (1)
14-18: Nice addition of URL decoding test coverage!I see you've added a test for percent-encoded characters — this is a great edge case to cover. The expected values are correct:
%25decodes to%and%26decodes to&.One thing to think about: what other encoding scenarios might be worth testing? For instance, have you considered what happens with
+characters (which represent spaces in query strings) or with malformed percent-encoding like%2G?Sprint-2/implement/tally.test.js (1)
26-44: Good test coverage!Nice work covering the main scenarios: empty array, duplicates, and invalid input validation. The error-throwing test is a great addition for robustness.
A few edge cases you might explore if you want to expand coverage:
- What about an array with a single item like
["a"]?- What happens with non-string items like numbers:
[1, 1, 2]?- What about
nullorundefinedas input?These aren't required, just food for thought!
Sprint-2/interpret/invert.test.js (1)
1-8: Nice, clear tests that pin the behavior.These cases make the expected key/value swap unambiguous. 👍
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| test("Given an empty object, return false", () => { | ||
| expect(contains({})).toEqual(false); | ||
| }); |
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.
I'm curious about this test — what behavior are we verifying here?
Looking at the acceptance criteria (lines 16-18), the function expects both an object AND a property name. But this test only passes an empty object without specifying which property to check for.
What should contains({}) return when no property is specified? Is this intentionally testing how the function handles missing arguments, or should the test include a property to check? If it's meant to test edge case handling, perhaps the test name could make that clearer?
🤖 Prompt for AI Agents
In `@Sprint-2/implement/contains.test.js` around lines 23 - 25, Test is calling
contains with only an object but acceptance criteria require both an object and
a property name; update the test to pass a property (e.g., expect(contains({},
"someKey")).toEqual(false)) or, if you intend to test missing-argument behavior,
rename the test to clarify it's verifying that contains(obj) returns false when
property is omitted and ensure the implementation of contains handles undefined
property by returning false; reference the contains function and the test case
in contains.test.js when making the change.
| test("Given invalid parameters like an array, return false or throw an error", () => { | ||
| expect(contains(["a", 1, "b", 2, "c"])).toEqual(false); | ||
| }); |
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.
Similar question here about the test intent
This test passes an array without a property argument. The comment says it should "return false or throw an error," but you're only asserting false.
A few things to consider:
- Should the function validate that its first argument is a plain object (not an array)?
- If "throw an error" is a valid outcome, how would you test for that?
- What property are we checking for in the array?
If you want to test both possible outcomes, Jest's toThrow matcher could help for the error case.
🤖 Prompt for AI Agents
In `@Sprint-2/implement/contains.test.js` around lines 43 - 45, The test passes an
array to contains without a property and asserts false while the comment allows
either false or an error; make the behavior deterministic: either (A) if
contains should validate input types, update the test to expect an error using
expect(() => contains(["a",1,"b"], "someProp")).toThrow() and add a test for
arrays without property if needed, or (B) if contains should simply return false
for non-plain-object first args, change the test to include a property argument
(e.g., contains(["a",1], "prop")) and assert toEqual(false); update the test to
match whichever behavior you implement for the contains function.
| const decodedPair = decodeURIComponent(pair); | ||
| const [key, value] = decodedPair.split(/=(.*)/s); |
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.
Interesting approach! Have you considered the order of operations here?
You're decoding the entire pair before splitting on =. What do you think would happen with a query string like key=hello%3Dworld (where %3D is an encoded =)?
Try tracing through your code:
decodeURIComponent("key=hello%3Dworld")→"key=hello=world"- Split on first
=→["key", "hello=world"]
Hmm, that actually works for this case! But what about key%3Dname=value (where the key contains an encoded =)? Or what about %26hidden=secret (where %26 is an encoded &)?
The general best practice is to split first on your delimiters (& and =), then decode the individual components. This prevents encoded delimiters from being misinterpreted. What do you think?
Suggested approach
for (const pair of keyValuePairs) {
- const decodedPair = decodeURIComponent(pair);
- const [key, value] = decodedPair.split(/=(.*)/s);
-
- queryParams[key] = value;
+ const [key, value] = pair.split(/=(.*)/s);
+ queryParams[decodeURIComponent(key)] = value !== undefined ? decodeURIComponent(value) : undefined;
}🤖 Prompt for AI Agents
In `@Sprint-2/implement/querystring.js` around lines 9 - 10, The current code
decodes the whole 'pair' (decodedPair = decodeURIComponent(pair)) before
splitting, which can mis-handle encoded delimiters; instead split the raw 'pair'
into [key, value] using the existing split (pair.split(/=(.*)/s)) first, then
individually decodeURIComponent the resulting key and value variables (handling
absent value as empty string), and replace usages of decodedPair with decoded
key/value so encoded '=' or '&' in either component aren't interpreted as
delimiters.
| @@ -1,3 +1,11 @@ | |||
| function tally() {} | |||
| function tally(arrayOfItems) { | |||
| object = {}; | |||
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.
I notice something about how this variable is declared — what do you think might happen here?
When you write object = {} without const or let, JavaScript creates an implicit global variable. This can lead to some tricky bugs — imagine if another function also used a global called object!
What would happen if you added "use strict"; at the top of your file and ran this code? Give it a try — it's a great way to catch these kinds of issues early.
Suggested fix
function tally(arrayOfItems) {
- object = {};
+ const object = {};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| object = {}; | |
| function tally(arrayOfItems) { | |
| const object = {}; |
🤖 Prompt for AI Agents
In `@Sprint-2/implement/tally.js` at line 2, The assignment "object = {}" creates
an implicit global; change it to an explicit local binding (e.g., use "const" or
"let") and/or rename the variable to avoid colliding with built-ins (replace the
"object = {}" occurrence with something like "const tally = {}" or "let obj =
{}"); also consider adding "use strict"; at the top of tally.js to enforce
errors on accidental globals.
| if (!Array.isArray(arrayOfItems)) { | ||
| throw new Error("Invalid input"); | ||
| } else { | ||
| for (char of arrayOfItems) object[char] = (object[char] || 0) + 1; |
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.
Same question applies here — how is char being declared?
The for (char of arrayOfItems) loop has the same issue: char becomes an implicit global variable. Also, I'm curious about the name char — does the array always contain characters, or could it contain other types of items? Choosing a more generic name like item might better communicate intent.
Suggested fix
- for (char of arrayOfItems) object[char] = (object[char] || 0) + 1;
+ for (const item of arrayOfItems) object[item] = (object[item] || 0) + 1;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (char of arrayOfItems) object[char] = (object[char] || 0) + 1; | |
| for (const item of arrayOfItems) object[item] = (object[item] || 0) + 1; |
🤖 Prompt for AI Agents
In `@Sprint-2/implement/tally.js` at line 6, The loop currently uses an undeclared
implicit global variable `char` in `for (char of arrayOfItems)` and a misleading
name; change it to a properly declared loop variable (e.g., `for (const item of
arrayOfItems)` or `for (let item of arrayOfItems)`) and update references inside
the loop to use `item` instead of `char`, keeping `arrayOfItems` and `object`
as-is so the tally logic remains `object[item] = (object[item] || 0) + 1`.
Learners, PR Template
Self checklist
Changelist
done sprint 2 exercises
Questions
no questions
Summary by CodeRabbit
Bug Fixes
New Features
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.