mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 04:10:40 -07:00
feat: inline comment tag (#514)
* style: remove unnecessary intermediate constant * feat: add inline comment tag * refactor: use readIdentifier when reading tag names * docs: add inline comment tag
This commit is contained in:
@@ -78,6 +78,7 @@ filters:
|
||||
|
||||
tags:
|
||||
overview: overview.html
|
||||
"# (inline comment)": inline_comment.html
|
||||
assign: assign.html
|
||||
capture: capture.html
|
||||
case: case.html
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: "# (inline comment)"
|
||||
---
|
||||
|
||||
{% since %}v9.38.0{% endsince %}
|
||||
|
||||
Add comments to a Liquid template using an inline tag. Text enclosed in an inline comment tag will not be printed.
|
||||
|
||||
Input
|
||||
```liquid
|
||||
Anything inside an inline comment tag will not be printed.
|
||||
{% # this is an inline comment %}
|
||||
But every line must start with a '#'.
|
||||
{%
|
||||
# this is a comment
|
||||
# that spans multiple lines
|
||||
%}
|
||||
```
|
||||
|
||||
Output
|
||||
```text
|
||||
Anything inside an inline comment tag will not be printed.
|
||||
But every line must start with a '#'.
|
||||
```
|
||||
|
||||
Inline comments are useful inside <a href="./liquid.html">`liquid`</a> tags too.
|
||||
|
||||
```liquid
|
||||
{% liquid
|
||||
# required args
|
||||
assign product = collection.products.first
|
||||
|
||||
# optional args
|
||||
assign should_show_border = should_show_border | default: true
|
||||
assign should_highlight = should_highlight | default: false
|
||||
%}
|
||||
```
|
||||
|
||||
But they don't work well for commenting out blocks of Liquid code. The <a href="./comment.html">`comment`</a> block tag is the better option when you need to temporarily stop other tags from being executed.
|
||||
|
||||
Input
|
||||
```liquid
|
||||
{%- # {% echo 'Welcome to LiquidJS!' %} -%}
|
||||
{% comment %}{% echo 'Welcome to LiquidJS!' %}{% endcomment %}
|
||||
```
|
||||
|
||||
Output
|
||||
```text
|
||||
-%}
|
||||
```
|
||||
@@ -18,10 +18,11 @@ import Break from './break'
|
||||
import Continue from './continue'
|
||||
import echo from './echo'
|
||||
import liquid from './liquid'
|
||||
import inlineComment from './inline-comment'
|
||||
import { TagImplOptions } from '../../template/tag/tag-impl-options'
|
||||
|
||||
const tags: { [key: string]: TagImplOptions } = {
|
||||
assign, 'for': For, capture, 'case': Case, comment, include, render, decrement, increment, cycle, 'if': If, layout, block, raw, tablerow, unless, 'break': Break, 'continue': Continue, echo, liquid
|
||||
assign, 'for': For, capture, 'case': Case, comment, include, render, decrement, increment, cycle, 'if': If, layout, block, raw, tablerow, unless, 'break': Break, 'continue': Continue, echo, liquid, '#': inlineComment
|
||||
}
|
||||
|
||||
export default tags
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { TagToken } from '../../tokens/tag-token'
|
||||
import { TopLevelToken } from '../../tokens/toplevel-token'
|
||||
import { TagImplOptions } from '../../template/tag/tag-impl-options'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken: TagToken, remainTokens: TopLevelToken[]) {
|
||||
if (tagToken.args.search(/\n\s*[^#\s]/g) !== -1) {
|
||||
throw new Error('every line of an inline comment must start with a \'#\' character')
|
||||
}
|
||||
}
|
||||
} as TagImplOptions
|
||||
@@ -207,8 +207,7 @@ export class Tokenizer {
|
||||
const begin = this.p
|
||||
let end = this.N
|
||||
if (this.readToDelimiter('\n') !== -1) end = this.p
|
||||
const token = new LiquidTagToken(input, begin, end, options, file)
|
||||
return token
|
||||
return new LiquidTagToken(input, begin, end, options, file)
|
||||
}
|
||||
|
||||
mkError (msg: string, begin: number) {
|
||||
@@ -234,6 +233,13 @@ export class Tokenizer {
|
||||
return new IdentifierToken(this.input, begin, this.p, this.file)
|
||||
}
|
||||
|
||||
readTagName (): string {
|
||||
this.skipBlank()
|
||||
// Handle inline comment tags
|
||||
if (this.input[this.p] === '#') return this.input.slice(this.p, ++this.p)
|
||||
return this.readIdentifier().getText()
|
||||
}
|
||||
|
||||
readHashes (jekyllStyle?: boolean) {
|
||||
const hashes = []
|
||||
while (true) {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class LiquidTagToken extends DelimitedToken {
|
||||
this.args = ''
|
||||
} else {
|
||||
const tokenizer = new Tokenizer(this.content, options.operatorsTrie)
|
||||
this.name = tokenizer.readIdentifier().getText()
|
||||
this.name = tokenizer.readTagName()
|
||||
if (!this.name) throw new TokenizationError(`illegal liquid tag syntax`, this)
|
||||
|
||||
tokenizer.skipBlank()
|
||||
|
||||
@@ -19,7 +19,7 @@ export class TagToken extends DelimitedToken {
|
||||
super(TokenKind.Tag, value, input, begin, end, trimTagLeft, trimTagRight, file)
|
||||
|
||||
const tokenizer = new Tokenizer(this.content, options.operatorsTrie)
|
||||
this.name = tokenizer.readIdentifier().getText()
|
||||
this.name = tokenizer.readTagName()
|
||||
if (!this.name) throw new TokenizationError(`illegal tag syntax`, this)
|
||||
|
||||
tokenizer.skipBlank()
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Liquid } from '../../../../src/liquid'
|
||||
import { expect, use } from 'chai'
|
||||
import * as chaiAsPromised from 'chai-as-promised'
|
||||
|
||||
use(chaiAsPromised)
|
||||
|
||||
describe('tags/inline-comment', function () {
|
||||
const liquid = new Liquid()
|
||||
it('should ignore plain string', async function () {
|
||||
const src = 'My name is {% # super %} Shopify.'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('My name is Shopify.')
|
||||
})
|
||||
it('should ignore output tokens', async function () {
|
||||
const src = '{% #\n{{ foo}} \n %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('')
|
||||
})
|
||||
it('should support whitespace control', async function () {
|
||||
const src = '{%- # some comment \n -%}\nfoo'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('foo')
|
||||
})
|
||||
it('should handle hash without trailing whitespace', async function () {
|
||||
const src = '{% #some comment %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('')
|
||||
})
|
||||
it('should handle hash without leading whitespace', async function () {
|
||||
const src = '{%#some comment %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('')
|
||||
})
|
||||
it('should handle empty comment', async function () {
|
||||
const src = '{%#%}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('')
|
||||
})
|
||||
it('should support multiple lines', async function () {
|
||||
const src = [
|
||||
'{%-',
|
||||
' # spread inline comments',
|
||||
' # over multiple lines',
|
||||
'-%}'
|
||||
].join('\n')
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('')
|
||||
})
|
||||
it('should enforce leading hashes', async function () {
|
||||
const src = [
|
||||
'{%-',
|
||||
' # spread inline comments',
|
||||
' over multiple lines',
|
||||
'-%}'
|
||||
].join('\n')
|
||||
return expect(liquid.parseAndRender(src))
|
||||
.to.be.rejectedWith(/every line of an inline comment must start with a '#' character/)
|
||||
})
|
||||
describe('sync support', function () {
|
||||
it('should ignore plain string', function () {
|
||||
const src = 'My name is {% # super %} Shopify.'
|
||||
const html = liquid.parseAndRenderSync(src)
|
||||
return expect(html).to.equal('My name is Shopify.')
|
||||
})
|
||||
})
|
||||
describe('liquid tag', function () {
|
||||
it('should treat lines starting with a hash as a comment', async function () {
|
||||
const src = [
|
||||
'{% liquid ',
|
||||
' # first comment line',
|
||||
' # second comment line',
|
||||
'',
|
||||
' # another comment line',
|
||||
' echo \'Hello \'',
|
||||
'',
|
||||
' # more comments',
|
||||
' echo \'goodbye\'',
|
||||
'-%}'
|
||||
].join('\n')
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('Hello goodbye')
|
||||
})
|
||||
it('should handle lots of hashes', async function () {
|
||||
const src = [
|
||||
'{% liquid',
|
||||
' ##########################',
|
||||
' # spread inline comments #',
|
||||
' ##########################',
|
||||
'-%}'
|
||||
].join('\n')
|
||||
const html = await liquid.parseAndRender(src)
|
||||
return expect(html).to.equal('')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -525,4 +525,33 @@ describe('Tokenizer', function () {
|
||||
expect(() => tokenizer.readLiquidTagTokens()).to.throw(/illegal liquid tag syntax/)
|
||||
})
|
||||
})
|
||||
describe('#read inline comment tags', () => {
|
||||
it('should allow hash characters in tag names', () => {
|
||||
const tokenizer = new Tokenizer('{% # some comment %}', trie)
|
||||
const tokens = tokenizer.readTopLevelTokens()
|
||||
expect(tokens.length).to.equal(1)
|
||||
const tag = tokens[0] as TagToken
|
||||
expect(tag).instanceOf(TagToken)
|
||||
expect(tag.name).to.equal('#')
|
||||
expect(tag.args).to.equal('some comment')
|
||||
})
|
||||
it('should handle leading whitespace', () => {
|
||||
const tokenizer = new Tokenizer('{%\n # some comment %}', trie)
|
||||
const tokens = tokenizer.readTopLevelTokens()
|
||||
expect(tokens.length).to.equal(1)
|
||||
const tag = tokens[0] as TagToken
|
||||
expect(tag).instanceOf(TagToken)
|
||||
expect(tag.name).to.equal('#')
|
||||
expect(tag.args).to.equal('some comment')
|
||||
})
|
||||
it('should handle no trailing whitespace', () => {
|
||||
const tokenizer = new Tokenizer('{%\n #some comment %}', trie)
|
||||
const tokens = tokenizer.readTopLevelTokens()
|
||||
expect(tokens.length).to.equal(1)
|
||||
const tag = tokens[0] as TagToken
|
||||
expect(tag).instanceOf(TagToken)
|
||||
expect(tag.name).to.equal('#')
|
||||
expect(tag.args).to.equal('some comment')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user