From edb2cc1f376e6da1475c61bd0591f2da14fecd61 Mon Sep 17 00:00:00 2001 From: Patrick Malouin Date: Wed, 26 Jun 2019 20:34:26 -0400 Subject: [PATCH] Expose `fs` as an option to override the default implementations --- README.md | 2 ++ src/liquid-options.ts | 5 ++++- src/liquid.ts | 9 ++++++--- test/integration/liquid/fs-option.ts | 21 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 test/integration/liquid/fs-option.ts diff --git a/README.md b/README.md index d3e0349090..2faeff0c11 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,8 @@ Otherwise, undefined variables will cause an exception. Defaults to `false`. * `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`. +* `fs` is used to override the default file-system module with a custom implementation. + ## Register Filters ```javascript diff --git a/src/liquid-options.ts b/src/liquid-options.ts index 2e14e4d7f5..badb9f4141 100644 --- a/src/liquid-options.ts +++ b/src/liquid-options.ts @@ -1,4 +1,5 @@ import * as _ from './util/underscore' +import IFS from './fs/ifs'; export interface LiquidOptions { /** `root` is a directory or an array of directories to resolve layouts and includes, as well as the filename passed in when calling `.renderFile()`. If an array, the files are looked up in the order they occur in the array. Defaults to `["."]` */ @@ -28,7 +29,9 @@ export interface LiquidOptions { outputDelimiterLeft?: string, outputDelimiterRight?: 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 + greedy?: boolean, + /** `fs` is used to override the default file-system module with a custom implementation */ + fs?: IFS } interface NormalizedOptions extends LiquidOptions { diff --git a/src/liquid.ts b/src/liquid.ts index e1f0af588f..eb4f7b4280 100644 --- a/src/liquid.ts +++ b/src/liquid.ts @@ -15,6 +15,7 @@ import builtinTags from './builtin/tags' import builtinFilters from './builtin/filters' import { LiquidOptions, NormalizedFullOptions, applyDefault, normalize } from './liquid-options' import { FilterImplOptions } from './template/filter/filter-impl-options' +import IFS from './fs/ifs'; export default class Liquid { public options: NormalizedFullOptions @@ -22,12 +23,14 @@ export default class Liquid { public parser: Parser private cache: object = {} private tokenizer: Tokenizer + private fs: IFS constructor (opts: LiquidOptions = {}) { this.options = applyDefault(normalize(opts)) this.parser = new Parser(this) this.renderer = new Render() this.tokenizer = new Tokenizer(this.options) + this.fs = opts.fs || fs _.forOwn(builtinTags, (conf, name) => this.registerTag(name, conf)) _.forOwn(builtinFilters, (handler, name) => this.registerFilter(name, handler)) @@ -48,14 +51,14 @@ export default class Liquid { async getTemplate (file: string, opts?: LiquidOptions) { const options = normalize(opts) const roots = options.root ? [...options.root, ...this.options.root] : this.options.root - const paths = roots.map(root => fs.resolve(root, file, this.options.extname)) + const paths = roots.map(root => this.fs.resolve(root, file, this.options.extname)) for (const filepath of paths) { if (this.options.cache && this.cache[filepath]) return this.cache[filepath] - if (!(await fs.exists(filepath))) continue + if (!(await this.fs.exists(filepath))) continue - const value = this.parse(await fs.readFile(filepath), filepath) + const value = this.parse(await this.fs.readFile(filepath), filepath) if (this.options.cache) this.cache[filepath] = value return value } diff --git a/test/integration/liquid/fs-option.ts b/test/integration/liquid/fs-option.ts new file mode 100644 index 0000000000..3fe466ff50 --- /dev/null +++ b/test/integration/liquid/fs-option.ts @@ -0,0 +1,21 @@ +import { expect } from 'chai' +import Liquid from '../../../src/liquid' + +describe('LiquidOptions#fs', function () { + let engine: Liquid + const fs = { + exists: () => Promise.resolve(true), + readFile: () => Promise.resolve('test file content'), + resolve: () => 'resolved' + } + beforeEach(function () { + engine = new Liquid({ + root: '/root/', + fs + }) + }) + it('should be used to read templates', function () { + return engine.renderFile('files/foo') + .then(x => expect(x).to.equal('test file content')) + }) +})