Skip to content

Commit

Permalink
feat: override output/tag delimiter, fixes #54
Browse files Browse the repository at this point in the history
  • Loading branch information
harttle committed Feb 20, 2019
1 parent 3dbab23 commit d20a043
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 23 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ Otherwise, undefined variables will cause an exception. Defaults to `false`.

* `trim_output_left` is similiar to `trim_output_right`, whereas the `\n` is exclusive. Defaults to `false`. See [Whitespace Control][whitespace control] for details.

* `tag_delimiter_left` and `tag_delimiter_right` are used to override the delimiter for liquid tags.

* `output_delimiter_left` and `output_delimiter_right` are used to override the delimiter for liquid outputs.

* `greedy` is used to specify whether `trim_left`/`trim_right` is greedy. When set to `true`, all consecutive blank characters including `\n` will be trimed regardless of line breaks. Defaults to `true`.

## Register Filters
Expand Down
10 changes: 10 additions & 0 deletions src/liquid-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export interface LiquidOptions {
trim_output_right?: boolean
/** `trim_output_left` is similar to `trim_output_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
trim_output_left?: boolean
/** `tag_delimiter_left` and `tag_delimiter_right` are used to override the delimiter for liquid tags **/
tag_delimiter_left?: string,
tag_delimiter_right?: string,
/** `output_delimiter_left` and `output_delimiter_right` are used to override the delimiter for liquid outputs **/
output_delimiter_left?: string,
output_delimiter_right?: string,
/** `greedy` is used to specify whether `trim_left`/`trim_right` is greedy. When set to `true`, all consecutive blank characters including `\n` will be trimed regardless of line breaks. Defaults to `true`. */
greedy?: boolean
}
Expand Down Expand Up @@ -55,6 +61,10 @@ const defaultOptions: NormalizedFullOptions = {
trim_output_right: false,
trim_output_left: false,
greedy: true,
tag_delimiter_left: '{%',
tag_delimiter_right: '%}',
output_delimiter_left: '{{',
output_delimiter_right: '}}',
strict_filters: false,
strict_variables: false
}
Expand Down
13 changes: 9 additions & 4 deletions src/parser/delimited-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import Token from './token'
export default class DelimitedToken extends Token {
trimLeft: boolean
trimRight: boolean
constructor (raw, pos, input, file, line) {
constructor (raw, value, pos, input, file, line) {
super(raw, pos, input, file, line)
this.trimLeft = raw[2] === '-'
this.trimRight = raw[raw.length - 3] === '-'
this.value = raw.slice(this.trimLeft ? 3 : 2, this.trimRight ? -3 : -2).trim()
this.trimLeft = value[0] === '-'
this.trimRight = value[value.length - 1] === '-'
this.value = value
.slice(
this.trimLeft ? 1 : 0,
this.trimRight ? -1 : value.length
)
.trim()
}
}
4 changes: 2 additions & 2 deletions src/parser/output-token.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import DelimitedToken from './delimited-token'

export default class OutputToken extends DelimitedToken {
constructor (raw, pos, input, file, line) {
super(raw, pos, input, file, line)
constructor (raw, value, pos, input, file, line) {
super(raw, value, pos, input, file, line)
this.type = 'output'
}
}
4 changes: 2 additions & 2 deletions src/parser/tag-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as lexical from './lexical'
export default class TagToken extends DelimitedToken {
name: string
args: string
constructor (raw, pos, input, file, line) {
super(raw, pos, input, file, line)
constructor (raw, value, pos, input, file, line) {
super(raw, value, pos, input, file, line)
this.type = 'tag'
const match = this.value.match(lexical.tagLine)
if (!match) {
Expand Down
37 changes: 24 additions & 13 deletions src/parser/tokenizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export default class Tokenizer {
}
tokenize (input: string, file?: string) {
const tokens = []
const tagL = this.options.tag_delimiter_left
const tagR = this.options.tag_delimiter_right
const outputL = this.options.output_delimiter_left
const outputR = this.options.output_delimiter_right
let p = 0
let curLine = 1
let state = ParseState.HTML
Expand All @@ -28,30 +32,37 @@ export default class Tokenizer {
curLine++
lineBegin = p + 1
}
const bin = input.substr(p, 2)
if (state === ParseState.HTML) {
if (bin === '{{' || bin === '{%') {
if (input.substr(p, outputL.length) === outputL) {
if (buffer) tokens.push(new HTMLToken(buffer, col, input, file, line))
buffer = bin
buffer = outputL
line = curLine
col = p - lineBegin + 1
p += 2
state = bin === '{{' ? ParseState.OUTPUT : ParseState.TAG
p += outputL.length
state = ParseState.OUTPUT
continue
} else if (input.substr(p, tagL.length) === tagL) {
if (buffer) tokens.push(new HTMLToken(buffer, col, input, file, line))
buffer = tagL
line = curLine
col = p - lineBegin + 1
p += tagL.length
state = ParseState.TAG
continue
}
} else if (state === ParseState.OUTPUT && bin === '}}') {
buffer += '}}'
tokens.push(new OutputToken(buffer, col, input, file, line))
p += 2
} else if (state === ParseState.OUTPUT && input.substr(p, outputR.length) === outputR) {
buffer += outputR
tokens.push(new OutputToken(buffer, buffer.slice(outputL.length, -outputR.length), col, input, file, line))
p += outputR.length
buffer = ''
line = curLine
col = p - lineBegin + 1
state = ParseState.HTML
continue
} else if (bin === '%}') {
buffer += '%}'
tokens.push(new TagToken(buffer, col, input, file, line))
p += 2
} else if (input.substr(p, tagR.length) === tagR) {
buffer += tagR
tokens.push(new TagToken(buffer, buffer.slice(tagL.length, -tagR.length), col, input, file, line))
p += tagR.length
buffer = ''
line = curLine
col = p - lineBegin + 1
Expand Down
4 changes: 2 additions & 2 deletions src/parser/whitespace-ctrl.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import DelimitedToken from 'src/parser/delimited-token'
import Token from 'src/parser/token'
import TagToken from 'src/parser/tag-token'
import { LiquidOptions } from 'src/liquid-options'
import { NormalizedFullOptions } from 'src/liquid-options'

export default function whiteSpaceCtrl (tokens: Token[], options: LiquidOptions) {
export default function whiteSpaceCtrl (tokens: Token[], options: NormalizedFullOptions) {
options = { greedy: true, ...options }
let inRaw = false

Expand Down
31 changes: 31 additions & 0 deletions test/unit/liquid/delimiter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'

describe('LiquidOptions#*_delimiter_*', function () {
it('should respect tag_delimiter_*', async function () {
const engine = new Liquid({
tag_delimiter_left: '<%=',
tag_delimiter_right: '%>'
})
const html = await engine.parseAndRender('<%=if true%>foo<%=endif%> ')
return expect(html).to.equal('foo ')
})
it('should respect output_delimiter_*', async function () {
const engine = new Liquid({
output_delimiter_left: '<<',
output_delimiter_right: '>>'
})
const html = await engine.parseAndRender('<< "liquid" | capitalize >>')
return expect(html).to.equal('Liquid')
})
it('should support trimming with tag_delimiter_* set', async function () {
const engine = new Liquid({
tag_delimiter_left: '<%=',
tag_delimiter_right: '%>',
trim_tag_left: true,
trim_tag_right: true
})
const html = await engine.parseAndRender(' <%=if true%> \tfoo\t <%=endif%> ')
return expect(html).to.equal('foo')
})
})

0 comments on commit d20a043

Please sign in to comment.