New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@hapify/ejs

Package Overview
Dependencies
Maintainers
2
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@hapify/ejs - npm Package Compare versions

Comparing version
0.4.1
to
1.0.0
+16
CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file. See
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# @hapify/ejs 1.0.0 (2021-04-16)
### Bug Fixes
* **ejs:** remove repository ([ecfd351](https://github.com/hapify/hapify/commit/ecfd3519dfb433d19928defd4a49f0bf5287d0c8))
### Features
* add ejs package ([#15](https://github.com/hapify/hapify/issues/15)) ([b8fe5f7](https://github.com/hapify/hapify/commit/b8fe5f7eae35dd1c6296c7e10e7b0dacc43cee02))
export declare class EjsEvaluationError extends Error {
code: number;
name: string;
lineNumber: number;
details: string;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EjsEvaluationError = void 0;
class EjsEvaluationError extends Error {
constructor() {
super(...arguments);
this.code = 7001;
this.name = 'EjsEvaluationError';
this.lineNumber = null;
this.details = null;
}
}
exports.EjsEvaluationError = EjsEvaluationError;
//# sourceMappingURL=EjsEvaluationError.js.map
{"version":3,"file":"EjsEvaluationError.js","sourceRoot":"","sources":["../../src/errors/EjsEvaluationError.ts"],"names":[],"mappings":";;;AAAA,MAAa,kBAAmB,SAAQ,KAAK;IAA7C;;QACE,SAAI,GAAG,IAAI,CAAC;QAEZ,SAAI,GAAG,oBAAoB,CAAC;QAE5B,eAAU,GAAW,IAAI,CAAC;QAE1B,YAAO,GAAW,IAAI,CAAC;IACzB,CAAC;CAAA;AARD,gDAQC"}

Sorry, the diff of this file is not supported yet

+2
-7

@@ -0,10 +1,6 @@

import { EjsEvaluationError } from './errors/EjsEvaluationError';
interface HapifyEJSOptions {
timeout: number;
}
export declare class EjsEvaluationError extends Error {
code: number;
name: string;
lineNumber: number;
details: string;
}
export { EjsEvaluationError };
export declare class HapifyEJS {

@@ -27,2 +23,1 @@ /** Default options */

}
export {};

@@ -7,19 +7,13 @@ "use strict";

exports.HapifyEJS = exports.EjsEvaluationError = void 0;
const vm_1 = require("@hapify/vm");
const fs_1 = require("fs");
const path_1 = require("path");
const vm_1 = require("@hapify/vm");
const pkg_dir_1 = __importDefault(require("pkg-dir"));
const EjsEvaluationError_1 = require("./errors/EjsEvaluationError");
Object.defineProperty(exports, "EjsEvaluationError", { enumerable: true, get: function () { return EjsEvaluationError_1.EjsEvaluationError; } });
const SECOND = 1000;
const RootDir = pkg_dir_1.default.sync(__dirname);
const EjsLibContent = fs_1.readFileSync(path_1.join(RootDir, 'libs', 'ejs.js'), { encoding: 'utf8' });
class EjsEvaluationError extends Error {
constructor() {
super(...arguments);
this.code = 7001;
this.name = 'EjsEvaluationError';
this.lineNumber = null;
this.details = null;
}
}
exports.EjsEvaluationError = EjsEvaluationError;
const EjsLibContent = fs_1.readFileSync(path_1.join(RootDir, 'libs', 'ejs.js'), {
encoding: 'utf8',
});
class HapifyEJS {

@@ -32,3 +26,3 @@ /** Constructor */

};
this.options = Object.assign({}, this.defaultOptions, options);
this.options = Object.assign(Object.assign({}, this.defaultOptions), options);
}

@@ -50,3 +44,3 @@ /** Wrap content in ejs compiler */

const wrappedContent = this.wrapWithEjs(content);
const options = Object.assign({}, this.options, { eval: true });
const options = Object.assign(Object.assign({}, this.options), { eval: true });
const vm = new vm_1.HapifyVM(options);

@@ -71,5 +65,7 @@ let result;

const lineNumberMatches = /Error: ejs:([0-9]+)/.exec(lines[0]);
const lineNumber = lineNumberMatches ? Number(lineNumberMatches[1]) : null;
const lineNumber = lineNumberMatches
? Number(lineNumberMatches[1])
: null;
const details = lines.join('\n').trim();
const ejsError = new EjsEvaluationError(lastLine);
const ejsError = new EjsEvaluationError_1.EjsEvaluationError(lastLine);
ejsError.details = details;

@@ -76,0 +72,0 @@ ejsError.lineNumber = lineNumber;

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,mCAAuD;AACvD,2BAAkC;AAClC,+BAA4B;AAC5B,sDAA6B;AAE7B,MAAM,MAAM,GAAG,IAAI,CAAC;AACpB,MAAM,OAAO,GAAG,iBAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACvC,MAAM,aAAa,GAAG,iBAAY,CAAC,WAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AAM1F,MAAa,kBAAmB,SAAQ,KAAK;IAA7C;;QACC,SAAI,GAAG,IAAI,CAAC;QACZ,SAAI,GAAG,oBAAoB,CAAC;QAC5B,eAAU,GAAW,IAAI,CAAC;QAC1B,YAAO,GAAW,IAAI,CAAC;IACxB,CAAC;CAAA;AALD,gDAKC;AAED,MAAa,SAAS;IAQrB,kBAAkB;IAClB,YAAY,UAAqC,EAAE;QARnD,sBAAsB;QACd,mBAAc,GAAqB;YAC1C,OAAO,EAAE,MAAM;SACf,CAAC;QAMD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAChE,CAAC;IAED,mCAAmC;IAC3B,WAAW,CAAC,OAAe;QAClC,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACnD,OAAO,GAAG,aAAa;oBACL,cAAc;;GAE/B,CAAC;IACH,CAAC;IAED,iCAAiC;IACzB,aAAa,CAAC,OAAe;QACpC,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,sBAAsB;IACtB,GAAG,CAAC,OAAe,EAAE,OAA+B;QACnD,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,EAAE,GAAG,IAAI,aAAQ,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,MAAM,CAAC;QAEX,IAAI;YACH,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;SAC7C;QAAC,OAAO,KAAK,EAAE;YACf,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;SACpC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAEO,iBAAiB,CAAC,KAA8B;QACvD,IAAI,KAAK,YAAY,oBAAe,EAAE;YACrC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;gBAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAExC,MAAM,QAAQ,GAAG,KAAK;qBACpB,GAAG,EAAE;qBACL,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;qBAC9C,IAAI,EAAE,CAAC;gBAET,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC/D,MAAM,UAAU,GAAG,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAE3E,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;gBAExC,MAAM,QAAQ,GAAG,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC;gBAClD,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;gBAC3B,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;gBAEjC,OAAO,QAAQ,CAAC;aAChB;SACD;QACD,OAAO,KAAK,CAAC;IACd,CAAC;CACD;AAnED,8BAmEC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,2BAAkC;AAClC,+BAA4B;AAE5B,mCAAuD;AACvD,sDAA6B;AAE7B,oEAAiE;AAYxD,mGAZA,uCAAkB,OAYA;AAV3B,MAAM,MAAM,GAAG,IAAI,CAAC;AACpB,MAAM,OAAO,GAAG,iBAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACvC,MAAM,aAAa,GAAG,iBAAY,CAAC,WAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE;IAClE,QAAQ,EAAE,MAAM;CACjB,CAAC,CAAC;AAQH,MAAa,SAAS;IASpB,kBAAkB;IAClB,YAAY,UAAqC,EAAE;QATnD,sBAAsB;QACd,mBAAc,GAAqB;YACzC,OAAO,EAAE,MAAM;SAChB,CAAC;QAOA,IAAI,CAAC,OAAO,mCAAQ,IAAI,CAAC,cAAc,GAAK,OAAO,CAAE,CAAC;IACxD,CAAC;IAED,mCAAmC;IAC3B,WAAW,CAAC,OAAe;QACjC,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACnD,OAAO,GAAG,aAAa;oBACP,cAAc;;GAE/B,CAAC;IACF,CAAC;IAED,iCAAiC;IACzB,aAAa,CAAC,OAAe;QACnC,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;IAED,sBAAsB;IACtB,GAAG,CAAC,OAAe,EAAE,OAA+B;QAClD,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,OAAO,mCAAQ,IAAI,CAAC,OAAO,KAAE,IAAI,EAAE,IAAI,GAAE,CAAC;QAChD,MAAM,EAAE,GAAG,IAAI,aAAQ,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,MAAM,CAAC;QAEX,IAAI;YACF,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;SAC9C;QAAC,OAAO,KAAK,EAAE;YACd,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;SACrC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,iBAAiB,CACvB,KAA8B;QAE9B,IAAI,KAAK,YAAY,oBAAe,EAAE;YACpC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;gBAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAExC,MAAM,QAAQ,GAAG,KAAK;qBACnB,GAAG,EAAE;qBACL,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;qBAC9C,IAAI,EAAE,CAAC;gBAEV,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC/D,MAAM,UAAU,GAAG,iBAAiB;oBAClC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;oBAC9B,CAAC,CAAC,IAAI,CAAC;gBAET,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;gBAExC,MAAM,QAAQ,GAAG,IAAI,uCAAkB,CAAC,QAAQ,CAAC,CAAC;gBAClD,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;gBAC3B,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;gBAEjC,OAAO,QAAQ,CAAC;aACjB;SACF;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAxED,8BAwEC"}
+404
-410
// This is a minimalist version of EJS 3.1.5 without usage of require, cache or filesystem
//==========================================================================

@@ -21,15 +20,15 @@ // utils.js

utils.escapeRegExpChars = function (string) {
// istanbul ignore if
if (!string) {
return '';
}
return String(string).replace(regExpChars, '\\$&');
// istanbul ignore if
if (!string) {
return '';
}
return String(string).replace(regExpChars, '\\$&');
};
const _ENCODE_HTML_RULES = {
'&': '&',
'<': '&lt;',
'>': '&gt;',
'"': '&#34;',
"'": '&#39;'
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&#34;',
"'": '&#39;',
};

@@ -39,3 +38,3 @@ const _MATCH_HTML = /[&<>'"]/g;

function encode_char(c) {
return _ENCODE_HTML_RULES[c] || c;
return _ENCODE_HTML_RULES[c] || c;
}

@@ -53,13 +52,13 @@

const escapeFuncStr =
'const _ENCODE_HTML_RULES = {\n'
+ ' "&": "&amp;"\n'
+ ' , "<": "&lt;"\n'
+ ' , ">": "&gt;"\n'
+ ' , \'"\': "&#34;"\n'
+ ' , "\'": "&#39;"\n'
+ ' }\n'
+ ' , _MATCH_HTML = /[&<>\'"]/g;\n'
+ 'function encode_char(c) {\n'
+ ' return _ENCODE_HTML_RULES[c] || c;\n'
+ '};\n';
'const _ENCODE_HTML_RULES = {\n' +
' "&": "&amp;"\n' +
' , "<": "&lt;"\n' +
' , ">": "&gt;"\n' +
' , \'"\': "&#34;"\n' +
' , "\'": "&#39;"\n' +
' }\n' +
' , _MATCH_HTML = /[&<>\'"]/g;\n' +
'function encode_char(c) {\n' +
' return _ENCODE_HTML_RULES[c] || c;\n' +
'};\n';

@@ -79,9 +78,6 @@ /**

utils.escapeXML = function (markup) {
return markup == undefined
? ''
: String(markup)
.replace(_MATCH_HTML, encode_char);
return markup == undefined ? '' : String(markup).replace(_MATCH_HTML, encode_char);
};
utils.escapeXML.toString = function () {
return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
};

@@ -94,4 +90,4 @@

*/
utils.basename =function (path) {
return path.split('/').reverse()[0];
utils.basename = function (path) {
return path.split('/').reverse()[0];
};

@@ -104,4 +100,4 @@

*/
utils.extname = function(filename) {
return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename) : undefined;
utils.extname = function (filename) {
return /[.]/.exec(filename) ? /[^.]+$/.exec(filename) : undefined;
};

@@ -136,27 +132,24 @@

function rethrow(err, str, flnm, lineno, esc) {
const lines = str.split('\n');
const start = Math.max(lineno - 3, 0);
const end = Math.min(lines.length, lineno + 3);
const filename = esc(flnm);
// Error context
const context = lines.slice(start, end).map(function (line, i){
const curr = i + start + 1;
return (curr == lineno ? ' >> ' : ' ')
+ curr
+ '| '
+ line;
}).join('\n');
const lines = str.split('\n');
const start = Math.max(lineno - 3, 0);
const end = Math.min(lines.length, lineno + 3);
const filename = esc(flnm);
// Error context
const context = lines
.slice(start, end)
.map(function (line, i) {
const 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;
// Alter exception message
err.path = filename;
err.message = (filename || 'ejs') + ':' + lineno + '\n' + context + '\n\n' + err.message;
throw err;
throw err;
}
function stripSemi(str){
return str.replace(/;(\s*$)/, '$1');
function stripSemi(str) {
return str.replace(/;(\s*$)/, '$1');
}

@@ -178,19 +171,19 @@

ejs.compile = function compile(template, opts) {
let templ;
let 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();
// 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();
};

@@ -205,379 +198,380 @@

function Template(text, opts) {
opts = opts || {};
const options = {};
this.templateText = text;
/** @type {string | null} */
this.mode = null;
this.truncate = false;
this.currentLine = 1;
this.source = '';
options.client = opts.client || false;
options.escapeFunction = opts.escape || opts.escapeFunction || utils.escapeXML;
options.compileDebug = opts.compileDebug !== false;
options.debug = !!opts.debug;
options.filename = opts.filename;
options.openDelimiter = opts.openDelimiter || _DEFAULT_OPEN_DELIMITER;
options.closeDelimiter = opts.closeDelimiter || _DEFAULT_CLOSE_DELIMITER;
options.delimiter = opts.delimiter || _DEFAULT_DELIMITER;
options.strict = opts.strict || false;
options.context = opts.context;
options.rmWhitespace = opts.rmWhitespace;
options.root = opts.root;
options.includer = opts.includer;
options.outputFunctionName = opts.outputFunctionName;
options.localsName = opts.localsName || _DEFAULT_LOCALS_NAME;
options.views = opts.views;
options.async = opts.async;
options.destructuredLocals = opts.destructuredLocals;
options.legacyInclude = typeof opts.legacyInclude != 'undefined' ? !!opts.legacyInclude : true;
opts = opts || {};
const options = {};
this.templateText = text;
/** @type {string | null} */
this.mode = null;
this.truncate = false;
this.currentLine = 1;
this.source = '';
options.client = opts.client || false;
options.escapeFunction = opts.escape || opts.escapeFunction || utils.escapeXML;
options.compileDebug = opts.compileDebug !== false;
options.debug = !!opts.debug;
options.filename = opts.filename;
options.openDelimiter = opts.openDelimiter || _DEFAULT_OPEN_DELIMITER;
options.closeDelimiter = opts.closeDelimiter || _DEFAULT_CLOSE_DELIMITER;
options.delimiter = opts.delimiter || _DEFAULT_DELIMITER;
options.strict = opts.strict || false;
options.context = opts.context;
options.rmWhitespace = opts.rmWhitespace;
options.root = opts.root;
options.includer = opts.includer;
options.outputFunctionName = opts.outputFunctionName;
options.localsName = opts.localsName || _DEFAULT_LOCALS_NAME;
options.views = opts.views;
options.async = opts.async;
options.destructuredLocals = opts.destructuredLocals;
options.legacyInclude = typeof opts.legacyInclude != 'undefined' ? !!opts.legacyInclude : true;
if (options.strict) {
options._with = false;
}
else {
options._with = typeof opts._with != 'undefined' ? opts._with : true;
}
if (options.strict) {
options._with = false;
} else {
options._with = typeof opts._with != 'undefined' ? opts._with : true;
}
this.opts = options;
this.opts = options;
this.regex = this.createRegex();
this.regex = this.createRegex();
}
Template.modes = {
EVAL: 'eval',
ESCAPED: 'escaped',
RAW: 'raw',
COMMENT: 'comment',
LITERAL: 'literal'
EVAL: 'eval',
ESCAPED: 'escaped',
RAW: 'raw',
COMMENT: 'comment',
LITERAL: 'literal',
};
Template.prototype = {
createRegex: function () {
let str = _REGEX_STRING;
const delim = utils.escapeRegExpChars(this.opts.delimiter);
const open = utils.escapeRegExpChars(this.opts.openDelimiter);
const close = utils.escapeRegExpChars(this.opts.closeDelimiter);
str = str.replace(/%/g, delim)
.replace(/</g, open)
.replace(/>/g, close);
return new RegExp(str);
},
createRegex: function () {
let str = _REGEX_STRING;
const delim = utils.escapeRegExpChars(this.opts.delimiter);
const open = utils.escapeRegExpChars(this.opts.openDelimiter);
const close = utils.escapeRegExpChars(this.opts.closeDelimiter);
str = str.replace(/%/g, delim).replace(/</g, open).replace(/>/g, close);
return new RegExp(str);
},
compile: function () {
/** @type {string} */
let src;
/** @type {ClientFunction} */
let fn;
const opts = this.opts;
let prepended = '';
let appended = '';
/** @type {EscapeCallback} */
const escapeFn = opts.escapeFunction;
/** @type {FunctionConstructor} */
let ctor;
compile: function () {
/** @type {string} */
let src;
/** @type {ClientFunction} */
let fn;
const opts = this.opts;
let prepended = '';
let appended = '';
/** @type {EscapeCallback} */
const escapeFn = opts.escapeFunction;
/** @type {FunctionConstructor} */
let ctor;
if (!this.source) {
this.generateSource();
prepended +=
' let __output = "";\n' +
' function __append(s) { if (s !== undefined && s !== null) __output += s }\n';
if (opts.outputFunctionName) {
prepended += ' let ' + opts.outputFunctionName + ' = __append;' + '\n';
}
if (opts.destructuredLocals && opts.destructuredLocals.length) {
let destructuring = ' let __locals = (' + opts.localsName + ' || {}),\n';
for (let i = 0; i < opts.destructuredLocals.length; i++) {
const name = opts.destructuredLocals[i];
if (i > 0) {
destructuring += ',\n ';
}
destructuring += name + ' = __locals.' + name;
}
prepended += destructuring + ';\n';
}
if (opts._with !== false) {
prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
appended += ' }' + '\n';
}
appended += ' return __output;' + '\n';
this.source = prepended + this.source + appended;
}
if (!this.source) {
this.generateSource();
prepended += ' let __output = "";\n' + ' function __append(s) { if (s !== undefined && s !== null) __output += s }\n';
if (opts.outputFunctionName) {
prepended += ' let ' + opts.outputFunctionName + ' = __append;' + '\n';
}
if (opts.destructuredLocals && opts.destructuredLocals.length) {
let destructuring = ' let __locals = (' + opts.localsName + ' || {}),\n';
for (let i = 0; i < opts.destructuredLocals.length; i++) {
const name = opts.destructuredLocals[i];
if (i > 0) {
destructuring += ',\n ';
}
destructuring += name + ' = __locals.' + name;
}
prepended += destructuring + ';\n';
}
if (opts._with !== false) {
prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
appended += ' }' + '\n';
}
appended += ' return __output;' + '\n';
this.source = prepended + this.source + appended;
}
if (opts.compileDebug) {
src = 'let __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.compileDebug) {
src =
'let __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.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);
}
if (opts.compileDebug && opts.filename) {
src = src + '\n'
+ '//# sourceURL=' + opts.filename + '\n';
}
if (opts.strict) {
src = '"use strict";\n' + src;
}
if (opts.debug) {
console.log(src);
}
if (opts.compileDebug && opts.filename) {
src = src + '\n' + '//# sourceURL=' + opts.filename + '\n';
}
try {
if (opts.async) {
// Have to use generated function for this, since in envs without support,
// it breaks in parsing
try {
ctor = (new Function('return (async function(){}).constructor;'))();
}
catch(e) {
if (e instanceof SyntaxError) {
throw new Error('This environment does not support async/await');
}
else {
throw e;
}
}
}
else {
ctor = Function;
}
fn = new ctor(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';
if (!opts.async) {
e.message += '\n';
e.message += 'Or, if you meant to create an async function, pass `async: true` as an option.';
}
}
throw e;
}
try {
if (opts.async) {
// Have to use generated function for this, since in envs without support,
// it breaks in parsing
try {
ctor = new Function('return (async function(){}).constructor;')();
} catch (e) {
if (e instanceof SyntaxError) {
throw new Error('This environment does not support async/await');
} else {
throw e;
}
}
} else {
ctor = Function;
}
fn = new ctor(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';
if (!opts.async) {
e.message += '\n';
e.message += 'Or, if you meant to create an async function, pass `async: true` as an option.';
}
}
throw e;
}
// 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
const returnedFn = opts.client ? fn : function anonymous(data) {
const include = function (path, includeData) {
throw new Error('Cannot use include');
};
return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]);
};
if (opts.filename && typeof Object.defineProperty === 'function') {
const filename = opts.filename;
const basename = utils.basename(filename, utils.extname(filename));
try {
Object.defineProperty(returnedFn, 'name', {
value: basename,
writable: false,
enumerable: false,
configurable: true
});
} catch (e) {/* ignore */}
}
return returnedFn;
},
// 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
const returnedFn = opts.client
? fn
: function anonymous(data) {
const include = function (path, includeData) {
throw new Error('Cannot use include');
};
return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]);
};
if (opts.filename && typeof Object.defineProperty === 'function') {
const filename = opts.filename;
const basename = utils.basename(filename, utils.extname(filename));
try {
Object.defineProperty(returnedFn, 'name', {
value: basename,
writable: false,
enumerable: false,
configurable: true,
});
} catch (e) {
/* ignore */
}
}
return returnedFn;
},
generateSource: function () {
const opts = this.opts;
generateSource: function () {
const opts = this.opts;
if (opts.rmWhitespace) {
// Have to use two separate replace here as `^` and `$` operators don't
// work well with `\r` and empty lines don't work well with the `m` flag.
this.templateText =
this.templateText.replace(/[\r\n]+/g, '\n').replace(/^\s+|\s+$/gm, '');
}
if (opts.rmWhitespace) {
// Have to use two separate replace here as `^` and `$` operators don't
// work well with `\r` and empty lines don't work well with the `m` flag.
this.templateText = this.templateText.replace(/[\r\n]+/g, '\n').replace(/^\s+|\s+$/gm, '');
}
// Slurp spaces and tabs before <%_ and after _%>
this.templateText =
this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>');
// Slurp spaces and tabs before <%_ and after _%>
this.templateText = this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>');
const self = this;
const matches = this.parseTemplateText();
const d = this.opts.delimiter;
const o = this.opts.openDelimiter;
const c = this.opts.closeDelimiter;
const self = this;
const matches = this.parseTemplateText();
const d = this.opts.delimiter;
const o = this.opts.openDelimiter;
const c = this.opts.closeDelimiter;
if (matches && matches.length) {
matches.forEach(function (line, index) {
let closing;
// 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 openDelimiter + delimiter as key
// Then this can simply check against the map
if ( line.indexOf(o + d) === 0 // If it is a tag
&& line.indexOf(o + d + d) !== 0) { // and is not escaped
closing = matches[index + 2];
if (!(closing == d + c || closing == '-' + d + c || closing == '_' + d + c)) {
throw new Error('Could not find matching close tag for "' + line + '".');
}
}
self.scanLine(line);
});
}
if (matches && matches.length) {
matches.forEach(function (line, index) {
let closing;
// 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 openDelimiter + delimiter as key
// Then this can simply check against the map
if (
line.indexOf(o + d) === 0 && // If it is a tag
line.indexOf(o + d + d) !== 0
) {
// and is not escaped
closing = matches[index + 2];
if (!(closing == d + c || closing == '-' + d + c || closing == '_' + d + c)) {
throw new Error('Could not find matching close tag for "' + line + '".');
}
}
self.scanLine(line);
});
}
},
},
parseTemplateText: function () {
let str = this.templateText;
const pat = this.regex;
let result = pat.exec(str);
const arr = [];
let firstPos;
parseTemplateText: function () {
let str = this.templateText;
const pat = this.regex;
let result = pat.exec(str);
const arr = [];
let firstPos;
while (result) {
firstPos = result.index;
while (result) {
firstPos = result.index;
if (firstPos !== 0) {
arr.push(str.substring(0, firstPos));
str = str.slice(firstPos);
}
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);
}
arr.push(result[0]);
str = str.slice(result[0].length);
result = pat.exec(str);
}
if (str) {
arr.push(str);
}
if (str) {
arr.push(str);
}
return arr;
},
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;
}
if (!line) {
return line;
}
_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;
}
if (!line) {
return line;
}
// Preserve literal slashes
line = line.replace(/\\/g, '\\\\');
// Preserve literal slashes
line = line.replace(/\\/g, '\\\\');
// Convert linebreaks
line = line.replace(/\n/g, '\\n');
line = line.replace(/\r/g, '\\r');
// 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';
},
// Escape double-quotes
// - this will be the delimiter during execution
line = line.replace(/"/g, '\\"');
this.source += ' ; __append("' + line + '")' + '\n';
},
scanLine: function (line) {
const self = this;
const d = this.opts.delimiter;
const o = this.opts.openDelimiter;
const c = this.opts.closeDelimiter;
let newLineCount = 0;
scanLine: function (line) {
const self = this;
const d = this.opts.delimiter;
const o = this.opts.openDelimiter;
const c = this.opts.closeDelimiter;
let newLineCount = 0;
newLineCount = line.split('\n').length - 1;
newLineCount = (line.split('\n').length - 1);
switch (line) {
case o + d:
case o + d + '_':
this.mode = Template.modes.EVAL;
break;
case o + d + '=':
this.mode = Template.modes.ESCAPED;
break;
case o + d + '-':
this.mode = Template.modes.RAW;
break;
case o + d + '#':
this.mode = Template.modes.COMMENT;
break;
case o + d + d:
this.mode = Template.modes.LITERAL;
this.source += ' ; __append("' + line.replace(o + d + d, o + d) + '")' + '\n';
break;
case d + d + c:
this.mode = Template.modes.LITERAL;
this.source += ' ; __append("' + line.replace(d + d + c, d + c) + '")' + '\n';
break;
case d + c:
case '-' + d + c:
case '_' + d + c:
if (this.mode == Template.modes.LITERAL) {
this._addOutput(line);
}
switch (line) {
case o + d:
case o + d + '_':
this.mode = Template.modes.EVAL;
break;
case o + d + '=':
this.mode = Template.modes.ESCAPED;
break;
case o + d + '-':
this.mode = Template.modes.RAW;
break;
case o + d + '#':
this.mode = Template.modes.COMMENT;
break;
case o + d + d:
this.mode = Template.modes.LITERAL;
this.source += ' ; __append("' + line.replace(o + d + d, o + d) + '")' + '\n';
break;
case d + d + c:
this.mode = Template.modes.LITERAL;
this.source += ' ; __append("' + line.replace(d + d + c, d + c) + '")' + '\n';
break;
case d + c:
case '-' + d + c:
case '_' + d + c:
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);
}
}
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';
}
}
if (self.opts.compileDebug && newLineCount) {
this.currentLine += newLineCount;
this.source += ' ; __line = ' + this.currentLine + '\n';
}
},
};
{
"name": "@hapify/ejs",
"version": "0.4.1",
"version": "1.0.0",
"description": "Sandbox for EJS templates",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"update": "npm-check -u",
"test": "nyc mocha",
"lint": "prettier --write '**/*.ts'",
"build": "rimraf dist && tsc -p ."
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com:hapify/ejs.git"
},
"keywords": [

@@ -22,23 +10,29 @@ "hapify",

],
"license": "MIT",
"author": "Edouard Demotes-Mainard <edouard@tractr.net>",
"license": "MIT",
"homepage": "https://github.com/hapify/ejs#readme",
"homepage": "https://github.com/hapify/hapify",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "rimraf dist && tsc -p .",
"clean": "rimraf dist node_modules coverage .nyc_output",
"prepublishOnly": "npm run build",
"lint": "npm run lint:tsc && npm run lint:prettier && npm run lint:eslint",
"lint:eslint": "eslint \"{src,test}/**/*.{ts,js}\"",
"lint:eslint:fix": "npm run lint:eslint -- --fix",
"lint:fix": "npm run lint:tsc:fix && npm run lint:prettier:fix && npm run lint:eslint:fix",
"lint:prettier": "prettier --check \"{src,test}/**/*.{ts,js}\"",
"lint:prettier:fix": "prettier --write \"{src,test}/**/*.{ts,js}\"",
"lint:tsc": "tsc --noEmit",
"lint:tsc:fix": "npm run lint:tsc",
"test": "nyc mocha",
"update": "npm-check -u"
},
"devDependencies": {
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@hapi/code": "^8.0.2",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.22",
"husky": "^4.3.8",
"mocha": "^8.2.1",
"npm-check": "^5.9.2",
"nyc": "^15.1.0",
"prettier": "^2.2.1",
"pretty-quick": "^3.1.0",
"rimraf": "^3.0.2",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
"mocha": "^8.2.1"
},
"dependencies": {
"@hapify/vm": "^0.3.6",
"@hapify/vm": "1.1.0",
"pkg-dir": "^5.0.0"

@@ -48,9 +42,3 @@ },

"node": ">=12"
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-commit": "pretty-quick --staged --pattern \"**/*.ts\""
}
}
}

@@ -7,3 +7,3 @@ # Hapify EJS

[![Build Status](https://travis-ci.org/hapify/ejs.svg?branch=master)](https://travis-ci.org/hapify/ejs) [![codecov](https://codecov.io/gh/hapify/ejs/branch/master/graph/badge.svg)](https://codecov.io/gh/hapify/ejs)
[![Build Status](https://api.travis-ci.com/hapify/ejs.svg?branch=master)](https://api.travis-ci.com/hapify/ejs) [![codecov](https://codecov.io/gh/hapify/ejs/branch/master/graph/badge.svg)](https://codecov.io/gh/hapify/ejs)

@@ -10,0 +10,0 @@ ## Usage