mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-12 19:00:39 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49c45a463b | ||
|
|
cef5d1aa1a | ||
|
|
6e6ea0ae58 | ||
|
|
dc9a6e019e | ||
|
|
5adebaa710 | ||
|
|
34d5af25a4 | ||
|
|
88c89fe3b3 | ||
|
|
e6f5f1cd85 | ||
|
|
570400ebcc | ||
|
|
3f5e23c42b | ||
|
|
96c061bee0 | ||
|
|
edb2cc1f37 | ||
|
|
2ae8c37a4f | ||
|
|
0bc5908f17 | ||
|
|
1ffba2bc76 | ||
|
|
bbebb5515c | ||
|
|
b14430a161 | ||
|
|
505c408a85 | ||
|
|
224679a7d7 | ||
|
|
2cb4bffd3e | ||
|
|
c940e6c997 | ||
|
|
d8ba009773 | ||
|
|
fdf0043b9c | ||
|
|
bef290923c | ||
|
|
4282accaa2 | ||
|
|
6075c0a54f | ||
|
|
87489f6098 | ||
|
|
6c5dc336e7 | ||
|
|
00bc1efe6a | ||
|
|
6fb4796202 | ||
|
|
7483613b23 | ||
|
|
7762dd9612 | ||
|
|
daa0b574fc | ||
|
|
a084183246 | ||
|
|
eadb6f3711 | ||
|
|
dba26f24e6 | ||
|
|
722da6a7ee | ||
|
|
82d7673554 | ||
|
|
64dd057552 | ||
|
|
45e3c2bb8e | ||
|
|
76345a64c3 | ||
|
|
9e69652655 | ||
|
|
defbb58e66 | ||
|
|
b7b92c63cf | ||
|
|
265534b7b7 | ||
|
|
84ea2c7488 | ||
|
|
64e0c876e9 | ||
|
|
4a8088d4e4 | ||
|
|
ad0930f152 | ||
|
|
998832c772 | ||
|
|
4ba224043b | ||
|
|
5ffc904f80 | ||
|
|
08646f75b0 | ||
|
|
3647305dcf | ||
|
|
cca0306f5b | ||
|
|
eeeacc4492 | ||
|
|
d44e1d727a | ||
|
|
f960904df4 | ||
|
|
b4acdb463a | ||
|
|
21d674e22b | ||
|
|
7bee9fc92d | ||
|
|
b69c3a3203 | ||
|
|
d5b9916b2f | ||
|
|
d0118402e4 | ||
|
|
31bc71d472 | ||
|
|
53a835ab54 | ||
|
|
75b3e15ca9 | ||
|
|
f34573ee21 | ||
|
|
875f71d5f2 | ||
|
|
407ac6d0a4 | ||
|
|
f9f35ebd6c | ||
|
|
88c9e96392 | ||
|
|
54b2adce12 | ||
|
|
542968e133 | ||
|
|
3b7351d9a0 | ||
|
|
e977669118 | ||
|
|
279458c670 | ||
|
|
37d12a14eb | ||
|
|
3cf01603e8 | ||
|
|
56c7992b76 | ||
|
|
5b6100d12b | ||
|
|
51f7e66f60 | ||
|
|
952ab6e73b |
+11
-2
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "standard",
|
||||
"extends": ["standard", "plugin:@typescript-eslint/recommended"],
|
||||
"env": {
|
||||
"mocha": true,
|
||||
"es6": true,
|
||||
@@ -17,6 +17,15 @@
|
||||
"no-var": 2,
|
||||
"prefer-const": 2,
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "vars": "all", "args": "after-used", "ignoreRestSiblings": false }]
|
||||
"indent": "off",
|
||||
"@typescript-eslint/indent": ["error", 2],
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-object-literal-type-assertion": "off",
|
||||
"@typescript-eslint/no-use-before-define": "off",
|
||||
"@typescript-eslint/interface-name-prefix": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"import/export": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": false }]
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ coverage/
|
||||
|
||||
# modules
|
||||
node_modules/
|
||||
build/
|
||||
dist/
|
||||
|
||||
# editors
|
||||
.*.swp
|
||||
|
||||
@@ -2,7 +2,6 @@ language: node_js
|
||||
node_js:
|
||||
- "10"
|
||||
- "8"
|
||||
- "6"
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
|
||||
+160
@@ -1,3 +1,159 @@
|
||||
## [8.4.1](https://github.com/harttle/liquidjs/compare/v8.4.0...v8.4.1) (2019-07-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* some filters on undefined variable throws, [#140](https://github.com/harttle/liquidjs/issues/140) ([6e6ea0a](https://github.com/harttle/liquidjs/commit/6e6ea0a))
|
||||
|
||||
# [8.4.0](https://github.com/harttle/liquidjs/compare/v8.3.0...v8.4.0) (2019-07-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* at_least, at_most, sort_naturual for [#132](https://github.com/harttle/liquidjs/issues/132) ([e6f5f1c](https://github.com/harttle/liquidjs/commit/e6f5f1c))
|
||||
|
||||
# [8.3.0](https://github.com/harttle/liquidjs/compare/v8.2.4...v8.3.0) (2019-06-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* fs option implemented by [#138](https://github.com/harttle/liquidjs/issues/138) ([3f5e23c](https://github.com/harttle/liquidjs/commit/3f5e23c))
|
||||
|
||||
## [8.2.4](https://github.com/harttle/liquidjs/compare/v8.2.3...v8.2.4) (2019-06-17)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* improve getTemplate() when cache is enabled ([1ffba2b](https://github.com/harttle/liquidjs/commit/1ffba2b))
|
||||
|
||||
## [8.2.3](https://github.com/harttle/liquidjs/compare/v8.2.2...v8.2.3) (2019-05-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* reverse filter not pure, see [#126](https://github.com/harttle/liquidjs/issues/126) ([505c408](https://github.com/harttle/liquidjs/commit/505c408))
|
||||
|
||||
## [8.2.2](https://github.com/harttle/liquidjs/compare/v8.2.1...v8.2.2) (2019-05-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* date from integer, [#125](https://github.com/harttle/liquidjs/issues/125) ([fdf0043](https://github.com/harttle/liquidjs/commit/fdf0043))
|
||||
* pass drops directly to filters/tags ([bef2909](https://github.com/harttle/liquidjs/commit/bef2909))
|
||||
|
||||
## [8.2.1](https://github.com/harttle/liquidjs/compare/v8.2.0...v8.2.1) (2019-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* `default` filter is not working with an empty string, [#122](https://github.com/harttle/liquidjs/issues/122) ([6075c0a](https://github.com/harttle/liquidjs/commit/6075c0a))
|
||||
|
||||
# [8.2.0](https://github.com/harttle/liquidjs/compare/v8.1.0...v8.2.0) (2019-04-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* pass context to filters ([00bc1ef](https://github.com/harttle/liquidjs/commit/00bc1ef))
|
||||
|
||||
# [8.1.0](https://github.com/harttle/liquidjs/compare/v8.0.3...v8.1.0) (2019-04-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* where filter, working on [#118](https://github.com/harttle/liquidjs/issues/118) ([daa0b57](https://github.com/harttle/liquidjs/commit/daa0b57))
|
||||
|
||||
## [8.0.3](https://github.com/harttle/liquidjs/compare/v8.0.2...v8.0.3) (2019-04-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* slice filter on negative `begin`, [#117](https://github.com/harttle/liquidjs/issues/117) ([eadb6f3](https://github.com/harttle/liquidjs/commit/eadb6f3))
|
||||
|
||||
## [8.0.2](https://github.com/harttle/liquidjs/compare/v8.0.1...v8.0.2) (2019-03-25)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* use polymophism instead duck test ([82d7673](https://github.com/harttle/liquidjs/commit/82d7673))
|
||||
|
||||
## [8.0.1](https://github.com/harttle/liquidjs/compare/v8.0.0...v8.0.1) (2019-03-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* incorrect scope when using assign with for, fixes [#115](https://github.com/harttle/liquidjs/issues/115) ([defbb58](https://github.com/harttle/liquidjs/commit/defbb58))
|
||||
|
||||
# [8.0.0](https://github.com/harttle/liquidjs/compare/v7.5.1...v8.0.0) (2019-03-10)
|
||||
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* use camelCase for JavaScript APIs ([64e0c87](https://github.com/harttle/liquidjs/commit/64e0c87))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* promise support for drops, working on [#65](https://github.com/harttle/liquidjs/issues/65) ([4a8088d](https://github.com/harttle/liquidjs/commit/4a8088d))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Options and method names in JavaScript API are now renamed to cammelCase, for a complete list see #109
|
||||
|
||||
## [7.5.1](https://github.com/harttle/liquidjs/compare/v7.5.0...v7.5.1) (2019-03-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* named params for filters, working on [#113](https://github.com/harttle/liquidjs/issues/113) ([5ffc904](https://github.com/harttle/liquidjs/commit/5ffc904))
|
||||
|
||||
# [7.5.0](https://github.com/harttle/liquidjs/compare/v7.4.0...v7.5.0) (2019-03-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* tablerowloop object ([3647305](https://github.com/harttle/liquidjs/commit/3647305))
|
||||
|
||||
# [7.4.0](https://github.com/harttle/liquidjs/compare/v7.3.1...v7.4.0) (2019-02-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* math filters now return number, resolves [#110](https://github.com/harttle/liquidjs/issues/110) ([b4acdb4](https://github.com/harttle/liquidjs/commit/b4acdb4))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* exported Drop interface for [#107](https://github.com/harttle/liquidjs/issues/107) ([7bee9fc](https://github.com/harttle/liquidjs/commit/7bee9fc)), closes [#109](https://github.com/harttle/liquidjs/issues/109)
|
||||
|
||||
## [7.3.1](https://github.com/harttle/liquidjs/compare/v7.3.0...v7.3.1) (2019-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#108:** remove absolute path in emitted d.ts ([53a835a](https://github.com/harttle/liquidjs/commit/53a835a)), closes [#108](https://github.com/harttle/liquidjs/issues/108)
|
||||
|
||||
# [7.3.0](https://github.com/harttle/liquidjs/compare/v7.2.2...v7.3.0) (2019-02-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* nil/null/empty/blank literals, resolves [#102](https://github.com/harttle/liquidjs/issues/102) ([88c9e96](https://github.com/harttle/liquidjs/commit/88c9e96))
|
||||
|
||||
## [7.2.2](https://github.com/harttle/liquidjs/compare/v7.2.1...v7.2.2) (2019-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* filters break when argument contains [()|, fixes [#89](https://github.com/harttle/liquidjs/issues/89) ([e977669](https://github.com/harttle/liquidjs/commit/e977669))
|
||||
|
||||
## [7.2.1](https://github.com/harttle/liquidjs/compare/v7.2.0...v7.2.1) (2019-02-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* default length for truncate and truncatewords ([56c7992](https://github.com/harttle/liquidjs/commit/56c7992))
|
||||
|
||||
# [7.2.0](https://github.com/harttle/liquidjs/compare/v7.1.0...v7.2.0) (2019-02-20)
|
||||
|
||||
|
||||
@@ -5,6 +161,10 @@
|
||||
|
||||
* override output/tag delimiter, fixes [#54](https://github.com/harttle/liquidjs/issues/54) ([d20a043](https://github.com/harttle/liquidjs/commit/d20a043))
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* `trim_value_left` option renamed to `trim_output_left`, `trim_value_right` option renamed to `trim_output_right`
|
||||
|
||||
# [7.1.0](https://github.com/harttle/liquidjs/compare/v7.0.2...v7.1.0) (2019-02-20)
|
||||
|
||||
|
||||
|
||||
@@ -12,51 +12,61 @@
|
||||
[](http://github.com/harttle/liquidjs)
|
||||
[](https://github.com/harttle/liquidjs)
|
||||
|
||||
This is a liquid implementation for both Node.js and browsers. Website: <http://harttle.github.io/liquidjs/>, Live Demo: <https://jsfiddle.net/6u40xbzs/>
|
||||
A [shopify][shopify/liquid] compatible [Liquid][tutorial] template engine in pure JavaScript. Install via npm:
|
||||
|
||||
**Features**
|
||||
```bash
|
||||
npm install --save liquidjs
|
||||
```
|
||||
|
||||
* Fully compatible to [shopify][shopify/liquid], with all [tags][tags] and [filters][filters] implemented
|
||||
* Support layout(extend) and include syntax
|
||||
* In pure JavaScript with Promise-based API
|
||||
Or include the UMD build (You may need a [Promise polyfill][pp] for Node.js < 4 and ES5 browsers like [IE and Android UC][caniuse-promises]):
|
||||
|
||||
**Differences**
|
||||
```html
|
||||
<script src="//unpkg.com/liquidjs/dist/liquid.min.js"></script> <!--for production-->
|
||||
<script src="//unpkg.com/liquidjs/dist/liquid.js"></script> <!--for development-->
|
||||
```
|
||||
|
||||
Though being compatible with [Ruby Liquid](https://github.com/shopify/liquid) is one of our priorities, there're still certain differences. You may need some configuration to get it compatible in these senarios:
|
||||
**The purpose of this repo** is to provide a standard Liquid implementation for the JavaScript community.
|
||||
All features, filters and tags in [shopify/liquid](https://github.com/Shopify/liquid) are supposed to be supported here,
|
||||
though there are still some differences:
|
||||
|
||||
* Dynamic file locating (enabled by default), which means layout/partial name can be an variable in liquidjs. See [#51](https://github.com/harttle/liquidjs/issues/51).
|
||||
* Dynamic file locating (enabled by default), that means layout/partial names are treated as variables in liquidjs. See [#51](https://github.com/harttle/liquidjs/issues/51).
|
||||
* Truthy and Falsy. All values except `undefined`, `null`, `false` are truthy, whereas in Ruby Liquid all except `nil` and `false` are truthy. See [#26](https://github.com/harttle/liquidjs/pull/26).
|
||||
* Number Rendering. Since JavaScript do not distinguish `float` and `integer`, we cannot either convert between them nor render regarding to their type. See [#59](https://github.com/harttle/liquidjs/issues/59).
|
||||
* [.to_liquid()](https://github.com/Shopify/liquid/wiki/Introduction-to-Drops) has a `.toLiquid()` alias and and the JavaScript `.toString()` is aliased to `.to_s()`.
|
||||
* [.to_s()](https://www.rubydoc.info/gems/liquid/Liquid/Drop) uses `JSON.prototype.stringify` as default, rather than Ruby's inspect.
|
||||
* Number. In JavaScript we cannot distinguish or convert between `float` and `integer`, see [#59](https://github.com/harttle/liquidjs/issues/59). And when applied `size` filter, numbers always return 0, which is 8 for integer in ruby, cause they do not have a `length` property.
|
||||
* [.to_liquid()](https://github.com/Shopify/liquid/wiki/Introduction-to-Drops) is replaced by `.toLiquid()`
|
||||
* [.to_s()](https://www.rubydoc.info/gems/liquid/Liquid/Drop) is replaced by JavaScript `.toString()`
|
||||
|
||||
Features that available on shopify website but not on shopify/liquid repo will not be implemented in this repo,
|
||||
but there're some plugins available (feel free to add yours):
|
||||
|
||||
* color filters: https://github.com/harttle/liquidjs-color-filters
|
||||
* sections tags (WIP): https://github.com/harttle/liquidjs-section-tags
|
||||
|
||||
## TOC
|
||||
|
||||
* Usage
|
||||
* Get Started
|
||||
* [Render from String](#render-from-string)
|
||||
* [Render from File](#render-from-file)
|
||||
* [Use with Express.js](#use-with-expressjs)
|
||||
* [Use in Browser](#use-in-browser)
|
||||
* [Include Partials](#include-partials)
|
||||
* [Layout Templates (Extends)](#layout-templates-extends)
|
||||
* API Spec
|
||||
* [Constructor Options](#options)
|
||||
* Demos
|
||||
* Node.js: [/demo/node/](demo/node/)
|
||||
* Browser: <https://jsfiddle.net/6u40xbzs/>, [/demo/browser/](demo/browser/).
|
||||
* Express.js: [/demo/express/](demo/express/)
|
||||
* TypeScript: [/demo/typescript/](demo/typescript/)
|
||||
* React JS: [/demo/reactjs/](demo/reactjs/)
|
||||
* Advanced
|
||||
* [Options](#options)
|
||||
* [Register Filters](#register-filters), [Builtin Filters](https://github.com/harttle/liquidjs/wiki/Builtin-Filters)
|
||||
* [Register Tags](#register-tags), [Builtin Tags](https://github.com/harttle/liquidjs/wiki/Builtin-Tags)
|
||||
* [Operators](https://github.com/harttle/liquidjs/wiki/Operators)
|
||||
* [Whitespace Control](https://github.com/harttle/liquidjs/wiki/Whitespace-Control)
|
||||
* [Plugin API](#plugin-api)
|
||||
* [Contribute Guidelines](#contribute-guidelines)
|
||||
|
||||
## Render from String
|
||||
|
||||
Install as Node.js dependency:
|
||||
|
||||
```bash
|
||||
# You'll need a promise-polyfill for Node.js < 4
|
||||
npm install --save liquidjs
|
||||
```
|
||||
|
||||
Parse and Render:
|
||||
Just render a template string with a context:
|
||||
|
||||
```javascript
|
||||
var Liquid = require('liquidjs');
|
||||
@@ -64,35 +74,27 @@ var engine = new Liquid();
|
||||
|
||||
engine
|
||||
.parseAndRender('{{name | capitalize}}', {name: 'alice'})
|
||||
.then(console.log);
|
||||
|
||||
// outputs 'Alice'
|
||||
.then(console.log); // outputs 'Alice'
|
||||
```
|
||||
|
||||
Caching templates:
|
||||
Caching parsed templates:
|
||||
|
||||
```javascript
|
||||
var tpl = engine.parse('{{name | capitalize}}');
|
||||
engine
|
||||
.render(tpl, {name: 'alice'})
|
||||
.then(console.log);
|
||||
|
||||
// outputs 'Alice'
|
||||
.then(console.log); // outputs 'Alice'
|
||||
```
|
||||
|
||||
## Render from File
|
||||
|
||||
```javascript
|
||||
var engine = new Liquid({
|
||||
root: path.resolve(__dirname, 'views/'), // dirs to lookup layouts/includes
|
||||
extname: '.liquid' // the extname used for layouts/includes, defaults ""
|
||||
root: path.resolve(__dirname, 'views/'), // root for layouts/includes lookup
|
||||
extname: '.liquid' // used for layouts/includes, defaults ""
|
||||
});
|
||||
engine.renderFile("hello.liquid", {name: 'alice'})
|
||||
.then(console.log) // outputs "Alice"
|
||||
|
||||
// which is equivalent to:
|
||||
engine
|
||||
.renderFile("hello", {name: 'alice'})
|
||||
.renderFile("hello", {name: 'alice'}) // will read and render `views/hello.liquid`
|
||||
.then(console.log) // outputs "Alice"
|
||||
```
|
||||
|
||||
@@ -105,24 +107,9 @@ app.set('views', './views'); // specify the views directory
|
||||
app.set('view engine', 'liquid'); // set to default
|
||||
```
|
||||
|
||||
[Here](demo/express/)'s an Express demo. When used with Express.js,
|
||||
Express [`views`][express-views] will be included when looking up
|
||||
[`views`][express-views] in express.js will be included when looking up
|
||||
partials(includes and layouts).
|
||||
|
||||
## Use in Browser
|
||||
|
||||
You can get a dist file for browsers from
|
||||
|
||||
* [Releases][releases] page for liquidjs, or
|
||||
* unpkg.com: <https://unpkg.com/liquidjs/dist/liquid.min.js>
|
||||
|
||||
Here's the demo:
|
||||
|
||||
* JSFiddle: <https://jsfiddle.net/6u40xbzs/>
|
||||
* Demo directory: [/demo/browser/](demo/browser/).
|
||||
|
||||
Note: For [IE and Android UC][caniuse-promises] browser, you will need a [Promise polyfill][pp].
|
||||
|
||||
## Include Partials
|
||||
|
||||
```
|
||||
@@ -182,25 +169,27 @@ Defaults to `["."]`
|
||||
|
||||
* `dynamicPartials`: if set, treat `<filepath>` parameter in `{%include filepath %}`, `{%layout filepath%}` as a variable, otherwise as a literal value. Defaults to `true`.
|
||||
|
||||
* `strict_filters` is used to enable strict filter existence. If set to `false`, undefined filters will be rendered as empty string. Otherwise, undefined filters will cause an exception. Defaults to `false`.
|
||||
* `strictFilters` is used to enable strict filter existence. If set to `false`, undefined filters will be rendered as empty string. Otherwise, undefined filters will cause an exception. Defaults to `false`.
|
||||
|
||||
* `strict_variables` is used to enable strict variable derivation.
|
||||
* `strictVariables` is used to enable strict variable derivation.
|
||||
If set to `false`, undefined variables will be rendered as empty string.
|
||||
Otherwise, undefined variables will cause an exception. Defaults to `false`.
|
||||
|
||||
* `trim_tag_right` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`.
|
||||
* `trimTagRight` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`.
|
||||
|
||||
* `trim_tag_left` is similiar to `trim_tag_right`, whereas the `\n` is exclusive. Defaults to `false`. See [Whitespace Control][whitespace control] for details.
|
||||
* `trimTagLeft` is similiar to `trimTagRight`, whereas the `\n` is exclusive. Defaults to `false`. See [Whitespace Control][whitespace control] for details.
|
||||
|
||||
* `trim_output_right` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of values (`{{ }}`) until `\n` (inclusive). Defaults to `false`.
|
||||
* `trimOutputRight` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of values (`{{ }}`) until `\n` (inclusive). 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.
|
||||
* `trimOutputLeft` is similiar to `trimOutputRight`, 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.
|
||||
* `tagDelimiterLeft` and `tagDelimiterRight` 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.
|
||||
* `outputDelimiterLeft` and `outputDelimiterRight` 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`.
|
||||
* `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
|
||||
|
||||
@@ -226,9 +215,9 @@ engine.registerTag('upper', {
|
||||
parse: function(tagToken, remainTokens) {
|
||||
this.str = tagToken.args; // name
|
||||
},
|
||||
render: function(scope, hash) {
|
||||
var str = Liquid.evalValue(this.str, scope); // 'alice'
|
||||
return Promise.resolve(str.toUpperCase()); // 'Alice'
|
||||
render: async function(scope, hash) {
|
||||
var str = await Liquid.evalValue(this.str, scope); // 'alice'
|
||||
return str.toUpperCase() // 'Alice'
|
||||
}
|
||||
});
|
||||
```
|
||||
@@ -253,10 +242,6 @@ module.exports = function (Liquid) {
|
||||
}
|
||||
```
|
||||
|
||||
Plugin List:
|
||||
|
||||
* To add your plugin, contact me or simply send a PR.
|
||||
|
||||
## Contribute Guidelines
|
||||
|
||||
This repo uses [eslint](https://eslint.org/) to check code style, [semantic-release](https://github.com/semantic-release/semantic-release) to generate changelog and publish to npm and Github Releases.
|
||||
@@ -269,7 +254,6 @@ This repo uses [eslint](https://eslint.org/) to check code style, [semantic-rele
|
||||
[shopify/liquid]: https://shopify.github.io/liquid/
|
||||
[jekyll]: http://jekyllrb.com/
|
||||
[gh]: https://pages.github.com/
|
||||
[releases]: https://github.com/harttle/liquidjs/releases
|
||||
[any-promise]: https://github.com/kevinbeaty/any-promise
|
||||
[test]: https://github.com/harttle/liquidjs/tree/master/test
|
||||
[caniuse-promises]: http://caniuse.com/#feat=promises
|
||||
@@ -278,3 +262,4 @@ This repo uses [eslint](https://eslint.org/) to check code style, [semantic-rele
|
||||
[filters]: https://github.com/harttle/liquidjs/wiki/Builtin-Filters
|
||||
[express-views]: http://expressjs.com/en/guide/using-template-engines.html
|
||||
[pp]: https://github.com/taylorhakes/promise-polyfill
|
||||
[tutorial]: https://shopify.github.io/liquid/basics/introduction/
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-unused-expressions": "off"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import * as Benchmark from 'benchmark'
|
||||
import Liquid from '../src/liquid'
|
||||
import TagToken from '../src/parser/tag-token'
|
||||
import Context from '../src/context/context'
|
||||
|
||||
const engine = new Liquid({
|
||||
root: __dirname,
|
||||
extname: '.liquid'
|
||||
})
|
||||
|
||||
engine.registerTag('header', {
|
||||
parse: function (token: TagToken) {
|
||||
const [key, val] = token.args.split(':')
|
||||
this[key] = val
|
||||
},
|
||||
render: function (ctx: Context) {
|
||||
const title = this.liquid.evalValue(this.content, ctx)
|
||||
return `<h1>${title}</h1>`
|
||||
}
|
||||
})
|
||||
|
||||
const ctx = {
|
||||
todos: ['fork and clone', 'make it better', 'make a pull request'],
|
||||
title: 'Welcome to liquidjs!'
|
||||
}
|
||||
|
||||
const template = `
|
||||
{%header content: "welcome to liquid" | capitalize%}
|
||||
|
||||
<ul>
|
||||
{% for todo in todos %}
|
||||
<li>{{forloop.index}} - {{todo}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
`
|
||||
|
||||
export default function () {
|
||||
console.log('--- demo ---')
|
||||
return new Promise(resolve => {
|
||||
new Benchmark.Suite('demo')
|
||||
.add('demo', {
|
||||
defer: true,
|
||||
fn: (d: any) => engine.parseAndRender(template, ctx).then(x => d.resolve(x))
|
||||
})
|
||||
.on('cycle', (event: any) => console.log(String(event.target)))
|
||||
.on('complete', resolve)
|
||||
.run({ 'async': true })
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import output from './output'
|
||||
import tag from './tag'
|
||||
import demo from './demo'
|
||||
import layout from './layout'
|
||||
|
||||
async function main () {
|
||||
await output()
|
||||
await tag()
|
||||
await demo()
|
||||
await layout()
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,36 @@
|
||||
import * as Benchmark from 'benchmark'
|
||||
import Liquid from '../src/liquid'
|
||||
|
||||
const engineOptions = {
|
||||
root: __dirname,
|
||||
extname: '.liquid'
|
||||
}
|
||||
|
||||
const engine = new Liquid(engineOptions)
|
||||
const cachingEngine = new Liquid({
|
||||
...engineOptions,
|
||||
cache: true
|
||||
})
|
||||
|
||||
const template = `
|
||||
{% layout "./templates/layout.liquid" %}
|
||||
{% block body %}a small body{% endblock %}
|
||||
`
|
||||
|
||||
export default function () {
|
||||
console.log('--- layout ---')
|
||||
return new Promise(resolve => {
|
||||
new Benchmark.Suite('layout')
|
||||
.add('cache=false', {
|
||||
defer: true,
|
||||
fn: (d: any) => engine.parseAndRender(template, {}).then(x => d.resolve(x))
|
||||
})
|
||||
.add('cache=true', {
|
||||
defer: true,
|
||||
fn: (d: any) => cachingEngine.parseAndRender(template, {}).then(x => d.resolve(x))
|
||||
})
|
||||
.on('cycle', (event: any) => console.log(String(event.target)))
|
||||
.on('complete', resolve)
|
||||
.run({ 'async': true })
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import * as Benchmark from 'benchmark'
|
||||
import Liquid from '../src/liquid'
|
||||
|
||||
const liquid = new Liquid()
|
||||
|
||||
export default function () {
|
||||
console.log('--- output ---')
|
||||
return new Promise(resolve => {
|
||||
new Benchmark.Suite('output')
|
||||
.add('literal', test('{{false}}{{"foo"}}{{32.322}}'))
|
||||
.add('truncate', test('{{"foobar" | truncate: 3}}'))
|
||||
.add('date', test('{{"now" | date: "%d%Y%m"}}'))
|
||||
.add('escape', test('{{"1<2" | escape}}'))
|
||||
.add('default', test('{{"" | default: 3}}'))
|
||||
.on('cycle', (event: any) => console.log(String(event.target)))
|
||||
.on('complete', resolve)
|
||||
.run({ 'async': true })
|
||||
})
|
||||
}
|
||||
|
||||
function test (str: string) {
|
||||
return {
|
||||
defer: true,
|
||||
fn: (d: any) => liquid.parseAndRender(str).then(x => d.resolve(x))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import * as Benchmark from 'benchmark'
|
||||
import Liquid from '../src/liquid'
|
||||
|
||||
const liquid = new Liquid()
|
||||
|
||||
export default function () {
|
||||
console.log('--- tag ---')
|
||||
return new Promise(resolve => {
|
||||
new Benchmark.Suite('tag')
|
||||
.add('if', test('{% if "foobar" %}foo{% endif %}'))
|
||||
.add('unless', test('{%unless "foo"%}true{%else%}false{%endunless%}'))
|
||||
.add('for', test('{% for i in (1..3) %}{{fooloop.index}}{% endfor %}'))
|
||||
.add('switch', test('{%case 3%}{% when 1 %}1{% when 2 %}2{% when 3 %}3{%endcase%}'))
|
||||
.add('assign', test('{%assign a="foo bar"%}'))
|
||||
.add('capture', test('{%capture foo%}what is this{%endcapture%}'))
|
||||
.add('increment', test('{%increment a%}'))
|
||||
.add('decrement', test('{%decrement a%}'))
|
||||
.add('tablerow', test('{%tablerow i in (1..10) cols:3%}{%endtablerow%}'))
|
||||
.on('cycle', (event: any) => console.log(String(event.target)))
|
||||
.on('complete', resolve)
|
||||
.run({ 'async': true })
|
||||
})
|
||||
}
|
||||
|
||||
function test (str: string) {
|
||||
return {
|
||||
defer: true,
|
||||
fn: (d: any) => liquid.parseAndRender(str).then(x => d.resolve(x))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
This is a barely empty layout with a body:
|
||||
{% block body %}{% endblock %}
|
||||
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
declare const _default: {
|
||||
'join': (v: any, arg: any) => any;
|
||||
'last': (v: any) => any;
|
||||
'first': (v: any) => any;
|
||||
'map': (arr: any, arg: any) => any;
|
||||
'reverse': (v: any) => any;
|
||||
'sort': (v: any, arg: any) => any;
|
||||
'size': (v: any) => any;
|
||||
'slice': (v: any, begin: any, length: any) => any;
|
||||
'uniq': (arr: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
declare const _default: {
|
||||
'date': (v: any, arg: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
declare function escape(str: any): string;
|
||||
declare const _default: {
|
||||
'escape': typeof escape;
|
||||
'escape_once': (str: any) => string;
|
||||
'newline_to_br': (v: any) => any;
|
||||
'strip_html': (v: any) => string;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-46
@@ -1,46 +0,0 @@
|
||||
declare const _default: {
|
||||
'join': (v: any, arg: any) => any;
|
||||
'last': (v: any) => any;
|
||||
'first': (v: any) => any;
|
||||
'map': (arr: any, arg: any) => any;
|
||||
'reverse': (v: any) => any;
|
||||
'sort': (v: any, arg: any) => any;
|
||||
'size': (v: any) => any;
|
||||
'slice': (v: any, begin: any, length: any) => any;
|
||||
'uniq': (arr: any) => any;
|
||||
'default': (v: any, arg: any) => any;
|
||||
'date': (v: any, arg: any) => any;
|
||||
'url_decode': (x: any) => any;
|
||||
'url_encode': (x: any) => any;
|
||||
'abs': (v: any) => number;
|
||||
'ceil': (v: any) => number;
|
||||
'divided_by': (v: any, arg: any) => number;
|
||||
'floor': (v: any) => number;
|
||||
'minus': (l: any, r: any) => any;
|
||||
'modulo': (l: any, r: any) => any;
|
||||
'round': (v: any, arg: any) => number;
|
||||
'plus': (l: any, r: any) => any;
|
||||
'times': (v: any, arg: any) => number;
|
||||
'append': (v: any, arg: any) => any;
|
||||
'prepend': (v: any, arg: any) => any;
|
||||
'capitalize': (str: any) => string;
|
||||
'concat': (v: any, arg: any) => any;
|
||||
'lstrip': (v: any) => string;
|
||||
'downcase': (v: any) => any;
|
||||
'upcase': (str: any) => string;
|
||||
'remove': (v: any, arg: any) => any;
|
||||
'remove_first': (v: any, l: any) => any;
|
||||
'replace': (v: any, pattern: any, replacement: any) => string;
|
||||
'replace_first': (v: any, arg1: any, arg2: any) => string;
|
||||
'rstrip': (str: any) => string;
|
||||
'split': (v: any, arg: any) => string[];
|
||||
'strip': (v: any) => string;
|
||||
'strip_newlines': (v: any) => string;
|
||||
'truncate': (v: any, l: any, o: any) => any;
|
||||
'truncatewords': (v: any, l: any, o: any) => any;
|
||||
'escape': (str: any) => string;
|
||||
'escape_once': (str: any) => string;
|
||||
'newline_to_br': (v: any) => any;
|
||||
'strip_html': (v: any) => string;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
declare const _default: {
|
||||
'abs': (v: any) => number;
|
||||
'ceil': (v: any) => number;
|
||||
'divided_by': (v: any, arg: any) => number;
|
||||
'floor': (v: any) => number;
|
||||
'minus': (l: any, r: any) => any;
|
||||
'modulo': (l: any, r: any) => any;
|
||||
'round': (v: any, arg: any) => number;
|
||||
'plus': (l: any, r: any) => any;
|
||||
'times': (v: any, arg: any) => number;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
declare const _default: {
|
||||
'default': (v: any, arg: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-20
@@ -1,20 +0,0 @@
|
||||
declare const _default: {
|
||||
'append': (v: any, arg: any) => any;
|
||||
'prepend': (v: any, arg: any) => any;
|
||||
'capitalize': (str: any) => string;
|
||||
'concat': (v: any, arg: any) => any;
|
||||
'lstrip': (v: any) => string;
|
||||
'downcase': (v: any) => any;
|
||||
'upcase': (str: any) => string;
|
||||
'remove': (v: any, arg: any) => any;
|
||||
'remove_first': (v: any, l: any) => any;
|
||||
'replace': (v: any, pattern: any, replacement: any) => string;
|
||||
'replace_first': (v: any, arg1: any, arg2: any) => string;
|
||||
'rstrip': (str: any) => string;
|
||||
'split': (v: any, arg: any) => string[];
|
||||
'strip': (v: any) => string;
|
||||
'strip_newlines': (v: any) => string;
|
||||
'truncate': (v: any, l: any, o: any) => any;
|
||||
'truncatewords': (v: any, l: any, o: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
'url_decode': (x: any) => any;
|
||||
'url_encode': (x: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (token: any) => void;
|
||||
render: (scope: any) => Promise<string>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (token: any, remainTokens: any) => void;
|
||||
render: (scope: any) => Promise<any>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
declare const _default: {
|
||||
render: () => Promise<never>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
import TagToken from 'src/parser/tag-token';
|
||||
import Token from 'src/parser/token';
|
||||
import Scope from 'src/scope/scope';
|
||||
declare const _default: {
|
||||
parse: (tagToken: TagToken, remainTokens: Token[]) => void;
|
||||
render: (scope: Scope) => Promise<void>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (tagToken: any, remainTokens: any) => void;
|
||||
render: (scope: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (tagToken: any, remainTokens: any) => void;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
declare const _default: {
|
||||
render: () => Promise<never>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (tagToken: any) => void;
|
||||
render: (scope: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
import TagToken from 'src/parser/tag-token';
|
||||
import Scope from 'src/scope/scope';
|
||||
declare const _default: {
|
||||
parse: (token: TagToken) => void;
|
||||
render: (scope: Scope) => number;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
declare function parse(tagToken: any, remainTokens: any): void;
|
||||
declare function render(scope: any, hash: any): Promise<any>;
|
||||
declare const _default: {
|
||||
parse: typeof parse;
|
||||
render: typeof render;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (tagToken: any, remainTokens: any) => void;
|
||||
render: (scope: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (token: any) => void;
|
||||
render: (scope: any, hash: any) => Promise<any>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (token: any) => void;
|
||||
render: (scope: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
import ITagImplOptions from 'src/template/tag/itag-impl-options';
|
||||
declare const tags: {
|
||||
[key: string]: ITagImplOptions;
|
||||
};
|
||||
export default tags;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (token: any, remainTokens: any) => void;
|
||||
render: (scope: any, hash: any) => Promise<any>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (tagToken: any, remainTokens: any) => void;
|
||||
render: () => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (tagToken: any, remainTokens: any) => void;
|
||||
render: (scope: any, hash: any) => Promise<string>;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare const _default: {
|
||||
parse: (tagToken: any, remainTokens: any) => void;
|
||||
render: (scope: any) => any;
|
||||
};
|
||||
export default _default;
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
import IFS from './ifs';
|
||||
declare const _default: IFS;
|
||||
export default _default;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
export default interface IFS {
|
||||
exists: (filepath?: string) => Promise<boolean>;
|
||||
readFile: (filepath: string) => Promise<string>;
|
||||
resolve: (root: string, file: string, ext: string) => string;
|
||||
}
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
import IFS from './ifs';
|
||||
declare const fs: IFS;
|
||||
export default fs;
|
||||
Vendored
-48
@@ -1,48 +0,0 @@
|
||||
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 `["."]` */
|
||||
root?: string | string[];
|
||||
/** `extname` is used to lookup the template file when filepath doesn't include an extension name. Eg: setting to `".html"` will allow including file by basename. Defaults to `""`. */
|
||||
extname?: string;
|
||||
/** `cache` indicates whether or not to cache resolved templates. Defaults to `false`. */
|
||||
cache?: boolean;
|
||||
/** `dynamicPartials`: if set, treat `<filepath>` parameter in `{%include filepath %}`, `{%layout filepath%}` as a variable, otherwise as a literal value. Defaults to `true`. */
|
||||
dynamicPartials?: boolean;
|
||||
/** `strict_filters` is used to enable strict filter existence. If set to `false`, undefined filters will be rendered as empty string. Otherwise, undefined filters will cause an exception. Defaults to `false`. */
|
||||
strict_filters?: boolean;
|
||||
/** `strict_variables` is used to enable strict variable derivation. If set to `false`, undefined variables will be rendered as empty string. Otherwise, undefined variables will cause an exception. Defaults to `false`. */
|
||||
strict_variables?: boolean;
|
||||
/** `trim_tag_right` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of tags (`{% %}`) until `\n` (inclusive). Defaults to `false`. */
|
||||
trim_tag_right?: boolean;
|
||||
/** `trim_tag_left` is similar to `trim_tag_right`, whereas the `\n` is exclusive. Defaults to `false`. See Whitespace Control for details. */
|
||||
trim_tag_left?: boolean;
|
||||
/** ``trim_output_right` is used to strip blank characters (including ` `, `\t`, and `\r`) from the right of values (`{{ }}`) until `\n` (inclusive). Defaults to `false`. */
|
||||
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;
|
||||
}
|
||||
export interface NormalizedOptions extends LiquidOptions {
|
||||
root?: string[];
|
||||
}
|
||||
export interface NormalizedFullOptions extends NormalizedOptions {
|
||||
root: string[];
|
||||
extname: string;
|
||||
cache: boolean;
|
||||
dynamicPartials: boolean;
|
||||
strict_filters: boolean;
|
||||
strict_variables: boolean;
|
||||
trim_tag_right: boolean;
|
||||
trim_tag_left: boolean;
|
||||
trim_output_right: boolean;
|
||||
trim_output_left: boolean;
|
||||
greedy: boolean;
|
||||
}
|
||||
export declare function normalize(options: LiquidOptions): NormalizedOptions;
|
||||
export declare function applyDefault(options: NormalizedOptions): NormalizedFullOptions;
|
||||
Vendored
-2291
File diff suppressed because it is too large
Load Diff
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
-30
@@ -1,30 +0,0 @@
|
||||
import Scope from './scope/scope';
|
||||
import * as Types from './types';
|
||||
import ITemplate from './template/itemplate';
|
||||
import ITagImplOptions from './template/tag/itag-impl-options';
|
||||
import { isTruthy, isFalsy, evalExp, evalValue } from './render/syntax';
|
||||
import { LiquidOptions, NormalizedFullOptions } from './liquid-options';
|
||||
export default class Liquid {
|
||||
options: NormalizedFullOptions;
|
||||
private cache;
|
||||
private parser;
|
||||
private renderer;
|
||||
private tokenizer;
|
||||
constructor(opts?: LiquidOptions);
|
||||
parse(html: string, filepath?: string): any[];
|
||||
render(tpl: Array<ITemplate>, ctx?: object, opts?: LiquidOptions): Promise<string>;
|
||||
parseAndRender(html: string, ctx?: object, opts?: LiquidOptions): Promise<string>;
|
||||
getTemplate(file: any, opts?: LiquidOptions): Promise<any>;
|
||||
renderFile(file: any, ctx?: object, opts?: LiquidOptions): Promise<string>;
|
||||
evalValue(str: string, scope: Scope): any;
|
||||
registerFilter(name: any, filter: any): void;
|
||||
registerTag(name: string, tag: ITagImplOptions): void;
|
||||
plugin(plugin: any): any;
|
||||
express(): (filePath: string, ctx: object, cb: (err: Error, html?: string) => void) => void;
|
||||
static default: typeof Liquid;
|
||||
static isTruthy: typeof isTruthy;
|
||||
static isFalsy: typeof isFalsy;
|
||||
static evalExp: typeof evalExp;
|
||||
static evalValue: typeof evalValue;
|
||||
static Types: typeof Types;
|
||||
}
|
||||
Vendored
-2318
File diff suppressed because it is too large
Load Diff
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
-2
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
import Token from './token';
|
||||
export default class DelimitedToken extends Token {
|
||||
trimLeft: boolean;
|
||||
trimRight: boolean;
|
||||
constructor(raw: any, value: any, pos: any, input: any, file: any, line: any);
|
||||
}
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
import Token from './token';
|
||||
export default class HTMLToken extends Token {
|
||||
constructor(str: any, begin: any, input: any, file: any, line: any);
|
||||
}
|
||||
Vendored
-35
@@ -1,35 +0,0 @@
|
||||
export declare const quoted: RegExp;
|
||||
export declare const quoteBalanced: RegExp;
|
||||
export declare const integer: RegExp;
|
||||
export declare const number: RegExp;
|
||||
export declare const bool: RegExp;
|
||||
export declare const identifier: RegExp;
|
||||
export declare const subscript: RegExp;
|
||||
export declare const literal: RegExp;
|
||||
export declare const variable: RegExp;
|
||||
export declare const rangeLimit: RegExp;
|
||||
export declare const range: RegExp;
|
||||
export declare const rangeCapture: RegExp;
|
||||
export declare const value: RegExp;
|
||||
export declare const hash: RegExp;
|
||||
export declare const hashCapture: RegExp;
|
||||
export declare const tagLine: RegExp;
|
||||
export declare const literalLine: RegExp;
|
||||
export declare const variableLine: RegExp;
|
||||
export declare const numberLine: RegExp;
|
||||
export declare const boolLine: RegExp;
|
||||
export declare const quotedLine: RegExp;
|
||||
export declare const rangeLine: RegExp;
|
||||
export declare const integerLine: RegExp;
|
||||
export declare const valueDeclaration: RegExp;
|
||||
export declare const valueList: RegExp;
|
||||
export declare const filter: RegExp;
|
||||
export declare const filterCapture: RegExp;
|
||||
export declare const filterLine: RegExp;
|
||||
export declare const operators: RegExp[];
|
||||
export declare function isInteger(str: any): boolean;
|
||||
export declare function isLiteral(str: any): boolean;
|
||||
export declare function isRange(str: any): boolean;
|
||||
export declare function isVariable(str: any): boolean;
|
||||
export declare function matchValue(str: any): RegExpExecArray;
|
||||
export declare function parseLiteral(str: any): any;
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
import DelimitedToken from './delimited-token';
|
||||
export default class OutputToken extends DelimitedToken {
|
||||
constructor(raw: any, value: any, pos: any, input: any, file: any, line: any);
|
||||
}
|
||||
Vendored
-16
@@ -1,16 +0,0 @@
|
||||
import Token from 'src/parser/token';
|
||||
import ITemplate from 'src/template/itemplate';
|
||||
declare type parseToken = (token: Token, remainTokens: Array<Token>) => ITemplate;
|
||||
declare type eventHandler = ((arg?: Token | ITemplate) => void);
|
||||
export default class ParseStream {
|
||||
private tokens;
|
||||
private handlers;
|
||||
private stopRequested;
|
||||
private parseToken;
|
||||
constructor(tokens: Array<Token>, parseToken: parseToken);
|
||||
on(name: string, cb: eventHandler): this;
|
||||
trigger(event: string, arg?: Token | ITemplate): boolean;
|
||||
start(): this;
|
||||
stop(): this;
|
||||
}
|
||||
export {};
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
import Liquid from 'src/liquid';
|
||||
import ParseStream from './parse-stream';
|
||||
import Token from './token';
|
||||
import Tag from 'src/template/tag/tag';
|
||||
import Output from 'src/template/output';
|
||||
import HTML from 'src/template/html';
|
||||
export default class Parser {
|
||||
liquid: Liquid;
|
||||
constructor(liquid: Liquid);
|
||||
parse(tokens: Array<Token>): any[];
|
||||
parseToken(token: Token, remainTokens: Array<Token>): Tag | Output | HTML;
|
||||
parseStream(tokens: Array<Token>): ParseStream;
|
||||
}
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
import DelimitedToken from './delimited-token';
|
||||
export default class TagToken extends DelimitedToken {
|
||||
name: string;
|
||||
args: string;
|
||||
constructor(raw: any, value: any, pos: any, input: any, file: any, line: any);
|
||||
}
|
||||
Vendored
-10
@@ -1,10 +0,0 @@
|
||||
export default class Token {
|
||||
type: string;
|
||||
line: number;
|
||||
col: number;
|
||||
raw: string;
|
||||
input: string;
|
||||
file: string;
|
||||
value: string;
|
||||
constructor(raw: any, col: any, input: any, file: any, line: any);
|
||||
}
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
import { NormalizedFullOptions } from '../liquid-options';
|
||||
export default class Tokenizer {
|
||||
options: NormalizedFullOptions;
|
||||
constructor(options?: NormalizedFullOptions);
|
||||
tokenize(input: string, file?: string): any[];
|
||||
}
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
import Token from 'src/parser/token';
|
||||
import { NormalizedFullOptions } from 'src/liquid-options';
|
||||
export default function whiteSpaceCtrl(tokens: Token[], options: NormalizedFullOptions): void;
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
export default class Render {
|
||||
renderTemplates(templates: any, scope: any): Promise<string>;
|
||||
}
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
export declare function evalExp(exp: any, scope: any): any;
|
||||
export declare function evalValue(str: any, scope: any): any;
|
||||
export declare function isTruthy(val: any): boolean;
|
||||
export declare function isFalsy(val: any): boolean;
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare enum BlockMode {
|
||||
OUTPUT = 0,
|
||||
STORE = 1
|
||||
}
|
||||
export default BlockMode;
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
import { NormalizedFullOptions } from '../liquid-options';
|
||||
import BlockMode from './block-mode';
|
||||
export default class Scope {
|
||||
opts: NormalizedFullOptions;
|
||||
contexts: Array<object>;
|
||||
blocks: object;
|
||||
blockMode: BlockMode;
|
||||
constructor(ctx?: object, opts?: NormalizedFullOptions);
|
||||
getAll(): object;
|
||||
get(path: string): any;
|
||||
set(path: string, v: any): void;
|
||||
unshift(ctx: object): number;
|
||||
push(ctx: object): number;
|
||||
pop(ctx?: object): object;
|
||||
findContextFor(key: string, filter?: ((conttext: object) => boolean)): object;
|
||||
readProperty(obj: any, key: any): any;
|
||||
propertyAccessSeq(str: any): any[];
|
||||
}
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
export declare class CaptureScope {
|
||||
}
|
||||
export declare class AssignScope {
|
||||
}
|
||||
export declare class IncrementScope {
|
||||
}
|
||||
export declare class DecrementScope {
|
||||
}
|
||||
Vendored
-14
@@ -1,14 +0,0 @@
|
||||
import Scope from 'src/scope/scope';
|
||||
declare type impl = (value: any, ...args: any[]) => any;
|
||||
export default class Filter {
|
||||
name: string;
|
||||
impl: impl;
|
||||
args: string[];
|
||||
private static impls;
|
||||
constructor(str: string, strictFilters?: boolean);
|
||||
parseArgs(argList: string): string[];
|
||||
render(value: any, scope: Scope): any;
|
||||
static register(name: any, filter: any): void;
|
||||
static clear(): void;
|
||||
}
|
||||
export {};
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
import Template from 'src/template/template';
|
||||
import ITemplate from 'src/template/itemplate';
|
||||
import Token from 'src/parser/token';
|
||||
export default class extends Template implements ITemplate {
|
||||
str: string;
|
||||
constructor(token: Token);
|
||||
render(): Promise<string>;
|
||||
}
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
import Scope from 'src/scope/scope';
|
||||
import Token from 'src/parser/token';
|
||||
export default interface ITemplate {
|
||||
token: Token;
|
||||
render(scope: Scope): Promise<string>;
|
||||
}
|
||||
Vendored
-10
@@ -1,10 +0,0 @@
|
||||
import Value from './value';
|
||||
import Template from 'src/template/template';
|
||||
import ITemplate from 'src/template/itemplate';
|
||||
import Scope from 'src/scope/scope';
|
||||
import OutputToken from 'src/parser/output-token';
|
||||
export default class Output extends Template implements ITemplate {
|
||||
value: Value;
|
||||
constructor(token: OutputToken, strictFilters?: boolean);
|
||||
render(scope: Scope): Promise<string>;
|
||||
}
|
||||
Vendored
-10
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Key-Value Pairs Representing Tag Arguments
|
||||
* Example:
|
||||
* For the markup `{% include 'head.html' foo='bar' %}`,
|
||||
* hash['foo'] === 'bar'
|
||||
*/
|
||||
export default class Hash {
|
||||
[key: string]: any;
|
||||
constructor(markup: any, scope: any);
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import Scope from 'src/scope/scope';
|
||||
import TagToken from 'src/parser/tag-token';
|
||||
import Token from 'src/parser/token';
|
||||
import Hash from 'src/template/tag/hash';
|
||||
import ITagImpl from './itag-impl';
|
||||
export default interface ITagImplOptions {
|
||||
parse?: (this: ITagImpl, token: TagToken, remainingTokens: Array<Token>) => void;
|
||||
render?: (this: ITagImpl, scope: Scope, hash: Hash) => any | Promise<any>;
|
||||
}
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
import Liquid from 'src/liquid';
|
||||
import ITagImplOptions from './itag-impl-options';
|
||||
export default interface ITagImpl extends ITagImplOptions {
|
||||
liquid: Liquid;
|
||||
}
|
||||
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
import Scope from 'src/scope/scope';
|
||||
import ITagImplOptions from './itag-impl-options';
|
||||
import Liquid from 'src/liquid';
|
||||
import Template from 'src/template/template';
|
||||
import ITemplate from 'src/template/itemplate';
|
||||
import TagToken from 'src/parser/tag-token';
|
||||
import Token from 'src/parser/token';
|
||||
export default class Tag extends Template implements ITemplate {
|
||||
name: string;
|
||||
token: TagToken;
|
||||
private impl;
|
||||
static impls: {
|
||||
[key: string]: ITagImplOptions;
|
||||
};
|
||||
constructor(token: TagToken, tokens: Token[], liquid: Liquid);
|
||||
render(scope: Scope): Promise<string>;
|
||||
static register(name: string, tag: ITagImplOptions): void;
|
||||
static clear(): void;
|
||||
}
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
import Token from 'src/parser/token';
|
||||
export default class Template {
|
||||
token: Token;
|
||||
constructor(token: any);
|
||||
}
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
import Scope from 'src/scope/scope';
|
||||
export default class {
|
||||
initial: any;
|
||||
filters: Array<any>;
|
||||
constructor(str: string, strictFilters?: boolean);
|
||||
value(scope: Scope): any;
|
||||
}
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
export { AssignScope, CaptureScope, IncrementScope, DecrementScope } from './scope/scopes';
|
||||
export { ParseError, TokenizationError, RenderBreakError, AssertionError } from './util/error';
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
export default function (predicate: any, message?: string): void;
|
||||
Vendored
-30
@@ -1,30 +0,0 @@
|
||||
declare abstract class LiquidError {
|
||||
name: string;
|
||||
message: string;
|
||||
stack: string;
|
||||
private file;
|
||||
private input;
|
||||
private token;
|
||||
private originalError;
|
||||
constructor(err: any, token: any);
|
||||
captureStackTrace(obj: any): void;
|
||||
}
|
||||
export declare class TokenizationError extends LiquidError {
|
||||
constructor(message: any, token: any);
|
||||
}
|
||||
export declare class ParseError extends LiquidError {
|
||||
constructor(err: any, token: any);
|
||||
}
|
||||
export declare class RenderError extends LiquidError {
|
||||
constructor(err: any, tpl: any);
|
||||
}
|
||||
export declare class RenderBreakError {
|
||||
message: string;
|
||||
resolvedHTML: string;
|
||||
constructor(message: any);
|
||||
}
|
||||
export declare class AssertionError {
|
||||
message: string;
|
||||
constructor(message: any);
|
||||
}
|
||||
export {};
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
export declare function anySeries(iterable: any, iteratee: any): Promise<any>;
|
||||
export declare function mapSeries(iterable: any, iteratee: any): Promise<any[]>;
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
export default function (d: any, format: any): string;
|
||||
Vendored
-15
@@ -1,15 +0,0 @@
|
||||
export declare function isString(value: any): boolean;
|
||||
export declare function isFunction(value: any): boolean;
|
||||
export declare function promisify(fn: any): (...args: any[]) => Promise<{}>;
|
||||
export declare function stringify(value: any): string;
|
||||
export declare function create<T1 extends object, T2 extends T1 = T1>(proto: T1): T2;
|
||||
export declare function isNil(value: any): boolean;
|
||||
export declare function isArray(value: any): boolean;
|
||||
export declare function isError(value: any): boolean;
|
||||
export declare function forOwn(object: any, iteratee: ((val: any, key: string, obj: object) => boolean | void)): any;
|
||||
export declare function assign(obj: object, ...srcs: object[]): object;
|
||||
export declare function last(arr: any[]): any;
|
||||
export declare function uniq(arr: any[]): any[];
|
||||
export declare function isObject(value: any): boolean;
|
||||
export declare function range(start: number, stop?: number, step?: number): any[];
|
||||
export declare function padStart(str: any, length: number, ch?: string): any;
|
||||
@@ -0,0 +1,6 @@
|
||||
declare module 'rollup-plugin-uglify' {
|
||||
export function uglify (): any
|
||||
}
|
||||
declare module 'rollup-plugin-replace' {
|
||||
export default function replace(options: any): any
|
||||
}
|
||||
Generated
+2944
-2574
File diff suppressed because it is too large
Load Diff
+31
-18
@@ -1,19 +1,21 @@
|
||||
{
|
||||
"name": "liquidjs",
|
||||
"version": "7.2.0",
|
||||
"version": "8.4.1",
|
||||
"description": "Liquid template engine by pure JavaScript: compatible to shopify, easy to extend.",
|
||||
"main": "dist/liquid.common.js",
|
||||
"types": "dist/liquid.d.ts",
|
||||
"browser": "dist/liquid.js",
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts --ext .js",
|
||||
"unit": "mocha 'test/unit/**/*.ts'",
|
||||
"e2e": "npm run build && mocha 'test/e2e/**/*.ts'",
|
||||
"test": "npm run unit && npm run e2e",
|
||||
"coverage-html": "nyc npm run unit && nyc report --reporter=html",
|
||||
"coverage-coveralls": "nyc npm run unit && nyc report --reporter=text-lcov | coveralls",
|
||||
"build": "rollup -c && ls -lh dist",
|
||||
"version": "npm run build && git add -A dist"
|
||||
"lint": "eslint . --ext .ts",
|
||||
"unit": "mocha \"test/unit/**/*.ts\"",
|
||||
"integration": "mocha \"test/integration/**/*.ts\"",
|
||||
"e2e": "npm run build && mocha \"test/e2e/**/*.ts\"",
|
||||
"test": "cross-env BUNDLES=cjs,umd npm run build && mocha \"test/**/*.ts\"",
|
||||
"benchmark": "ts-node benchmark",
|
||||
"coverage-html": "nyc --reporter=html mocha \"test/{unit,integration}/**/*.ts\"",
|
||||
"coverage-coveralls": "nyc mocha \"test/{unit,integration}/**/*.ts\" && nyc report --reporter=text-lcov | coveralls",
|
||||
"build": "rollup -c rollup.config.ts && ls -lh dist",
|
||||
"version": "npm run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -44,11 +46,20 @@
|
||||
"@semantic-release/changelog": "^3.0.2",
|
||||
"@semantic-release/commit-analyzer": "^6.1.0",
|
||||
"@semantic-release/git": "^7.0.8",
|
||||
"@semantic-release/npm": "^5.1.4",
|
||||
"@semantic-release/npm": "^5.1.8",
|
||||
"@semantic-release/release-notes-generator": "^7.1.4",
|
||||
"@types/benchmark": "^1.0.31",
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/chai-as-promised": "^7.1.0",
|
||||
"@types/express": "^4.16.1",
|
||||
"@types/jsdom": "^12.2.2",
|
||||
"@types/mocha": "^5.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^1.3.0",
|
||||
"@types/sinon": "^7.0.6",
|
||||
"@types/sinon-chai": "^3.2.2",
|
||||
"@types/supertest": "^2.0.7",
|
||||
"@typescript-eslint/eslint-plugin": "^1.11.0",
|
||||
"@typescript-eslint/parser": "^1.11.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"coveralls": "^3.0.2",
|
||||
@@ -56,7 +67,7 @@
|
||||
"eslint": "^5.12.1",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-plugin-import": "^2.15.0",
|
||||
"eslint-plugin-mocha": "^5.2.1",
|
||||
"eslint-plugin-mocha": "^5.3.0",
|
||||
"eslint-plugin-node": "^8.0.1",
|
||||
"eslint-plugin-promise": "^4.0.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
@@ -66,15 +77,15 @@
|
||||
"nyc": "^13.1.0",
|
||||
"regenerator-runtime": "^0.12.1",
|
||||
"rollup": "^1.1.2",
|
||||
"rollup-plugin-shim": "^1.0.0",
|
||||
"rollup-plugin-typescript2": "^0.19.2",
|
||||
"rollup-plugin-replace": "^2.1.0",
|
||||
"rollup-plugin-typescript2": "^0.21.1",
|
||||
"rollup-plugin-uglify": "^6.0.2",
|
||||
"semantic-release": "^15.13.3",
|
||||
"semantic-release": "^15.13.14",
|
||||
"sinon": "^7.2.3",
|
||||
"sinon-chai": "^3.3.0",
|
||||
"supertest": "^3.4.2",
|
||||
"ts-node": "^8.0.2",
|
||||
"tsconfig-paths": "^3.8.0",
|
||||
"tslib": "^1.9.3",
|
||||
"typescript": "^3.3.3"
|
||||
},
|
||||
"release": {
|
||||
@@ -84,12 +95,14 @@
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/changelog",
|
||||
"@semantic-release/npm",
|
||||
"@semantic-release/git"
|
||||
"@semantic-release/git",
|
||||
"@semantic-release/github"
|
||||
]
|
||||
},
|
||||
"nyc": {
|
||||
"extension": [
|
||||
".ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import shim from 'rollup-plugin-shim'
|
||||
import { uglify } from 'rollup-plugin-uglify'
|
||||
import pkg from './package.json'
|
||||
import typescript from 'rollup-plugin-typescript2'
|
||||
import replace from 'rollup-plugin-replace'
|
||||
|
||||
const fake = { fs: `export default {}`, path: `export default {}` }
|
||||
const version = process.env.VERSION || pkg.version
|
||||
const sourcemap = true
|
||||
const banner = `/*
|
||||
@@ -14,9 +13,9 @@ const banner = `/*
|
||||
const treeshake = {
|
||||
propertyReadSideEffects: false
|
||||
}
|
||||
const input = 'src/liquid.ts'
|
||||
const input = './src/liquid.ts'
|
||||
|
||||
export default [{
|
||||
const cjs = {
|
||||
output: [{
|
||||
file: 'dist/liquid.common.js',
|
||||
name: 'Liquid',
|
||||
@@ -27,15 +26,19 @@ export default [{
|
||||
external: ['path', 'fs'],
|
||||
plugins: [typescript({
|
||||
tsconfigOverride: {
|
||||
exclude: [ 'test' ],
|
||||
include: [ 'src' ],
|
||||
exclude: [ 'test', 'benchmark' ],
|
||||
compilerOptions: {
|
||||
target: 'es5',
|
||||
module: 'ES2015'
|
||||
}
|
||||
}
|
||||
})],
|
||||
treeshake,
|
||||
input
|
||||
}, {
|
||||
}
|
||||
|
||||
const umd = {
|
||||
output: [{
|
||||
file: 'dist/liquid.js',
|
||||
name: 'Liquid',
|
||||
@@ -44,20 +47,27 @@ export default [{
|
||||
banner
|
||||
}],
|
||||
plugins: [
|
||||
shim(fake),
|
||||
replace({
|
||||
include: './src/liquid.ts',
|
||||
delimiters: ['', ''],
|
||||
'./fs/node': './fs/browser'
|
||||
}),
|
||||
typescript({
|
||||
tsconfigOverride: {
|
||||
exclude: [ 'test' ],
|
||||
include: [ 'src' ],
|
||||
exclude: [ 'test', 'benchmark' ],
|
||||
compilerOptions: {
|
||||
module: 'ES2015',
|
||||
paths: { 'src/fs': ['src/fs/browser'] }
|
||||
target: 'es5',
|
||||
module: 'ES2015'
|
||||
}
|
||||
}
|
||||
})
|
||||
],
|
||||
treeshake,
|
||||
input
|
||||
}, {
|
||||
}
|
||||
|
||||
const min = {
|
||||
output: [{
|
||||
file: 'dist/liquid.min.js',
|
||||
name: 'Liquid',
|
||||
@@ -65,13 +75,18 @@ export default [{
|
||||
sourcemap
|
||||
}],
|
||||
plugins: [
|
||||
shim(fake),
|
||||
replace({
|
||||
include: './src/liquid.ts',
|
||||
delimiters: ['', ''],
|
||||
'./fs/node': './fs/browser'
|
||||
}),
|
||||
typescript({
|
||||
tsconfigOverride: {
|
||||
exclude: [ 'test' ],
|
||||
include: [ 'src' ],
|
||||
exclude: [ 'test', 'benchmark' ],
|
||||
compilerOptions: {
|
||||
module: 'ES2015',
|
||||
paths: { 'src/fs': ['src/fs/browser'] }
|
||||
target: 'es5',
|
||||
module: 'ES2015'
|
||||
}
|
||||
}
|
||||
}),
|
||||
@@ -79,4 +94,13 @@ export default [{
|
||||
],
|
||||
treeshake,
|
||||
input
|
||||
}]
|
||||
}
|
||||
|
||||
const bundles = []
|
||||
const env = process.env.BUNDLES || ''
|
||||
if (env.includes('cjs')) bundles.push(cjs)
|
||||
if (env.includes('umd')) bundles.push(umd)
|
||||
if (env.includes('min')) bundles.push(min)
|
||||
if (bundles.length === 0) bundles.push(cjs, umd, min)
|
||||
|
||||
export default bundles
|
||||
@@ -1,25 +1,42 @@
|
||||
import { last } from 'src/util/underscore'
|
||||
import { isArray, last } from '../../util/underscore'
|
||||
import { isTruthy } from '../../render/syntax'
|
||||
|
||||
export default {
|
||||
'join': (v, arg) => v.join(arg === undefined ? ' ' : arg),
|
||||
'last': v => last(v),
|
||||
'first': v => v[0],
|
||||
'map': (arr, arg) => arr.map(v => v[arg]),
|
||||
'reverse': v => v.reverse(),
|
||||
'sort': (v, arg) => v.sort(arg),
|
||||
'size': v => v.length,
|
||||
'slice': (v, begin, length) => {
|
||||
if (length === undefined) length = 1
|
||||
return v.slice(begin, begin + length)
|
||||
},
|
||||
'uniq': function (arr) {
|
||||
const u = {}
|
||||
return (arr || []).filter(val => {
|
||||
if (u.hasOwnProperty(val)) {
|
||||
return false
|
||||
}
|
||||
u[val] = true
|
||||
return true
|
||||
})
|
||||
}
|
||||
'join': (v: any[], arg: string) => v.join(arg === undefined ? ' ' : arg),
|
||||
'last': (v: any) => isArray(v) ? last(v) : '',
|
||||
'first': (v: any) => isArray(v) ? v[0] : '',
|
||||
'map': map,
|
||||
'reverse': (v: any[]) => [...v].reverse(),
|
||||
'sort': <T>(v: T[], arg: (lhs: T, rhs: T) => number) => v.sort(arg),
|
||||
'size': (v: string | any[]) => (v && v.length) || 0,
|
||||
'concat': concat,
|
||||
'slice': slice,
|
||||
'uniq': uniq,
|
||||
'where': where
|
||||
}
|
||||
|
||||
function map<T1, T2> (arr: {[key: string]: T1}[], arg: string): T1[] {
|
||||
return arr.map(v => v[arg])
|
||||
}
|
||||
|
||||
function concat<T1, T2> (v: T1[], arg: T2[] | T2): (T1 | T2)[] {
|
||||
return Array.prototype.concat.call(v, arg)
|
||||
}
|
||||
|
||||
function slice<T> (v: T[], begin: number, length: number = 1): T[] {
|
||||
begin = begin < 0 ? v.length + begin : begin
|
||||
return v.slice(begin, begin + length)
|
||||
}
|
||||
|
||||
function where<T> (arr: T[], property: string, value?: any): T[] {
|
||||
return arr.filter(obj => value === undefined ? isTruthy(obj[property]) : obj[property] === value)
|
||||
}
|
||||
|
||||
function uniq<T> (arr: T[]): T[] {
|
||||
const u = {}
|
||||
return (arr || []).filter(val => {
|
||||
if (u.hasOwnProperty(String(val))) return false
|
||||
u[String(val)] = true
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import strftime from 'src/util/strftime'
|
||||
import { isString } from 'src/util/underscore'
|
||||
import strftime from '../../util/strftime'
|
||||
import { isString, isNumber } from '../../util/underscore'
|
||||
|
||||
export default {
|
||||
'date': (v, arg) => {
|
||||
'date': (v: string | Date, arg: string) => {
|
||||
let date = v
|
||||
if (v === 'now') {
|
||||
date = new Date()
|
||||
} else if (isNumber(v)) {
|
||||
date = new Date(v * 1000)
|
||||
} else if (isString(v)) {
|
||||
date = new Date(v)
|
||||
date = /^\d+$/.test(v) ? new Date(+v * 1000) : new Date(v)
|
||||
}
|
||||
return isValidDate(date) ? strftime(date, arg) : v
|
||||
}
|
||||
}
|
||||
|
||||
function isValidDate (date) {
|
||||
function isValidDate (date: any): date is Date {
|
||||
return date instanceof Date && !isNaN(date.getTime())
|
||||
}
|
||||
|
||||
@@ -13,17 +13,17 @@ const unescapeMap = {
|
||||
''': "'"
|
||||
}
|
||||
|
||||
function escape (str) {
|
||||
function escape (str: string) {
|
||||
return String(str).replace(/&|<|>|"|'/g, m => escapeMap[m])
|
||||
}
|
||||
|
||||
function unescape (str) {
|
||||
function unescape (str: string) {
|
||||
return String(str).replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m])
|
||||
}
|
||||
|
||||
export default {
|
||||
'escape': escape,
|
||||
'escape_once': str => escape(unescape(str)),
|
||||
'newline_to_br': v => v.replace(/\n/g, '<br />'),
|
||||
'strip_html': v => String(v).replace(/<script.*?<\/script>|<!--.*?-->|<style.*?<\/style>|<.*?>/g, '')
|
||||
'escape_once': (str: string) => escape(unescape(str)),
|
||||
'newline_to_br': (v: string) => v.replace(/\n/g, '<br />'),
|
||||
'strip_html': (v: string) => v.replace(/<script.*?<\/script>|<!--.*?-->|<style.*?<\/style>|<.*?>/g, '')
|
||||
}
|
||||
|
||||
+30
-17
@@ -1,26 +1,39 @@
|
||||
const toLowerCase = String.prototype.toLowerCase
|
||||
|
||||
export default {
|
||||
'abs': v => Math.abs(v),
|
||||
'ceil': v => Math.ceil(v),
|
||||
'divided_by': (v, arg) => v / arg,
|
||||
'floor': v => Math.floor(v),
|
||||
'minus': bindFixed((v, arg) => v - arg),
|
||||
'modulo': bindFixed((v, arg) => v % arg),
|
||||
'round': (v, arg) => {
|
||||
const amp = Math.pow(10, arg || 0)
|
||||
'abs': (v: number) => Math.abs(v),
|
||||
'at_least': (v: number, n: number) => Math.max(v, n),
|
||||
'at_most': (v: number, n: number) => Math.min(v, n),
|
||||
'ceil': (v: number) => Math.ceil(v),
|
||||
'divided_by': (v: number, arg: number) => v / arg,
|
||||
'floor': (v: number) => Math.floor(v),
|
||||
'minus': (v: number, arg: number) => v - arg,
|
||||
'modulo': (v: number, arg: number) => v % arg,
|
||||
'round': (v: number, arg: number = 0) => {
|
||||
const amp = Math.pow(10, arg)
|
||||
return Math.round(v * amp) / amp
|
||||
},
|
||||
'plus': bindFixed((v, arg) => Number(v) + Number(arg)),
|
||||
'times': (v, arg) => v * arg
|
||||
'plus': (v: number, arg: number) => Number(v) + Number(arg),
|
||||
'sort_natural': sortNatural,
|
||||
'times': (v: number, arg: number) => v * arg
|
||||
}
|
||||
|
||||
function getFixed (v) {
|
||||
const p = String(v).split('.')
|
||||
return (p.length > 1) ? p[1].length : 0
|
||||
function caseInsensitiveCmp (a: any, b: any) {
|
||||
if (!b) return -1
|
||||
if (!a) return 1
|
||||
a = toLowerCase.call(a)
|
||||
b = toLowerCase.call(b)
|
||||
if (a < b) return -1
|
||||
if (a > b) return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
function bindFixed (cb) {
|
||||
return (l, r) => {
|
||||
const f = Math.max(getFixed(l), getFixed(r))
|
||||
return cb(l, r).toFixed(f)
|
||||
function sortNatural (input: any[], property?: string) {
|
||||
if (!input || !input.sort) return []
|
||||
if (property !== undefined) {
|
||||
return [...input].sort(
|
||||
(lhs, rhs) => caseInsensitiveCmp(lhs[property], rhs[property])
|
||||
)
|
||||
}
|
||||
return [...input].sort(caseInsensitiveCmp)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { isTruthy } from 'src/render/syntax'
|
||||
import { isFalsy } from '../../render/syntax'
|
||||
import { toValue } from '../../util/underscore'
|
||||
|
||||
export default {
|
||||
'default': (v, arg) => isTruthy(v) ? v : arg
|
||||
'default': function<T1, T2> (v: string | T1, arg: T2): string | T1 | T2 {
|
||||
return isFalsy(toValue(v)) || v === '' ? arg : v
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,51 @@
|
||||
/**
|
||||
* String related filters
|
||||
*
|
||||
* * prefer stringify() to String() since `undefined`, `null` should eval ''
|
||||
*/
|
||||
import { stringify } from '../../util/underscore'
|
||||
|
||||
export default {
|
||||
'append': (v, arg) => v + arg,
|
||||
'prepend': (v, arg) => arg + v,
|
||||
'capitalize': str => String(str).charAt(0).toUpperCase() + str.slice(1),
|
||||
'concat': (v, arg) => Array.prototype.concat.call(v, arg),
|
||||
'lstrip': v => String(v).replace(/^\s+/, ''),
|
||||
'downcase': v => v.toLowerCase(),
|
||||
'upcase': str => String(str).toUpperCase(),
|
||||
'remove': (v, arg) => v.split(arg).join(''),
|
||||
'remove_first': (v, l) => v.replace(l, ''),
|
||||
'replace': (v, pattern, replacement) =>
|
||||
String(v).split(pattern).join(replacement),
|
||||
'replace_first': (v, arg1, arg2) => String(v).replace(arg1, arg2),
|
||||
'rstrip': str => String(str).replace(/\s+$/, ''),
|
||||
'split': (v, arg) => String(v).split(arg),
|
||||
'strip': (v) => String(v).trim(),
|
||||
'strip_newlines': v => String(v).replace(/\n/g, ''),
|
||||
'truncate': (v, l, o) => {
|
||||
v = String(v)
|
||||
o = (o === undefined) ? '...' : o
|
||||
l = l || 16
|
||||
if (v.length <= l) return v
|
||||
return v.substr(0, l - o.length) + o
|
||||
},
|
||||
'truncatewords': (v, l, o) => {
|
||||
if (o === undefined) o = '...'
|
||||
const arr = v.split(' ')
|
||||
let ret = arr.slice(0, l).join(' ')
|
||||
if (arr.length > l) ret += o
|
||||
return ret
|
||||
}
|
||||
'append': (v: string, arg: string) => stringify(v) + arg,
|
||||
'prepend': (v: string, arg: string) => arg + stringify(v),
|
||||
'capitalize': capitalize,
|
||||
'lstrip': (v: string) => stringify(v).replace(/^\s+/, ''),
|
||||
'downcase': (v: string) => stringify(v).toLowerCase(),
|
||||
'upcase': (str: string) => stringify(str).toUpperCase(),
|
||||
'remove': (v: string, arg: string) => stringify(v).split(arg).join(''),
|
||||
'remove_first': (v: string, l: string) => stringify(v).replace(l, ''),
|
||||
'replace': replace,
|
||||
'replace_first': replaceFirst,
|
||||
'rstrip': (str: string) => stringify(str).replace(/\s+$/, ''),
|
||||
'split': (v: string, arg: string) => stringify(v).split(arg),
|
||||
'strip': (v: string) => stringify(v).trim(),
|
||||
'strip_newlines': (v: string) => stringify(v).replace(/\n/g, ''),
|
||||
'truncate': truncate,
|
||||
'truncatewords': truncateWords
|
||||
}
|
||||
|
||||
function capitalize (str: string) {
|
||||
str = stringify(str)
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
function replace (v: string, pattern: string, replacement: string) {
|
||||
return stringify(v).split(pattern).join(replacement)
|
||||
}
|
||||
|
||||
function replaceFirst (v: string, arg1: string, arg2: string) {
|
||||
return stringify(v).replace(arg1, arg2)
|
||||
}
|
||||
|
||||
function truncate (v: string, l: number = 50, o: string = '...') {
|
||||
v = stringify(v)
|
||||
if (v.length <= l) return v
|
||||
return v.substr(0, l - o.length) + o
|
||||
}
|
||||
|
||||
function truncateWords (v: string, l: number = 15, o: string = '...') {
|
||||
const arr = v.split(/\s+/)
|
||||
let ret = arr.slice(0, l).join(' ')
|
||||
if (arr.length >= l) ret += o
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export default {
|
||||
'url_decode': x => x.split('+').map(decodeURIComponent).join(' '),
|
||||
'url_encode': x => x.split(' ').map(encodeURIComponent).join('+')
|
||||
'url_decode': (x: string) => x.split('+').map(decodeURIComponent).join(' '),
|
||||
'url_encode': (x: string) => x.split(' ').map(encodeURIComponent).join('+')
|
||||
}
|
||||
|
||||
+10
-11
@@ -1,20 +1,19 @@
|
||||
import assert from 'src/util/assert'
|
||||
import { identifier } from 'src/parser/lexical'
|
||||
import { AssignScope } from 'src/scope/scopes'
|
||||
import assert from '../../util/assert'
|
||||
import { identifier } from '../../parser/lexical'
|
||||
import TagToken from '../../parser/tag-token'
|
||||
import Context from '../../context/context'
|
||||
import ITagImplOptions from '../../template/tag/itag-impl-options'
|
||||
|
||||
const re = new RegExp(`(${identifier.source})\\s*=([^]*)`)
|
||||
|
||||
export default {
|
||||
parse: function (token) {
|
||||
const match = token.args.match(re)
|
||||
parse: function (token: TagToken) {
|
||||
const match = token.args.match(re) as RegExpMatchArray
|
||||
assert(match, `illegal token ${token.raw}`)
|
||||
this.key = match[1]
|
||||
this.value = match[2]
|
||||
},
|
||||
render: function (scope) {
|
||||
const ctx = new AssignScope()
|
||||
ctx[this.key] = this.liquid.evalValue(this.value, scope)
|
||||
scope.push(ctx)
|
||||
return Promise.resolve('')
|
||||
render: async function (ctx: Context) {
|
||||
ctx.front()[this.key] = await this.liquid.evalValue(this.value, ctx)
|
||||
}
|
||||
}
|
||||
} as ITagImplOptions
|
||||
|
||||
+18
-12
@@ -1,29 +1,35 @@
|
||||
import BlockMode from 'src/scope/block-mode'
|
||||
import BlockMode from '../../context/block-mode'
|
||||
import TagToken from '../../parser/tag-token'
|
||||
import Token from '../../parser/token'
|
||||
import ITemplate from '../../template/itemplate'
|
||||
import Context from '../../context/context'
|
||||
import ITagImplOptions from '../../template/tag/itag-impl-options'
|
||||
import ParseStream from '../../parser/parse-stream'
|
||||
|
||||
export default {
|
||||
parse: function (token, remainTokens) {
|
||||
parse: function (token: TagToken, remainTokens: Token[]) {
|
||||
const match = /\w+/.exec(token.args)
|
||||
this.block = match ? match[0] : ''
|
||||
|
||||
this.tpls = []
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
this.tpls = [] as ITemplate[]
|
||||
const stream: ParseStream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('tag:endblock', () => stream.stop())
|
||||
.on('template', tpl => this.tpls.push(tpl))
|
||||
.on('template', (tpl: ITemplate) => this.tpls.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${token.raw} not closed`)
|
||||
})
|
||||
stream.start()
|
||||
},
|
||||
render: async function (scope) {
|
||||
const childDefined = scope.blocks[this.block]
|
||||
render: async function (ctx: Context) {
|
||||
const blocks = ctx.getRegister('blocks')
|
||||
const childDefined = blocks[this.block]
|
||||
const html = childDefined !== undefined
|
||||
? childDefined
|
||||
: await this.liquid.renderer.renderTemplates(this.tpls, scope)
|
||||
: await this.liquid.renderer.renderTemplates(this.tpls, ctx)
|
||||
|
||||
if (scope.blockMode === BlockMode.STORE) {
|
||||
scope.blocks[this.block] = html
|
||||
if (ctx.getRegister('blockMode', BlockMode.OUTPUT) === BlockMode.STORE) {
|
||||
blocks[this.block] = html
|
||||
return ''
|
||||
}
|
||||
return html
|
||||
}
|
||||
}
|
||||
} as ITagImplOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RenderBreakError } from 'src/util/error'
|
||||
import { RenderBreakError } from '../../util/error'
|
||||
|
||||
export default {
|
||||
render: async function () {
|
||||
|
||||
+12
-14
@@ -1,15 +1,15 @@
|
||||
import assert from 'src/util/assert'
|
||||
import { identifier } from 'src/parser/lexical'
|
||||
import { CaptureScope } from 'src/scope/scopes'
|
||||
import TagToken from 'src/parser/tag-token'
|
||||
import Token from 'src/parser/token'
|
||||
import Scope from 'src/scope/scope'
|
||||
import assert from '../../util/assert'
|
||||
import { identifier } from '../../parser/lexical'
|
||||
import TagToken from '../../parser/tag-token'
|
||||
import Token from '../../parser/token'
|
||||
import Context from '../../context/context'
|
||||
import ITagImplOptions from '../../template/tag/itag-impl-options'
|
||||
|
||||
const re = new RegExp(`(${identifier.source})`)
|
||||
|
||||
export default {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
const match = tagToken.args.match(re)
|
||||
const match = tagToken.args.match(re) as RegExpMatchArray
|
||||
assert(match, `${tagToken.args} not valid identifier`)
|
||||
|
||||
this.variable = match[1]
|
||||
@@ -17,16 +17,14 @@ export default {
|
||||
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
stream.on('tag:endcapture', () => stream.stop())
|
||||
.on('template', tpl => this.templates.push(tpl))
|
||||
.on('template', (tpl) => this.templates.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
stream.start()
|
||||
},
|
||||
render: async function (scope: Scope) {
|
||||
const html = await this.liquid.renderer.renderTemplates(this.templates, scope)
|
||||
const ctx = new CaptureScope()
|
||||
ctx[this.variable] = html
|
||||
scope.push(ctx)
|
||||
render: async function (ctx: Context) {
|
||||
const html = await this.liquid.renderer.renderTemplates(this.templates, ctx)
|
||||
ctx.front()[this.variable] = html
|
||||
}
|
||||
}
|
||||
} as ITagImplOptions
|
||||
|
||||
+18
-12
@@ -1,14 +1,20 @@
|
||||
import { evalExp } from 'src/render/syntax'
|
||||
import { evalExp } from '../../render/syntax'
|
||||
import TagToken from '../../parser/tag-token'
|
||||
import Token from '../../parser/token'
|
||||
import Context from '../../context/context'
|
||||
import ITemplate from '../../template/itemplate'
|
||||
import ITagImplOptions from '../../template/tag/itag-impl-options'
|
||||
import ParseStream from '../../parser/parse-stream'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken, remainTokens) {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
this.cond = tagToken.args
|
||||
this.cases = []
|
||||
this.elseTemplates = []
|
||||
|
||||
let p = []
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('tag:when', token => {
|
||||
let p: ITemplate[] = []
|
||||
const stream: ParseStream = this.liquid.parser.parseStream(remainTokens)
|
||||
.on('tag:when', (token: TagToken) => {
|
||||
this.cases.push({
|
||||
val: token.args,
|
||||
templates: p = []
|
||||
@@ -16,7 +22,7 @@ export default {
|
||||
})
|
||||
.on('tag:else', () => (p = this.elseTemplates))
|
||||
.on('tag:endcase', () => stream.stop())
|
||||
.on('template', tpl => p.push(tpl))
|
||||
.on('template', (tpl: ITemplate) => p.push(tpl))
|
||||
.on('end', () => {
|
||||
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||
})
|
||||
@@ -24,15 +30,15 @@ export default {
|
||||
stream.start()
|
||||
},
|
||||
|
||||
render: function (scope) {
|
||||
render: async function (ctx: Context) {
|
||||
for (let i = 0; i < this.cases.length; i++) {
|
||||
const branch = this.cases[i]
|
||||
const val = evalExp(branch.val, scope)
|
||||
const cond = evalExp(this.cond, scope)
|
||||
const val = await evalExp(branch.val, ctx)
|
||||
const cond = await evalExp(this.cond, ctx)
|
||||
if (val === cond) {
|
||||
return this.liquid.renderer.renderTemplates(branch.templates, scope)
|
||||
return this.liquid.renderer.renderTemplates(branch.templates, ctx)
|
||||
}
|
||||
}
|
||||
return this.liquid.renderer.renderTemplates(this.elseTemplates, scope)
|
||||
return this.liquid.renderer.renderTemplates(this.elseTemplates, ctx)
|
||||
}
|
||||
}
|
||||
} as ITagImplOptions
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import TagToken from '../../parser/tag-token'
|
||||
import Token from '../../parser/token'
|
||||
import ITagImplOptions from '../../template/tag/itag-impl-options'
|
||||
|
||||
export default {
|
||||
parse: function (tagToken, remainTokens) {
|
||||
parse: function (tagToken: TagToken, remainTokens: Token[]) {
|
||||
const stream = this.liquid.parser.parseStream(remainTokens)
|
||||
stream
|
||||
.on('token', token => {
|
||||
.on('token', (token: TagToken) => {
|
||||
if (token.name === 'endcomment') stream.stop()
|
||||
})
|
||||
.on('end', () => {
|
||||
@@ -10,4 +14,4 @@ export default {
|
||||
})
|
||||
stream.start()
|
||||
}
|
||||
}
|
||||
} as ITagImplOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RenderBreakError } from 'src/util/error'
|
||||
import { RenderBreakError } from '../../util/error'
|
||||
|
||||
export default {
|
||||
render: async function () {
|
||||
|
||||
+13
-11
@@ -1,13 +1,16 @@
|
||||
import assert from 'src/util/assert'
|
||||
import { value as rValue } from 'src/parser/lexical'
|
||||
import { evalValue } from 'src/render/syntax'
|
||||
import assert from '../../util/assert'
|
||||
import { value as rValue } from '../../parser/lexical'
|
||||
import { evalValue } from '../../render/syntax'
|
||||
import TagToken from '../../parser/tag-token'
|
||||
import Context from '../../context/context'
|
||||
import ITagImplOptions from '../../template/tag/itag-impl-options'
|
||||
|
||||
const groupRE = new RegExp(`^(?:(${rValue.source})\\s*:\\s*)?(.*)$`)
|
||||
const candidatesRE = new RegExp(rValue.source, 'g')
|
||||
|
||||
export default {
|
||||
parse: function (tagToken) {
|
||||
let match = groupRE.exec(tagToken.args)
|
||||
parse: function (tagToken: TagToken) {
|
||||
let match: RegExpExecArray | null = groupRE.exec(tagToken.args) as RegExpExecArray
|
||||
assert(match, `illegal tag: ${tagToken.raw}`)
|
||||
|
||||
this.group = match[1] || ''
|
||||
@@ -21,11 +24,10 @@ export default {
|
||||
assert(this.candidates.length, `empty candidates: ${tagToken.raw}`)
|
||||
},
|
||||
|
||||
render: function (scope) {
|
||||
const group = evalValue(this.group, scope)
|
||||
render: async function (ctx: Context) {
|
||||
const group = await evalValue(this.group, ctx)
|
||||
const fingerprint = `cycle:${group}:` + this.candidates.join(',')
|
||||
|
||||
const groups = scope.opts.groups = scope.opts.groups || {}
|
||||
const groups = ctx.getRegister('cycle')
|
||||
let idx = groups[fingerprint]
|
||||
|
||||
if (idx === undefined) {
|
||||
@@ -36,6 +38,6 @@ export default {
|
||||
idx = (idx + 1) % this.candidates.length
|
||||
groups[fingerprint] = idx
|
||||
|
||||
return evalValue(candidate, scope)
|
||||
return evalValue(candidate, ctx)
|
||||
}
|
||||
}
|
||||
} as ITagImplOptions
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user