Skip to content

Commit

Permalink
feat: support custom key-value separator, #752
Browse files Browse the repository at this point in the history
  • Loading branch information
Yang Jun authored and harttle committed Sep 22, 2024
1 parent 5ada07c commit 6aeed25
Show file tree
Hide file tree
Showing 10 changed files with 18 additions and 11 deletions.
3 changes: 3 additions & 0 deletions src/liquid-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ export interface LiquidOptions {
greedy?: boolean;
/** `fs` is used to override the default file-system module with a custom implementation. */
fs?: FS;
/** keyValue separator */
keyValueSeparator?: string;
/** Render from in-memory `templates` mapping instead of file system. File system related options like `fs`, 'root', and `relativeReference` will be ignored when `templates` is specified. */
templates?: {[key: string]: string};
/** the global scope passed down to all partial and layout templates, i.e. templates included by `include`, `layout` and `render` tags. */
Expand Down Expand Up @@ -166,6 +168,7 @@ export const defaultOptions: NormalizedFullOptions = {
partials: ['.'],
relativeReference: true,
jekyllInclude: false,
keyValueSeparator: ':',
cache: undefined,
extname: '',
fs: fs,
Expand Down
8 changes: 4 additions & 4 deletions src/parser/tokenizer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FilteredValueToken, TagToken, HTMLToken, HashToken, QuotedToken, LiquidTagToken, OutputToken, ValueToken, Token, RangeToken, FilterToken, TopLevelToken, PropertyAccessToken, OperatorToken, LiteralToken, IdentifierToken, NumberToken } from '../tokens'
import { OperatorHandler } from '../render/operator'
import { TrieNode, LiteralValue, Trie, createTrie, ellipsis, literalValues, TokenizationError, TYPES, QUOTE, BLANK, NUMBER, SIGN, isWord } from '../util'
import { TrieNode, LiteralValue, Trie, createTrie, ellipsis, literalValues, TokenizationError, TYPES, QUOTE, BLANK, NUMBER, SIGN, isWord, isString } from '../util'
import { Operators, Expression } from '../render'
import { NormalizedFullOptions, defaultOptions } from '../liquid-options'
import { FilterArg } from './filter-arg'
Expand Down Expand Up @@ -261,7 +261,7 @@ export class Tokenizer {
return this.readIdentifier().getText()
}

readHashes (jekyllStyle?: boolean) {
readHashes (jekyllStyle?: boolean | string) {
const hashes = []
while (true) {
const hash = this.readHash(jekyllStyle)
Expand All @@ -270,7 +270,7 @@ export class Tokenizer {
}
}

readHash (jekyllStyle?: boolean): HashToken | undefined {
readHash (jekyllStyle?: boolean | string): HashToken | undefined {
this.skipBlank()
if (this.peek() === ',') ++this.p
const begin = this.p
Expand All @@ -279,7 +279,7 @@ export class Tokenizer {
let value

this.skipBlank()
const sep = jekyllStyle ? '=' : ':'
const sep = isString(jekyllStyle) ? jekyllStyle : (jekyllStyle ? '=' : ':')
if (this.peek() === sep) {
++this.p
value = this.readValue()
Expand Down
2 changes: 1 addition & 1 deletion src/tags/for.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default class extends Tag {

this.variable = variable.content
this.collection = collection
this.hash = new Hash(this.tokenizer.remaining())
this.hash = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator)
this.templates = []
this.elseTemplates = []

Expand Down
2 changes: 1 addition & 1 deletion src/tags/include.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default class extends Tag {
} else tokenizer.p = begin
} else tokenizer.p = begin

this.hash = new Hash(tokenizer.remaining(), this.liquid.options.jekyllInclude)
this.hash = new Hash(tokenizer.remaining(), liquid.options.jekyllInclude || liquid.options.keyValueSeparator)
}
* render (ctx: Context, emitter: Emitter): Generator<unknown, void, unknown> {
const { liquid, hash, withVar } = this
Expand Down
2 changes: 1 addition & 1 deletion src/tags/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class extends Tag {
super(token, remainTokens, liquid)
this.file = parseFilePath(this.tokenizer, this.liquid, parser)
this['currentFile'] = token.file
this.args = new Hash(this.tokenizer.remaining())
this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator)
this.templates = parser.parseTokens(remainTokens)
}
* render (ctx: Context, emitter: Emitter): Generator<unknown, unknown, unknown> {
Expand Down
2 changes: 1 addition & 1 deletion src/tags/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default class extends Tag {
tokenizer.p = begin
break
}
this.hash = new Hash(tokenizer.remaining())
this.hash = new Hash(tokenizer.remaining(), liquid.options.keyValueSeparator)
}
* render (ctx: Context, emitter: Emitter): Generator<unknown, void, unknown> {
const { liquid, hash } = this
Expand Down
2 changes: 1 addition & 1 deletion src/tags/tablerow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default class extends Tag {

this.variable = variable.content
this.collection = collectionToken
this.args = new Hash(this.tokenizer.remaining())
this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator)
this.templates = []

let p
Expand Down
4 changes: 4 additions & 0 deletions src/template/hash.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ describe('Hash', function () {
num3: 4
})
})
it('should support custom separator', async function () {
const hash = await toPromise(new Hash('num=2.3', '=').render(new Context()))
expect(hash.num).toBe(2.3)
})
})
2 changes: 1 addition & 1 deletion src/template/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type HashValueTokens = Record<string, Token | undefined>
*/
export class Hash {
hash: HashValueTokens = {}
constructor (markup: string, jekyllStyle?: boolean) {
constructor (markup: string, jekyllStyle?: boolean | string) {
const tokenizer = new Tokenizer(markup, {})
for (const hash of tokenizer.readHashes(jekyllStyle)) {
this.hash[hash.name.content] = hash.value
Expand Down
2 changes: 1 addition & 1 deletion src/template/tag-options-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function createTagClass (options: TagImplOptions): TagClass {
}
}
* render (ctx: Context, emitter: Emitter): TagRenderReturn {
const hash = (yield new Hash(this.token.args).render(ctx)) as Record<string, any>
const hash = (yield new Hash(this.token.args, ctx.opts.keyValueSeparator).render(ctx)) as Record<string, any>
return yield options.render.call(this, ctx, emitter, hash)
}
}
Expand Down

0 comments on commit 6aeed25

Please sign in to comment.