pax_global_header00006660000000000000000000000064131372512630014515gustar00rootroot0000000000000052 comment=67ca0a80a5a68277774c693204ce49ef11bb84b4 ejs-2.5.7/000077500000000000000000000000001313725126300123115ustar00rootroot00000000000000ejs-2.5.7/.eslintignore000066400000000000000000000000411313725126300150070ustar00rootroot00000000000000coverage out /ejs.js /ejs.min.js ejs-2.5.7/.eslintrc.json000066400000000000000000000013051313725126300151040ustar00rootroot00000000000000{ "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/.gitignore000066400000000000000000000004351313725126300143030ustar00rootroot00000000000000# 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/.jshintignore000066400000000000000000000000541313725126300150140ustar00rootroot00000000000000node_modules coverage out ejs.js ejs.min.js ejs-2.5.7/.jshintrc000066400000000000000000000003141313725126300141340ustar00rootroot00000000000000{ "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/.npmignore000066400000000000000000000003241313725126300143070ustar00rootroot00000000000000test/ # 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.yml000066400000000000000000000000771313725126300144260ustar00rootroot00000000000000language: node_js sudo: false node_js: - "4" - "6" - "8" ejs-2.5.7/CHANGELOG.md000066400000000000000000000143541313725126300141310ustar00rootroot00000000000000## 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.md000066400000000000000000000045211313725126300151120ustar00rootroot00000000000000# 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/Jakefile000066400000000000000000000035571313725126300137600ustar00rootroot00000000000000var 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/LICENSE000066400000000000000000000261361313725126300133260ustar00rootroot00000000000000 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.md000066400000000000000000000213161313725126300135730ustar00rootroot00000000000000# EJS Embedded JavaScript templates [![Build Status](https://img.shields.io/travis/mde/ejs/master.svg?style=flat)](https://travis-ci.org/mde/ejs) [![Developing Dependencies](https://img.shields.io/david/dev/mde/ejs.svg?style=flat)](https://david-dm.org/mde/ejs?type=dev) [![Known Vulnerabilities](https://snyk.io/test/npm/ejs/badge.svg?style=flat-square)](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: 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/000077500000000000000000000000001313725126300142435ustar00rootroot00000000000000ejs-2.5.7/benchmark/bench-ejs.js.bak000077500000000000000000000137211313725126300172020ustar00rootroot00000000000000'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: `

<$= name $>

<%- num+1 -%>
<% if(num > 10) { %> <$= cheese $> <% } %> <%# comment #%> <%% literal <$= name $> %%> `, bench2: `

<$= name $>

<%- num+1 -%>
<% if(num > 10) { %> <$= cheese $> <% } %> <%# comment #%> <%% literal <$= name $> %%> `.repeat(100), simple1: `

<$= name $>

<%- num+1 -%>
`, locals1: `

<$= locals.name $>

<%- locals.num+1 -%>
<% if(locals.num > 10) { %> <$= locals.cheese $> <% } %> <%# comment #%> <%% literal <$= locals.name $> %%> `.repeat(10), include1: `

<$= name $>

<% include('/simple1') %>
<% include('/simple1') %>
<% include('/simple1') %>
`, include2: `

<$= name $>

<% include /include1 %>
<% include /simple1 %>
`, }; 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/000077500000000000000000000000001313725126300132415ustar00rootroot00000000000000ejs-2.5.7/docs/jsdoc/000077500000000000000000000000001313725126300143435ustar00rootroot00000000000000ejs-2.5.7/docs/jsdoc/cache.jsdoc000066400000000000000000000014431313725126300164340ustar00rootroot00000000000000/** * 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.jsdoc000066400000000000000000000004241313725126300173060ustar00rootroot00000000000000/** * 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.jsdoc000066400000000000000000000005441313725126300174400ustar00rootroot00000000000000/** * 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.jsdoc000066400000000000000000000044671313725126300170750ustar00rootroot00000000000000/** * 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.jsdoc000066400000000000000000000037121313725126300212130ustar00rootroot00000000000000/** * 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.md000066400000000000000000000305301313725126300151120ustar00rootroot00000000000000EJS 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:
<starting content closing>
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

Hello, <%= name %>.

Hello, <%= 'the Most Honorable ' + name %>.

``` ##### Locals ```json { "name": "Timoth" } ``` ##### HTML ```html

Hello, Timoth<y>.

Hello, the Most Honorable Timoth<y>.

``` ### `<%-`: 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

Hello, <%- myHtml %>.

Hello, <%= myHtml %>.

Hello, <%- myMaliciousHtml %>.

Hello, <%= myMaliciousHtml %>.

``` ##### Locals ```json { "myHtml": "Timothy" , "myMaliciousHtml": "

" } ``` ##### HTML ```html

Hello, Timothy.

Hello, <strong>Timothy</strong>.

Hello,

.

Hello, </p><script>document.write()</script><p>.

``` ### `<%#`: 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 */%>
<%= name %>
<%= age %>
<%}-%>
``` ##### Locals ```json { "users": [ { "name": "Timothy" , "age": 15 } , { "name": "Juan" , "age": 51 } ] } ``` ##### HTML ```html
Timothy
15
Juan
51
``` ### `<%_` "Whitespace Slurping" Scriptlet This tag is the same as a Scriptlet, except that it removes all whitespace before it. #### Example ##### EJS ```html ``` ##### HTML ```html ``` 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 %> <% }) -%>
    ``` ##### Locals ```json { "pets": [ { "name": "Hazel" } , { "name": "Crystal" } , { "name": "Catcher" } ] } ``` ##### “Preprocessor" output ```js
      <% pets.forEach(function (pet) { -%>
    • <%= pet.name %>
    • <% }) -%>
    ``` ##### HTML ```html
    • Hazel
    • Crystal
    • Catcher
    ``` ### 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
  • <%= pet.name %>
  • ``` ##### main.ejs ```html
      <% pets.forEach(function (pet) { -%> <%- include('included', { pet: pet }) %> <% }) -%>
    ``` ##### Locals ```json { "pets": [ { "name": "Hazel" } , { "name": "Crystal" } , { "name": "Catcher" } ] } ``` ##### HTML ```html
    • Hazel
    • Crystal
    • Catcher
    ``` ## Copyright This document is under the following license: Copyright © 2015 Tiancheng “Timothy” Gu 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/examples/000077500000000000000000000000001313725126300141275ustar00rootroot00000000000000ejs-2.5.7/examples/client-compilation.html000066400000000000000000000101711313725126300206070ustar00rootroot00000000000000 EJS compilation demo

    Input template

    Compilation options (JSON)

    Locals (JSON)

    Output

    
    
        
        
      
    
    ejs-2.5.7/examples/client-injection.html000066400000000000000000000027541313725126300202630ustar00rootroot00000000000000
    
    
      
        
        
        
        
      
      
      
    
    ejs-2.5.7/examples/functions.ejs000066400000000000000000000002701313725126300166410ustar00rootroot00000000000000

    Users

    <% function user(user) { %>
  • <%= user.name %> is a <%= user.age %> year old <%= user.species %>.
  • <% } %>
      <% users.map(user) %>
    ejs-2.5.7/examples/functions.js000066400000000000000000000007561313725126300165050ustar00rootroot00000000000000/* * 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.ejs000066400000000000000000000003531313725126300156060ustar00rootroot00000000000000<% 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.js000066400000000000000000000005151313725126300154410ustar00rootroot00000000000000/* * 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.json000066400000000000000000000004571313725126300143140ustar00rootroot00000000000000{ "_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/000077500000000000000000000000001313725126300130575ustar00rootroot00000000000000ejs-2.5.7/lib/ejs.js000077500000000000000000000571241313725126300142120ustar00rootroot00000000000000/* * 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.js000066400000000000000000000073361313725126300145660ustar00rootroot00000000000000/* * 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.json000066400000000000000000000020741313725126300146020ustar00rootroot00000000000000{ "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/000077500000000000000000000000001313725126300132705ustar00rootroot00000000000000ejs-2.5.7/test/ejs.js000077500000000000000000001023511313725126300144140ustar00rootroot00000000000000/* 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('

    ', {delimiter: '?'}); assert.equal(fn({name: 'geddy'}), '

    geddy

    '); fn = ejs.compile('

    <:= name :>

    ', {delimiter: ':'}); assert.equal(fn({name: 'geddy'}), '

    geddy

    '); fn = ejs.compile('

    <$= name $>

    ', {delimiter: '$'}); assert.equal(fn({name: 'geddy'}), '

    geddy

    '); }); test('default to using ejs.delimiter', function () { var fn; ejs.delimiter = '&'; fn = ejs.compile('

    <&= name &>

    '); assert.equal(fn({name: 'geddy'}), '

    geddy

    '); fn = ejs.compile('

    <|= name |>

    ', {delimiter: '|'}); assert.equal(fn({name: 'geddy'}), '

    geddy

    '); delete ejs.delimiter; }); test('support custom escape function', function () { var customEscape; var fn; customEscape = function customEscape(str) { return !str ? '' : str.toUpperCase(); }; fn = ejs.compile('HELLO <%= name %>', {escape: customEscape}); assert.equal(fn({name: 'world'}), 'HELLO WORLD'); }); test('strict mode works', function () { assert.equal(ejs.render(fixture('strict.ejs'), {}, {strict: true}), 'true'); }); }); suite('client mode', function () { test('have a working client option', function () { var fn; var str; var preFn; fn = ejs.compile('

    <%= foo %>

    ', {client: true}); str = fn.toString(); if (!process.env.running_under_istanbul) { eval('var preFn = ' + str); assert.equal(preFn({foo: 'bar'}), '

    bar

    '); } }); test('support client mode without locals', function () { var fn; var str; var preFn; fn = ejs.compile('

    <%= "foo" %>

    ', {client: true}); str = fn.toString(); if (!process.env.running_under_istanbul) { eval('var preFn = ' + str); assert.equal(preFn(), '

    foo

    '); } }); test('not include rethrow() in client mode if compileDebug is false', function () { var fn = ejs.compile('

    <%= "foo" %>

    ', { client: true, compileDebug: false }); // There could be a `rethrow` in the function declaration assert((fn.toString().match(/rethrow/g) || []).length <= 1); }); test('support custom escape function in client mode', function () { var customEscape; var fn; var str; customEscape = function customEscape(str) { return !str ? '' : str.toUpperCase(); }; fn = ejs.compile('HELLO <%= name %>', {escape: customEscape, client: true}); str = fn.toString(); if (!process.env.running_under_istanbul) { eval('var preFn = ' + str); assert.equal(preFn({name: 'world'}), 'HELLO WORLD'); // eslint-disable-line no-undef } }); test('escape filename in errors in client mode', function () { assert.throws(function () { var fn = ejs.compile('<% throw new Error("whoops"); %>', {client: true, filename: '