Skip to content
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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "airbnb-base",
"env": {
"node": true,
"jest": true
}
}
27 changes: 27 additions & 0 deletions .travis.yml
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
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Timur Shemsedinov <[email protected]>
Sergey Nanovsky <[email protected]>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @primeare to AUTHORS

Copy link
Member

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.

56 changes: 34 additions & 22 deletions README.md
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);
```
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./lib/tickplate');
48 changes: 48 additions & 0 deletions lib/__tests__/tickplate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* eslint-disable no-template-curly-in-string */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why underscores __tests__ ?

Copy link
Member

Choose a reason for hiding this comment

The 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 *.test.js or something like that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I change it?
By default, Jest uses this regex to detect test files.


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>&#96;${context.value}&#96;&#96;</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);
});
});
69 changes: 69 additions & 0 deletions lib/tickplate.js
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, '&#96;');

/**
* 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;
13 changes: 10 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
}
18 changes: 0 additions & 18 deletions test.js

This file was deleted.

15 changes: 0 additions & 15 deletions tickplate.js

This file was deleted.