Skip to content

Commit 8823c13

Browse files
committed
add customized jexl
1 parent a32d1ad commit 8823c13

File tree

3 files changed

+46
-20
lines changed

3 files changed

+46
-20
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,22 @@ HTML:
144144
<div>Xylo.js is a static site generator using <strong>pure HTML template</strong> like Vue.js and Thymeleaf.</div>
145145
```
146146

147+
## Advanced usage
148+
149+
### Use a customized Jexl
150+
151+
You can use a customized [Jexl](https://github.com/TomFrost/Jexl).
152+
153+
```js
154+
const { generate } = require('xylo');
155+
const template = '<html><head></head><body><ul><li x-for="item in items|split(' ')" x-text="item"></li></ul></body></html>';
156+
const data = {items: 'A B C'};
157+
const jexl = new jexl.Jexl();
158+
jexl.addTransform('split', (val, sep) => val.split(sep));
159+
const html = generate(template, data, jaxl);
160+
console.log(html); // `<html><head></head><body><ul><li>A</li><li>B</li><li>C</li></ul></body></html>`
161+
```
162+
147163
## Dependencies
148164

149165
* [parse5](https://github.com/inikulin/parse5) - HTML parsing/serialization toolset for Node.js. WHATWG HTML Living Standard (aka HTML5)-compliant.

src/index.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,36 @@ import {
55

66
import * as helper from './tree-helper';
77

8-
const jexl = new Jexl();
98
const PARSE_OPTS = {sourceCodeLocationInfo: true};
109

11-
export function generate(htmlTemplate: string, context: any): string {
10+
export function generate(htmlTemplate: string, context: any, jexl: any = new Jexl()): string {
1211
const startNode = parse(htmlTemplate, PARSE_OPTS);
13-
processChildNodes(startNode, context);
12+
processChildNodes(startNode, context, jexl);
1413
return serialize(startNode);
1514
}
1615

17-
function processChildNodes(parentNode: Node, context: any) {
16+
function processChildNodes(parentNode: Node, context: any, jexl: any) {
1817
const cloneChildNodes = [...helper.getChildNodes(parentNode)];
1918

2019
if (cloneChildNodes) {
2120
for (let i = 0, cnLength = cloneChildNodes.length; i < cnLength; i++) {
2221
const currentNode = cloneChildNodes[i];
2322

2423
if (helper.isElementNode(currentNode)) {
25-
processElement(currentNode as DefaultTreeElement, context);
24+
processElement(currentNode as DefaultTreeElement, context, jexl);
2625
}
2726
}
2827
}
2928
}
3029

31-
function processElement(node: DefaultTreeElement, context: any) {
30+
function processElement(node: DefaultTreeElement, context: any, jexl: any) {
3231
const clonedAttrs = [...helper.getAttrList(node)];
3332

3433
for (const attr of clonedAttrs) {
3534
try {
3635
const directive = directives.find((d) => d.match(attr));
3736
if (directive) {
38-
const result = directive.process(node, attr, context);
37+
const result = directive.process(node, attr, context, jexl);
3938
if (result.continue === false) {
4039
return;
4140
}
@@ -44,7 +43,7 @@ function processElement(node: DefaultTreeElement, context: any) {
4443
handleDirectiveError(e, node, attr);
4544
}
4645
}
47-
processChildNodes(node, context);
46+
processChildNodes(node, context, jexl);
4847
}
4948

5049
function handleDirectiveError(e: Error, node: DefaultTreeElement, attr?: Attribute) {
@@ -61,7 +60,7 @@ function handleDirectiveError(e: Error, node: DefaultTreeElement, attr?: Attribu
6160

6261
export interface Directive {
6362
match: (attr: Attribute) => boolean;
64-
process: (node: DefaultTreeElement, attr: Attribute, context: any) => DirectiveResult;
63+
process: (node: DefaultTreeElement, attr: Attribute, context: any, jexl: any) => DirectiveResult;
6564
}
6665

6766
export interface DirectiveResult {
@@ -72,7 +71,7 @@ const htmlDirective: Directive = {
7271
match(attr: Attribute): boolean {
7372
return attr.name === 'x-html';
7473
},
75-
process(node: DefaultTreeElement, attr: Attribute, context: any): DirectiveResult {
74+
process(node: DefaultTreeElement, attr: Attribute, context: any, jexl: any): DirectiveResult {
7675
const html = jexl.evalSync(attr.value, context);
7776
const fragments = helper.getChildNodes(parseFragment(html, PARSE_OPTS));
7877
helper.replaceChildNodes(node, fragments);
@@ -85,7 +84,7 @@ const textDirective: Directive = {
8584
match(attr: Attribute): boolean {
8685
return attr.name === 'x-text';
8786
},
88-
process(node: DefaultTreeElement, attr: Attribute, context: any): DirectiveResult {
87+
process(node: DefaultTreeElement, attr: Attribute, context: any, jexl: any): DirectiveResult {
8988
const rawText = jexl.evalSync(attr.value, context);
9089
const safeText = rawText ? helper.escapeString(rawText, false) : '';
9190
const fragments = helper.getChildNodes(parseFragment(safeText, PARSE_OPTS));
@@ -99,7 +98,7 @@ const attrDirective: Directive = {
9998
match(attr: Attribute): boolean {
10099
return attr.name.startsWith('x-attr:');
101100
},
102-
process(node: DefaultTreeElement, attr: Attribute, context: any): DirectiveResult {
101+
process(node: DefaultTreeElement, attr: Attribute, context: any, jexl: any): DirectiveResult {
103102
const attrs = helper.getAttrList(node);
104103
const [, attrName] = attr.name.split(':').map((v) => v.trim());
105104

@@ -114,7 +113,7 @@ const ifDirective: Directive = {
114113
match(attr: Attribute): boolean {
115114
return attr.name === 'x-if';
116115
},
117-
process(node: DefaultTreeElement, attr: Attribute, context: any): DirectiveResult {
116+
process(node: DefaultTreeElement, attr: Attribute, context: any, jexl: any): DirectiveResult {
118117
const condtion = jexl.evalSync(attr.value, context);
119118
if (!condtion) {
120119
helper.detachNode(node);
@@ -129,7 +128,7 @@ const forDirective: Directive = {
129128
match(attr: Attribute): boolean {
130129
return attr.name === 'x-for';
131130
},
132-
process(node: DefaultTreeElement, attr: Attribute, context: any): DirectiveResult {
131+
process(node: DefaultTreeElement, attr: Attribute, context: any, jexl: any): DirectiveResult {
133132
const parentNode = helper.getParentNode(node) as DefaultTreeElement;
134133
const currentIndex = parentNode.childNodes.indexOf(node);
135134
const prevNode = helper.getPrevNode(node);
@@ -150,7 +149,7 @@ const forDirective: Directive = {
150149
const newItemNode = helper.getFirstChild(fragments) as DefaultTreeElement;
151150
newItemNode.attrs = helper.getAttrList(newItemNode).filter((a) => a.name !== 'x-for');
152151

153-
processElement(newItemNode as DefaultTreeElement, newContext);
152+
processElement(newItemNode as DefaultTreeElement, newContext, jexl);
154153

155154
return newItemNode;
156155
});

test/index.test.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { readFileSync } from 'fs';
2-
import {
3-
DefaultTreeElement, parseFragment, serialize,
4-
} from 'parse5';
2+
import { Jexl } from 'jexl';
3+
import { DefaultTreeElement, parseFragment, serialize } from 'parse5';
54
import { join } from 'path';
6-
75
import { Directive, DirectiveResult, generate, testDirectives } from '../src/index';
86
import * as helper from '../src/tree-helper';
97

@@ -47,8 +45,21 @@ describe('generate', (): void => {
4745
expect(e.toString()).toBe(expected);
4846
}
4947
});
48+
test('override jexl', (): void => {
49+
const tmpl = `<html><head></head><body><ul><li x-for="item in items|split(' ')" x-text="item"></li></ul></body></html>`;
50+
const expected = `<html><head></head><body><ul><li>A</li><li>B</li><li>C</li></ul></body></html>`;
51+
const jexl = new Jexl();
52+
jexl.addTransform('split', (val, sep) => val.split(sep));
53+
const context = {
54+
items: 'A B C'
55+
};
56+
const html = generate(tmpl, context, jexl);
57+
58+
expect(html).toBe(expected);
59+
});
5060
});
5161

62+
5263
describe('directives', (): void => {
5364
const testDirective = (
5465
directive: Directive,
@@ -65,7 +76,7 @@ describe('directives', (): void => {
6576
if (attr) {
6677
expect(directive.match(attr)).toBe(true);
6778

68-
const result = directive.process(topNode, attr, context);
79+
const result = directive.process(topNode, attr, context, new Jexl());
6980
expect(result.continue).toBe(expectedResult.continue);
7081

7182
const rootElement = helper.createElement('template', topNode.namespaceURI);

0 commit comments

Comments
 (0)