From b72906085e2f82b896c49e8c7f177a119f3bf4d7 Mon Sep 17 00:00:00 2001 From: l3onhard Date: Mon, 20 Apr 2026 19:35:47 +0200 Subject: [PATCH] feat(curriculum): add workshop-word-counter to JS v9 cert (#64012) Co-authored-by: Jessica Wilkins <67210629+jdwilkin4@users.noreply.github.com> Co-authored-by: jdwilkin4 --- client/i18n/locales/english/intro.json | 6 + .../691f7bbf76229bb97c60827d.md | 41 +++++++ .../6920c9cda1c7f056f75e4b1a.md | 53 ++++++++ .../6920d189e36b6b60a6330fee.md | 47 ++++++++ .../6920dae65fb8bb6949bcdaba.md | 35 ++++++ .../6921d688b8d58581d34459b9.md | 46 +++++++ .../6921d90b5ce50185505d2004.md | 83 +++++++++++++ .../6921dae10700e300f26994e3.md | 51 ++++++++ .../6921de8d2a111d0341cff702.md | 61 ++++++++++ .../6921e10ae2681205b516fbe6.md | 88 ++++++++++++++ .../69220a03729c43082ad3e9f6.md | 114 ++++++++++++++++++ .../6978bd465213832659f3338b.md | 81 +++++++++++++ .../blocks/workshop-word-counter.json | 22 ++++ .../structure/superblocks/javascript-v9.json | 1 + 14 files changed, 729 insertions(+) create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/691f7bbf76229bb97c60827d.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6920c9cda1c7f056f75e4b1a.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6920d189e36b6b60a6330fee.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6920dae65fb8bb6949bcdaba.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6921d688b8d58581d34459b9.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6921d90b5ce50185505d2004.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6921dae10700e300f26994e3.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6921de8d2a111d0341cff702.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6921e10ae2681205b516fbe6.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/69220a03729c43082ad3e9f6.md create mode 100644 curriculum/challenges/english/blocks/workshop-word-counter/6978bd465213832659f3338b.md create mode 100644 curriculum/structure/blocks/workshop-word-counter.json diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 8487155bd94..3708e65f4b8 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -4860,6 +4860,12 @@ "Loops are an essential part of JavaScript. That's why the following lectures have been prepared for you to learn about the different types of loops and how they work, and also how iteration works." ] }, + "workshop-word-counter": { + "title": "Build a Word Counter", + "intro": [ + "In this workshop, you will practice using for...of loops by building a function that counts the occurrences of a string in an array of strings." + ] + }, "workshop-sentence-analyzer": { "title": "Build a Sentence Analyzer", "intro": [ diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/691f7bbf76229bb97c60827d.md b/curriculum/challenges/english/blocks/workshop-word-counter/691f7bbf76229bb97c60827d.md new file mode 100644 index 00000000000..175c2d957e2 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/691f7bbf76229bb97c60827d.md @@ -0,0 +1,41 @@ +--- +id: 691f7bbf76229bb97c60827d +title: Step 1 +challengeType: 1 +dashedName: step-1 +--- + +# --description-- + +In this workshop, you will practice using `for...of` loops by building a function that counts how often a string appears in an array of strings. + +Before you write that function, you will create a simpler one that logs each character of a string to the console. + +Start by defining an empty function called `printCharacters` with the parameter `str`. + +# --hints-- + +You should create a `printCharacters` function. + +```js +assert.isFunction(printCharacters); +``` + +Your `printCharacters` function should have one parameter called `str`. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const functionRegex = __helpers.functionRegex('printCharacters', ['str']); + +assert.match(codeWithoutJSComments, functionRegex); +``` + +# --seed-- + +## --seed-contents-- + +```js +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6920c9cda1c7f056f75e4b1a.md b/curriculum/challenges/english/blocks/workshop-word-counter/6920c9cda1c7f056f75e4b1a.md new file mode 100644 index 00000000000..49379f66ed0 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6920c9cda1c7f056f75e4b1a.md @@ -0,0 +1,53 @@ +--- +id: 6920c9cda1c7f056f75e4b1a +title: Step 2 +challengeType: 1 +dashedName: step-2 +--- + +# --description-- + +Now it’s time to write your first `for...of` loop. In the preceding lessons, you learned that you can use a `for...of` loop to iterate over values from an iterable (e.g., strings or arrays). + +Here is an example for a `for...of` loop: + +```js +for (const num of [1, 2, 3]) { + // code block to be executed +} +``` + +Add a `for...of` loop with an empty code block inside your function. It should iterate over every character in the `str` argument. + +# --hints-- + +Your `printCharacters` function should have a `for...of` loop inside its code block. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); + +assert.match(normalizedCode, /functionprintCharacters\(str\)\{for\(\S+of\S+\)\{\S*?\}\}/); +``` + +Your `for...of` loop should iterate over the `str` argument of your function. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const forLoopRegex = /function printCharacters\(str\) \{\s*for\s*\(([\S\s]*?)\)\s*\{[\S\s]*?\}\s*\}/; +const forLoopCode = codeWithoutJSComments.match(forLoopRegex)[1]; + +assert.match(forLoopCode, /(const|let|var)\s+\w+\s+of\s+str/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6920d189e36b6b60a6330fee.md b/curriculum/challenges/english/blocks/workshop-word-counter/6920d189e36b6b60a6330fee.md new file mode 100644 index 00000000000..46962cca4e7 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6920d189e36b6b60a6330fee.md @@ -0,0 +1,47 @@ +--- +id: 6920d189e36b6b60a6330fee +title: Step 3 +challengeType: 1 +dashedName: step-3 +--- + +# --description-- + +Now, inside the loop, log the `char` variable to the console. + +# --hints-- + +You should have a `console.log` statement with `char` as its argument inside the loop. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const functionRegex = __helpers.functionRegex('printCharacters', ['str'], { capture: true }); +const functionCode = codeWithoutJSComments.match(functionRegex)[1]; +const normalizedFunctionCode = __helpers.removeWhiteSpace(functionCode); +const loopCodeBlock = normalizedFunctionCode.match(/for\(constcharofstr\)\{(\S*?)}/)[1] + +assert.match(loopCodeBlock, /console\.log\(char\)/); +``` + +When the `printCharacters` function is called with the argument `'test'`, the `console.log()` statement inside the function should be called four times with the following arguments, in order: `'t'`, `'e'`, `'s'`, and `'t'`. Instead, it was called with the following arguments: `--fcc-actual--`. + +```js +const consoleLogSpy = __helpers.spyOn(console, 'log'); +printCharacters('test'); +assert.deepEqual(consoleLogSpy.calls, [['t'], ['e'], ['s'], ['t']]); +consoleLogSpy.restore(); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { +--fcc-editable-region-- + +--fcc-editable-region-- + } +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6920dae65fb8bb6949bcdaba.md b/curriculum/challenges/english/blocks/workshop-word-counter/6920dae65fb8bb6949bcdaba.md new file mode 100644 index 00000000000..5019161bdf0 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6920dae65fb8bb6949bcdaba.md @@ -0,0 +1,35 @@ +--- +id: 6920dae65fb8bb6949bcdaba +title: Step 4 +challengeType: 1 +dashedName: step-4 +--- + +# --description-- + +To see how the loop inside `printCharacters` behaves, call it with the argument `"hello"`. + +# --hints-- + +You should call the function `printCharacters` with `"hello"` as its argument. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); +assert.match(normalizedCode, /printCharacters\(('|"|`)hello\1\)/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6921d688b8d58581d34459b9.md b/curriculum/challenges/english/blocks/workshop-word-counter/6921d688b8d58581d34459b9.md new file mode 100644 index 00000000000..ad29dd260e7 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6921d688b8d58581d34459b9.md @@ -0,0 +1,46 @@ +--- +id: 6921d688b8d58581d34459b9 +title: Step 5 +challengeType: 1 +dashedName: step-5 +--- + +# --description-- + +In the next few steps, you will build a function that counts how often a string appears in an array of strings. + +To start, define an empty function named `getMatchedWordCount` with the parameters `sentence` and `match` in that order. + +# --hints-- + +You should create a `getMatchedWordCount` function. + +```js +assert.isFunction(getMatchedWordCount); +``` + +Your `getMatchedWordCount` function should have two parameters: `sentence` and `match`, in that order. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const functionRegex = __helpers.functionRegex('getMatchedWordCount', ['sentence', 'match']); + +assert.match(codeWithoutJSComments, functionRegex); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6921d90b5ce50185505d2004.md b/curriculum/challenges/english/blocks/workshop-word-counter/6921d90b5ce50185505d2004.md new file mode 100644 index 00000000000..81ccc84a0fd --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6921d90b5ce50185505d2004.md @@ -0,0 +1,83 @@ +--- +id: 6921d90b5ce50185505d2004 +title: Step 6 +challengeType: 1 +dashedName: step-6 +--- + +# --description-- + +Since the `getMatchedWordCount` function needs to return a numerical count, you will start by setting up a counter variable. + +Create a variable named `count` using the `let` keyword, initialize it with the value `0`, and add a `return` statement that returns the `count` variable. + +# --hints-- + +You should declare the `count` variable inside the function `getMatchedWordCount`. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const functionRegex = __helpers.functionRegex('getMatchedWordCount', ['sentence', 'match'], { capture: true }); +const functionCode = codeWithoutJSComments.match(functionRegex)[1]; +const normalizedFunctionCode = __helpers.removeWhiteSpace(functionCode); + +assert.match(normalizedFunctionCode, /(const|let|var)count/); +``` + +To allow the `count` variable to be incremented later, declare it with the `let` keyword. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const functionRegex = __helpers.functionRegex('getMatchedWordCount', ['sentence', 'match'], { capture: true }); +const functionCode = codeWithoutJSComments.match(functionRegex)[1]; +const normalizedFunctionCode = __helpers.removeWhiteSpace(functionCode); + +assert.match(normalizedFunctionCode, /letcount/); +``` + +Your function should contain an assignment of the value `0` to the `count` variable. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const functionRegex = __helpers.functionRegex('getMatchedWordCount', ['sentence', 'match'], { capture: true }); +const functionCode = codeWithoutJSComments.match(functionRegex)[1]; +const normalizedFunctionCode = __helpers.removeWhiteSpace(functionCode); + +assert.match(normalizedFunctionCode, /count=0/); +``` + +Your function should contain a `return` statement that returns the `count` variable. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const functionRegex = __helpers.functionRegex('getMatchedWordCount', ['sentence', 'match'], { capture: true }); +const functionCode = codeWithoutJSComments.match(functionRegex)[1]; +const normalizedFunctionCode = __helpers.removeWhiteSpace(functionCode); + +assert.match(normalizedFunctionCode, /returncount/); +``` + +Your `getMatchedWordCount` function should return the value `0`. + +```js +assert.strictEqual(getMatchedWordCount(["foo", "bar"], "foo"), 0); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +function getMatchedWordCount(sentence, match) { +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6921dae10700e300f26994e3.md b/curriculum/challenges/english/blocks/workshop-word-counter/6921dae10700e300f26994e3.md new file mode 100644 index 00000000000..f09d8ee0c3c --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6921dae10700e300f26994e3.md @@ -0,0 +1,51 @@ +--- +id: 6921dae10700e300f26994e3 +title: Step 7 +challengeType: 1 +dashedName: step-7 +--- + +# --description-- + +To view the output of your `getMatchedWordCount` function in its current state, add a `console.log` statement below it. Inside the `console.log()`, call the function with the argument `["I", "really", "really", "really", "like", "to", "code"]` for the `sentence` parameter and `"really"` for the `match` parameter. + +# --hints-- + +You should call the function `getMatchedWordCount` inside a `console.log` statement. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); +assert.match(normalizedCode, /console\.log\(getMatchedWordCount\(\S*?\)\)/); +``` + +You should call the function `getMatchedWordCount` with the argument `["I", "really", "really", "really", "like", "to", "code"]` for the `sentence` parameter and `"really"` for the `match` parameter. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); +const normalizedConsoleLogCode = normalizedCode.match(/console\.log\(getMatchedWordCount\(\S*?\)\)/)[0]; +assert.match(normalizedConsoleLogCode, /\[('|"|`)I\1,('|"|`)really\2,('|"|`)really\3,('|"|`)really\4,('|"|`)like\5,('|"|`)to\6,('|"|`)code\7\],('|"|`)really\8/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +function getMatchedWordCount(sentence, match) { + let count = 0; + return count; +} + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6921de8d2a111d0341cff702.md b/curriculum/challenges/english/blocks/workshop-word-counter/6921de8d2a111d0341cff702.md new file mode 100644 index 00000000000..ac90fdfea2c --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6921de8d2a111d0341cff702.md @@ -0,0 +1,61 @@ +--- +id: 6921de8d2a111d0341cff702 +title: Step 8 +challengeType: 1 +dashedName: step-8 +--- + +# --description-- + +Great, your function returns a `0`, but it doesn’t count anything yet. + +To fix this, inside `getMatchedWordCount`, create a `for...of` loop with an empty code block that iterates over each word in `sentence`. + +# --hints-- + +Your `getMatchedWordCount` function should have a `for...of` loop inside its code block. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); + +assert.match(normalizedCode, /functiongetMatchedWordCount\(sentence,match\)\{letcount=0\;for\(\S+of\S+\)\{\S*?\}returncount;\}/); +``` + +Your `for...of` loop should iterate over the `sentence` argument of your function. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const forLoopRegex = /function getMatchedWordCount\(sentence, match\) \{\s*let count = 0\;\s*for\s*\(([\S\s]*?)\)\s*\{[\S\s]*?\}\s*return count\;\s*\}/; +const forLoopCode = codeWithoutJSComments.match(forLoopRegex)[1]; + +assert.match(forLoopCode, /(const|let|var)\s+\w+\s+of\s+sentence/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +function getMatchedWordCount(sentence, match) { + let count = 0; +--fcc-editable-region-- + +--fcc-editable-region-- + return count; +} + +console.log( + getMatchedWordCount( + ["I", "really", "really", "really", "like", "to", "code"], + "really" + ) +); +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6921e10ae2681205b516fbe6.md b/curriculum/challenges/english/blocks/workshop-word-counter/6921e10ae2681205b516fbe6.md new file mode 100644 index 00000000000..846f103ec1f --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6921e10ae2681205b516fbe6.md @@ -0,0 +1,88 @@ +--- +id: 6921e10ae2681205b516fbe6 +title: Step 10 +challengeType: 1 +dashedName: step-10 +--- + +# --description-- + +Now it's time to add the logic to your loop that increments `count` appropriately. + +Inside the loop, use a conditional statement to increment `count` by `1` if the variable `word` equals the variable `match`. Otherwise, leave the value of `count` unchanged. + +# --hints-- + +Calling `getMatchedWordCount([], "bar")`, `getMatchedWordCount(["foo"], "bar")`, `getMatchedWordCount(["foo", "bar", "foo"], "bar")`, and `getMatchedWordCount(["foo", "bar", "foo"], "foo")` in that order should each return a value of type `"number"`; instead, it returned values of type `--fcc-actual--`. + +```js +const obj = { method: (arg1, arg2) => typeof getMatchedWordCount(arg1, arg2) }; +const spy = __helpers.spyOn(obj, 'method'); +obj.method([], "bar"); +obj.method(["foo"], "bar"); +obj.method(["foo", "bar", "foo"], "bar"); +obj.method(["foo", "bar", "foo"], "foo"); +assert.deepEqual(spy.returns, ["number", "number", "number", "number"]); +spy.restore(); +``` + +`getMatchedWordCount([], "bar")` should return `0`, but it returnes `--fcc-actual--`. + +```js +const resultString = String(getMatchedWordCount([], "bar")); +assert.strictEqual(resultString, "0"); +``` + +`getMatchedWordCount(["foo"], "bar")` should return `0`, but it returnes `--fcc-actual--`. + +```js +const resultString = String(getMatchedWordCount(["foo"], "bar")); +assert.equal(resultString, "0"); +``` + +`getMatchedWordCount(["foo", "bar", "foo"], "bar")` should return `1`, but it returnes `--fcc-actual--`. + +```js +const resultString = String(getMatchedWordCount(["foo", "bar", "foo"], "bar")); +assert.equal(resultString, "1"); +``` + +`getMatchedWordCount(["foo", "bar", "foo"], "foo")` should return `2`, but it returnes `--fcc-actual--`. + +```js +const resultString = String(getMatchedWordCount(["foo", "bar", "foo"], "foo")); +assert.equal(resultString, "2"); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +function getMatchedWordCount(sentence, match) { + let count = 0; + + for (const word of sentence) { +--fcc-editable-region-- + +--fcc-editable-region-- + console.log(`Checking "${word}" against "${match}" | Running count: ${count}`); + } + + return count; +} + +console.log( + getMatchedWordCount( + ["I", "really", "really", "really", "like", "to", "code"], + "really" + ) +); +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/69220a03729c43082ad3e9f6.md b/curriculum/challenges/english/blocks/workshop-word-counter/69220a03729c43082ad3e9f6.md new file mode 100644 index 00000000000..a5b34d58e3c --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/69220a03729c43082ad3e9f6.md @@ -0,0 +1,114 @@ +--- +id: 69220a03729c43082ad3e9f6 +title: Step 11 +challengeType: 1 +dashedName: step-11 +--- + +# --description-- + +You’ve finished working on your `getMatchedWordCount` function! + +Now you are going to test it with different data to see how it behaves. + +Add a new `console.log` statement below the existing one that calls `getMatchedWordCount` with these parameters: + +- sentence: `["Do", "not", "fear", "the", "dandy", "lion"]` +- match: `"dandy"` + +Congratulations! You’ve completed this workshop. + +# --hints-- + +You should have a second `console.log` statement that calls the `getMatchedWordCount` function inside. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); +const normalizedConsoleLogCode = normalizedCode.match(/console\.log\(getMatchedWordCount\(\S*?\)\)/g)[1]; +assert.exists(normalizedConsoleLogCode); +``` + +In your second `console.log` statement, call the `getMatchedWordCount` function with `["Do", "not", "fear", "the", "dandy", "lion"]` as the `sentence` argument and `"dandy"` as the `match` argument. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); +const normalizedConsoleLogCode = normalizedCode.match(/console\.log\(getMatchedWordCount\(\S*?\)\)/g)[1]; +assert.match(normalizedConsoleLogCode, /\[('|"|`)Do\1,('|"|`)not\2,('|"|`)fear\3,('|"|`)the\4,('|"|`)dandy\5,('|"|`)lion\6\],('|"|`)dandy\7/); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +function getMatchedWordCount(sentence, match) { + let count = 0; + + for (const word of sentence) { + if (word === match) { + count++; + } + console.log(`Checking "${word}" against "${match}" | Running count: ${count}`); + } + + return count; +} + +console.log( + getMatchedWordCount( + ["I", "really", "really", "really", "like", "to", "code"], + "really" + ) +); + +--fcc-editable-region-- + +--fcc-editable-region-- +``` + +# --solutions-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +function getMatchedWordCount(sentence, match) { + let count = 0; + + for (const word of sentence) { + if (word === match) { + count++; + } + console.log(`Checking "${word}" against "${match}" | Running count: ${count}`); + } + + return count; +} + +console.log( + getMatchedWordCount( + ["I", "really", "really", "really", "like", "to", "code"], + "really" + ) +); + +console.log( + getMatchedWordCount( + ["Do", "not", "fear", "the", "dandy", "lion"], + "dandy" + ) +); +``` diff --git a/curriculum/challenges/english/blocks/workshop-word-counter/6978bd465213832659f3338b.md b/curriculum/challenges/english/blocks/workshop-word-counter/6978bd465213832659f3338b.md new file mode 100644 index 00000000000..7c065008793 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-word-counter/6978bd465213832659f3338b.md @@ -0,0 +1,81 @@ +--- +id: 6978bd465213832659f3338b +title: Step 9 +challengeType: 1 +dashedName: step-9 +--- + +# --description-- + +Now, inside the loop, log the following template literal to the console: `Checking "${word}" against "${match}" | Running count: ${count}` + +# --hints-- + +You should have exactly one `console.log` statement inside the loop in your `getMatchedWordCount` function. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); +const functionRegex = /(functiongetMatchedWordCount\(sentence,match\)\{\S*?returncount;\})/; +const normalizedFunctionCode = normalizedCode.match(functionRegex)[1]; +console.log(normalizedFunctionCode); + +assert.match(normalizedFunctionCode, /for\(constwordofsentence\)\{\S*?console\.log\(\S*?\)\S*?\}/); +assert.notMatch(normalizedFunctionCode, /for\(constwordofsentence\)\{\S*?(console\.log\(\S*?\))\S*?(console\.log\(\S*?\))\S*?\}/); +``` + +Your `console.log` statement inside the loop in your `getMatchedWordCount` function should use a template literal with the following placeholders: `${word}`, `${match}`, and `${count}`. + +```js +const codeWithoutJSComments = __helpers.removeJSComments(code); +const normalizedCode = __helpers.removeWhiteSpace(codeWithoutJSComments); +const functionRegex = /(functiongetMatchedWordCount\(sentence,match\)\{\S*?returncount;\})/; +const normalizedFunctionCode = normalizedCode.match(functionRegex)[1]; +const consoleLogArguments = normalizedFunctionCode.match(/for\(constwordofsentence\)\{\S*?console\.log\((\S*?)\)\S*?\}/)[1] +const templateLiteral = consoleLogArguments.match(/(^\`\S*\`$)/)[1]; + +assert.include(templateLiteral, "${word}"); +assert.include(templateLiteral, "${match}"); +assert.include(templateLiteral, "${count}"); +``` + +When the `getMatchedWordCount` function is called with `(['foo'], 'bar')`, the `console.log()` statement inside the function should be called once with the string `Checking "foo" against "bar" | Running count: 0`. Instead, it was called with each string in the following comma-separated list: `--fcc-actual--`. + +```js +const consoleLogSpy = __helpers.spyOn(console, 'log'); +getMatchedWordCount(['foo'], 'bar'); +assert.deepEqual(consoleLogSpy.calls, [['Checking "foo" against "bar" | Running count: 0']]); +consoleLogSpy.restore(); +``` + +# --seed-- + +## --seed-contents-- + +```js +function printCharacters(str) { + for (const char of str) { + console.log(char); + } +} +printCharacters("hello"); + +function getMatchedWordCount(sentence, match) { + let count = 0; + + for (const word of sentence) { +--fcc-editable-region-- + +--fcc-editable-region-- + } + + return count; +} + +console.log( + getMatchedWordCount( + ["I", "really", "really", "really", "like", "to", "code"], + "really" + ) +); +``` diff --git a/curriculum/structure/blocks/workshop-word-counter.json b/curriculum/structure/blocks/workshop-word-counter.json new file mode 100644 index 00000000000..4272c968b28 --- /dev/null +++ b/curriculum/structure/blocks/workshop-word-counter.json @@ -0,0 +1,22 @@ +{ + "isUpcomingChange": false, + "dashedName": "workshop-word-counter", + "helpCategory": "JavaScript", + "blockLayout": "challenge-grid", + "challengeOrder": [ + { "id": "691f7bbf76229bb97c60827d", "title": "Step 1" }, + { "id": "6920c9cda1c7f056f75e4b1a", "title": "Step 2" }, + { "id": "6920d189e36b6b60a6330fee", "title": "Step 3" }, + { "id": "6920dae65fb8bb6949bcdaba", "title": "Step 4" }, + { "id": "6921d688b8d58581d34459b9", "title": "Step 5" }, + { "id": "6921d90b5ce50185505d2004", "title": "Step 6" }, + { "id": "6921dae10700e300f26994e3", "title": "Step 7" }, + { "id": "6921de8d2a111d0341cff702", "title": "Step 8" }, + { "id": "6978bd465213832659f3338b", "title": "Step 9" }, + { "id": "6921e10ae2681205b516fbe6", "title": "Step 10" }, + { "id": "69220a03729c43082ad3e9f6", "title": "Step 11" } + ], + "blockLabel": "workshop", + "usesMultifileEditor": true, + "hasEditableBoundaries": true +} diff --git a/curriculum/structure/superblocks/javascript-v9.json b/curriculum/structure/superblocks/javascript-v9.json index 9e2f1c4e129..db47f0273a4 100644 --- a/curriculum/structure/superblocks/javascript-v9.json +++ b/curriculum/structure/superblocks/javascript-v9.json @@ -97,6 +97,7 @@ "dashedName": "javascript-loops", "blocks": [ "lecture-working-with-loops", + "workshop-word-counter", "workshop-sentence-analyzer", "workshop-space-mission-roster", "workshop-heritage-library-catalog",