feat: nicer formatting for fill in the blank challenges (#52552)

This commit is contained in:
Oliver Eyton-Williams
2023-12-19 00:33:20 +01:00
committed by GitHub
parent 0673847088
commit 9fe6a46b81
11 changed files with 1236 additions and 34 deletions
@@ -0,0 +1,130 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { parseBlanks } from './parse-blanks';
describe('parseBlanks', () => {
it('handles strings without blanks', () => {
expect(parseBlanks('<p>hello world</p>')).toEqual([
[{ type: 'text', value: 'hello world' }]
]);
});
it('handles strings without blanks and with multiple paragraphs', () => {
expect(parseBlanks('<p>hello world</p><p>dlrow olleh</p>')).toEqual([
[{ type: 'text', value: 'hello world' }],
[{ type: 'text', value: 'dlrow olleh' }]
]);
});
it('handles strings with blanks', () => {
expect(parseBlanks('<p>hello _!</p>')).toEqual([
[
{ type: 'text', value: 'hello ' },
{ type: 'blank', value: 0 },
{ type: 'text', value: '!' }
]
]);
expect(parseBlanks('<p>hello _! Nice _ to meet you.</p>')).toEqual([
[
{ type: 'text', value: 'hello ' },
{ type: 'blank', value: 0 },
{ type: 'text', value: '! Nice ' },
{ type: 'blank', value: 1 },
{ type: 'text', value: ' to meet you.' }
]
]);
});
it('handles paragraphs with a leading blank', () => {
expect(parseBlanks('<p>_ hello</p>')).toEqual([
[
{ type: 'blank', value: 0 },
{ type: 'text', value: ' hello' }
]
]);
});
it('removes trailing empty strings', () => {
expect(parseBlanks('<p>hello _</p>')).toEqual([
[
{ type: 'text', value: 'hello ' },
{ type: 'blank', value: 0 }
]
]);
});
it('handles strings with blanks and multiple paragraphs', () => {
expect(parseBlanks(`<p>hello _!</p><p>dlrow _</p>`)).toEqual([
[
{ type: 'text', value: 'hello ' },
{ type: 'blank', value: 0 },
{ type: 'text', value: '!' }
],
[
{ type: 'text', value: 'dlrow ' },
{ type: 'blank', value: 1 }
]
]);
});
it('ignores newlines between paragraphs', () => {
expect(
parseBlanks(`<p>hello _!</p>
<p>dlrow _</p>`)
).toEqual([
[
{ type: 'text', value: 'hello ' },
{ type: 'blank', value: 0 },
{ type: 'text', value: '!' }
],
[
{ type: 'text', value: 'dlrow ' },
{ type: 'blank', value: 1 }
]
]);
});
it('ignores whitespace surrounding the input', () => {
expect(
parseBlanks(` <p>hello _!</p>
`)
).toEqual([
[
{ type: 'text', value: 'hello ' },
{ type: 'blank', value: 0 },
{ type: 'text', value: '!' }
]
]);
});
it('counts blanks across multiple paragraphs', () => {
expect(
parseBlanks(`<p>hello _!</p><p>dlrow _ _</p><p> even _ more _</p>`)
).toEqual([
[
{ type: 'text', value: 'hello ' },
{ type: 'blank', value: 0 },
{ type: 'text', value: '!' }
],
[
{ type: 'text', value: 'dlrow ' },
{ type: 'blank', value: 1 },
{ type: 'text', value: ' ' },
{ type: 'blank', value: 2 }
],
[
{ type: 'text', value: ' even ' },
{ type: 'blank', value: 3 },
{ type: 'text', value: ' more ' },
{ type: 'blank', value: 4 }
]
]);
});
it('throws if the string is not wrapped in p tags', () => {
expect(() => parseBlanks('hello _!')).toThrow();
expect(() => parseBlanks('<p>hello _!</p>hello _!')).toThrow();
expect(() => parseBlanks('hello _!<p>hello</p>')).toThrow();
});
});
@@ -0,0 +1,52 @@
type TextNode = { type: 'text'; value: string };
type BlankNode = { type: 'blank'; value: number };
type ParagraphElement = TextNode | BlankNode;
export const parseBlanks = (text: string) => {
const trimmed = text.trim();
if (!trimmed.startsWith('<p>') || !trimmed.endsWith('</p>')) {
throw new Error(`Expected
${text}
to be wrapped in <p> tags`);
}
// We're expecting only paragraphs, so text after </p> and before <p> can be
// ignored.
const rawParagraphs = trimmed
.split('<p>')
.map(s => s.replace(/<\/p>\s*/, ''));
// There is always a leading empty string, so we remove it.
rawParagraphs.shift();
const { paragraphs } = rawParagraphs.reduce(
(acc, p) => {
const splitByBlank = p.split('_');
const parsedParagraph = splitByBlank
.map<ParagraphElement[]>((text, i) => [
{ type: 'text', value: text },
{ type: 'blank', value: acc.count + i }
])
.flat();
parsedParagraph.pop(); // remove last blank
const paragraph = parsedParagraph.filter(p => {
// remove empty strings
if (p.type === 'text') {
return p.value;
} else {
return true;
}
});
return {
count: acc.count + splitByBlank.length - 1,
paragraphs: [...acc.paragraphs, paragraph]
};
},
{ count: 0, paragraphs: [] } as {
count: number;
paragraphs: ParagraphElement[][];
}
);
return paragraphs;
};
@@ -27,12 +27,13 @@ import {
openModal,
updateSolutionFormValues
} from '../redux/actions';
import Scene from '../components/scene/scene';
import { isChallengeCompletedSelector } from '../redux/selectors';
import { parseBlanks } from './parse-blanks';
// Styles
import '../video.css';
import './show.css';
import Scene from '../components/scene/scene';
// Redux Setup
const mapStateToProps = createSelector(
@@ -273,8 +274,8 @@ class ShowFillInTheBlank extends Component<
)} - ${title}`;
const { allBlanksFilled, feedback, showFeedback, showWrong } = this.state;
const paragraphs = parseBlanks(sentence);
const splitSentence = sentence.replace(/^<p>|<\/p>$/g, '').split('_');
const blankAnswers = blanks.map(b => b.answer);
return (
@@ -328,37 +329,37 @@ class ShowFillInTheBlank extends Component<
if it encounters a key combination, so we have to pass in the individual keys to observe */}
<ObserveKeys only={['ctrl', 'cmd', 'enter']}>
<div>
<p>
{splitSentence.map((s, i) => {
return (
<Fragment key={i}>
<PrismFormatted
text={this.addCodeTags(s, i, blankAnswers.length)}
className={`code-tag ${this.addPrismClass(
i,
blankAnswers.length
)}`}
useSpan
noAria
/>
{blankAnswers[i] && (
<input
type='text'
maxLength={blankAnswers[i].length + 3}
className={`fill-in-the-blank-input ${this.addInputClass(
i
)}`}
onChange={this.handleInputChange}
data-index={i}
style={{
width: `${blankAnswers[i].length * 11 + 11}px`
}}
/>
)}
</Fragment>
);
})}
</p>
{paragraphs.map((p, i) => {
return (
// both keys, i and j, are stable between renders, since
// the paragraphs are static.
<p key={i}>
{p.map((node, j) => {
if (node.type === 'text') return node.value;
if (node.type === 'blank')
return (
<input
key={j}
type='text'
maxLength={
blankAnswers[node.value].length + 3
}
className={`fill-in-the-blank-input ${this.addInputClass(
node.value
)}`}
onChange={this.handleInputChange}
data-index={node.value}
style={{
width: `${
blankAnswers[node.value].length * 11 + 11
}px`
}}
/>
);
})}
</p>
);
})}
</div>
</ObserveKeys>
<Spacer size='medium' />
@@ -0,0 +1,291 @@
{
"type": "root",
"children": [
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "--description--",
"position": {
"start": { "line": 1, "column": 3, "offset": 2 },
"end": { "line": 1, "column": 18, "offset": 17 }
}
}
],
"position": {
"start": { "line": 1, "column": 1, "offset": 0 },
"end": { "line": 1, "column": 18, "offset": 17 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "In English, to check or confirm something people sometimes use tag questions. For example, ",
"position": {
"start": { "line": 3, "column": 1, "offset": 19 },
"end": { "line": 3, "column": 92, "offset": 110 }
}
},
{
"type": "inlineCode",
"value": "You are a programmer, right?",
"position": {
"start": { "line": 3, "column": 92, "offset": 110 },
"end": { "line": 3, "column": 122, "offset": 140 }
}
},
{
"type": "text",
"value": " Here, ",
"position": {
"start": { "line": 3, "column": 122, "offset": 140 },
"end": { "line": 3, "column": 129, "offset": 147 }
}
},
{
"type": "inlineCode",
"value": "right?",
"position": {
"start": { "line": 3, "column": 129, "offset": 147 },
"end": { "line": 3, "column": 137, "offset": 155 }
}
},
{
"type": "text",
"value": " is used as a tag to check or confirm the previous statement.",
"position": {
"start": { "line": 3, "column": 137, "offset": 155 },
"end": { "line": 3, "column": 198, "offset": 216 }
}
}
],
"position": {
"start": { "line": 3, "column": 1, "offset": 19 },
"end": { "line": 3, "column": 198, "offset": 216 }
}
},
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "--fillInTheBlank--",
"position": {
"start": { "line": 5, "column": 3, "offset": 220 },
"end": { "line": 5, "column": 21, "offset": 238 }
}
}
],
"position": {
"start": { "line": 5, "column": 1, "offset": 218 },
"end": { "line": 5, "column": 21, "offset": 238 }
}
},
{
"type": "heading",
"depth": 2,
"children": [
{
"type": "text",
"value": "--sentence--",
"position": {
"start": { "line": 7, "column": 4, "offset": 243 },
"end": { "line": 7, "column": 16, "offset": 255 }
}
}
],
"position": {
"start": { "line": 7, "column": 1, "offset": 240 },
"end": { "line": 7, "column": 16, "offset": 255 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "A sentence _ paragraph 1",
"position": {
"start": { "line": 9, "column": 1, "offset": 257 },
"end": { "line": 9, "column": 27, "offset": 283 }
}
},
{
"type": "text",
"value": "\n",
"position": {
"start": { "line": 9, "column": 27, "offset": 283 },
"end": { "line": 10, "column": 1, "offset": 284 }
}
},
{
"type": "inlineCode",
"value": "not enough newlines, so no paragraph 2",
"position": {
"start": { "line": 10, "column": 1, "offset": 284 },
"end": { "line": 10, "column": 41, "offset": 324 }
}
}
],
"position": {
"start": { "line": 9, "column": 1, "offset": 257 },
"end": { "line": 10, "column": 41, "offset": 324 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Sentence in _ 2",
"position": {
"start": { "line": 12, "column": 1, "offset": 326 },
"end": { "line": 12, "column": 16, "offset": 341 }
}
}
],
"position": {
"start": { "line": 12, "column": 1, "offset": 326 },
"end": { "line": 12, "column": 16, "offset": 341 }
}
},
{
"type": "heading",
"depth": 2,
"children": [
{
"type": "text",
"value": "--blanks--",
"position": {
"start": { "line": 14, "column": 4, "offset": 346 },
"end": { "line": 14, "column": 14, "offset": 356 }
}
}
],
"position": {
"start": { "line": 14, "column": 1, "offset": 343 },
"end": { "line": 14, "column": 14, "offset": 356 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "are",
"position": {
"start": { "line": 16, "column": 1, "offset": 358 },
"end": { "line": 16, "column": 6, "offset": 363 }
}
}
],
"position": {
"start": { "line": 16, "column": 1, "offset": 358 },
"end": { "line": 16, "column": 6, "offset": 363 }
}
},
{
"type": "heading",
"depth": 3,
"children": [
{
"type": "text",
"value": "--feedback--",
"position": {
"start": { "line": 18, "column": 5, "offset": 369 },
"end": { "line": 18, "column": 17, "offset": 381 }
}
}
],
"position": {
"start": { "line": 18, "column": 1, "offset": 365 },
"end": { "line": 18, "column": 17, "offset": 381 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Pay attention to the verb in the sentence.",
"position": {
"start": { "line": 20, "column": 1, "offset": 383 },
"end": { "line": 20, "column": 43, "offset": 425 }
}
}
],
"position": {
"start": { "line": 20, "column": 1, "offset": 383 },
"end": { "line": 20, "column": 43, "offset": 425 }
}
},
{
"type": "thematicBreak",
"position": {
"start": { "line": 22, "column": 1, "offset": 427 },
"end": { "line": 22, "column": 4, "offset": 430 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "right",
"position": {
"start": { "line": 24, "column": 1, "offset": 432 },
"end": { "line": 24, "column": 8, "offset": 439 }
}
}
],
"position": {
"start": { "line": 24, "column": 1, "offset": 432 },
"end": { "line": 24, "column": 8, "offset": 439 }
}
},
{
"type": "heading",
"depth": 3,
"children": [
{
"type": "text",
"value": "--feedback--",
"position": {
"start": { "line": 26, "column": 5, "offset": 445 },
"end": { "line": 26, "column": 17, "offset": 457 }
}
}
],
"position": {
"start": { "line": 26, "column": 1, "offset": 441 },
"end": { "line": 26, "column": 17, "offset": 457 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Pay attention to the verb in the sentence.",
"position": {
"start": { "line": 28, "column": 1, "offset": 459 },
"end": { "line": 28, "column": 43, "offset": 501 }
}
}
],
"position": {
"start": { "line": 28, "column": 1, "offset": 459 },
"end": { "line": 28, "column": 43, "offset": 501 }
}
}
],
"position": {
"start": { "line": 1, "column": 1, "offset": 0 },
"end": { "line": 29, "column": 1, "offset": 502 }
}
}
@@ -0,0 +1,275 @@
{
"type": "root",
"children": [
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "--description--",
"position": {
"start": { "line": 1, "column": 3, "offset": 2 },
"end": { "line": 1, "column": 18, "offset": 17 }
}
}
],
"position": {
"start": { "line": 1, "column": 1, "offset": 0 },
"end": { "line": 1, "column": 18, "offset": 17 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "In English, to check or confirm something people sometimes use tag questions. For example, ",
"position": {
"start": { "line": 3, "column": 1, "offset": 19 },
"end": { "line": 3, "column": 92, "offset": 110 }
}
},
{
"type": "inlineCode",
"value": "You are a programmer, right?",
"position": {
"start": { "line": 3, "column": 92, "offset": 110 },
"end": { "line": 3, "column": 122, "offset": 140 }
}
},
{
"type": "text",
"value": " Here, ",
"position": {
"start": { "line": 3, "column": 122, "offset": 140 },
"end": { "line": 3, "column": 129, "offset": 147 }
}
},
{
"type": "inlineCode",
"value": "right?",
"position": {
"start": { "line": 3, "column": 129, "offset": 147 },
"end": { "line": 3, "column": 137, "offset": 155 }
}
},
{
"type": "text",
"value": " is used as a tag to check or confirm the previous statement.",
"position": {
"start": { "line": 3, "column": 137, "offset": 155 },
"end": { "line": 3, "column": 198, "offset": 216 }
}
}
],
"position": {
"start": { "line": 3, "column": 1, "offset": 19 },
"end": { "line": 3, "column": 198, "offset": 216 }
}
},
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "--fillInTheBlank--",
"position": {
"start": { "line": 5, "column": 3, "offset": 220 },
"end": { "line": 5, "column": 21, "offset": 238 }
}
}
],
"position": {
"start": { "line": 5, "column": 1, "offset": 218 },
"end": { "line": 5, "column": 21, "offset": 238 }
}
},
{
"type": "heading",
"depth": 2,
"children": [
{
"type": "text",
"value": "--sentence--",
"position": {
"start": { "line": 7, "column": 4, "offset": 243 },
"end": { "line": 7, "column": 16, "offset": 255 }
}
}
],
"position": {
"start": { "line": 7, "column": 1, "offset": 240 },
"end": { "line": 7, "column": 16, "offset": 255 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "A sentence _ paragraph 1",
"position": {
"start": { "line": 9, "column": 1, "offset": 257 },
"end": { "line": 9, "column": 27, "offset": 283 }
}
}
],
"position": {
"start": { "line": 9, "column": 1, "offset": 257 },
"end": { "line": 9, "column": 27, "offset": 283 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Sentence in _ 2",
"position": {
"start": { "line": 11, "column": 1, "offset": 285 },
"end": { "line": 11, "column": 16, "offset": 300 }
}
}
],
"position": {
"start": { "line": 11, "column": 1, "offset": 285 },
"end": { "line": 11, "column": 16, "offset": 300 }
}
},
{
"type": "heading",
"depth": 2,
"children": [
{
"type": "text",
"value": "--blanks--",
"position": {
"start": { "line": 13, "column": 4, "offset": 305 },
"end": { "line": 13, "column": 14, "offset": 315 }
}
}
],
"position": {
"start": { "line": 13, "column": 1, "offset": 302 },
"end": { "line": 13, "column": 14, "offset": 315 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "are",
"position": {
"start": { "line": 15, "column": 1, "offset": 317 },
"end": { "line": 15, "column": 6, "offset": 322 }
}
}
],
"position": {
"start": { "line": 15, "column": 1, "offset": 317 },
"end": { "line": 15, "column": 6, "offset": 322 }
}
},
{
"type": "heading",
"depth": 3,
"children": [
{
"type": "text",
"value": "--feedback--",
"position": {
"start": { "line": 17, "column": 5, "offset": 328 },
"end": { "line": 17, "column": 17, "offset": 340 }
}
}
],
"position": {
"start": { "line": 17, "column": 1, "offset": 324 },
"end": { "line": 17, "column": 17, "offset": 340 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Pay attention to the verb in the sentence.",
"position": {
"start": { "line": 19, "column": 1, "offset": 342 },
"end": { "line": 19, "column": 43, "offset": 384 }
}
}
],
"position": {
"start": { "line": 19, "column": 1, "offset": 342 },
"end": { "line": 19, "column": 43, "offset": 384 }
}
},
{
"type": "thematicBreak",
"position": {
"start": { "line": 21, "column": 1, "offset": 386 },
"end": { "line": 21, "column": 4, "offset": 389 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "right",
"position": {
"start": { "line": 23, "column": 1, "offset": 391 },
"end": { "line": 23, "column": 8, "offset": 398 }
}
}
],
"position": {
"start": { "line": 23, "column": 1, "offset": 391 },
"end": { "line": 23, "column": 8, "offset": 398 }
}
},
{
"type": "heading",
"depth": 3,
"children": [
{
"type": "text",
"value": "--feedback--",
"position": {
"start": { "line": 25, "column": 5, "offset": 404 },
"end": { "line": 25, "column": 17, "offset": 416 }
}
}
],
"position": {
"start": { "line": 25, "column": 1, "offset": 400 },
"end": { "line": 25, "column": 17, "offset": 416 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Pay attention to the verb in the sentence.",
"position": {
"start": { "line": 27, "column": 1, "offset": 418 },
"end": { "line": 27, "column": 43, "offset": 460 }
}
}
],
"position": {
"start": { "line": 27, "column": 1, "offset": 418 },
"end": { "line": 27, "column": 43, "offset": 460 }
}
}
],
"position": {
"start": { "line": 1, "column": 1, "offset": 0 },
"end": { "line": 28, "column": 1, "offset": 461 }
}
}
@@ -0,0 +1,275 @@
{
"type": "root",
"children": [
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "--description--",
"position": {
"start": { "line": 1, "column": 3, "offset": 2 },
"end": { "line": 1, "column": 18, "offset": 17 }
}
}
],
"position": {
"start": { "line": 1, "column": 1, "offset": 0 },
"end": { "line": 1, "column": 18, "offset": 17 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "In English, to check or confirm something people sometimes use tag questions. For example, ",
"position": {
"start": { "line": 3, "column": 1, "offset": 19 },
"end": { "line": 3, "column": 92, "offset": 110 }
}
},
{
"type": "inlineCode",
"value": "You are a programmer, right?",
"position": {
"start": { "line": 3, "column": 92, "offset": 110 },
"end": { "line": 3, "column": 122, "offset": 140 }
}
},
{
"type": "text",
"value": " Here, ",
"position": {
"start": { "line": 3, "column": 122, "offset": 140 },
"end": { "line": 3, "column": 129, "offset": 147 }
}
},
{
"type": "inlineCode",
"value": "right?",
"position": {
"start": { "line": 3, "column": 129, "offset": 147 },
"end": { "line": 3, "column": 137, "offset": 155 }
}
},
{
"type": "text",
"value": " is used as a tag to check or confirm the previous statement.",
"position": {
"start": { "line": 3, "column": 137, "offset": 155 },
"end": { "line": 3, "column": 198, "offset": 216 }
}
}
],
"position": {
"start": { "line": 3, "column": 1, "offset": 19 },
"end": { "line": 3, "column": 198, "offset": 216 }
}
},
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "--fillInTheBlank--",
"position": {
"start": { "line": 5, "column": 3, "offset": 220 },
"end": { "line": 5, "column": 21, "offset": 238 }
}
}
],
"position": {
"start": { "line": 5, "column": 1, "offset": 218 },
"end": { "line": 5, "column": 21, "offset": 238 }
}
},
{
"type": "heading",
"depth": 2,
"children": [
{
"type": "text",
"value": "--sentence--",
"position": {
"start": { "line": 7, "column": 4, "offset": 243 },
"end": { "line": 7, "column": 16, "offset": 255 }
}
}
],
"position": {
"start": { "line": 7, "column": 1, "offset": 240 },
"end": { "line": 7, "column": 16, "offset": 255 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "A sentence _ paragraph 1",
"position": {
"start": { "line": 9, "column": 1, "offset": 257 },
"end": { "line": 9, "column": 27, "offset": 283 }
}
}
],
"position": {
"start": { "line": 9, "column": 1, "offset": 257 },
"end": { "line": 9, "column": 27, "offset": 283 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "Sentence in _ 2",
"position": {
"start": { "line": 11, "column": 1, "offset": 285 },
"end": { "line": 11, "column": 18, "offset": 302 }
}
}
],
"position": {
"start": { "line": 11, "column": 1, "offset": 285 },
"end": { "line": 11, "column": 18, "offset": 302 }
}
},
{
"type": "heading",
"depth": 2,
"children": [
{
"type": "text",
"value": "--blanks--",
"position": {
"start": { "line": 13, "column": 4, "offset": 307 },
"end": { "line": 13, "column": 14, "offset": 317 }
}
}
],
"position": {
"start": { "line": 13, "column": 1, "offset": 304 },
"end": { "line": 13, "column": 14, "offset": 317 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "are",
"position": {
"start": { "line": 15, "column": 1, "offset": 319 },
"end": { "line": 15, "column": 6, "offset": 324 }
}
}
],
"position": {
"start": { "line": 15, "column": 1, "offset": 319 },
"end": { "line": 15, "column": 6, "offset": 324 }
}
},
{
"type": "heading",
"depth": 3,
"children": [
{
"type": "text",
"value": "--feedback--",
"position": {
"start": { "line": 17, "column": 5, "offset": 330 },
"end": { "line": 17, "column": 17, "offset": 342 }
}
}
],
"position": {
"start": { "line": 17, "column": 1, "offset": 326 },
"end": { "line": 17, "column": 17, "offset": 342 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Pay attention to the verb in the sentence.",
"position": {
"start": { "line": 19, "column": 1, "offset": 344 },
"end": { "line": 19, "column": 43, "offset": 386 }
}
}
],
"position": {
"start": { "line": 19, "column": 1, "offset": 344 },
"end": { "line": 19, "column": 43, "offset": 386 }
}
},
{
"type": "thematicBreak",
"position": {
"start": { "line": 21, "column": 1, "offset": 388 },
"end": { "line": 21, "column": 4, "offset": 391 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "inlineCode",
"value": "right",
"position": {
"start": { "line": 23, "column": 1, "offset": 393 },
"end": { "line": 23, "column": 8, "offset": 400 }
}
}
],
"position": {
"start": { "line": 23, "column": 1, "offset": 393 },
"end": { "line": 23, "column": 8, "offset": 400 }
}
},
{
"type": "heading",
"depth": 3,
"children": [
{
"type": "text",
"value": "--feedback--",
"position": {
"start": { "line": 25, "column": 5, "offset": 406 },
"end": { "line": 25, "column": 17, "offset": 418 }
}
}
],
"position": {
"start": { "line": 25, "column": 1, "offset": 402 },
"end": { "line": 25, "column": 17, "offset": 418 }
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Pay attention to the verb in the sentence.",
"position": {
"start": { "line": 27, "column": 1, "offset": 420 },
"end": { "line": 27, "column": 43, "offset": 462 }
}
}
],
"position": {
"start": { "line": 27, "column": 1, "offset": 420 },
"end": { "line": 27, "column": 43, "offset": 462 }
}
}
],
"position": {
"start": { "line": 1, "column": 1, "offset": 0 },
"end": { "line": 28, "column": 1, "offset": 463 }
}
}
@@ -0,0 +1,28 @@
# --description--
In English, to check or confirm something people sometimes use tag questions. For example, `You are a programmer, right?` Here, `right?` is used as a tag to check or confirm the previous statement.
# --fillInTheBlank--
## --sentence--
`A sentence _ paragraph 1`
`not enough newlines, so no paragraph 2`
Sentence in _ 2
## --blanks--
`are`
### --feedback--
Pay attention to the verb in the sentence.
---
`right`
### --feedback--
Pay attention to the verb in the sentence.
@@ -0,0 +1,27 @@
# --description--
In English, to check or confirm something people sometimes use tag questions. For example, `You are a programmer, right?` Here, `right?` is used as a tag to check or confirm the previous statement.
# --fillInTheBlank--
## --sentence--
`A sentence _ paragraph 1`
Sentence in _ 2
## --blanks--
`are`
### --feedback--
Pay attention to the verb in the sentence.
---
`right`
### --feedback--
Pay attention to the verb in the sentence.
@@ -0,0 +1,27 @@
# --description--
In English, to check or confirm something people sometimes use tag questions. For example, `You are a programmer, right?` Here, `right?` is used as a tag to check or confirm the previous statement.
# --fillInTheBlank--
## --sentence--
`A sentence _ paragraph 1`
`Sentence in _ 2`
## --blanks--
`are`
### --feedback--
Pay attention to the verb in the sentence.
---
`right`
### --feedback--
Pay attention to the verb in the sentence.
@@ -6,6 +6,32 @@ const mdastToHtml = require('./utils/mdast-to-html');
const { splitOnThematicBreak } = require('./utils/split-on-thematic-break');
const NOT_IN_PARAGRAPHS = `Each inline code block in the fillInTheBlank sentence section must in its own paragraph
If you have more than one code block, check that they're separated by a blank line
Example of bad formatting:
\`too close\`
\`to each other\`
Example of good formatting:
\`separated\`
\`by a blank line\`
`;
const NOT_IN_CODE_BLOCK = `Each paragraph in the fillInTheBlank sentence section must be inside an inline code block
Example of bad formatting:
## --sentence--
This is a sentence
Example of good formatting:
## --sentence--
\`This is a sentence\`
`;
function plugin() {
return transformer;
function transformer(tree, file) {
@@ -24,7 +50,17 @@ function plugin() {
}
function getfillInTheBlank(sentenceNodes, blanksNodes) {
const sentence = mdastToHtml(sentenceNodes);
const sentenceWithoutCodeBlocks = sentenceNodes.map(node => {
node.children.forEach(child => {
if (child.type === 'text' && child.value.trim() === '')
throw Error(NOT_IN_PARAGRAPHS);
if (child.type !== 'inlineCode') throw Error(NOT_IN_CODE_BLOCK);
});
const children = node.children.map(child => ({ ...child, type: 'text' }));
return { ...node, children };
});
const sentence = mdastToHtml(sentenceWithoutCodeBlocks);
const blanks = getBlanks(blanksNodes);
if (!sentence) throw Error('sentence is missing from fill in the blank');
@@ -1,5 +1,8 @@
const mockFillInTheBlankAST = require('../__fixtures__/ast-fill-in-the-blank.json');
const mockFillInTheBlankYouAreAST = require('../__fixtures__/ast-fill-in-the-blank-one-blank.json');
const mockFillInTheBlankTwoSentencesAST = require('../__fixtures__/ast-fill-in-the-blank-two-sentences.json');
const mockFillInTheBlankBadSentence = require('../__fixtures__/ast-fill-in-the-blank-bad-sentence.json');
const mockFillInTheBlankBadParagraph = require('../__fixtures__/ast-fill-in-the-blank-bad-paragraph.json');
const addFillInTheBlankQuestion = require('./add-fill-in-the-blank');
describe('fill-in-the-blanks plugin', () => {
@@ -66,6 +69,63 @@ describe('fill-in-the-blanks plugin', () => {
});
});
it('should extract the sentence from the surrounding inline code block', () => {
plugin(mockFillInTheBlankAST, file);
const testObject = file.data.fillInTheBlank;
expect(testObject.sentence).toBe(
'<p>Hello, You _ the new graphic designer, _? _ to meet you!</p>'
);
});
it('should extract sentences from multiple inline code blocks', () => {
plugin(mockFillInTheBlankTwoSentencesAST, file);
const testObject = file.data.fillInTheBlank;
expect(testObject.sentence).toBe(
`<p>A sentence _ paragraph 1</p>
<p>Sentence in _ 2</p>`
);
});
it('should throw if a sentence is not inside an inline code block', () => {
expect(() => {
plugin(mockFillInTheBlankBadSentence, file);
}).toThrow(
`Each paragraph in the fillInTheBlank sentence section must be inside an inline code block
Example of bad formatting:
## --sentence--
This is a sentence
Example of good formatting:
## --sentence--
\`This is a sentence\`
`
);
});
it('should throw if there are multiple inline code blocks in the same paragraph', () => {
expect(() => {
plugin(mockFillInTheBlankBadParagraph, file);
}).toThrow(
`Each inline code block in the fillInTheBlank sentence section must in its own paragraph
If you have more than one code block, check that they're separated by a blank line
Example of bad formatting:
\`too close\`
\`to each other\`
Example of good formatting:
\`separated\`
\`by a blank line\`
`
);
});
it('should handle one blank', () => {
plugin(mockFillInTheBlankYouAreAST, file);
const testObject = file.data.fillInTheBlank;