Skip to content

Commit

Permalink
various bug fixes
Browse files Browse the repository at this point in the history
closes rooseveltframework#412

closes many unreported bugs

wrote a test for rooseveltframework#404

wrote a test for rooseveltframework#357 but upon further investigate now consider it a wontfix
  • Loading branch information
kethinov committed Sep 26, 2020
1 parent ceb45da commit b71e33c
Show file tree
Hide file tree
Showing 129 changed files with 414 additions and 90 deletions.
9 changes: 5 additions & 4 deletions conditionals.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ function parseConditional (charList, type, model) {
var readMode = false // Start parsing literal equality condition (ex: <if something='here'>)
var outsideTags = false // Flag telling us we are inbetween condition tags
var isNested = false // Extra check for whether or not the nested condition also has an <else>
var sawOpeningElseFirst = false // Tracks if an <else> tag gets opened and prevents the closing tag from being skipped by nesting logic
var nested = 0 // Keeps track of how many nested conditionals are present
var teddyVarName = '' // Teddy conditional argument name or operator used (i.e: or, and, xor, not)
var teddyVarExpected = '' // Literal value for a conditional teddy argument (i.e: <if something='some content'>)
Expand Down Expand Up @@ -111,10 +112,9 @@ function parseConditional (charList, type, model) {
commentIndices.push(i)
} else if (twoArraysEqual(charList.slice(i - tagLengths.if + 1, i + 1), primaryTags.if) || twoArraysEqual(charList.slice(i - tagLengths.unless + 1, i + 1), primaryTags.unless)) { // nested <if> or <unless>
nested++
} else if (validEndingTag(charList, i) && (twoArraysEqual(charList.slice(i - tagLengths.cif + 1, i + 1), primaryTags.cif) || twoArraysEqual(charList.slice(i - tagLengths.cunless + 1, i + 1), primaryTags.cunless) || (twoArraysEqual(charList.slice(i - tagLengths.celse + 1, i + 1), secondaryTags.celse) && nested > 0))) { // Closing <if> tag
} else if (validEndingTag(charList, i) && (twoArraysEqual(charList.slice(i - tagLengths.cif + 1, i + 1), primaryTags.cif) || twoArraysEqual(charList.slice(i - tagLengths.cunless + 1, i + 1), primaryTags.cunless))) { // Closing <if> tag
if (nested > 0) { // Outside one level of nested conditional (only looks for <if> or <unless>)
nested--

if (nested === 0) { // In case the nested conditional has an else tag
isNested = true
}
Expand All @@ -127,7 +127,6 @@ function parseConditional (charList, type, model) {
if (!isNested) {
// Set the condition type to be either if or unless dependent on the tag being currently read
condition.type = charList[i - 5] === 'i' ? 'if' : 'unless'

readingConditional = true
tagStart = i
i = charList.lastIndexOf(' ', i)
Expand All @@ -140,13 +139,15 @@ function parseConditional (charList, type, model) {
} else if (twoArraysEqual(charList.slice(i - tagLengths.else + 1, i + 1), secondaryTags.else) && nested < 1) { // <else> tag
if (!isNested) { // Push [start, end] indices of <else> to list
boc.push([i, i - tagLengths.else])
sawOpeningElseFirst = true // Forces the </else> to render regardless of nested conditional tags within
}
} else if (validEndingTag(charList, i) && twoArraysEqual(charList.slice(i - tagLengths.celse + 1, i + 1), secondaryTags.celse) && nested < 1) { // </else> tag
if (isNested) { // skip </else> tag for a nested condition
if (isNested && !sawOpeningElseFirst) { // skip </else> tag for a nested condition
isNested = false
} else { // Push [start, end] indices of </else> to list
const endOfClosingTag = charList.lastIndexOf('>', i)
eoc.push([i, endOfClosingTag])
sawOpeningElseFirst = false
break
}
}
Expand Down
16 changes: 16 additions & 0 deletions looping.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ function parseLoop (charList, model, passes, endParse, fs, contextModels, curren
if (currentChar === '}') { // Closing curly bracket means we are done reading variable name
if (teddyName === params.val) { // {var} name read is a val
teddyString = `${vals[i]}`
if (teddyString === '') {
teddyString = ' ' // Temporary workaround; we don't want it to print the variable name
}
// TODO: handle when typeof vals[i] is an object or an array
// if the val is an object or an array, it needs to be possible to loop through it
// https://github.com/rooseveltframework/teddy/issues/404
// if (typeof vals[i] === 'string') {
// // teddyString = `${vals[i]}`
// if (teddyString === '') {
// // teddyString = ' ' // Temporary workaround; we don't want it to print the variable name
// } else {
// // handle it here
// }
} else if (teddyName === params.key) { // {var} name read is a key
teddyString = `${keyVals[i]}`
} else if (teddyName.indexOf('.') >= 0 && (teddyName.slice(0, teddyName.indexOf('.')) === params.val)) { // {var.next} name read is a val that is an object
Expand All @@ -135,6 +148,9 @@ function parseLoop (charList, model, passes, endParse, fs, contextModels, curren
}
// Replace teddy variable name with actual value
if (teddyString !== '' && teddyString !== 'undefined') {
if (teddyString === ' ') {
teddyString = '' // Undoing temporary workaround set above
}
slicedTemplate = insertValue(slicedTemplate, teddyString.split('').reverse().join(''), sov, j)

// Recalibrate iterator based on length of inserted value (if necessary)
Expand Down
20 changes: 20 additions & 0 deletions test/conditionals.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,4 +353,24 @@ describe('Conditionals', function () {
assert.equalIgnoreSpaces(teddy.render('conditionals/ifMultipleCommentsElse.html', model), '<!-- HTML comment --><!-- MOAR HTML comments --><p>The variable \'doesntexist\' is not present</p>')
done()
})

it('should render the nested <else> condition (conditionals/nestedConditionalInElse.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('conditionals/nestedConditionalInElse.html', model), '<p>The variable \'something\' and \'somethingElse\' are both present</p>')
done()
})

it('should evaluate the <unless> condition as true and not render the other conditions (conditionals/ifWithSiblingIfWithNestedIfElse.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('conditionals/ifWithSiblingIfWithNestedIfElse.html', model), '<p>Should render.</p>')
done()
})

it('should print the letters behind both <if> statements nested in the <loop> (conditionals/ifLoopDoubleIf.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('conditionals/ifLoopDoubleIf.html', model), '<p>a</p><p>b</p><p>a</p><p>b</p><p>a</p><p>b</p>')
done()
})

it('should correctly print the JSON string as unmodified text (conditionals/ifJSONStringPrintJSONString.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('conditionals/ifJSONStringPrintJSONString.html', model), '<pre>{"content":{"appTitle":"Some App","pageTitle":"{content.appTitle}"},"currentYear":1858,"mainDomain":"localhost:43711","NODE_ENV":"development"}</pre>')
done()
})
})
5 changes: 5 additions & 0 deletions test/includes.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,9 @@ describe('Includes', function () {
assert.equalIgnoreSpaces(teddy.render('includes/nestedOneliner', model), '<p class="Some content">One line if.</p>')
done()
})

it('should populate <include> <arg> in the child template (includes/includeArgCheckedByOneLineIfWrapper.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('includes/includeArgCheckedByOneLineIfWrapper', model), '<p class="populated">Is it populated? populated</p>')
done()
})
})
16 changes: 16 additions & 0 deletions test/looping.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ describe('Looping', function () {
done()
})

