Added skeleton support for evaluated macro parameters

This commit is contained in:
Jeremy Ruston 2011-12-21 16:54:51 +00:00
parent 02a2630dd6
commit 4c11503bae
6 changed files with 121 additions and 40 deletions

View File

@ -14,7 +14,11 @@ Options and their defaults are:
defaultName: null,
defaultValue: null,
noNames: false,
cascadeDefaults: false
cascadeDefaults: false,
allowEval: true
globals: null
`globals` is the global variable object provided to evaluated parameters
\*/
(function(){
@ -22,23 +26,26 @@ Options and their defaults are:
/*jslint node: true */
"use strict";
var Sandbox = require("./Sandbox.js").Sandbox;
var ArgParser = function(argString,options) {
var parseToken = function(match,p) {
var n;
if(match[p]) // Double quoted
n = match[p];
else if(match[p+1]) // Single quoted
n = match[p+1];
else if(match[p+2]) // Double-square-bracket quoted
n = match[p+2];
else if(match[p+3]) // Double-brace quoted
n = match[p+3];
else if(match[p+4]) // Unquoted
n = match[p+4];
else if(match[p+5]) // empty quote
n = "";
return n;
};
var n;
if(match[p]) { // Double quoted
n = match[p];
} else if(match[p+1]) { // Single quoted
n = match[p+1];
} else if(match[p+2]) { // Double-square-bracket quoted
n = match[p+2];
} else if(match[p+3]) { // Double-brace quoted
n = options.allowEval === false ? match[p+3] : Sandbox(match[p+3],options.globals);
} else if(match[p+4]) { // Unquoted
n = match[p+4];
} else if(match[p+5]) { // empty quote
n = "";
}
return n;
};
this.byPos = [];
var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")",
sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')",

53
js/Sandbox.js Normal file
View File

@ -0,0 +1,53 @@
/*\
title: js/Sandbox.js
Execute a fragment of JavaScript in a sandbox
\*/
(function(){
/*jslint node: true */
"use strict";
var uglify = require("uglify-js");
var safeEval = function(e) {
return eval(e);
};
var Sandbox = function(code,globals) {
var globalNames = [],
globalValues = [],
collectGlobals = function(globals) {
if(globals) {
for(var g in globals) {
globalNames.push(g);
globalValues.push(globals[g]);
}
}
};
// Collect the supplied globals
collectGlobals(globals);
// Add the default globals
collectGlobals({
tiddlywiki: "5"
});
// Compose the code
var out = [];
out.push("(function(")
out.push(globalNames.join(","));
out.push(") { return ");
out.push(code);
out.push(";})");
// Parse the code
var tree = uglify.parser.parse(out.join(""));
// XXX: Sanitise the code by checking for references to globals
// Recompile the code
var compiledCode = uglify.uglify.gen_code(tree);
// Execute it
return eval(compiledCode).apply(null,globalValues);
};
exports.Sandbox = Sandbox;
})();

View File

@ -129,7 +129,19 @@ WikiTextRenderer.prototype.executeMacro = function(macroNode,title) {
var macroInfo = WikiTextRenderer.macros[macroNode.name];
macroNode.output = [];
if(macroInfo) {
macroInfo.handler.call(this,macroNode,title);
var args;
if(macroInfo.argOptions) {
var argOptions = {
globals: {
title: title
}
};
for(var g in macroInfo.argOptions) {
argOptions[g] = macroInfo.argOptions[g];
}
args = new ArgParser(macroNode.params,argOptions);
}
macroInfo.handler.call(this,macroNode,args,title);
} else {
macroNode.output.push({type: "text", value: "Unknown macro " + macroNode.name});
}
@ -139,18 +151,25 @@ WikiTextRenderer.versionTiddlyWiki = "2.6.5";
WikiTextRenderer.macros = {
allTags: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
}
},
br: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
macroNode.output.push({type: "br"});
}
},
echo: {
argOptions: {defaultName: "anon"},
handler: function(macroNode,args,title) {
var globals = {title: title};
macroNode.output.push({type: "text", value: args.byPos[0].v});
}
},
timeline: {
handler: function(macroNode,title) {
var args = new ArgParser(macroNode.params,{defaultName:"anon"}),
anonByPos = args.getValuesByName("anon",[]),
argOptions: {defaultName:"anon"},
handler: function(macroNode,args,title) {
var anonByPos = args.getValuesByName("anon",[]),
field = anonByPos[0] || "modified",
limit = anonByPos[1] || null,
dateformat = anonByPos[2] || "DD MMM YYYY",
@ -214,9 +233,9 @@ WikiTextRenderer.macros = {
}
},
list: {
handler: function(macroNode,title) {
var args = new ArgParser(macroNode.params,{defaultName:"type"}),
type = args.getValueByName("type","all"),
argOptions: {defaultName:"type"},
handler: function(macroNode,args,title) {
var type = args.getValueByName("type","all"),
template = args.getValueByName("template",null),
templateType = "text/x-tiddlywiki", templateText = "<<view title link>>",
emptyMessage = args.getValueByName("emptyMessage",null);
@ -275,29 +294,29 @@ WikiTextRenderer.macros = {
}
},
slider: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
}
},
tabs: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
}
},
tag: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
}
},
tagging: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
}
},
tags: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
}
},
tiddler: {
handler: function(macroNode,title) {
var args = new ArgParser(macroNode.params,{defaultName:"name",cascadeDefaults:true}),
targetTitle = args.getValueByName("name",null),
argOptions: {defaultName:"name",cascadeDefaults:true},
handler: function(macroNode,args,title) {
var targetTitle = args.getValueByName("name",null),
withTokens = args.getValuesByName("with",[]),
tiddler = this.store.getTiddler(targetTitle),
text = this.store.getTiddlerText(targetTitle,""),
@ -312,22 +331,22 @@ WikiTextRenderer.macros = {
}
},
today: {
handler: function(macroNode,title) {
argOptions: {noNames:true},
handler: function(macroNode,args,title) {
var now = new Date(),
args = new ArgParser(macroNode.params,{noNames:true}),
value = args.byPos[0] ? utils.formatDateString(now,args.byPos[0].v) : now.toLocaleString();
macroNode.output.push({type: "text", value: value});
}
},
version: {
handler: function(macroNode,title) {
handler: function(macroNode,args,title) {
macroNode.output.push({type: "text", value: WikiTextRenderer.versionTiddlyWiki});
}
},
view: {
handler: function(macroNode,title) {
var args = new ArgParser(macroNode.params,{noNames:true}),
field = args.byPos[0] ? args.byPos[0].v : null,
argOptions: {noNames:true},
handler: function(macroNode,args,title) {
var field = args.byPos[0] ? args.byPos[0].v : null,
format = args.byPos[1] ? args.byPos[1].v : "text",
tiddler = this.store.getTiddler(title),
value = tiddler ? tiddler.fields[field] : null;

View File

@ -7,7 +7,6 @@
Given the absolute path of a srcModule, and a relative reference to a dstModule, return the fully resolved module name
*/
function resolveModuleName(srcModule,dstModule) {
console.log("Resolving " + dstModule + " in the context of " + srcModule);
var src = srcModule.split("/"),
dst = dstModule.split("/"),
c;

View File

@ -8,3 +8,5 @@ TiddlyWiki is a unique [[wiki|WikiWikiWeb]] that people [[love using|Raves]] to
TiddlyWiki is written in [[HTML]], [[CSS]] and JavaScript to run on any reasonably modern [[browser|Browsers]] without needing any ServerSide logic. It allows anyone to create personal SelfContained hypertext documents that can be published to a WebServer, sent by email, stored in a DropBox or kept on a USB thumb drive to make a WikiOnAStick. Because it doesn't need to be installed and configured it makes a great GuerillaWiki. This is revision <<version>> of TiddlyWiki, and is published under an OpenSourceLicense.
Unlike most wikis, TiddlyWiki doesn't directly support group collaboration; it is a wiki in the sense of elevating linking be a part of the punctuation of writing. You can easily publish a TiddlyWiki you have created by placing the single file on a web server (for instance the homepage hosting provided by many ISPs). If you need full group collaboration features, there are several HostedOptions to choose from.
<<echo {{2+2 /* something */ - 3 * 17 + title + tiddlywiki + out.length}}>>

View File

@ -9,6 +9,7 @@ recipe: tiddlers/split.recipe
jslib: ../test/tiddlywiki.2.6.5/source/tiddlywiki/jquery/jquery.js
jsmodule: ../js/Sandbox.js
jsmodule: ../js/ArgParser.js
jsmodule: ../js/FileRetriever.js
jsmodule: ../js/Utils.js