pax_global_header 0000666 0000000 0000000 00000000064 13137251263 0014515 g ustar 00root root 0000000 0000000 52 comment=67ca0a80a5a68277774c693204ce49ef11bb84b4
ejs-2.5.7/ 0000775 0000000 0000000 00000000000 13137251263 0012311 5 ustar 00root root 0000000 0000000 ejs-2.5.7/.eslintignore 0000664 0000000 0000000 00000000041 13137251263 0015007 0 ustar 00root root 0000000 0000000 coverage
out
/ejs.js
/ejs.min.js
ejs-2.5.7/.eslintrc.json 0000664 0000000 0000000 00000001305 13137251263 0015104 0 ustar 00root root 0000000 0000000 {
"env": {
"browser": true,
"commonjs": true,
"node": true
},
"extends": "eslint:recommended",
"rules": {
"linebreak-style": [
"error",
"unix"
],
"no-trailing-spaces": 2,
"indent": [
"error",
2
],
"quotes": [
"error",
"single",
{
"avoidEscape": true
}
],
"semi": [
"error",
"always"
],
"comma-style": [
"error",
"last"
],
"one-var": [
"error",
"never"
],
"no-console": 0
}
}
ejs-2.5.7/.gitignore 0000664 0000000 0000000 00000000435 13137251263 0014303 0 ustar 00root root 0000000 0000000 # If you add anything here, consider also adding to .npmignore
v8.log
*.swp
*.swo
auth_info.js
dist
.idea/
tags
nbproject/
spec/browser/autogen_suite.js
node_modules
tmtags
*.DS_Store
examples/*/log/*
site/log/*
.log
npm-debug.log
doc/
test/tmp
coverage/
/ejs.js
/ejs.min.js
out/
pkg/
ejs-2.5.7/.jshintignore 0000664 0000000 0000000 00000000054 13137251263 0015014 0 ustar 00root root 0000000 0000000 node_modules
coverage
out
ejs.js
ejs.min.js
ejs-2.5.7/.jshintrc 0000664 0000000 0000000 00000000314 13137251263 0014134 0 ustar 00root root 0000000 0000000 {
"evil": true,
"laxcomma": true,
"laxbreak": true,
"supernew": true,
"curly": true,
"immed": true,
"undef": true,
"node": true,
"unused": true,
"globals": {
"window": false
}
}
ejs-2.5.7/.npmignore 0000664 0000000 0000000 00000000324 13137251263 0014307 0 ustar 00root root 0000000 0000000 test/
# Copied from .gitignore
v8.log
*.swp
*.swo
auth_info.js
dist
.idea/
tags
nbproject/
spec/browser/autogen_suite.js
tmtags
*.DS_Store
examples/*/log/*
site/log/*
.log
npm-debug.log
doc/
coverage/
out/
pkg/
ejs-2.5.7/.travis.yml 0000664 0000000 0000000 00000000077 13137251263 0014426 0 ustar 00root root 0000000 0000000 language: node_js
sudo: false
node_js:
- "4"
- "6"
- "8"
ejs-2.5.7/CHANGELOG.md 0000664 0000000 0000000 00000014354 13137251263 0014131 0 ustar 00root root 0000000 0000000 ## v2.5.7: 2017-07-29
* Pass configured escape function to `rethrow` (@straker)
+ Added vulnerabilities info into README (@mde)
* Avoid creating function object in hot execution path (@User4martin)
+ Added benchmark (@User4martin)
+ Tests for looped includes (@User4martin)
## v2.5.6: 2017-02-16
* Use configured escape function for filenames in errors (@mde)
+ Make file-loader configurable to allow template pre-processing (@hacke2)
* Improved `renderFile` performance (@nwoltman)
## v2.5.5: 2016-12-06
* Allow 'filename' for opts-in-data, but sanitize when rendered (@mde)
## v2.5.4: 2016-12-05
* Blackist more options from opts-in-data (@mde)
* Allow trailing comments in output modes (@mde)
+ Added 'name' attribute for easy identification (@designfrontier)
## v2.5.3: 2016-11-28
* Blackist 'root' option from opts-in-data (@mde)
## v2.5.2: 2016-07-25
+ Added link to EJS Playground (@RyanZim)
- Revert express auto 'root' option (@RyanZim)
## v2.5.1: 2016-07-25
+ Output literal `%>` with `%%>` (Roy Miloh)
+ Allow setting project root for includes (@cnwhy)
+ UMD support for the browser (@RyanZim)
+ Exported `escapeXML` method to allow manual escaping of output (@mde)
+ Tests for strict mode (@RyanZim, @mde)
+ Added ESLint for project source code (@mde)
* Whitespace slurp in preprocessor include (@mmis1000)
* Improved line-number handling in errors (@Spikef)
* Various doc improvements (@RyanZim, Ionică Bizău)
## v2.4.2: 2016-05-24
+ Added LICENSE file to release package
* Various documentation improvements (@RyanZim)
* Better line-numbers in errors (@dgofman)
## v2.4.1: 2016-01-23
+ Strict-mode support (@mde)
+ Express 4 support (@mde)
+ Configurable localsName option (@mde)
## v2.3.4: 2015-09-04
+ Whitespace slurp tag syntax -- `<%_ _%>` (@andidev)
## v2.3.3: 2015-07-11
* Fixed false positives for old `include` preprocessor directive (@mde)
## v2.3.2: 2015-06-28
* Do not require semicolons in `<%- %>` (@TimothyGu)
* Use `__append` instead of `pushToOutput` (@dominykas)
* Cache the character-encoding function (@alubbe)
* Correctly specify execution context with opts.context (@mde)
## v2.3.1: 2015-02-22
* Stop deferring execution of `renderFile` callback, revert to sync
execution (@mde)
+ Generated template functions are now prettier (@whitneyit)
+ Add official documentation for EJS syntax (#9) (@TimothyGu)
+ Add inline JSDoc-style documentation for public functions (#9) (@TimothyGu)
+ Add a new dynamic client-side template compilation example in
`examples/client-compile.html` (@TimothyGu)
* Fix running on Node.js v0.8. Note that we still do not support 0.8
officially, but if you found something that can be fixed easily please
point it out. (#57) (@TimothyGu)
* Do not trim newlines at the end of files. This might be considered
incompatible by some, but the new behavior is the correct one, and is
consistent with EJS v1. (#60) (@TimothyGu)
* Readd deprecation warning for `scope` option that was removed in v2.2.4. It
never caused any problems with Express or anything else so its removal was
a mistake. (@TimothyGu)
* Always rethrow the error from `new Function()` (@TimothyGu)
## v2.2.4: 2015-02-01
+ Ability to customize name of the locals object with `ejs.localsName` (@mde)
+ Ability to override `resolveInclude` for include-path lookup
(@olivierkaisin)
* Only bundle rethrow() in client scripts when compileDebug is enabled
(@TimothyGu)
* Copy `_with` from locals object to options object (@TimothyGu)
* Removed deprecation warnings (@mde)
* Significantly increased performance (@TimothyGu)
* Defer execution for `renderFile` callback, ensure async (@TimothyGu)
## v2.2.3: 2015-01-23
* Better filtering for deprecation notice when called from Express (@mde)
## v2.2.2: 2015-01-21
* Fix handling of variable output containing semicolons (@TimothyGu)
* Fix included files caching (@TimothyGu)
* Simplified caching routine (@TimothyGu)
* Filter out deprecation warning for `renderFile` when called from
Express (@mde)
## v2.2.1: 2015-01-19
+ 4x faster HTML escaping function, especially beneficial if you use lots
of escaped locals (@TimothyGu)
+ Up to 4x faster compiled functions in addition to above (@TimothyGu)
+ Caching mode regression test coverage (@TimothyGu)
* Fix `//` in an expanded string (@TimothyGu)
* Fix literal mode without an end tag (@TimothyGu)
* Fix setting options to renderFile() through the legacy 3-argument interface
(as is the case for Express.js) (@TimothyGu)
+ Added version string to exported object for use in browsers (@mde)
## v2.1.4: 2015-01-12
* Fix harmony mode (@mde)
## v2.1.3: 2015-01-11
* Fix `debug` option (@TimothyGu)
* Fix two consecutive tags together (@TimothyGu)
## v2.1.2: 2015-01-11
* Fix `scope` option handling
+ Improve testing coverage (@TimothyGu)
## v2.1.1: 2015-01-11
+ Add `_with` option to control whether or not to use `with() {}` constructs
(@TimothyGu)
+ Improve test coverage (@mde & @TimothyGu)
+ Add a few more metadata fields to `package.json` (@TimothyGu)
- Revert hack for Etherpad Lite (@TimothyGu)
* Do not claim node < 0.10.0 support (@TimothyGu)
* Pin dependencies more loosely (@TimothyGu)
* Fix client function generation without using locals (@TimothyGu)
* Fix error case where the callback be called twice (@TimothyGu)
* Add `"use strict";` to all JS files (@TimothyGu)
* Fix absolute path inclusion (@TimothyGu) (#11)
## v2.0.8: 2015-01-06
* Fix crash on missing file
## v2.0.7: 2015-01-05
* Linting and cosmetics
## v2.0.6: 2015-01-04
* Temporary hack for Etherpad Lite. It will be removed soon.
## v2.0.5: 2015-01-04
* Fix leaking global `fn`
## v2.0.4: 2015-01-04
* Fix leaking global `includeSource`
* Update client-side instructions
## v2.0.3: 2015-01-04
+ Add Travis CI support
+ Add LICENSE file
+ Better compatibility with EJS v1 for options
+ Add `debug` option
* Fix typos in examples in README
## v2.0.2: 2015-01-03
* Use lowercase package name in `package.json`
## v2.0.1: 2015-01-02
+ Completely rewritten
+ Single custom delimiter (e.g., `?`) with `delimiter` option instead of
`open`/`close` options
+ `include` now runtime function call instead of preprocessor directive
+ Variable-based includes now possible
+ Comment tag support (`<%#`)
* Data and options now separate params (i.e., `render(str, data, options);`)
- Removed support for filters
ejs-2.5.7/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000004521 13137251263 0015112 0 ustar 00root root 0000000 0000000 # Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer at mde@fleegix.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/
ejs-2.5.7/Jakefile 0000664 0000000 0000000 00000003557 13137251263 0013760 0 ustar 00root root 0000000 0000000 var fs = require('fs');
var execSync = require('child_process').execSync;
var exec = function (cmd) {
execSync(cmd, {stdio: 'inherit'});
};
/* global jake, task, desc, publishTask */
task('build', ['lint', 'clean', 'browserify', 'minify'], function () {
console.log('Build completed.');
});
desc('Cleans browerified/minified files and package files');
task('clean', ['clobber'], function () {
jake.rmRf('./ejs.js');
jake.rmRf('./ejs.min.js');
console.log('Cleaned up compiled files.');
});
desc('Lints the source code');
task('lint', function () {
exec('./node_modules/.bin/eslint \"**/*.js\" Jakefile');
console.log('Linting completed.');
});
task('browserify', function () {
exec('./node_modules/browserify/bin/cmd.js --standalone ejs lib/ejs.js > ejs.js');
console.log('Browserification completed.');
});
task('minify', function () {
exec('./node_modules/uglify-js/bin/uglifyjs ejs.js > ejs.min.js');
console.log('Minification completed.');
});
task('doc', function (dev) {
jake.rmRf('out');
var p = dev ? '-p' : '';
exec('./node_modules/.bin/jsdoc ' + p + ' -c jsdoc.json lib/* docs/jsdoc/*');
console.log('Documentation generated.');
});
task('docPublish', ['doc'], function () {
fs.writeFileSync('out/CNAME', 'api.ejs.co');
console.log('Pushing docs to gh-pages...');
exec('./node_modules/.bin/git-directory-deploy --directory out/');
console.log('Docs published to gh-pages.');
});
task('test', ['lint'], function () {
exec('./node_modules/.bin/mocha');
});
publishTask('ejs', ['build'], function () {
this.packageFiles.include([
'Jakefile',
'README.md',
'LICENSE',
'package.json',
'ejs.js',
'ejs.min.js',
'lib/**'
]);
});
jake.Task.publish.on('complete', function () {
console.log('Updating hosted docs...');
console.log('If this fails, run jake docPublish to re-try.');
jake.Task.docPublish.invoke();
});
ejs-2.5.7/LICENSE 0000664 0000000 0000000 00000026136 13137251263 0013326 0 ustar 00root root 0000000 0000000
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
ejs-2.5.7/README.md 0000664 0000000 0000000 00000021316 13137251263 0013573 0 ustar 00root root 0000000 0000000 # EJS
Embedded JavaScript templates
[](https://travis-ci.org/mde/ejs)
[](https://david-dm.org/mde/ejs?type=dev)
[](https://snyk.io/test/npm/ejs)
## Installation
```bash
$ npm install ejs
```
## Features
* Control flow with `<% %>`
* Escaped output with `<%= %>` (escape function configurable)
* Unescaped raw output with `<%- %>`
* Newline-trim mode ('newline slurping') with `-%>` ending tag
* Whitespace-trim mode (slurp all whitespace) for control flow with `<%_ _%>`
* Custom delimiters (e.g., use ` ?>` instead of `<% %>`)
* Includes
* Client-side support
* Static caching of intermediate JavaScript
* Static caching of templates
* Complies with the [Express](http://expressjs.com) view system
## Example
```html
<% if (user) { %>
<%= user.name %>
<% } %>
```
Try EJS online at: https://ionicabizau.github.io/ejs-playground/.
## Usage
```javascript
var template = ejs.compile(str, options);
template(data);
// => Rendered HTML string
ejs.render(str, data, options);
// => Rendered HTML string
ejs.renderFile(filename, data, options, function(err, str){
// str => Rendered HTML string
});
```
It is also possible to use `ejs.render(dataAndOptions);` where you pass
everything in a single object. In that case, you'll end up with local variables
for all the passed options. However, be aware that your code could break if we
add an option with the same name as one of your data object's properties.
Therefore, we do not recommend using this shortcut.
## Options
- `cache` Compiled functions are cached, requires `filename`
- `filename` The name of the file being rendered. Not required if you
are using `renderFile()`. Used by `cache` to key caches, and for includes.
- `root` Set project root for includes with an absolute path (/file.ejs).
- `context` Function execution context
- `compileDebug` When `false` no debug instrumentation is compiled
- `client` When `true`, compiles a function that can be rendered
in the browser without needing to load the EJS Runtime
([ejs.min.js](https://github.com/mde/ejs/releases/latest)).
- `delimiter` Character to use with angle brackets for open/close
- `debug` Output generated function body
- `strict` When set to `true`, generated function is in strict mode
- `_with` Whether or not to use `with() {}` constructs. If `false` then the locals will be stored in the `locals` object. Set to `false` in strict mode.
- `localsName` Name to use for the object storing local variables when not using `with` Defaults to `locals`
- `rmWhitespace` Remove all safe-to-remove whitespace, including leading
and trailing whitespace. It also enables a safer version of `-%>` line
slurping for all scriptlet tags (it does not strip new lines of tags in
the middle of a line).
- `escape` The escaping function used with `<%=` construct. It is
used in rendering and is `.toString()`ed in the generation of client functions. (By default escapes XML).
This project uses [JSDoc](http://usejsdoc.org/). For the full public API
documentation, clone the repository and run `npm run doc`. This will run JSDoc
with the proper options and output the documentation to `out/`. If you want
the both the public & private API docs, run `npm run devdoc` instead.
## Tags
- `<%` 'Scriptlet' tag, for control-flow, no output
- `<%_` 'Whitespace Slurping' Scriptlet tag, strips all whitespace before it
- `<%=` Outputs the value into the template (escaped)
- `<%-` Outputs the unescaped value into the template
- `<%#` Comment tag, no execution, no output
- `<%%` Outputs a literal '<%'
- `%%>` Outputs a literal '%>'
- `%>` Plain ending tag
- `-%>` Trim-mode ('newline slurp') tag, trims following newline
- `_%>` 'Whitespace Slurping' ending tag, removes all whitespace after it
For the full syntax documentation, please see [docs/syntax.md](https://github.com/mde/ejs/blob/master/docs/syntax.md).
## Includes
Includes either have to be an absolute path, or, if not, are assumed as
relative to the template with the `include` call. For example if you are
including `./views/user/show.ejs` from `./views/users.ejs` you would
use `<%- include('user/show') %>`.
You must specify the `filename` option for the template with the `include`
call unless you are using `renderFile()`.
You'll likely want to use the raw output tag (`<%-`) with your include to avoid
double-escaping the HTML output.
```html
```
Includes are inserted at runtime, so you can use variables for the path in the
`include` call (for example `<%- include(somePath) %>`). Variables in your
top-level data object are available to all your includes, but local variables
need to be passed down.
NOTE: Include preprocessor directives (`<% include user/show %>`) are
still supported.
## Custom delimiters
Custom delimiters can be applied on a per-template basis, or globally:
```javascript
var ejs = require('ejs'),
users = ['geddy', 'neil', 'alex'];
// Just one template
ejs.render('= users.join(" | "); ?>', {users: users}, {delimiter: '?'});
// => 'geddy | neil | alex'
// Or globally
ejs.delimiter = '$';
ejs.render('<$= users.join(" | "); $>', {users: users});
// => 'geddy | neil | alex'
```
## Caching
EJS ships with a basic in-process cache for caching the intermediate JavaScript
functions used to render templates. It's easy to plug in LRU caching using
Node's `lru-cache` library:
```javascript
var ejs = require('ejs')
, LRU = require('lru-cache');
ejs.cache = LRU(100); // LRU cache with 100-item limit
```
If you want to clear the EJS cache, call `ejs.clearCache`. If you're using the
LRU cache and need a different limit, simple reset `ejs.cache` to a new instance
of the LRU.
## Custom FileLoader
The default file loader is `fs.readFileSync`, if you want to customize it, you can set ejs.fileLoader.
```javascript
var ejs = require('ejs');
var myFileLoad = function (filePath) {
return 'myFileLoad: ' + fs.readFileSync(filePath);
};
ejs.fileLoader = myFileLoad;
```
With this feature, you can preprocess the template before reading it.
## Layouts
EJS does not specifically support blocks, but layouts can be implemented by
including headers and footers, like so:
```html
<%- include('header') -%>
Title
My page
<%- include('footer') -%>
```
## Client-side support
Go to the [Latest Release](https://github.com/mde/ejs/releases/latest), download
`./ejs.js` or `./ejs.min.js`. Alternately, you can compile it yourself by cloning
the repository and running `jake build` (or `$(npm bin)/jake build` if jake is
not installed globally).
Include one of these files on your page, and `ejs` should be available globally.
### Example
```html
```
### Caveats
Most of EJS will work as expected; however, there are a few things to note:
1. Obviously, since you do not have access to the filesystem, `ejs.renderFile()` won't work.
2. For the same reason, `include`s do not work unless you use an `IncludeCallback`. Here is an example:
```javascript
var str = "Hello <%= include('file', {person: 'John'}); %>",
fn = ejs.compile(str, {client: true});
fn(data, null, function(path, d){ // IncludeCallback
// path -> 'file'
// d -> {person: 'John'}
// Put your code here
// Return the contents of file as a string
}); // returns rendered string
```
## Related projects
There are a number of implementations of EJS:
* TJ's implementation, the v1 of this library: https://github.com/tj/ejs
* Jupiter Consulting's EJS: http://www.embeddedjs.com/
* EJS Embedded JavaScript Framework on Google Code: https://code.google.com/p/embeddedjavascript/
* Sam Stephenson's Ruby implementation: https://rubygems.org/gems/ejs
* Erubis, an ERB implementation which also runs JavaScript: http://www.kuwata-lab.com/erubis/users-guide.04.html#lang-javascript
## License
Licensed under the Apache License, Version 2.0
()
- - -
EJS Embedded JavaScript templates copyright 2112
mde@fleegix.org.
ejs-2.5.7/benchmark/ 0000775 0000000 0000000 00000000000 13137251263 0014243 5 ustar 00root root 0000000 0000000 ejs-2.5.7/benchmark/bench-ejs.js.bak 0000775 0000000 0000000 00000013721 13137251263 0017202 0 ustar 00root root 0000000 0000000 'use strict';
var ejs = require('..');
ejs.fileLoader = function(n) { return files[n.replace(/^\//, '').replace(/\.ejs$/, '')]; };
var loops = 10000;
var runs = 9; // min 4 for median
var runCompile = false;
var runNoCache = false;
var runCache = false;
var i = 1;
while (i < process.argv.length) {
var a = process.argv[i];
i++;
var b;
if (i < process.argv.length) b = process.argv[i];
switch (a) {
case '-r': if(b) runs = b;
i++;
break;
case '-l': if(b) loops = b;
i++;
break;
case '--compile':
runCompile = true;
break;
case '--nocache':
runNoCache = true;
break;
case '--cache':
runCache = true;
break;
}
}
if (! (runCompile || runNoCache || runCache)) {
runCompile = true;
runNoCache = true;
runCache = true;
}
var files = {
bench1: `
`,
};
var data = {
name: 'foo',
num: 42,
cheese: 'out of',
};
var sp = ' ';
function fill(s, l) { s=String(s); return s + sp.slice(0,l-s.length); }
function fillR(s, l) { s=String(s); return sp.slice(0,l-s.length)+s; }
function log(name, runTimes, totalLoops) {
runTimes = runTimes.sort(function(a,b) { return a-b; });
var m = Math.trunc(runs/2);
var m2 = (runs % 2 == 0) ? m-1 : m;
var med1 = Math.round((runTimes[m]+runTimes[m2])/2);
var med2;
if (runs % 2 == 0)
med2 = Math.round((runTimes[m2-1]+runTimes[m2]+runTimes[m]+runTimes[m+1])/4);
else
med2 = Math.round((runTimes[m-1]+runTimes[m]+runTimes[m+1])/3);
var avg = Math.round(runTimes.reduce(function(a,b) {return a+b;}) / runTimes.length);
console.log(fill(name +': ',30), fill(avg/1000,10), fill(med1/1000,10), fill(med2/1000,10), fill(runTimes[0]/1000,10), fill(runTimes[runTimes.length-1]/1000,10),fillR(totalLoops, 15));
}
function benchRender(name, file, data, opts, benchOpts) {
ejs.cache.reset();
var runTimes = [];
opts = opts || {};
benchOpts = benchOpts || {};
opts.filename = file;
var totalLoops = Math.round(loops * (benchOpts.loopFactor || 1))
var tmpl = files[file];
for (var r = 0; r < runs; r++) {
ejs.render(tmpl, data, opts); // one run in advance
var t = Date.now();
for (var i = 0; i < totalLoops; i++) {
ejs.render(tmpl, data, opts);
}
t = Date.now() - t;
runTimes.push(t);
}
log(name, runTimes, totalLoops);
}
function benchCompile(name, file, opts, benchOpts) {
ejs.cache.reset();
var runTimes = [];
opts = opts || {};
benchOpts = benchOpts || {};
opts.filename = file;
var totalLoops = Math.round(loops * (benchOpts.loopFactor || 1))
var tmpl = files[file];
for (var r = 0; r < runs; r++) {
ejs.compile(tmpl, opts); // one run in advance
var t = Date.now();
for (var i = 0; i < totalLoops; i++) {
ejs.compile(tmpl, opts);
}
t = Date.now() - t;
runTimes.push(t);
}
log(name, runTimes, totalLoops);
}
if (runCompile) {
console.log('Running avg accross: ', runs);
console.log(fill('name: ',30), fill('avg',10), fill('med',10), fill('med/avg',10), fill('min',10), fill('max',10), fillR('loops',15));
benchCompile('single tmpl compile', 'bench1', {compileDebug: false}, { loopFactor: 2 });
benchCompile('single tmpl compile (debug)', 'bench1', {compileDebug: true}, { loopFactor: 2 });
benchCompile('large tmpl compile', 'bench2', {compileDebug: false}, { loopFactor: 0.1 });
benchCompile('include-1 compile', 'include1', {compileDebug: false}, { loopFactor: 2 });
console.log('-');
};
if (runCache) {
benchRender('single tmpl cached', 'bench1', data, {cache:true, compileDebug: false}, { loopFactor: 5 });
benchRender('single tmpl cached (debug)', 'bench1', data, {cache:true, compileDebug: true}, { loopFactor: 5 });
benchRender('large tmpl cached', 'bench2', data, {cache:true, compileDebug: false}, { loopFactor: 0.4 });
benchRender('include-1 cached', 'include1', data, {cache:true, compileDebug: false}, { loopFactor: 2 });
benchRender('include-2 cached', 'include2', data, {cache:true, compileDebug: false}, { loopFactor: 2 });
benchRender('locals tmpl cached "with"', 'locals1', data, {cache:true, compileDebug: false, _with: true}, { loopFactor: 3 });
benchRender('locals tmpl cached NO-"with"', 'locals1', data, {cache:true, compileDebug: false, _with: false}, { loopFactor: 3 });
console.log('-');
}
if (runNoCache) {
benchRender('single tmpl NO-cache', 'bench1', data, {cache:false, compileDebug: false});
benchRender('single tmpl NO-cache (debug)', 'bench1', data, {cache:false, compileDebug: true});
benchRender('large tmpl NO-cache', 'bench2', data, {cache:false, compileDebug: false}, { loopFactor: 0.1 });
benchRender('include-1 NO-cache', 'include1', data, {cache:false, compileDebug: false});
benchRender('include-2 NO-cache', 'include2', data, {cache:false, compileDebug: false});
}
ejs-2.5.7/docs/ 0000775 0000000 0000000 00000000000 13137251263 0013241 5 ustar 00root root 0000000 0000000 ejs-2.5.7/docs/jsdoc/ 0000775 0000000 0000000 00000000000 13137251263 0014343 5 ustar 00root root 0000000 0000000 ejs-2.5.7/docs/jsdoc/cache.jsdoc 0000664 0000000 0000000 00000001443 13137251263 0016434 0 ustar 00root root 0000000 0000000 /**
* A JavaScript function cache. This is implemented by the lru-cache module
* on NPM, so you can simply do `ejs.cache = LRU(10)` to get a
* least-recently-used cache.
*
* @interface Cache
* @global
*/
/**
* Cache the intermediate JavaScript function for a template.
*
* @function
* @name Cache#set
* @param {String} key key for caching
* @param {Function} val cached function
*/
/**
* Get the cached intermediate JavaScript function for a template.
*
* If the cache does not contain the specified key, `null` shall be returned.
*
* @function
* @name Cache#get
* @param {String} key key for caching
* @return {null|Function}
*/
/**
* Reset the entire cache.
*
* Erases the entire cache. Called by {@link module:ejs.clearCache}
*
* @function
* @name Cache#reset
*/
ejs-2.5.7/docs/jsdoc/callbacks.jsdoc 0000664 0000000 0000000 00000000424 13137251263 0017306 0 ustar 00root root 0000000 0000000 /**
* Callback for receiving data from {@link module:ejs.renderFile}.
*
* @callback RenderFileCallback
* @param {?Error} err error, if any resulted from the rendering process
* @param {?String} str output string, is `null` if there is an error
* @static
* @global
*/
ejs-2.5.7/docs/jsdoc/fileLoader.jsdoc 0000664 0000000 0000000 00000000544 13137251263 0017440 0 ustar 00root root 0000000 0000000 /**
* A file read function, similar to fs.readFileSync, this function
* can be read a file by path, return a string after processing
*
* @function
* @name fileLoader
* @param {String} path the path of the file to be read
* @return {String|Object} the contents of the file as a string or objects that implement the toString() method
* @global
*/
ejs-2.5.7/docs/jsdoc/options.jsdoc 0000664 0000000 0000000 00000004467 13137251263 0017075 0 ustar 00root root 0000000 0000000 /**
* Compilation and rendering options.
*
* @typedef Options
* @type {Object}
*
* @property {Boolean} [debug=false]
* Log generated JavaScript source for the EJS template to the console.
*
* @property {Boolean} [compileDebug=true]
* Include additional runtime debugging information in generated template
* functions.
*
* @property {Boolean} [_with=true]
* Whether or not to use `with () {}` construct in the generated template
* functions. If set to `false`, data is still accessible through the object
* whose name is specified by {@link module:ejs.localsName} (default to
* `locals`).
*
* @property {Boolean} [rmWhitespace=false]
* Remove all safe-to-remove whitespace, including leading and trailing
* whitespace. It also enables a safer version of `-%>` line slurping for all
* scriptlet tags (it does not strip new lines of tags in the middle of a
* line).
*
* @property {Boolean} [client=false]
* Whether or not to compile a {@link ClientFunction} that can be rendered
* in the browser without depending on ejs.js. Otherwise, a {@link TemplateFunction}
* will be compiled.
*
* @property {EscapeCallback} [escape={@link module:utils.escapeXML}]
* The escaping function used with `<%=` construct. It is used in rendering
* and is `.toString()`ed in the generation of client functions.
*
* @property {String} [filename=undefined]
* The filename of the template. Required for inclusion and caching unless
* you are using {@link module:ejs.renderFile}. Also used for error reporting.
*
* @property {String} [root=undefined]
* The path to the project root. When this is set, absolute paths for includes
* (/filename.ejs) will be relative to the project root.
*
* @property {String} [delimiter='%']
* The delimiter used in template compilation.
*
* @property {Boolean} [cache=false]
* Whether or not to enable caching of template functions. Beware that
* the options of compilation are not checked as being the same, so
* special handling is required if, for example, you want to cache client
* and regular functions of the same file.
*
* Requires `filename` to be set. Only works with rendering function.
*
* @property {Object} [context=this]
* The Object to which `this` is set during rendering.
*
* @property {Object} [scope=this]
* Alias of `context`. Deprecated.
*
* @static
* @global
*/
ejs-2.5.7/docs/jsdoc/template-functions.jsdoc 0000664 0000000 0000000 00000003712 13137251263 0021213 0 ustar 00root root 0000000 0000000 /**
* This type of function is returned from {@link module:ejs.compile}, when
* {@link Options}`.client` is false.
*
* @callback TemplateFunction
* @param {Object} [locals={}]
* an object of data to be passed into the template.
* @static
* @global
*/
/**
* This type of function is returned from {@link module:ejs.compile}, when
* {@link Options}`.client` is true.
*
* This is also used internally to generate a
* {@link TemplateFunction}.
*
* @callback ClientFunction
* @param {Object} [locals={}]
* an object of data to be passed into the template. The name of this variable
* is adjustable through {@link module:ejs.localsName}.
*
* @param {EscapeCallback} [escape={@link Options}.escape]
* callback used to escape variables
*
* @param {IncludeCallback} [include]
* callback used to include files at runtime with `include()`
*
* @param {RethrowCallback} [rethrow={@link module:ejs-internal.rethrow}]
* callback used to handle and rethrow errors
*
* @static
* @global
*/
/**
* Escapes a string using HTML/XML escaping rules.
*
* @callback EscapeCallback
* @param {String} markup Input string
* @return {String} Escaped string
* @static
* @global
*/
/**
* This type of callback is used when {@link Options}`.compileDebug`
* is true, and an error in the template is thrown. By default it is used to
* rethrow an error in a better-formatted way.
*
* @callback RethrowCallback
* @param {Error} err Error object
* @param {String} str full EJS source
* @param {String} filename file name of the EJS file
* @param {String} lineno line number of the error
* @static
* @global
*/
/**
* The callback called by {@link ClientFunction} to include files at runtime with `include()`
*
* @callback IncludeCallback
* @param {String} path Path to be included
* @param {Object} [data] Data passed to the template
* @return {String} Contents of the file requested
* @static
* @global
*/
ejs-2.5.7/docs/syntax.md 0000664 0000000 0000000 00000030530 13137251263 0015112 0 ustar 00root root 0000000 0000000 EJS Syntax Reference
====================
EJS is designed to be flexible and easy-to-write, but without too much
abstractions to cover up the HTML base.
Table of contents
-----------------
- Basic format
- Delimiters
- Starting tags
- `<%=`: Escaped output
- `<%-`: Unescaped output
- `<%#`: Comments
- `<%`: Scriptlet
- `<%_`: Scriptlet, removes all preceeding whitespace
- Ending tags
- `%>`: Regular ending tag
- `-%>`: Removes trailing newline
- `_%>`: Removes all trailing whitespace
- Literal tags
- Including other files
- “Preprocessor” directive
- JavaScript `include()` function
- Copyright
Basic format
------------
An EJS “tag” is the primary functioning unit in an EJS template. With the
exception of the literal tags, all tags are formed by the following format:
<startingcontentclosing>
The spaces between *starting* and *content*, and *content* and *closing* are
not required; they are recommended though for readability.
Delimiters
----------
The *starting* and *closing* tags contain a special string called the
delimiter. In this document, all tags are shown using the `%` delimiter, which
is the default. You can, however, change that to your liking. See
https://github.com/mde/ejs#custom-delimiters for more information on how to
change it.
Starting tags
-------------
### `<%=`: Escaped output
The most important thing for a template language is the ability to pass
variables to the template. In EJS, this is done with the `<%=` and `<%-` tags.
`<%=` is the starting tag to use for variables that need to be escaped. If the
specified string contains forbidden characters like `<` and `&`, they are
escaped automatically with HTML codes.
The content of the tag can be any valid JavaScript operators, so tags like
`<%= name ? name : (lastName || 'John Doe') %>` would work as intended.
#### Example
##### EJS
```html
```
### `<%-`: Unescaped output
If your local contains preformatted HTML, you might not want to escape it. In
this case, use the `<%-` tag.
However, always **be 100% sure** the rendered local is sanitized, to prevent
cross-site scripting (XSS) attacks.
#### Example
##### EJS
```html
```
### `<%#`: Comments
The `<%#` starting tag denotes that the statement is a comment that is not to
be executed or rendered in the resulting HTML.
#### Whitespace
The use of `<%#` might cause some useless whitespace, as illustrated by the
example below. You can trim it using the `-%>` ending tag.
#### Example
##### EJS
```html
<%# comment %>
<%# comment -%>
```
##### HTML
```html
```
### `<%`: Scriptlets
Scriptlets in the `<%` tag allows logic to be embedded in an EJS template. You
are free to use *any* JavaScript syntax in this tag, and to mix JavaScript
with EJS. You can also put multiple statements in one tag.
#### Comments
All types of JavaScript comments are allowed, although it is preferable to use
the `<%#` tag for comments. For example, the following three code blocks are
equivalent, though `<%#` is the shortest.
```js
<%# comment %>
<%/* comment */%>
<%// comment %>
```
#### Curly brackets
Always use brackets in loops and conditionals that involves mixing EJS
template and JavaScript scriptlets. Omitting brackets might work for some
statements, but the behavior is undefined and subject to change.
It is not necessary to use curly brackets for scriptlet-only code.
```html
<%# Bad practice %>
<% if (true) %>
Yay it's true!
<%# Good practice %>
<% if (true) { %>
Yay it's true!
<% } %>
```
```js
<%# These are all valid statements %>
<% var output
, exclamation = ''
, shouldOutput = false
if (true)
output = 'true!'
if (true) {
exclamation = 'Yay! ';
}
if (true) shouldOutput = true; %>
<% if (shouldOutput) { %>
<%= exclamation + 'It\'s ' + output %>
<% } %>
```
#### Line breaks inside a tag
Line breaks are allowed in `<%` tags.
Unless the statement involves mixing EJS and JavaScript scriptlet, always put
complete statements in a tag. For example, the following works:
```js
<% var stringToShow = thisIsABooleanVariableWithAVeryLongName
? 'OK'
: 'not OK' %>
```
While the following does not:
```js
<% var stringToShow = thisIsABooleanVariableWithAVeryLongName %>
<% ? 'OK' %>
<% : 'not OK' %>
```
#### Semicolons
As is in JavaScript, semicolons are not required if proper line breaks are
preserved.
#### Whitespace
The use of scriptlets might cause some useless whitespace, as illustrated by
the example below. You can trim it by
1. using the `-%>` ending tag, and
2. using the `<%_` starting tag or starting the tag in the beginning of a line.
#### Example
In the following example, several different coding styles are used
simultaneously, to show that EJS is flexible with regards to personal habits.
It does *not* mean that we recommend mixing coding styles in your own project.
##### EJS
```html
<%for (var i = 0; i < users.length; i++) { %><%
var user = users[i]
, name = user.name // the name of the user
%><%# comment %>
<%var age = user.age; /* the age of the user */%>
```
### `<%_` "Whitespace Slurping" Scriptlet
This tag is the same as a Scriptlet, except that it removes all whitespace before it.
#### Example
##### EJS
```html
<% users.forEach(function(user, i, arr){ -%>
<%= user %>
<% }); -%>
<%_ users.forEach(function(user, i, arr){ -%>
<%= user %>
<%_ }); -%>
```
##### HTML
```html
Anne
Bob
Anne
Bob
```
Ending tags
-----------
There are three flavors of ending tags: the regular one, the
newline-trimming one, and the whitespace-slurping one.
### `%>`: Regular ending tag
As used in all of the examples above, `%>` is the standard tag used to end an
EJS expression.
### `-%>`: Newline-trimming ending tag
`-%>` trims all extra newlines a scriptlet or a comment might cause. It does
not have any effect on output tags.
#### Example
##### EJS
```html
Beginning of template
<% 'this is a statement'
+ ' that is long'
+ ' and long'
+ ' and long' %>
End of template
---
Beginning of template
<% 'this is a statement'
+ ' that is long'
+ ' and long'
+ ' and long' -%>
End of template
```
##### Output
```html
Beginning of template
End of template
---
Beginning of template
End of template
```
### `_%>`: Whitespace-slurping ending tag
`_%>` removes all whitespace after it.
Literal tags
------------
To output literal `<%` or `%>`, use `<%%` or `%%>`, respectively. If a customized delimiter is used, use
the same syntax. E.g. use `<$$` to get `<$` if the delimiter is `$`.
In regards to all the other tags, the literal tags are special as they do not
need a closing tag to function.
However, think twice before you use these tags because `<` and `>` characters might
need to be escaped as `<` and `>`, respectively.
#### Example
The following example wrap `<%` and `%>` in a `
`, where it is not necessary to
escape `<` or `>` at all.
##### EJS
```html
This is literal: <%%
This is literal too: <%% %>
This is literal as well: %%>
```
##### HTML
```html
This is literal: <%
This is literal too: <% %>
This is literal as well: %>
```
## Including other files
EJS offer two ways of including other files. You can even include files that
are not EJS templates, as the case is for CSS stylesheets.
For both flavors, if the file specified does not have an extension, `.ejs` is
automatically appended. If it is an absolute path, that file is included.
Otherwise, the file is assumed to be in the same directory as the parent
template.
The behavior of resolving included file path can be overridden using the
`ejs.resolveInclude` function.
### “Preprocessor” directive
As a compatibility layer with EJS version 1, it is possible to use the
`include` directive in an unescaped output tag to directly “yank” the
text from another file, just like including a C header. However, as it is done
as a simple inclusion, you cannot pass arguments to the included template. You
can however make variables available in the parent template, that will be
visible to the child template as well.
This flavor of `include` is **static**, which means that the resulting
function contains the copy of the included file as when it was compiled, so
if you changed the file after compilation, the changes are not reflected.
#### Whitespace control
You most probably should not use the `-%>` ending tag on an `include`
directive, as it trims the whitespace after the included file.
#### Example
##### included.ejs
```html
<%= pet.name %>
```
##### main.ejs
```html
<% pets.forEach(function (pet) { -%>
<% include included %>
<% }) -%>
```
### JavaScript `include()` function
With the release of EJS version 2, we have added a new way of including files
that is more intuitive. The `include()` function is available to the
templates, with the following signature:
```js
include(filename, [locals])
```
One major difference with the method described above is that the variables in
the parent function are not visible to the child template, unless it is
explicitly declared in the `locals` object, or is passed as a local to the
parent template.
Also, the included file is compiled upon execution of the script, which means
performance might be theoretically lower than the “preprocessor” flavor. In
practice however, caching can make this difference negligible.
Some cautions **MUST** to be taken if the included filename is fetched from a
user during rendering time, as one could easily use private files as the file
name, like `/etc/passwd` or `../api-keys`.
#### Example
This has the exact same effect as the example for the `include` directive.
##### included.ejs
```html
<%= user.name %> is a <%= user.age %> year old <%= user.species %>.
<% } %>
<% users.map(user) %>
ejs-2.5.7/examples/functions.js 0000664 0000000 0000000 00000000756 13137251263 0016505 0 ustar 00root root 0000000 0000000 /*
* Believe it or not, you can declare and use functions in EJS templates too.
*/
var ejs = require('../');
var read = require('fs').readFileSync;
var join = require('path').join;
var path = join(__dirname, '/functions.ejs');
var data = {
users: [
{ name: 'Tobi', age: 2, species: 'ferret' },
{ name: 'Loki', age: 2, species: 'ferret' },
{ name: 'Jane', age: 6, species: 'ferret' }
]
};
var ret = ejs.compile(read(path, 'utf8'), {filename: path})(data);
console.log(ret);
ejs-2.5.7/examples/list.ejs 0000664 0000000 0000000 00000000353 13137251263 0015606 0 ustar 00root root 0000000 0000000 <% if (names.length) { %>
<% names.forEach(function (name) { %>
<%# Notice how the single quotation mark is escaped in the output HTML %>
'><%= name %>
<% }) %>
<% } %>
ejs-2.5.7/examples/list.js 0000664 0000000 0000000 00000000515 13137251263 0015441 0 ustar 00root root 0000000 0000000 /*
* This example demonstrates how to use Array.prototype.forEach() in an EJS
* template.
*/
var ejs = require('../');
var read = require('fs').readFileSync;
var join = require('path').join;
var str = read(join(__dirname, '/list.ejs'), 'utf8');
var ret = ejs.compile(str)({
names: ['foo', 'bar', 'baz']
});
console.log(ret);
ejs-2.5.7/jsdoc.json 0000664 0000000 0000000 00000000457 13137251263 0014314 0 ustar 00root root 0000000 0000000 {
"_comment": "Configuration file for JSDoc."
, "tags": {
"allowUnknownTags": true
}
, "source": {
"includePattern": ".+\\.js(doc)?$"
, "excludePattern": "(^|\\/|\\\\)_"
}
, "plugins": [ "plugins/markdown" ]
, "templates": {
"cleverLinks": true
, "monospaceLinks": false
}
}
ejs-2.5.7/lib/ 0000775 0000000 0000000 00000000000 13137251263 0013057 5 ustar 00root root 0000000 0000000 ejs-2.5.7/lib/ejs.js 0000775 0000000 0000000 00000057124 13137251263 0014212 0 ustar 00root root 0000000 0000000 /*
* EJS Embedded JavaScript templates
* Copyright 2112 Matthew Eernisse (mde@fleegix.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
'use strict';
/**
* @file Embedded JavaScript templating engine. {@link http://ejs.co}
* @author Matthew Eernisse
* @author Tiancheng "Timothy" Gu
* @project EJS
* @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0}
*/
/**
* EJS internal functions.
*
* Technically this "module" lies in the same file as {@link module:ejs}, for
* the sake of organization all the private functions re grouped into this
* module.
*
* @module ejs-internal
* @private
*/
/**
* Embedded JavaScript templating engine.
*
* @module ejs
* @public
*/
var fs = require('fs');
var path = require('path');
var utils = require('./utils');
var scopeOptionWarned = false;
var _VERSION_STRING = require('../package.json').version;
var _DEFAULT_DELIMITER = '%';
var _DEFAULT_LOCALS_NAME = 'locals';
var _NAME = 'ejs';
var _REGEX_STRING = '(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)';
var _OPTS = ['delimiter', 'scope', 'context', 'debug', 'compileDebug',
'client', '_with', 'rmWhitespace', 'strict', 'filename'];
// We don't allow 'cache' option to be passed in the data obj
// for the normal `render` call, but this is where Express puts it
// so we make an exception for `renderFile`
var _OPTS_EXPRESS = _OPTS.concat('cache');
var _BOM = /^\uFEFF/;
/**
* EJS template function cache. This can be a LRU object from lru-cache NPM
* module. By default, it is {@link module:utils.cache}, a simple in-process
* cache that grows continuously.
*
* @type {Cache}
*/
exports.cache = utils.cache;
/**
* Custom file loader. Useful for template preprocessing or restricting access
* to a certain part of the filesystem.
*
* @type {fileLoader}
*/
exports.fileLoader = fs.readFileSync;
/**
* Name of the object containing the locals.
*
* This variable is overridden by {@link Options}`.localsName` if it is not
* `undefined`.
*
* @type {String}
* @public
*/
exports.localsName = _DEFAULT_LOCALS_NAME;
/**
* Get the path to the included file from the parent file path and the
* specified path.
*
* @param {String} name specified path
* @param {String} filename parent file path
* @param {Boolean} isDir parent file path whether is directory
* @return {String}
*/
exports.resolveInclude = function(name, filename, isDir) {
var dirname = path.dirname;
var extname = path.extname;
var resolve = path.resolve;
var includePath = resolve(isDir ? filename : dirname(filename), name);
var ext = extname(name);
if (!ext) {
includePath += '.ejs';
}
return includePath;
};
/**
* Get the path to the included file by Options
*
* @param {String} path specified path
* @param {Options} options compilation options
* @return {String}
*/
function getIncludePath(path, options) {
var includePath;
var filePath;
var views = options.views;
// Abs path
if (path.charAt(0) == '/') {
includePath = exports.resolveInclude(path.replace(/^\/*/,''), options.root || '/', true);
}
// Relative paths
else {
// Look relative to a passed filename first
if (options.filename) {
filePath = exports.resolveInclude(path, options.filename);
if (fs.existsSync(filePath)) {
includePath = filePath;
}
}
// Then look in any views directories
if (!includePath) {
if (Array.isArray(views) && views.some(function (v) {
filePath = exports.resolveInclude(path, v, true);
return fs.existsSync(filePath);
})) {
includePath = filePath;
}
}
if (!includePath) {
throw new Error('Could not find include include file.');
}
}
return includePath;
}
/**
* Get the template from a string or a file, either compiled on-the-fly or
* read from cache (if enabled), and cache the template if needed.
*
* If `template` is not set, the file specified in `options.filename` will be
* read.
*
* If `options.cache` is true, this function reads the file from
* `options.filename` so it must be set prior to calling this function.
*
* @memberof module:ejs-internal
* @param {Options} options compilation options
* @param {String} [template] template source
* @return {(TemplateFunction|ClientFunction)}
* Depending on the value of `options.client`, either type might be returned.
* @static
*/
function handleCache(options, template) {
var func;
var filename = options.filename;
var hasTemplate = arguments.length > 1;
if (options.cache) {
if (!filename) {
throw new Error('cache option requires a filename');
}
func = exports.cache.get(filename);
if (func) {
return func;
}
if (!hasTemplate) {
template = fileLoader(filename).toString().replace(_BOM, '');
}
}
else if (!hasTemplate) {
// istanbul ignore if: should not happen at all
if (!filename) {
throw new Error('Internal EJS error: no file name or template '
+ 'provided');
}
template = fileLoader(filename).toString().replace(_BOM, '');
}
func = exports.compile(template, options);
if (options.cache) {
exports.cache.set(filename, func);
}
return func;
}
/**
* Try calling handleCache with the given options and data and call the
* callback with the result. If an error occurs, call the callback with
* the error. Used by renderFile().
*
* @memberof module:ejs-internal
* @param {Options} options compilation options
* @param {Object} data template data
* @param {RenderFileCallback} cb callback
* @static
*/
function tryHandleCache(options, data, cb) {
var result;
try {
result = handleCache(options)(data);
}
catch (err) {
return cb(err);
}
return cb(null, result);
}
/**
* fileLoader is independent
*
* @param {String} filePath ejs file path.
* @return {String} The contents of the specified file.
* @static
*/
function fileLoader(filePath){
return exports.fileLoader(filePath);
}
/**
* Get the template function.
*
* If `options.cache` is `true`, then the template is cached.
*
* @memberof module:ejs-internal
* @param {String} path path for the specified file
* @param {Options} options compilation options
* @return {(TemplateFunction|ClientFunction)}
* Depending on the value of `options.client`, either type might be returned
* @static
*/
function includeFile(path, options) {
var opts = utils.shallowCopy({}, options);
opts.filename = getIncludePath(path, opts);
return handleCache(opts);
}
/**
* Get the JavaScript source of an included file.
*
* @memberof module:ejs-internal
* @param {String} path path for the specified file
* @param {Options} options compilation options
* @return {Object}
* @static
*/
function includeSource(path, options) {
var opts = utils.shallowCopy({}, options);
var includePath;
var template;
includePath = getIncludePath(path, opts);
template = fileLoader(includePath).toString().replace(_BOM, '');
opts.filename = includePath;
var templ = new Template(template, opts);
templ.generateSource();
return {
source: templ.source,
filename: includePath,
template: template
};
}
/**
* Re-throw the given `err` in context to the `str` of ejs, `filename`, and
* `lineno`.
*
* @implements RethrowCallback
* @memberof module:ejs-internal
* @param {Error} err Error object
* @param {String} str EJS source
* @param {String} filename file name of the EJS file
* @param {String} lineno line number of the error
* @static
*/
function rethrow(err, str, flnm, lineno, esc){
var lines = str.split('\n');
var start = Math.max(lineno - 3, 0);
var end = Math.min(lines.length, lineno + 3);
var filename = esc(flnm); // eslint-disable-line
// Error context
var context = lines.slice(start, end).map(function (line, i){
var curr = i + start + 1;
return (curr == lineno ? ' >> ' : ' ')
+ curr
+ '| '
+ line;
}).join('\n');
// Alter exception message
err.path = filename;
err.message = (filename || 'ejs') + ':'
+ lineno + '\n'
+ context + '\n\n'
+ err.message;
throw err;
}
function stripSemi(str){
return str.replace(/;(\s*$)/, '$1');
}
/**
* Compile the given `str` of ejs into a template function.
*
* @param {String} template EJS template
*
* @param {Options} opts compilation options
*
* @return {(TemplateFunction|ClientFunction)}
* Depending on the value of `opts.client`, either type might be returned.
* @public
*/
exports.compile = function compile(template, opts) {
var templ;
// v1 compat
// 'scope' is 'context'
// FIXME: Remove this in a future version
if (opts && opts.scope) {
if (!scopeOptionWarned){
console.warn('`scope` option is deprecated and will be removed in EJS 3');
scopeOptionWarned = true;
}
if (!opts.context) {
opts.context = opts.scope;
}
delete opts.scope;
}
templ = new Template(template, opts);
return templ.compile();
};
/**
* Render the given `template` of ejs.
*
* If you would like to include options but not data, you need to explicitly
* call this function with `data` being an empty object or `null`.
*
* @param {String} template EJS template
* @param {Object} [data={}] template data
* @param {Options} [opts={}] compilation and rendering options
* @return {String}
* @public
*/
exports.render = function (template, d, o) {
var data = d || {};
var opts = o || {};
// No options object -- if there are optiony names
// in the data, copy them to options
if (arguments.length == 2) {
utils.shallowCopyFromList(opts, data, _OPTS);
}
return handleCache(opts, template)(data);
};
/**
* Render an EJS file at the given `path` and callback `cb(err, str)`.
*
* If you would like to include options but not data, you need to explicitly
* call this function with `data` being an empty object or `null`.
*
* @param {String} path path to the EJS file
* @param {Object} [data={}] template data
* @param {Options} [opts={}] compilation and rendering options
* @param {RenderFileCallback} cb callback
* @public
*/
exports.renderFile = function () {
var filename = arguments[0];
var cb = arguments[arguments.length - 1];
var opts = {filename: filename};
var data;
if (arguments.length > 2) {
data = arguments[1];
// No options object -- if there are optiony names
// in the data, copy them to options
if (arguments.length === 3) {
// Express 4
if (data.settings) {
if (data.settings['view options']) {
utils.shallowCopyFromList(opts, data.settings['view options'], _OPTS_EXPRESS);
}
if (data.settings.views) {
opts.views = data.settings.views;
}
}
// Express 3 and lower
else {
utils.shallowCopyFromList(opts, data, _OPTS_EXPRESS);
}
}
else {
// Use shallowCopy so we don't pollute passed in opts obj with new vals
utils.shallowCopy(opts, arguments[2]);
}
opts.filename = filename;
}
else {
data = {};
}
return tryHandleCache(opts, data, cb);
};
/**
* Clear intermediate JavaScript cache. Calls {@link Cache#reset}.
* @public
*/
exports.clearCache = function () {
exports.cache.reset();
};
function Template(text, opts) {
opts = opts || {};
var options = {};
this.templateText = text;
this.mode = null;
this.truncate = false;
this.currentLine = 1;
this.source = '';
this.dependencies = [];
options.client = opts.client || false;
options.escapeFunction = opts.escape || utils.escapeXML;
options.compileDebug = opts.compileDebug !== false;
options.debug = !!opts.debug;
options.filename = opts.filename;
options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
options.strict = opts.strict || false;
options.context = opts.context;
options.cache = opts.cache || false;
options.rmWhitespace = opts.rmWhitespace;
options.root = opts.root;
options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
options.views = opts.views;
if (options.strict) {
options._with = false;
}
else {
options._with = typeof opts._with != 'undefined' ? opts._with : true;
}
this.opts = options;
this.regex = this.createRegex();
}
Template.modes = {
EVAL: 'eval',
ESCAPED: 'escaped',
RAW: 'raw',
COMMENT: 'comment',
LITERAL: 'literal'
};
Template.prototype = {
createRegex: function () {
var str = _REGEX_STRING;
var delim = utils.escapeRegExpChars(this.opts.delimiter);
str = str.replace(/%/g, delim);
return new RegExp(str);
},
compile: function () {
var src;
var fn;
var opts = this.opts;
var prepended = '';
var appended = '';
var escapeFn = opts.escapeFunction;
if (!this.source) {
this.generateSource();
prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n';
if (opts._with !== false) {
prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
appended += ' }' + '\n';
}
appended += ' return __output.join("");' + '\n';
this.source = prepended + this.source + appended;
}
if (opts.compileDebug) {
src = 'var __line = 1' + '\n'
+ ' , __lines = ' + JSON.stringify(this.templateText) + '\n'
+ ' , __filename = ' + (opts.filename ?
JSON.stringify(opts.filename) : 'undefined') + ';' + '\n'
+ 'try {' + '\n'
+ this.source
+ '} catch (e) {' + '\n'
+ ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
+ '}' + '\n';
}
else {
src = this.source;
}
if (opts.client) {
src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;
if (opts.compileDebug) {
src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;
}
}
if (opts.strict) {
src = '"use strict";\n' + src;
}
if (opts.debug) {
console.log(src);
}
try {
fn = new Function(opts.localsName + ', escapeFn, include, rethrow', src);
}
catch(e) {
// istanbul ignore else
if (e instanceof SyntaxError) {
if (opts.filename) {
e.message += ' in ' + opts.filename;
}
e.message += ' while compiling ejs\n\n';
e.message += 'If the above error is not helpful, you may want to try EJS-Lint:\n';
e.message += 'https://github.com/RyanZim/EJS-Lint';
}
throw e;
}
if (opts.client) {
fn.dependencies = this.dependencies;
return fn;
}
// Return a callable function which will execute the function
// created by the source-code, with the passed data as locals
// Adds a local `include` function which allows full recursive include
var returnedFn = function (data) {
var include = function (path, includeData) {
var d = utils.shallowCopy({}, data);
if (includeData) {
d = utils.shallowCopy(d, includeData);
}
return includeFile(path, opts)(d);
};
return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]);
};
returnedFn.dependencies = this.dependencies;
return returnedFn;
},
generateSource: function () {
var opts = this.opts;
if (opts.rmWhitespace) {
// Have to use two separate replace here as `^` and `$` operators don't
// work well with `\r`.
this.templateText =
this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, '');
}
// Slurp spaces and tabs before <%_ and after _%>
this.templateText =
this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>');
var self = this;
var matches = this.parseTemplateText();
var d = this.opts.delimiter;
if (matches && matches.length) {
matches.forEach(function (line, index) {
var opening;
var closing;
var include;
var includeOpts;
var includeObj;
var includeSrc;
// If this is an opening tag, check for closing tags
// FIXME: May end up with some false positives here
// Better to store modes as k/v with '<' + delimiter as key
// Then this can simply check against the map
if ( line.indexOf('<' + d) === 0 // If it is a tag
&& line.indexOf('<' + d + d) !== 0) { // and is not escaped
closing = matches[index + 2];
if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) {
throw new Error('Could not find matching close tag for "' + line + '".');
}
}
// HACK: backward-compat `include` preprocessor directives
if ((include = line.match(/^\s*include\s+(\S+)/))) {
opening = matches[index - 1];
// Must be in EVAL or RAW mode
if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) {
includeOpts = utils.shallowCopy({}, self.opts);
includeObj = includeSource(include[1], includeOpts);
if (self.opts.compileDebug) {
includeSrc =
' ; (function(){' + '\n'
+ ' var __line = 1' + '\n'
+ ' , __lines = ' + JSON.stringify(includeObj.template) + '\n'
+ ' , __filename = ' + JSON.stringify(includeObj.filename) + ';' + '\n'
+ ' try {' + '\n'
+ includeObj.source
+ ' } catch (e) {' + '\n'
+ ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
+ ' }' + '\n'
+ ' ; }).call(this)' + '\n';
}else{
includeSrc = ' ; (function(){' + '\n' + includeObj.source +
' ; }).call(this)' + '\n';
}
self.source += includeSrc;
self.dependencies.push(exports.resolveInclude(include[1],
includeOpts.filename));
return;
}
}
self.scanLine(line);
});
}
},
parseTemplateText: function () {
var str = this.templateText;
var pat = this.regex;
var result = pat.exec(str);
var arr = [];
var firstPos;
while (result) {
firstPos = result.index;
if (firstPos !== 0) {
arr.push(str.substring(0, firstPos));
str = str.slice(firstPos);
}
arr.push(result[0]);
str = str.slice(result[0].length);
result = pat.exec(str);
}
if (str) {
arr.push(str);
}
return arr;
},
_addOutput: function (line) {
if (this.truncate) {
// Only replace single leading linebreak in the line after
// -%> tag -- this is the single, trailing linebreak
// after the tag that the truncation mode replaces
// Handle Win / Unix / old Mac linebreaks -- do the \r\n
// combo first in the regex-or
line = line.replace(/^(?:\r\n|\r|\n)/, '');
this.truncate = false;
}
else if (this.opts.rmWhitespace) {
// rmWhitespace has already removed trailing spaces, just need
// to remove linebreaks
line = line.replace(/^\n/, '');
}
if (!line) {
return line;
}
// Preserve literal slashes
line = line.replace(/\\/g, '\\\\');
// Convert linebreaks
line = line.replace(/\n/g, '\\n');
line = line.replace(/\r/g, '\\r');
// Escape double-quotes
// - this will be the delimiter during execution
line = line.replace(/"/g, '\\"');
this.source += ' ; __append("' + line + '")' + '\n';
},
scanLine: function (line) {
var self = this;
var d = this.opts.delimiter;
var newLineCount = 0;
newLineCount = (line.split('\n').length - 1);
switch (line) {
case '<' + d:
case '<' + d + '_':
this.mode = Template.modes.EVAL;
break;
case '<' + d + '=':
this.mode = Template.modes.ESCAPED;
break;
case '<' + d + '-':
this.mode = Template.modes.RAW;
break;
case '<' + d + '#':
this.mode = Template.modes.COMMENT;
break;
case '<' + d + d:
this.mode = Template.modes.LITERAL;
this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n';
break;
case d + d + '>':
this.mode = Template.modes.LITERAL;
this.source += ' ; __append("' + line.replace(d + d + '>', d + '>') + '")' + '\n';
break;
case d + '>':
case '-' + d + '>':
case '_' + d + '>':
if (this.mode == Template.modes.LITERAL) {
this._addOutput(line);
}
this.mode = null;
this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0;
break;
default:
// In script mode, depends on type of tag
if (this.mode) {
// If '//' is found without a line break, add a line break.
switch (this.mode) {
case Template.modes.EVAL:
case Template.modes.ESCAPED:
case Template.modes.RAW:
if (line.lastIndexOf('//') > line.lastIndexOf('\n')) {
line += '\n';
}
}
switch (this.mode) {
// Just executing code
case Template.modes.EVAL:
this.source += ' ; ' + line + '\n';
break;
// Exec, esc, and output
case Template.modes.ESCAPED:
this.source += ' ; __append(escapeFn(' + stripSemi(line) + '))' + '\n';
break;
// Exec and output
case Template.modes.RAW:
this.source += ' ; __append(' + stripSemi(line) + ')' + '\n';
break;
case Template.modes.COMMENT:
// Do nothing
break;
// Literal <%% mode, append as raw output
case Template.modes.LITERAL:
this._addOutput(line);
break;
}
}
// In string mode, just add the output
else {
this._addOutput(line);
}
}
if (self.opts.compileDebug && newLineCount) {
this.currentLine += newLineCount;
this.source += ' ; __line = ' + this.currentLine + '\n';
}
}
};
/**
* Escape characters reserved in XML.
*
* This is simply an export of {@link module:utils.escapeXML}.
*
* If `markup` is `undefined` or `null`, the empty string is returned.
*
* @param {String} markup Input string
* @return {String} Escaped string
* @public
* @func
* */
exports.escapeXML = utils.escapeXML;
/**
* Express.js support.
*
* This is an alias for {@link module:ejs.renderFile}, in order to support
* Express.js out-of-the-box.
*
* @func
*/
exports.__express = exports.renderFile;
// Add require support
/* istanbul ignore else */
if (require.extensions) {
require.extensions['.ejs'] = function (module, flnm) {
var filename = flnm || /* istanbul ignore next */ module.filename;
var options = {
filename: filename,
client: true
};
var template = fileLoader(filename).toString();
var fn = exports.compile(template, options);
module._compile('module.exports = ' + fn.toString() + ';', filename);
};
}
/**
* Version of EJS.
*
* @readonly
* @type {String}
* @public
*/
exports.VERSION = _VERSION_STRING;
/**
* Name for detection of EJS.
*
* @readonly
* @type {String}
* @public
*/
exports.name = _NAME;
/* istanbul ignore if */
if (typeof window != 'undefined') {
window.ejs = exports;
}
ejs-2.5.7/lib/utils.js 0000664 0000000 0000000 00000007336 13137251263 0014566 0 ustar 00root root 0000000 0000000 /*
* EJS Embedded JavaScript templates
* Copyright 2112 Matthew Eernisse (mde@fleegix.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
* Private utility functions
* @module utils
* @private
*/
'use strict';
var regExpChars = /[|\\{}()[\]^$+*?.]/g;
/**
* Escape characters reserved in regular expressions.
*
* If `string` is `undefined` or `null`, the empty string is returned.
*
* @param {String} string Input string
* @return {String} Escaped string
* @static
* @private
*/
exports.escapeRegExpChars = function (string) {
// istanbul ignore if
if (!string) {
return '';
}
return String(string).replace(regExpChars, '\\$&');
};
var _ENCODE_HTML_RULES = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
var _MATCH_HTML = /[&<>\'"]/g;
function encode_char(c) {
return _ENCODE_HTML_RULES[c] || c;
}
/**
* Stringified version of constants used by {@link module:utils.escapeXML}.
*
* It is used in the process of generating {@link ClientFunction}s.
*
* @readonly
* @type {String}
*/
var escapeFuncStr =
'var _ENCODE_HTML_RULES = {\n'
+ ' "&": "&"\n'
+ ' , "<": "<"\n'
+ ' , ">": ">"\n'
+ ' , \'"\': """\n'
+ ' , "\'": "'"\n'
+ ' }\n'
+ ' , _MATCH_HTML = /[&<>\'"]/g;\n'
+ 'function encode_char(c) {\n'
+ ' return _ENCODE_HTML_RULES[c] || c;\n'
+ '};\n';
/**
* Escape characters reserved in XML.
*
* If `markup` is `undefined` or `null`, the empty string is returned.
*
* @implements {EscapeCallback}
* @param {String} markup Input string
* @return {String} Escaped string
* @static
* @private
*/
exports.escapeXML = function (markup) {
return markup == undefined
? ''
: String(markup)
.replace(_MATCH_HTML, encode_char);
};
exports.escapeXML.toString = function () {
return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
};
/**
* Naive copy of properties from one object to another.
* Does not recurse into non-scalar properties
* Does not check to see if the property has a value before copying
*
* @param {Object} to Destination object
* @param {Object} from Source object
* @return {Object} Destination object
* @static
* @private
*/
exports.shallowCopy = function (to, from) {
from = from || {};
for (var p in from) {
to[p] = from[p];
}
return to;
};
/**
* Naive copy of a list of key names, from one object to another.
* Only copies property if it is actually defined
* Does not recurse into non-scalar properties
*
* @param {Object} to Destination object
* @param {Object} from Source object
* @param {Array} list List of properties to copy
* @return {Object} Destination object
* @static
* @private
*/
exports.shallowCopyFromList = function (to, from, list) {
for (var i = 0; i < list.length; i++) {
var p = list[i];
if (typeof from[p] != 'undefined') {
to[p] = from[p];
}
}
return to;
};
/**
* Simple in-process cache implementation. Does not implement limits of any
* sort.
*
* @implements Cache
* @static
* @private
*/
exports.cache = {
_data: {},
set: function (key, val) {
this._data[key] = val;
},
get: function (key) {
return this._data[key];
},
reset: function () {
this._data = {};
}
};
ejs-2.5.7/package.json 0000664 0000000 0000000 00000002074 13137251263 0014602 0 ustar 00root root 0000000 0000000 {
"name": "ejs",
"description": "Embedded JavaScript templates",
"keywords": [
"template",
"engine",
"ejs"
],
"version": "2.5.7",
"author": "Matthew Eernisse (http://fleegix.org)",
"contributors": [
"Timothy Gu (https://timothygu.github.io)"
],
"license": "Apache-2.0",
"main": "./lib/ejs.js",
"repository": {
"type": "git",
"url": "git://github.com/mde/ejs.git"
},
"bugs": "https://github.com/mde/ejs/issues",
"homepage": "https://github.com/mde/ejs",
"dependencies": {},
"devDependencies": {
"browserify": "^13.0.1",
"eslint": "^3.0.0",
"git-directory-deploy": "^1.5.1",
"istanbul": "~0.4.3",
"jake": "^8.0.0",
"jsdoc": "^3.4.0",
"lru-cache": "^4.0.1",
"mocha": "^3.0.2",
"uglify-js": "^2.6.2"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "jake test",
"lint": "eslint \"**/*.js\" Jakefile",
"coverage": "istanbul cover node_modules/mocha/bin/_mocha",
"doc": "jake doc",
"devdoc": "jake doc[dev]"
}
}
ejs-2.5.7/test/ 0000775 0000000 0000000 00000000000 13137251263 0013270 5 ustar 00root root 0000000 0000000 ejs-2.5.7/test/ejs.js 0000775 0000000 0000000 00000102351 13137251263 0014414 0 ustar 00root root 0000000 0000000 /* jshint mocha: true */
/* eslint-env node, mocha */
/**
* Module dependencies.
*/
var ejs = require('..');
var fs = require('fs');
var read = fs.readFileSync;
var assert = require('assert');
var path = require('path');
var LRU = require('lru-cache');
try {
fs.mkdirSync(__dirname + '/tmp');
} catch (ex) {
if (ex.code !== 'EEXIST') {
throw ex;
}
}
// From https://gist.github.com/pguillory/729616
function hook_stdio(stream, callback) {
var old_write = stream.write;
stream.write = (function() {
return function(string, encoding, fd) {
callback(string, encoding, fd);
};
})(stream.write);
return function() {
stream.write = old_write;
};
}
/**
* Load fixture `name`.
*/
function fixture(name) {
return read('test/fixtures/' + name, 'utf8');
}
/**
* User fixtures.
*/
var users = [];
users.push({name: 'geddy'});
users.push({name: 'neil'});
users.push({name: 'alex'});
suite('ejs.compile(str, options)', function () {
test('compile to a function', function () {
var fn = ejs.compile('
yay
');
assert.equal(fn(), '
yay
');
});
test('empty input works', function () {
var fn = ejs.compile('');
assert.equal(fn(), '');
});
test('throw if there are syntax errors', function () {
try {
ejs.compile(fixture('fail.ejs'));
}
catch (err) {
assert.ok(err.message.indexOf('compiling ejs') > -1);
try {
ejs.compile(fixture('fail.ejs'), {filename: 'fail.ejs'});
}
catch (err) {
assert.ok(err.message.indexOf('fail.ejs') > -1);
return;
}
}
throw new Error('no error reported when there should be');
});
test('allow customizing delimiter local var', function () {
var fn;
fn = ejs.compile('