// TODO: https://github.com/rooseveltframework/teddy/issues/404
it.skip('should loop through {arrays} correctly (looping/loopArrayOfArrays.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('looping/loopArrayOfArrays.html', model), '<p>0</p><p>a</p><p>b</p><p>c</p><p>1</p><p>d</p><p>e</p><p>f</p><p>2</p><p>g</p><p>h</p><p>i</p>')
done()
})

it('should loop through {objects} correctly (looping/loopArrayOfObjects.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('looping/loopArrayOfObjects.html', model), '<p>0</p> <p>1</p> <p>2</p> <p>3</p><p>1</p> <p>4</p> <p>5</p> <p>6</p><p>2</p> <p>7</p> <p>8</p> <p>9</p>')
done()
Expand Down Expand Up @@ -193,4 +199,14 @@ describe('Looping', function () {
assert.equalIgnoreSpaces(teddy.render('looping/nestedObjectWithTeddyContentNoParse.html', model), '<p>1</p><p><if something>Something Exists</if></p><p>2</p><p><if something>Something Exists</if></p>')
done()
})

it('should not crash if attempting to set a <loop> val that matches the name of something else in the model (looping/loopValNameCollision.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('looping/loopValNameCollision.html', model), '<p>2</p><p>5</p><p>8</p>')
done()
})

it('should print an empty string for array member set to an empty string (looping/loopValEmptyString.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('looping/loopValEmptyString.html', model), '<p>one</p><p>two</p><p></p><p>three</p>')
done()
})
})
8 changes: 7 additions & 1 deletion test/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ describe('Misc', function () {
})

it('should prevent infinitely referencing variables (misc/varRefVar.html)', function (done) {
assert.equalIgnoreSpaces(teddy.render('misc/varRefVar.html', model), '{bar}')
assert.equalIgnoreSpaces(teddy.render('misc/varRefVar.html', model), '{foo}')
done()
})

