-
-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement new syntax. Closes #1. #5
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "airbnb-base", | ||
"env": { | ||
"node": true, | ||
"jest": true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
language: node_js | ||
node_js: | ||
- "6.0" | ||
- "6.1" | ||
- "6.2" | ||
- "6.3" | ||
- "6.4" | ||
- "6.5" | ||
- "6.6" | ||
- "6.7" | ||
- "6.8" | ||
- "6.9" | ||
- "6.10" | ||
- "7.0" | ||
- "7.1" | ||
- "7.2" | ||
- "7.3" | ||
- "7.4" | ||
- "7.5" | ||
- "7.6" | ||
- "7.7" | ||
- "7.8" | ||
- "7.9" | ||
- "7.10" | ||
script: | ||
- npm test | ||
- npm run lint |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
Timur Shemsedinov <[email protected]> | ||
Sergey Nanovsky <[email protected]> | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,42 @@ | ||
## Tickplate | ||
# Tickplate | ||
Backtick template engine for JavaScript | ||
|
||
Back-tick template engine for JavaScript | ||
## Install | ||
``` | ||
$ npm install --save tickplate | ||
``` | ||
|
||
## Usage | ||
|
||
- Install: `npm install tickplate` | ||
- Require: `const t = require('tickplate');` | ||
- Place tag `t` before templated string | ||
|
||
## Examples: | ||
|
||
```js | ||
const t = require('tickplate'); | ||
|
||
const data = { | ||
hello: 'Ave!', | ||
myFriend: { | ||
name: 'Marcus Aurelius', | ||
toString() { | ||
return this.name | ||
} | ||
const tickplate = require('tickplate'); | ||
|
||
const template = '\ | ||
<article>\n\ | ||
<h2>${article.title}</h2>\n\ | ||
<p>${article.description}</p>\n\ | ||
<span>${article.author.firstName} ${article.author.lastName}</span>\n\ | ||
<span>${article.formattedDate()}</span>\n\ | ||
</article>\ | ||
'; | ||
|
||
const context = { | ||
article: { | ||
title: 'Lorem ipsum', | ||
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit', | ||
author: { | ||
firstName: 'FirstName', | ||
lastName: 'LastName', | ||
}, | ||
createdAt: new Date(), | ||
formattedDate() { | ||
const date = this.createdAt.getDate(); | ||
const month = this.createdAt.getMonth(); | ||
const year = this.createdAt.getFullYear(); | ||
return `${date}.${month}.${year}`; | ||
}, | ||
}, | ||
positions: ['imperor', 'philosopher', 'writer'] | ||
}; | ||
|
||
const template1 = t`Example: ${'hello'} ${'myFriend'} great ${'positions'} of Rome`; | ||
|
||
console.log(template1(data)); | ||
const result = tickplate(template, context); | ||
console.log(result); | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require('./lib/tickplate'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* eslint-disable no-template-curly-in-string */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why underscores There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's how it is usually done in Jest, but it is not a requirement. If I recall correctly, you may as well name the directory as you wish and just name your test files as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should I change it? |
||
|
||
const tickplate = require('../tickplate'); | ||
|
||
describe('tickplate', () => { | ||
it('should insert values from parameters', () => { | ||
const template = '<p>${person.firstName} ${person.lastName}</p>'; | ||
const context = { | ||
person: { | ||
firstName: 'FirstName', | ||
lastName: 'LastName', | ||
}, | ||
}; | ||
const actual = tickplate(template, context); | ||
const expected = `<p>${context.person.firstName} ${context.person.lastName}</p>`; | ||
expect(actual).toBe(expected); | ||
}); | ||
|
||
it('should evaluate functions from parameters', () => { | ||
const template = '<p>${test()}</p>'; | ||
const context = { | ||
test: () => 1 + 1, | ||
}; | ||
const actual = tickplate(template, context); | ||
const expected = `<p>${context.test()}</p>`; | ||
expect(actual).toBe(expected); | ||
}); | ||
|
||
it('should correctly escape backticks', () => { | ||
const template = '<p>`${value}``</p>'; | ||
const context = { | ||
value: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.', | ||
}; | ||
const actual = tickplate(template, context); | ||
const expected = `<p>`${context.value}``</p>`; | ||
expect(actual).toBe(expected); | ||
}); | ||
|
||
it('should work with nested template literals', () => { | ||
const template = '<p>${`${`${value}`}`}</p>'; | ||
const context = { | ||
value: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.', | ||
}; | ||
const actual = tickplate(template, context); | ||
const expected = `<p>${`${`${context.value}`}`}</p>`; | ||
expect(actual).toBe(expected); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
const vm = require('vm'); | ||
|
||
/** | ||
* Replace backticks with corresponding HTML entity | ||
* @param {String} string String to be escaped | ||
* @return {String} Escaped string | ||
*/ | ||
const escapeBackticks = string => string.replace(/`/g, '`'); | ||
|
||
/** | ||
* Format correct body for template literal string | ||
* @param {String} string String to be formatted | ||
* @return {String} Body for template literal string | ||
*/ | ||
const formatBody = (string) => { | ||
const delimiters = { | ||
start: '${', | ||
end: '}', | ||
}; | ||
let result = ''; | ||
let buffer = ''; | ||
let startFound = false; | ||
let endFound = false; | ||
let nested = 0; | ||
for (let i = 0; i < string.length; i += 1) { | ||
const startDelimiter = i < string.length - 1 ? string[i] + string[i + 1] : null; | ||
if (startDelimiter && startDelimiter === delimiters.start) { | ||
if (startFound) { | ||
nested += 1; | ||
} else { | ||
if (buffer.length !== 0) { | ||
result += escapeBackticks(buffer); | ||
buffer = ''; | ||
} | ||
startFound = true; | ||
} | ||
} else if (startFound && string[i] === delimiters.end) { | ||
if (nested !== 0) { | ||
nested -= 1; | ||
} else { | ||
endFound = true; | ||
} | ||
} | ||
buffer += string[i]; | ||
if (startFound && endFound) { | ||
result += buffer; | ||
startFound = false; | ||
endFound = false; | ||
buffer = ''; | ||
} | ||
if (buffer.length !== 0 && i === string.length - 1) { | ||
result += escapeBackticks(buffer); | ||
} | ||
} | ||
return result; | ||
}; | ||
|
||
/** | ||
* Compile template with passed context | ||
* @param {String} template String representing template | ||
* @param {Object} context Object representing template context | ||
* @return {String} Compiled template | ||
*/ | ||
const tickplate = (template, context) => { | ||
const code = `\`${formatBody(template)}\``; | ||
return vm.runInNewContext(code, context); | ||
}; | ||
|
||
module.exports = tickplate; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
"name": "tickplate", | ||
"version": "0.0.1", | ||
"author": "", | ||
"description": "Back-tick template engine for JavaScript", | ||
"description": "Backtick template engine for JavaScript", | ||
"license": "MIT", | ||
"keywords": [ | ||
"tickplate", | ||
|
@@ -20,12 +20,19 @@ | |
"url": "https://github.com/metarhia/tickplate/issues", | ||
"email": "[email protected]" | ||
}, | ||
"main": "./tickplate.js", | ||
"main": "./index.js", | ||
"engines": { | ||
"node": ">=6.0.0" | ||
}, | ||
"readmeFilename": "README.md", | ||
"scripts": { | ||
"test": "node ./test.js" | ||
"test": "jest", | ||
"lint": "eslint ." | ||
}, | ||
"devDependencies": { | ||
"eslint": "^3.19.0", | ||
"eslint-config-airbnb-base": "^11.1.3", | ||
"eslint-plugin-import": "^2.2.0", | ||
"jest": "^20.0.1" | ||
} | ||
} |
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add @primeare to
AUTHORS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would not be related to this PR :)
I am okay with @sun1x adding himself to the list in his first PR, though I would not say it is a good thing to do generally. But adding other people should definitely be done separately.