feat: support jekyll-like include, see #433

This commit is contained in:
Harttle
2021-12-18 15:26:15 +08:00
committed by Harttle
parent 2c14a9541d
commit 23279a816a
8 changed files with 229 additions and 65 deletions
+11 -6
View File
@@ -92,15 +92,20 @@ export function parseFilePath (tokenizer: Tokenizer, liquid: Liquid): ParsedFile
if (file.getText() === 'none') return null
if (TypeGuards.isQuotedToken(file)) {
// for filenames like "files/{{file}}", eval as liquid template
const tpls = liquid.parse(evalQuotedToken(file))
// for filenames like "files/file.liquid", extract the string directly
if (tpls.length === 1 && TypeGuards.isHTMLToken(tpls[0].token)) return tpls[0].token.getContent()
return tpls
const templates = liquid.parse(evalQuotedToken(file))
return optimize(templates)
}
return file
}
const filepath = tokenizer.readFileName().getText()
return filepath === 'none' ? null : filepath
const tokens = [...tokenizer.readFileNameTemplate(liquid.options)]
const templates = optimize(liquid.parser.parseTokens(tokens))
return templates === 'none' ? null : templates
}
function optimize (templates: Template[]): string | Template[] {
// for filenames like "files/file.liquid", extract the string directly
if (templates.length === 1 && TypeGuards.isHTMLToken(templates[0].token)) return templates[0].token.getContent()
return templates
}
export function renderFilePath (file: ParsedFileName, ctx: Context, liquid: Liquid) {
+14 -10
View File
@@ -33,7 +33,7 @@ export class Tokenizer {
constructor (
public input: string,
private trie: Trie,
private file: string = ''
public file: string = ''
) {
this.N = input.length
}
@@ -119,15 +119,13 @@ export class Tokenizer {
if (this.rawBeginAt > -1) return this.readEndrawOrRawContent(options)
if (this.match(tagDelimiterLeft)) return this.readTagToken(options)
if (this.match(outputDelimiterLeft)) return this.readOutputToken(options)
return this.readHTMLToken(options)
return this.readHTMLToken([tagDelimiterLeft, outputDelimiterLeft])
}
readHTMLToken (options: NormalizedFullOptions): HTMLToken {
readHTMLToken (stopStrings: string[]): HTMLToken {
const begin = this.p
while (this.p < this.N) {
const { tagDelimiterLeft, outputDelimiterLeft } = options
if (this.match(tagDelimiterLeft)) break
if (this.match(outputDelimiterLeft)) break
if (stopStrings.some(str => this.match(str))) break
++this.p
}
return new HTMLToken(this.input, begin, this.p, this.file)
@@ -334,10 +332,16 @@ export class Tokenizer {
return new QuotedToken(this.input, begin, this.p, this.file)
}
readFileName (): IdentifierToken {
const begin = this.p
while (!(this.peekType() & BLANK) && this.peek() !== ',' && this.p < this.N) this.p++
return new IdentifierToken(this.input, begin, this.p, this.file)
* readFileNameTemplate (options: NormalizedFullOptions): IterableIterator<TopLevelToken> {
const { outputDelimiterLeft } = options
const htmlStopStrings = [',', ' ', outputDelimiterLeft]
const htmlStopStringSet = new Set(htmlStopStrings)
// break on ',' and ' ', outputDelimiterLeft only stops HTML token
while (this.p < this.N && !htmlStopStringSet.has(this.peek())) {
yield this.match(outputDelimiterLeft)
? this.readOutputToken(options)
: this.readHTMLToken(htmlStopStrings)
}
}
match (word: string) {