Expand All @@ -253,6 +253,12 @@ describe('Misc', function () {
done()
})

// wontfix: https://github.com/rooseveltframework/teddy/issues/357
it.skip('should not render excessive whitespace in a <textarea> as a result of teddy tag indententation / formatting (misc/excessiveWhitespace.html)', function (done) {
assert.equal(teddy.render('misc/excessiveWhitespace.html', model), '<textarea>Some text here</textarea>')
done()
})

it('should execute render callback function for errors and non errors', function (done) {
teddy.setMaxPasses(100)
teddy.setVerbosity(3)
Expand Down
8 changes: 8 additions & 0 deletions test/models/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@ function makeModel () {
definedParent: { undefinedMember: undefined, emptyMember: '' },
camelLetters: ['a', 'b', 'c'],
missingLetter: ['a', undefined, 'c'],
coolArray: [
'one',
'two',
'',
'three'
],
names: { jack: 'guy', jill: 'girl', hill: 'landscape' },
objects: [{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 }],
arrays: [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']],
missingNumbers: [{ a: undefined, b: undefined, c: undefined }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 }],
objectOfObjects: { one: { a: 1, b: 2, c: 3 }, two: { a: 4, b: 5, c: 6 }, three: { a: 7, b: 8, c: 9 } },
nestedObjects: [
Expand Down Expand Up @@ -65,6 +72,7 @@ function makeModel () {
name: 'test'
},
teddyNull: null,
complexJSONString: '{"content":{"appTitle":"Some App","pageTitle":"{content.appTitle}"},"currentYear":1858,"mainDomain":"localhost:43711","NODE_ENV":"development"}',
obj: {
one: {
prop: 'prop_one',
Expand Down
1 change: 0 additions & 1 deletion test/templates/conditionals/andExplicit.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,3 @@
<else>
<p>and: false</p>
</else>

1 change: 0 additions & 1 deletion test/templates/conditionals/andImplicit.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@
<else>
<p>and: false</p>
</else>

2 changes: 1 addition & 1 deletion test/templates/conditionals/ifElseUnless.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
</if>
<elseunless something='maybe'>
<p>The variable 'something' is not set to 'maybe'</p>
</elseunless>
</elseunless>
1 change: 1 addition & 0 deletions test/templates/conditionals/ifElseValue.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should evaluate <if something='no'> as false and trigger <else> condition
!}

<if something='no'>
<p>The variable 'something' is set to 'no'</p>
</if>
Expand Down
1 change: 1 addition & 0 deletions test/templates/conditionals/ifEmptyArray.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should evaluate <if emptyArray> as false
!}

<if emptyArray>
<p>The variable 'emptyArray' is considered truthy</p>
</if>
Expand Down
1 change: 1 addition & 0 deletions test/templates/conditionals/ifEscapeRegex.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should evaluate if statement that contains an element with a regex pattern
!}

<if something>
<input type='text' name='date' placeholder='DD/MM/YYYY' id='date' pattern='^(3[0-1]|[1-2]\d|[1-9]|0\d)\/(1[0-2]|[1-9]|0\d)\/[1-2]\d{3}$'>
</if>
10 changes: 10 additions & 0 deletions test/templates/conditionals/ifJSONStringPrintJSONString.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{!
should correctly print the JSON string as unmodified text
!}

<if complexJSONString>
<pre>{complexJSONString|p|s}</pre>
</if>
<else>
<p>Should not render.</p>
</else>
14 changes: 14 additions & 0 deletions test/templates/conditionals/ifLoopDoubleIf.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{!
should print the letters behind both <if> statements nested in the <loop>
!}

<if something>
<loop through='objectOfObjects' val='obj'>
<if obj.a>
<p>a</p>
</if>
<if obj.a>
<p>b</p>
</if>
</loop>
</if>
1 change: 1 addition & 0 deletions test/templates/conditionals/ifMultipleCommentsElse.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should evaluate <if doesntexist> as false and trigger <else> condition with multiple preceding HTML comments
!}

<if doesntexist>
<p>The variable 'doesntexist' is present</p>
</if>
Expand Down
2 changes: 1 addition & 1 deletion test/templates/conditionals/ifNestedProperties.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should evaluate if statement where elseif condition is a three character named object
!}

<if nothingToSeeHere>
<p>Should not render</p>
</if>
Expand All @@ -10,4 +11,3 @@
<else>
<p>Should render</p>
</else>

1 change: 1 addition & 0 deletions test/templates/conditionals/ifNotPresent.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should render nothing if condition isn't met
!}

