Skip to content

Commit

Permalink
feat: add @includeIf tag
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Mar 26, 2020
1 parent eed0249 commit a8cd83b
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 35 deletions.
11 changes: 11 additions & 0 deletions fixtures/include-if-identifier/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
let out = "";
let $lineNumber = 1;
let $filename = "{{__dirname}}index.edge";
try {
if (state.username === 'virk') {
out += template.renderInline(state.partial)(template,state,ctx);
}
} catch (error) {
ctx.reThrow(error, $filename, $lineNumber);
}
return out;
1 change: 1 addition & 0 deletions fixtures/include-if-identifier/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@includeIf(username === 'virk', partial)
4 changes: 4 additions & 0 deletions fixtures/include-if-identifier/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"partial": "include-if-identifier/partial",
"username": "virk"
}
1 change: 1 addition & 0 deletions fixtures/include-if-identifier/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello world
1 change: 1 addition & 0 deletions fixtures/include-if-identifier/partial.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello world
11 changes: 11 additions & 0 deletions fixtures/include-if-literal/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
let out = "";
let $lineNumber = 1;
let $filename = "{{__dirname}}index.edge";
try {
if (state.username === 'virk') {
out += template.renderInline("include-if-literal/partial")(template,state,ctx);
}
} catch (error) {
ctx.reThrow(error, $filename, $lineNumber);
}
return out;
1 change: 1 addition & 0 deletions fixtures/include-if-literal/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@includeIf(username === 'virk', "include-if-literal/partial")
2 changes: 2 additions & 0 deletions fixtures/include-if-literal/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
Empty file.
1 change: 1 addition & 0 deletions fixtures/include-if-literal/partial.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello world
77 changes: 42 additions & 35 deletions src/Tags/Include.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,50 @@
* file that was distributed with this source code.
*/

import { expressions } from 'edge-parser'
import { expressions, Parser } from 'edge-parser'

import { TagContract } from '../Contracts'
import { unallowedExpression, isSubsetOf, parseJsArg } from '../utils'

/**
* List of expressions allowed for the include tag
*/
export const ALLOWED_EXPRESSION = [
expressions.Identifier,
expressions.Literal,
expressions.LogicalExpression,
expressions.MemberExpression,
expressions.ConditionalExpression,
expressions.CallExpression,
expressions.TemplateLiteral,
]

/**
* Returns the expression for rendering the partial
*/
export function getRenderExpression (parser: Parser, parsedExpression: any) {
/**
* We need to pass the local variables to the partial render function
*/
const localVariables = parser.stack.list()

/**
* Arguments for the `renderInline` method
*/
const renderArgs = localVariables.length
? [parser.utils.stringify(parsedExpression), localVariables.map((localVar) => `"${localVar}"`).join(',')]
: [parser.utils.stringify(parsedExpression)]

/**
* Arguments for invoking the output function of `renderInline`
*/
const callFnArgs = localVariables.length
? ['template', 'state', 'ctx', localVariables.map((localVar) => localVar).join(',')]
: ['template', 'state', 'ctx']

return `template.renderInline(${renderArgs.join(',')})(${callFnArgs.join(',')})`
}

/**
* Include tag is used to include partials in the same scope of the parent
* template.
Expand All @@ -36,15 +75,7 @@ export const includeTag: TagContract = {
*/
isSubsetOf(
parsed,
[
expressions.Identifier,
expressions.Literal,
expressions.LogicalExpression,
expressions.MemberExpression,
expressions.ConditionalExpression,
expressions.CallExpression,
expressions.TemplateLiteral,
],
ALLOWED_EXPRESSION,
() => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @include tag`,
Expand All @@ -54,30 +85,6 @@ export const includeTag: TagContract = {
},
)

/**
* We need to pass the local variables to the partial render function
*/
const localVariables = parser.stack.list()

/**
* Arguments for the `renderInline` method
*/
const renderArgs = localVariables.length
? [parser.utils.stringify(parsed), localVariables.map((localVar) => `"${localVar}"`).join(',')]
: [parser.utils.stringify(parsed)]

/**
* Arguments for invoking the output function of `renderInline`
*/
const callFnArgs = localVariables.length
? ['template', 'state', 'ctx', localVariables.map((localVar) => localVar).join(',')]
: ['template', 'state', 'ctx']

buffer.outputExpression(
`template.renderInline(${renderArgs.join(',')})(${callFnArgs.join(',')})`,
token.filename,
token.loc.start.line,
false,
)
buffer.outputExpression(getRenderExpression(parser, parsed), token.filename, token.loc.start.line, false)
},
}
92 changes: 92 additions & 0 deletions src/Tags/IncludeIf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* edge
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { EdgeError } from 'edge-error'
import { expressions } from 'edge-parser'

import { TagContract } from '../Contracts'
import { ALLOWED_EXPRESSION, getRenderExpression } from './Include'
import { unallowedExpression, isSubsetOf, parseJsArg, isNotSubsetOf } from '../utils'

/**
* Include tag is used to include partials in the same scope of the parent
* template.
*
* ```edge
* @include('partials.header')
* ```
*/
export const includeIfTag: TagContract = {
block: false,
seekable: true,
tagName: 'includeIf',

/**
* Compiles else block node to Javascript else statement
*/
compile (parser, buffer, token) {
const parsed = parseJsArg(parser, token)

/**
* The include if only accepts the sequence expression
*/
isSubsetOf(
parsed,
[expressions.SequenceExpression],
() => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @includeIf tag`,
parsed,
token.filename,
)
},
)

/**
* Disallow more than or less than 2 values for the sequence expression
*/
if (parsed.expressions.length !== 2) {
throw new EdgeError('@includeIf expects a total of 2 arguments', 'E_ARGUMENTS_MIS_MATCH', {
line: parsed.loc.start.line,
col: parsed.loc.start.column,
filename: token.filename,
})
}

const [ conditional, include ] = parsed.expressions

isNotSubsetOf(
conditional,
[expressions.SequenceExpression],
() => {
unallowedExpression(
`"${conditional.type}" is not a valid 1st argument type for the @includeIf tag`,
conditional,
token.filename,
)
},
)

isSubsetOf(
include,
ALLOWED_EXPRESSION,
() => {
unallowedExpression(
`"${include.type}" is not a valid 2nd argument type for the @includeIf tag`,
include,
token.filename,
)
},
)

buffer.writeStatement(`if (${parser.utils.stringify(conditional)}) {`, token.filename, token.loc.start.line)
buffer.outputExpression(getRenderExpression(parser, include), token.filename, token.loc.start.line, false)
buffer.writeStatement('}', token.filename, -1)
},
}
1 change: 1 addition & 0 deletions src/Tags/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { ifTag as if } from './If'
export { elseTag as else } from './Else'
export { elseIfTag as elseif } from './ElseIf'
export { includeTag as include } from './Include'
export { includeIfTag as includeIf } from './IncludeIf'
export { eachTag as each } from './Each'
export { componentTag as component } from './Component'
export { slotTag as slot } from './Slot'
Expand Down

0 comments on commit a8cd83b

Please sign in to comment.