Skip to content
This repository has been archived by the owner on Sep 13, 2023. It is now read-only.

Commit

Permalink
BREAKING CHANGE, allowRequire: true is necc to use require in template
Browse files Browse the repository at this point in the history
  • Loading branch information
saurabhdaware committed May 28, 2020
1 parent 969310f commit dcfa75d
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 52 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v0.1.10
- **BREAKING CHANGE**, **SECURITY UPDATE**
To use `require()` in the template, user will have to pass `allowRequire: true` in option. This option is by default set to false.
```js
const newHTMLTemplate = abellRenderer.render(
myAbellTemplate,
mySandbox,
{allowRequire: true}
);
```

## v0.1.9
- Fix to recursively find and create nested `.abell` files

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ You can use JavaScript Array methods to loop over array. Other JavaScript Array
<h2>${user.name}</h2>
<span>Age: ${user.age}</span>
</div>
`)
`).join('')
}}
</main>

Expand All @@ -113,6 +113,8 @@ Ouputs:
```
### ⤵️ Import JS/JSON/NPM Modules
*NOTE: Starting v0.1.10 require() can only be used when `allowRequire: true` is passed from options or `--allow-require` flag is passed in CLI*
With Abell you can import your Native NodeJS Modules, NPM Modules, JS Files (should export data), and JSON Files with `require()`
Expand Down Expand Up @@ -196,6 +198,7 @@ Outputs:
`template`: Abell template in String
`sandbox`: Object over which the scripts execute, Can define variables and inject them into script.
`options.basePath`: basePath which is prefixed on `require()` paths in abellTemplate.
`options.allowRequire`: Passing `true` allows using `require()` in templates. Default is `false`.


## 🤗 Contributing
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "abell-renderer",
"version": "0.1.9",
"version": "0.1.10",
"description": "A wrapper arround Mustache that adds some additional features and some syntatic sugar required for abell",
"main": "dist/index.js",
"bin": {
Expand All @@ -14,8 +14,8 @@
"test": "mocha --recursive \"./tests/*.js\"",
"build": "node build/build.main.js",
"dev": "node src/example/example.js",
"dev:cli": "node src/bin.js build --input src/example/templates/cli_example.abell --output src/example/out/cli_example.html",
"dev:cli-dir": "node src/bin.js build --input src/example/templates/loop_example --output src/example/out/loop_example",
"dev:cli": "node src/bin.js build --input src/example/templates/cli_example.abell --output src/example/out/cli_example.html --allow-require",
"dev:cli-dir": "node src/bin.js build --input src/example/templates/loop_example --output src/example/out/loop_example --allow-require",
"cli": "npm run dev:cli",
"eslint": "eslint .",
"prepublishOnly": "npm run eslint && npm test && npm run build"
Expand Down
5 changes: 3 additions & 2 deletions src/bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,15 @@ function build() {
const outputPath = (indexOfOutput > -1)
? path.join(cwd, args[indexOfOutput + 1])
: inputPath.replace('.abell', '.html'); // file name of input
const allowRequire = args.includes('--allow-require');

const basePath = path.dirname(inputPath);

console.log(`${ green('-') } Rendering started ✨ \n`);

if (!fs.statSync(inputPath).isDirectory()) {
// If input is a file
generateHTMLFromAbell(inputPath, outputPath, {basePath});
generateHTMLFromAbell(inputPath, outputPath, {basePath, allowRequire});
} else {
// If input is a directory
const relativePaths = recursiveFind(inputPath, '.abell')
Expand All @@ -87,7 +88,7 @@ function build() {
generateHTMLFromAbell(
path.join(inputPath, filepath),
path.join(outputPath, filepath.replace('.abell', '.html')),
{basePath: path.dirname(path.join(inputPath, filepath))}
{basePath: path.dirname(path.join(inputPath, filepath)), allowRequire}
);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const execRegexOnAll = (regex, template) => {
* @param {object} options additional options e.g ({basePath})
* @return {string} htmlTemplate
*/
function render(abellTemplate, sandbox, options = {basePath: ''}) {
function render(abellTemplate, sandbox, options = {basePath: '', allowRequire: false}) {
// Finds all the JS expressions to be executed.
const {matches, input} = execRegexOnAll(/\\?{{(.+?)}}/gs, abellTemplate);
let renderedHTML = '';
Expand All @@ -54,6 +54,9 @@ function render(abellTemplate, sandbox, options = {basePath: ''}) {
// Ignore the match that starts with slash '\' and return the same value without slash
value = match[0].slice(1);
} else if (match[1].includes('require(')) {
if (!options.allowRequire) {
throw new Error('require() is not allowed in the script');
}
// the js block is trying to require (e.g const module1 = require('module1'))
const lines = match[1]
.trim()
Expand Down
45 changes: 45 additions & 0 deletions tests/execute.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const path = require('path');
const expect = require('chai').expect;

const {
execute,
executeRequireStatement
} = require('../src/execute.js');


describe('execute() - Executes JavaScript passed to it as string', () => {
it('should output added value when addition is performed on two values', () => {
expect(
execute('24 + 12', {}).value
).to.equal(36);
});

it('should update value of a to new value', () => {
expect(
execute('a = 22 + 22', {a: 4}).sandbox.a
).to.equal(44);
});

it('should not update value that is inside string', () => {
expect(
execute('(() => \'a = b\')()').value
).to.equal('a = b');
});
});


describe('executeRequireStatement() - executes the code with require() in its string', () => {
it('should add path native object when required', () => {
expect(
executeRequireStatement('const path = require(\'path\')')
.path.join('test', 'path')
).to.equal(path.join('test', 'path'));
});

it('should handle the case of require(\'module\').property', () => {
expect(
executeRequireStatement('const testPath = require(\'path\').join(\'test\',\'path\')')
.testPath
).to.equal(path.join('test', 'path'));
});
});
69 changes: 24 additions & 45 deletions tests/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ const fs = require('fs');
const path = require('path');
const expect = require('chai').expect;

const {
execute,
executeRequireStatement
} = require('../src/execute.js');

const abellRenderer = require('../src/index.js');

describe('render() - renders abellTemplate into HTML Text', () => {
Expand All @@ -33,7 +28,10 @@ describe('render() - renders abellTemplate into HTML Text', () => {
.render(
abellTemplate,
sampleSandbox,
{basePath: path.join(__dirname, 'resources')}
{
basePath: path.join(__dirname, 'resources'),
allowRequire: true
}
)
).to.equal(htmlTemplate);
});
Expand Down Expand Up @@ -79,11 +77,30 @@ describe('render() - renders abellTemplate into HTML Text', () => {
expect(
abellRenderer.render(
abellTemplate,
{}
{},
{allowRequire: true}
).trim()
).to.equal('<div>8 hi/hello hi/hello</div>');
});

it('should throw an error if require() is used without allowRequire: true option', () => {
const abellTemplate = `
{{
const path = require('path');
const hiHelloPath = require('path').join('hi', 'hello');
}}
<div>{{ path.join('hi', 'hello') }} {{ hiHelloPath }}</div>
`;

expect(
() =>
abellRenderer.render(
abellTemplate,
{},
)
).to.throw('require() is not allowed in the script');
});

it('should not throw error and return same value if blank brackets passed', () => {
expect(
abellRenderer.render(
Expand All @@ -102,41 +119,3 @@ describe('render() - renders abellTemplate into HTML Text', () => {
).to.equal('{{ This is ignored }}');
});
});


describe('execute() - Executes JavaScript passed to it as string', () => {
it('should output added value when addition is performed on two values', () => {
expect(
execute('24 + 12', {}).value
).to.equal(36);
});

it('should update value of a to new value', () => {
expect(
execute('a = 22 + 22', {a: 4}).sandbox.a
).to.equal(44);
});

it('should not update value that is inside string', () => {
expect(
execute('(() => \'a = b\')()').value
).to.equal('a = b');
});
});


describe('executeRequireStatement() - executes the code with require() in its string', () => {
it('should add path native object when required', () => {
expect(
executeRequireStatement('const path = require(\'path\')')
.path.join('test', 'path')
).to.equal(path.join('test', 'path'));
});

it('should handle the case of require(\'module\').property', () => {
expect(
executeRequireStatement('const testPath = require(\'path\').join(\'test\',\'path\')')
.testPath
).to.equal(path.join('test', 'path'));
});
});

0 comments on commit dcfa75d

Please sign in to comment.