Socket
Socket
Sign inDemoInstall

ssi

Package Overview
Dependencies
6
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.2 to 0.1.3

lib/Conditional.js

360

index.js
var fs = require("fs");
var path = require("path");
var mkdirp = require("mkdirp");
var glob = require("glob");
var SSI = require("./lib/SSI");
var DIRECTIVE_MATCHER = /<!--#([a-z]+)([ ]+([a-z]+)="(.+?)")* -->/g;
var ATTRIBUTE_MATCHER = /([a-z]+)="(.+?)"/g;
var INTERPOLATION_MATCHER = /\$\{(.+?)\}/g;
(function() {
"use strict";
var mergeSimpleObject = function() {
var output = {};
for (var i = 0; i < arguments.length; i++) {
var argument = arguments[i];
for (var key in argument) {
if (argument.hasOwnProperty(key)) {
output[key] = argument[key];
}
}
}
return output;
var ssi = function(inputDirectory, outputDirectory, matcher) {
this.parser = new SSI(inputDirectory, outputDirectory, matcher);
};
var IOUtils = function(documentRoot) {
this.documentRoot = documentRoot;
};
IOUtils.prototype = {
/* Public Methods */
readFileSync: function(currentFile, includeFile) {
var filename = path.resolve(path.dirname(currentFile), includeFile);
return fs.readFileSync(filename, {encoding: "utf8"});
},
readVirtualSync: function(includeFile) {
var filename = path.resolve(this.documentRoot, includeFile);
return fs.readFileSync(filename, {encoding: "utf8"});
},
writeFileSync: function(filename, contents) {
var directory = path.dirname(filename);
if (!fs.existsSync(directory)) {
// If the file's directory doesn't exists, recursively create it
mkdirp.sync(directory);
}
fs.writeFileSync(filename, contents, {encoding: "utf8"});
}
/* Private Methods */
};
var Conditional = function(expression) {
this.expression = expression;
this.directives = [];
};
Conditional.prototype = {
getExpression: function() {
return this.expression;
},
getDirectives: function() {
return this.directives;
},
addDirective: function(directive) {
this.directives.push(directive);
}
};
var DirectiveHandler = function(ioUtils) {
this.ioUtils = ioUtils;
this.conditionals = [];
this.currentConditional = undefined;
};
DirectiveHandler.prototype = {
/* Public Methods */
handleDirective: function(directive, directiveName, currentFile, variables) {
if (this._inConditional()) {
if (!this._isConditional(directiveName)) {
this.currentConditional.addDirective(directive);
return {output: ""};
}
}
var attributes = this._parseAttributes(directive);
function interpolate() {
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[i];
attribute.name = this._interpolate(attribute.name, variables, false);
attribute.value = this._interpolate(attribute.value, variables, false);
}
}
switch (directiveName) {
case "if":
interpolate.apply(this);
return this._handleIf(attributes);
case "elif":
interpolate.apply(this);
return this._handleElseIf(attributes);
case "else":
interpolate.apply(this);
return this._handleElse();
case "endif":
interpolate.apply(this);
return this._handleEndIf(currentFile, variables);
case "set":
interpolate.apply(this);
return this._handleSet(attributes);
case "include":
interpolate.apply(this);
return this._handleInclude(attributes, currentFile);
}
return {error: "Could not find parse directive #" + directiveName};
},
/* Private Methods */
_interpolate: function(string, variables, shouldWrap) {
var instance = this;
return string.replace(INTERPOLATION_MATCHER, function(variable, variableName) {
var value;
// Either return the variable value or the original expression if it doesn't exist
if (variables[variableName] !== undefined) {
value = variables[variableName];
} else if (process.env[variableName] !== undefined) {
value = process.env[variableName];
}
if (value !== undefined) {
if (shouldWrap) {
// Escape all double quotes and wrap the value in double quotes
return instance._wrap(variables[variableName]);
}
return value;
}
return variable;
});
},
_parseAttributes: function(directive) {
var attributes = [];
directive.replace(ATTRIBUTE_MATCHER, function(attribute, name, value) {
attributes.push({name: name, value: value});
});
return attributes;
},
_parseExpression: function(expression) {
if (expression.match(INTERPOLATION_MATCHER)) {
return {error: "Could not resolve all variables"}
}
// Return a boolean for the truthiness of the expression
return {truthy: !!eval(expression)};
},
_wrap: function(value) {
if (this._shouldWrap(value)) {
return "\"" + value.toString().replace(/"/g, "\\\"") + "\"";
}
return value;
},
_shouldWrap: function(value) {
var type = typeof value;
return (type !== "boolean" && type !== "number");
},
_handleSet: function(attributes) {
if (attributes.length === 2 && attributes[0].name === "var" &&
attributes[1].name === "value") {
return {variables: [{
name: attributes[0].value,
value: attributes[1].value
}]};
}
return {error: "Directive #set did not contain a 'var' and 'value' attribute"};
},
_handleInclude: function(attributes, currentFile) {
if (attributes.length === 1) {
var attribute = attributes[0];
var output = undefined;
if (attribute.name === "file") {
output = this.ioUtils.readFileSync(currentFile, attribute.value);
} else if (attribute.name === "virtual") {
output = this.ioUtils.readVirtualSync(attribute.value);
}
// TODO: Parse included file here
return {output: output};
}
return {error: "Directive #include did not contain a 'file' or 'virtual' attribute"};
},
_handleIf: function(attributes) {
if (attributes.length === 1 && attributes[0].name === "expr") {
// Create a new conditional, put it on the stack and assign as current conditional
var conditional = new Conditional(attributes[0].value);
this.conditionals.push(conditional);
this.currentConditional = conditional;
return {output: ""};
}
return {error: "If does not have a single 'expr' attribute"};
},
_handleElseIf: function(attributes) {
if (attributes.length === 1 && attributes[0].name === "expr") {
if (!this._inConditional()) {
return {error: "Elif while not inside of If block"};
}
var conditional = new Conditional(attributes[0].value);
this.conditionals.push(conditional);
this.currentConditional = conditional;
return {output: ""};
}
return {error: "Elif does not have a single 'expr' attribute"};
},
_handleElse: function() {
if (!this._inConditional()) {
return {error: "Else while not inside of If block"};
}
// As a hack, just provide an always true expression
var conditional = new Conditional("true");
this.conditionals.push(conditional);
this.currentConditional = conditional;
return {output: ""};
},
_handleEndIf: function(currentFile, pageVariables) {
if (!this._inConditional()) {
return {error: "Endif while not inside of If block"};
}
for (var i = 0; i < this.conditionals.length; i++) {
var conditional = this.conditionals[i];
var variables = {};
// Find the first conditional that is true
if (this._parseExpression(conditional.getExpression()).truthy) {
var directiveHandler = new DirectiveHandler(this.ioUtils);
var output = {output: "", variables: {}};
// Iterate over the directives contained by the conditional, and parse them
for (var j = 0; j < conditional.getDirectives().length; j++) {
var directive = conditional.getDirectives()[j];
// We can assume this matches the directive format
var directiveName = DIRECTIVE_MATCHER.exec(directive)[1];
var results = directiveHandler.handleDirective(directive, directiveName, currentFile,
mergeSimpleObject(variables, pageVariables));
output.output += results.output || "";
output.variables = mergeSimpleObject(output.variables, results.variables || {});
}
this.conditionals = [];
this.currentConditional = undefined;
return output;
}
}
this.conditionals = [];
this.currentConditional = undefined;
return {output: ""};
},
_isConditional: function(directive) {
return (directive === "if" || directive === "elif" || directive === "else" || directive === "endif");
},
_inConditional: function() {
return this.conditionals.length > 0;
}
};
var ssi = function(inputDirectory, outputDirectory, matcher) {
this.inputDirectory = inputDirectory;
this.documentRoot = inputDirectory;
this.outputDirectory = outputDirectory;
this.matcher = matcher;
this.ioUtils = new IOUtils(this.documentRoot);
this.directiveHandler = new DirectiveHandler(this.ioUtils);
};
ssi.prototype = {
/* Public Methods */
compile: function() {
var files = glob.sync(this.inputDirectory + this.matcher);
for (var i = 0; i < files.length; i++) {
var input = files[i];
var contents = fs.readFileSync(input, {encoding: "utf8"});
var data = this.parse(input, contents);
var output = input.replace(this.inputDirectory, this.outputDirectory);
this.ioUtils.writeFileSync(output, data.contents);
}
return this.parser.compile();
},
parse: function(filename, contents) {
var instance = this;
var variables = {};
contents = contents.replace(DIRECTIVE_MATCHER, function(directive, directiveName) {
var data = instance.directiveHandler.handleDirective(directive, directiveName, filename, variables);
if (data.error) throw data.error;
for (var key in data.variables) {
if (data.variables.hasOwnProperty(key)) {
variables[data.variables[key].name] = data.variables[key].value;
}
}
return (data && data.output) || "";
});
return {contents: contents, variables: variables};
return this.parser.parse(filename, contents);
}
/* Private Methods */
};

@@ -371,2 +22,1 @@

})();
{
"name": "ssi",
"version": "0.1.2",
"version": "0.1.3",
"description": "Server Side Includes for NodeJS",

@@ -5,0 +5,0 @@ "author": "Glenn Nelson <glenn@hexcoder.us> (glenn@hexcoder.us)",

var assert = require("assert");
var ssi = require("../index.js");
var SSI = require("../lib/SSI");
describe("testing conditional directives", function() {
var parser = new ssi("", "", "");
var parser = new SSI("", "", "");

@@ -23,2 +23,3 @@ it("#if should evaluate to true", function() {

var results = parser.parse("", conditional);
assert.equal("elif", results.variables["elif"]);

@@ -25,0 +26,0 @@ });

var fs = require("fs");
var assert = require("assert");
var ssi = require("../index.js");
function buildIncludeFile(file) {
return "<!--#include file=\"" + file + "\" -->";
}
describe("#include file", function() {

@@ -13,13 +11,9 @@ var parser = new ssi("test/html", "/tmp/out", "");

it("file-same should contain \"LEVEL2\"", function() {
var results = parser.parse("test/html/level1/level2/file-same.shtml", buildIncludeFile("level2.html"));
var filename = "test/html/level1/level2/file-same.shtml";
var contents = fs.readFileSync(filename, {encoding: "utf8"});
var results = parser.parse(filename, contents);
assert.equal("LEVEL2\n", results.contents);
assert.equal("LEVEL2\n\n", results.contents);
});
it("file-relative should contain \"LEVEL1\"", function() {
var results = parser.parse("test/html/level1/level2/file-relative.shtml", buildIncludeFile("../level1.html"));
assert.equal("LEVEL1\n", results.contents);
});
});
var fs = require("fs");
var assert = require("assert");
var ssi = require("../index.js");
function buildIncludeVirtual(virtual) {
return "<!--#include virtual=\"" + virtual + "\" -->";
}
describe("#include virtual", function() {
var parser = new ssi("test/html", "", "");
it("virtual-same should contain \"ROOT\"", function() {
var results = parser.parse("test/html/level1/level2/virtual-same.shtml", buildIncludeVirtual("root.html"));
it("virtual-same should contain \"LEVEL2\"", function() {
var filename = "test/html/level1/level2/virtual-same.shtml";
var contents = fs.readFileSync(filename, {encoding: "utf8"});
var results = parser.parse(filename, contents);
assert.equal("ROOT\n", results.contents);
assert.equal("LEVEL2\n\n", results.contents);
});
it("virtual-relative should contain \"LEVEL1\"", function() {
var results = parser.parse("test/html/level1/level2/virtual-relative.shtml", buildIncludeVirtual("level1/level1.html"));
var filename = "test/html/level1/level2/virtual-relative.shtml";
var contents = fs.readFileSync(filename, {encoding: "utf8"});
var results = parser.parse(filename, contents);
assert.equal("LEVEL1\n", results.contents);
assert.equal("LEVEL1\n\n", results.contents);
});
it("virtual-absolute should contain \"ROOT\"", function() {
var filename = "test/html/level1/level2/virtual-absolute.shtml";
var contents = fs.readFileSync(filename, {encoding: "utf8"});
var results = parser.parse(filename, contents);
assert.equal("ROOT\n\n", results.contents);
});
});
var assert = require("assert");
var ssi = require("../index.js");
var SSI = require("../lib/SSI.js");
describe("testing conditional expressions", function() {
var parser = new ssi("", "", "").directiveHandler;
var parser = new SSI("", "", "").directiveHandler;
var variables = {

@@ -8,0 +8,0 @@ "true": true,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc