-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: String literals templating engine
- Loading branch information
1 parent
40361d6
commit 9a5aa6e
Showing
10 changed files
with
282 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
name: Build and release pipeline | ||
on: | ||
push: | ||
branches: | ||
- main | ||
- next | ||
pull_request: | ||
branches: | ||
- main | ||
- next | ||
permissions: | ||
contents: write | ||
issues: write | ||
pull-requests: write | ||
id-token: write | ||
jobs: | ||
build: | ||
name: Build and Verify | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: | ||
- latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
- name: Setup Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
cache: 'npm' | ||
- name: Install dependencies | ||
run: npm ci | ||
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies | ||
run: npm audit signatures | ||
test: | ||
name: Fast Tests | ||
runs-on: ubuntu-latest | ||
needs: build | ||
strategy: | ||
matrix: | ||
node-version: | ||
- latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
- name: Use Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
cache: 'npm' | ||
- run: npm ci | ||
- run: npm test | ||
release: | ||
name: Release | ||
if: github.ref == 'refs/heads/main' && success() | ||
needs: [build, test] | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: | ||
- latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
- name: Semantic Release | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
run: npx semantic-release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import vm from 'node:vm' | ||
class Template { | ||
constructor (template, data, partials = new Map(), functions = {}) { | ||
this.template = template | ||
this.data = data | ||
this.partials = partials | ||
this.functions = functions | ||
} | ||
renderWithLayout (layout, body) { | ||
if (!layout || layout.length === 0) { | ||
return body | ||
} | ||
const sandbox = { | ||
...this.data, | ||
...this.functions, | ||
body, | ||
} | ||
const script = new vm.Script(`result = \`${layout}\``) | ||
const context = new vm.createContext(sandbox) | ||
script.runInContext(context) | ||
return context.result | ||
} | ||
async render() { | ||
let layout = null | ||
const hasLayout = layoutPath => { | ||
layout = layoutPath | ||
return '' | ||
} | ||
const script = new vm.Script(`result = \`${this.template}\``) | ||
const context = new vm.createContext({ | ||
...this.data, | ||
...this.functions, | ||
hasLayout | ||
}) | ||
script.runInContext(context) | ||
if (layout) { | ||
context.result = context.result.replace(/^\n/, '') | ||
return this.renderWithLayout(this.partials.get(layout), context.result) | ||
} | ||
return context.result | ||
} | ||
} | ||
export { | ||
Template | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { describe, it } from 'node:test' | ||
import assert from 'node:assert/strict' | ||
import { readFile } from 'node:fs/promises' | ||
import { Template } from './index.mjs' | ||
describe('Templating Engine', () => { | ||
it('should render a string literal with the variables interpolated', async () => { | ||
const data = { | ||
name: 'John', | ||
time: 'today' | ||
} | ||
const template = new Template('Hello ${name}! How are you ${time}?', data) | ||
const expected = 'Hello John! How are you today?' | ||
const actual = await template.render() | ||
assert.equal(actual, expected) | ||
}) | ||
|
||
it('should inject a file into a template with ${await file(path/to/file)}', async () => { | ||
const partials = new Map() | ||
partials.set('layout.html', await readFile('./layout.html', 'utf8')) | ||
const template = new Template(await readFile('./test.html', 'utf8'), {}, partials) | ||
|
||
const expected = `<html> | ||
<h1>This is a test html file</h1> | ||
</html>` | ||
const actual = await template.render() | ||
assert.equal(actual, expected) | ||
}) | ||
it('should loop over a list of items and render them in the template', async () => { | ||
const data = { | ||
items: [ | ||
{ | ||
name: 'John' | ||
}, | ||
{ | ||
name: 'Jane' | ||
} | ||
] | ||
} | ||
const template = new Template(await readFile('./test-loop.html', 'utf8'), data) | ||
const expected = `<html> | ||
<h1>John</h1> | ||
<h1>Jane</h1> | ||
</html>` | ||
const actual = await template.render() | ||
assert.equal(actual, expected) | ||
}) | ||
it('should render complex objects in the template', async () => { | ||
const data = { | ||
users: [ | ||
{ | ||
name: 'John', | ||
address: { | ||
street: '123 Main St', | ||
city: 'Anytown', | ||
state: 'CA' | ||
} | ||
}, | ||
{ | ||
name: 'Jane', | ||
address: { | ||
street: '456 Main St', | ||
city: 'Anytown', | ||
state: 'CA' | ||
} | ||
} | ||
] | ||
} | ||
const template = new Template(await readFile('./test-complex.html', 'utf8'), data) | ||
const expected = ` | ||
<h1>John</h1> | ||
<p>123 Main St</p> | ||
<p>Anytown</p> | ||
<p>CA</p> | ||
<h1>Jane</h1> | ||
<p>456 Main St</p> | ||
<p>Anytown</p> | ||
<p>CA</p>` | ||
const actual = await template.render() | ||
assert.equal(actual, expected) | ||
}) | ||
it('should allow custom functions to be used the template', async () => { | ||
const data = { | ||
name: 'John', | ||
time: 'today' | ||
} | ||
const template = new Template(await readFile('./test-custom-functions.html'), data, null, { | ||
customFunction: () => 'Hello' | ||
}) | ||
const expected = 'Hello John! How are you today?' | ||
const actual = await template.render() | ||
assert.equal(actual, expected) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<html> | ||
${body} | ||
</html> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "@hubot-friends/hubot-templating", | ||
"version": "0.0.0-development", | ||
"description": "Javascript Server side templating engine with string literals", | ||
"main": "index.mjs", | ||
"scripts": { | ||
"test": "node --test --experimental-vm-modules" | ||
}, | ||
"keywords": [ | ||
"templating", | ||
"engine", | ||
"string", | ||
"literals", | ||
"javascript" | ||
], | ||
"author": "Joey Guerra", | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "https://opensource.org/licenses/MIT" | ||
} | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/hubot-friends/hubot-templating.git" | ||
}, | ||
"engines": { | ||
"node": ">=20" | ||
}, | ||
"release": { | ||
"branches": [ | ||
"main", | ||
"next" | ||
], | ||
"dryRun": false | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
${hasLayout('layout.html')} | ||
${users.map(user => ` | ||
<h1>${user.name}</h1> | ||
<p>${user.address.street}</p> | ||
<p>${user.address.city}</p> | ||
<p>${user.address.state}</p>`).join('')} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
${customFunction()} John! How are you today? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<html> | ||
${items.map(item => '<h1>' + item.name + '</h1>\n').join('').replace(/\n$/, '')} | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
${hasLayout('layout.html')} | ||
<h1>This is a test html file</h1> |