<div>
<if Test>
<p>Shouldn't See Me!</p>
Expand Down
2 changes: 1 addition & 1 deletion test/templates/conditionals/ifOutsideIf.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
should ignore \'if-\' when not part of an if statement.
!}

<p> gif-something-jpg-png </p>
<p> gif-something-jpg-png </p>
1 change: 1 addition & 0 deletions test/templates/conditionals/ifValue.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should evaluate <if something='Some content'> as true
!}

<if something='Some content'>
<p>The variable 'something' is set to 'Some content'</p>
</if>
Expand Down
15 changes: 15 additions & 0 deletions test/templates/conditionals/ifWithSiblingIfWithNestedIfElse.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{!
should evaluate the <unless> condition as true and not render the other conditions
!}

<if something='It will not be this'>
<p>Should not render.</p>
</if>
<if something>
<unless something='Cannot be this'>
<p>Should render.</p>
</unless>
<else>
<p>Should not render.</p>
</else>
</if>
1 change: 1 addition & 0 deletions test/templates/conditionals/nestedConditional.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{!
should evaluate <if something> as true and the nested <if not:somethingElse> as false, triggering the nested <else> condition
!}

<if something>
<if not:somethingElse>
<p>The variable 'somethingElse' is not present but 'something' is</p>
Expand Down
20 changes: 20 additions & 0 deletions test/templates/conditionals/nestedConditionalInElse.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{!
should render the nested <else> condition
!}

<if something>
<if not:somethingElse>
<p>The variable 'somethingElse' is not present but 'something' is</p>
</if>
<else>
<p>The variable 'something' and 'somethingElse' are both present</p>
</else>
</if>
<elseif somethingElse>
<p>The variable 'somethingElse' is present but 'something' is not</p>
</elseif>
<else>
<if something>
<p>The variable 'something' is not present and the variable 'somethingElse' is not present</p>
</if>
</else>
2 changes: 1 addition & 1 deletion test/templates/conditionals/nestedIfOutsideIf.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
<p>
gif-jpg-png
<if something> If that should not be parsed, How art thou?</if>
</p>
</p>
1 change: 1 addition & 0 deletions test/templates/conditionals/oneLine.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{!
should evaluate one line if "if-something" as true
!}

<p if-something true="class='something-is-present'" false="class='something-is-not-present'">One line if.</p>
1 change: 1 addition & 0 deletions test/templates/conditionals/oneLineDynamicVariable.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{!
should evaluate one line if "if-something" with a dynamic value
!}

<p if-something='{dynamicValue}' true='class="some-class"'>{dynamicValue}</p>
1 change: 1 addition & 0 deletions test/templates/conditionals/oneLineEmpty.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{!
should evaluate one line if "if-something=''" as false
!}

<p if-something='' true="class='something-is-value'" false="class='something-is-not-empty'">One line if.</p>
1 change: 1 addition & 0 deletions test/templates/conditionals/oneLineFalse.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{!
should evaluate one line if as false and apply no class
!}

<p if-noExist true="class='something-is-present'"></p>
2 changes: 1 addition & 1 deletion test/templates/conditionals/oneLineIfInsideAttribute.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

<p id='gif-jpg-png'>hello</p>
<p class='gif-jpg-png'>hello</p>
<p filter='gif-jpg-png'>hello</p>
<p filter='gif-jpg-png'>hello</p>
2 changes: 1 addition & 1 deletion test/templates/conditionals/oneLineIfOutsideIf.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
should ignore \'if-\' when not part of an if statement combined with another oneline if statement
!}

<p> gif-jpg-png <p if-something true="class='something-is-present'" false="class='something-is-not-present'"> hello </p> </p>
<p> gif-jpg-png <p if-something true="class='something-is-present'" false="class='something-is-not-present'"> hello </p> </p>
2 changes: 1 addition & 1 deletion test/templates/conditionals/oneLineIfOutsideIfReverse.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
should ignore \'if-\' when not part of an if statement combined with another oneline if statement, reversed
!}

<p if-something true="class='something-is-present'" false="class='something-is-not-present'"> gif-jpg-png </p>
<p if-something true="class='something-is-present'" false="class='something-is-not-present'"> gif-jpg-png </p>
1 change: 1 addition & 0 deletions test/templates/conditionals/oneLineMulti.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{!
should evaluate both one line ifs "if-something" as true twice and apply two classes
!}

<p if-something true="class='something-is-present'" false="class='something-is-not-present'" if-something='' false="data-only-renders-when-something-is-not-empty" if-something true="data-should-render" false="data-should-not-render">One line if.</p>
Loading

0 comments on commit b71e33c

Please sign in to comment.