From 4eb464548b6233261074cdf68a10f0af51dd1c97 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Sun, 11 Dec 2011 14:51:48 +0000 Subject: [PATCH] Refactored tiddler serialization and deserialization Introduced TiddlerConverters, a sort of factory for them --- js/Recipe.js | 25 ++--- js/TiddlerConverters.js | 46 +++++++++ js/TiddlerInput.js | 200 +++++++++++++++++----------------------- js/TiddlerOutput.js | 37 ++++---- mytest | 0 tiddlywiki.js | 16 +++- wikitest.js | 8 +- 7 files changed, 185 insertions(+), 147 deletions(-) create mode 100644 js/TiddlerConverters.js create mode 100644 mytest diff --git a/js/Recipe.js b/js/Recipe.js index 883ce57c6..630eef59b 100755 --- a/js/Recipe.js +++ b/js/Recipe.js @@ -51,8 +51,6 @@ At this point tiddlers are placed in the store so that they can be referenced by var Tiddler = require("./Tiddler.js").Tiddler, WikiTextRenderer = require("./WikiTextRenderer").WikiTextRenderer, - tiddlerInput = require("./TiddlerInput.js"), - tiddlerOutput = require("./TiddlerOutput.js"), utils = require("./Utils.js"), retrieveFile = require("./FileRetriever.js").retrieveFile, fs = require("fs"), @@ -60,11 +58,11 @@ var Tiddler = require("./Tiddler.js").Tiddler, util = require("util"), async = require("async"); -// Create a new Recipe object from the specified recipe file, storing the tiddlers in a specified TiddlyWiki store. Invoke -// the callback function when all of the referenced tiddlers and recipes have been loaded successfully -var Recipe = function(store,filepath,callback) { +var Recipe = function(options,callback) { var me = this; - this.store = store; // Save a reference to the store + this.filepath = options.filepath; + this.store = options.store; + this.tiddlerConverters = options.tiddlerConverters; this.callback = callback; this.recipe = []; this.markers = {}; @@ -94,9 +92,9 @@ var Recipe = function(store,filepath,callback) { this.tiddlerQueue.drain = function() { me.chooseTiddlers(me.recipe); me.sortTiddlersForMarker("tiddler"); - me.callback(); + me.callback(null); }; - this.recipeQueue.push({filepath: filepath, + this.recipeQueue.push({filepath: this.filepath, contextPath: process.cwd(), recipe: this.recipe}); }; @@ -176,7 +174,7 @@ Recipe.prototype.readTiddlerFile = function(filepath,contextPath,callback) { var fields = { title: data.path }; - var tiddlers = tiddlerInput.parseTiddlerFile(data.text,data.extname,fields); + var tiddlers = me.tiddlerConverters.deserialize(data.extname,data.text,fields); // Check for the .meta file if(data.extname !== ".json" && tiddlers.length === 1) { var metafile = filepath + ".meta"; @@ -186,7 +184,10 @@ Recipe.prototype.readTiddlerFile = function(filepath,contextPath,callback) { } else { var fields = tiddlers[0]; if(!err) { - fields = tiddlerInput.parseMetaDataBlock(data.text,fields); + var text = data.text.split("\n\n")[0]; + if(text) { + fields = me.tiddlerConverters.deserialize("application/x-tiddler",text,fields)[0]; + } } callback(null,[fields]); } @@ -252,7 +253,7 @@ Recipe.tiddlerOutputter = { // Ordinary tiddlers are output as a
for(var t=0; t\s*)/gi, - startPos = storeAreaPos[0]; - endOfDivRegExp.lastIndex = startPos; - var match = endOfDivRegExp.exec(text); - while(match && startPos < storeAreaPos[1]) { - var endPos = endOfDivRegExp.lastIndex, - tiddlerFields = tiddlerInput.parseTiddlerDiv(text.substring(startPos,endPos),fields); - tiddlerFields.text = utils.htmlDecode(tiddlerFields.text); - results.push(tiddlerFields); - startPos = endPos; - match = endOfDivRegExp.exec(text); - } - } - return results; - } -}; - -tiddlerInput.locateStoreArea = function(tiddlywikidoc) { - var startSaveArea = '
', - startSaveAreaRegExp = /
/gi, - endSaveArea = '', - endSaveAreaCaps = '', - posOpeningDiv = tiddlywikidoc.search(startSaveAreaRegExp), - limitClosingDiv = tiddlywikidoc.indexOf("<"+"!--POST-STOREAREA--"+">"); - if(limitClosingDiv == -1) { - limitClosingDiv = tiddlywikidoc.indexOf("<"+"!--POST-BODY-START--"+">"); - } - var start = limitClosingDiv == -1 ? tiddlywikidoc.length : limitClosingDiv, - posClosingDiv = tiddlywikidoc.lastIndexOf(endSaveArea,start); - if(posClosingDiv == -1) { - posClosingDiv = tiddlywikidoc.lastIndexOf(endSaveAreaCaps,start); - } - return (posOpeningDiv != -1 && posClosingDiv != -1) ? [posOpeningDiv + startSaveArea.length,posClosingDiv] : null; -}; - -/* -Parse a block of metadata and merge the results into a hashmap of tiddler fields. +Utility function to parse a block of metadata and merge the results into a hashmap of tiddler fields. The block consists of newline delimited lines consisting of the field name, a colon, and then the value. For example: @@ -132,7 +22,7 @@ modified: 20110211131020 tags: browsers issues creator: psd */ -tiddlerInput.parseMetaDataBlock = function(metaData,fields) { +var parseMetaDataBlock = function(metaData,fields) { var result = {}; if(fields) { for(var t in fields) { @@ -151,7 +41,7 @@ tiddlerInput.parseMetaDataBlock = function(metaData,fields) { }; /* -Parse an old-style tiddler DIV. It looks like this: +Utility function to parse an old-style tiddler DIV. It looks like this:
The text of the tiddler (without the expected HTML encoding).
@@ -160,7 +50,7 @@ Parse an old-style tiddler DIV. It looks like this:
 
 Note that the field attributes are HTML encoded, but that the body of the 
 tag is not.
 */
-tiddlerInput.parseTiddlerDiv = function(text,fields) {
+var parseTiddlerDiv = function(text,fields) {
 	var result = {};
 	if(fields) {
 		for(var t in fields) {
@@ -190,3 +80,85 @@ tiddlerInput.parseTiddlerDiv = function(text,fields) {
 	}
 	return result;	
 };
+
+var inputTiddlerPlain = function(text,fields) {
+	fields.text = text;
+	return [fields];
+};
+
+var inputTiddlerDiv = function(text,fields) {
+	return [parseTiddlerDiv(text,fields)];
+};
+
+var inputTiddler = function(text,fields) {
+	var split = text.indexOf("\n\n");
+	if(split !== -1) {
+		fields.text = text.substr(split + 2);
+	}
+	if(split === -1) {
+		split = text.length;
+	}
+	fields = parseMetaDataBlock(text.substr(0,split),fields);
+	return [fields];
+};
+
+var inputTiddlerJSON = function(text,fields) {
+	var tiddlers = JSON.parse(text),
+		result = [],
+		getKnownFields = function(tid) {
+			var fields = {};
+			"title text created creator modified modifier type tags".split(" ").forEach(function(value) {
+				fields[value] = tid[value];
+			});
+			return fields;
+		};
+	for(var t=0; t',
+				startSaveAreaRegExp = /
/gi, + endSaveArea = '', + endSaveAreaCaps = '', + posOpeningDiv = tiddlywikidoc.search(startSaveAreaRegExp), + limitClosingDiv = tiddlywikidoc.indexOf("<"+"!--POST-STOREAREA--"+">"); + if(limitClosingDiv == -1) { + limitClosingDiv = tiddlywikidoc.indexOf("<"+"!--POST-BODY-START--"+">"); + } + var start = limitClosingDiv == -1 ? tiddlywikidoc.length : limitClosingDiv, + posClosingDiv = tiddlywikidoc.lastIndexOf(endSaveArea,start); + if(posClosingDiv == -1) { + posClosingDiv = tiddlywikidoc.lastIndexOf(endSaveAreaCaps,start); + } + return (posOpeningDiv != -1 && posClosingDiv != -1) ? [posOpeningDiv + startSaveArea.length,posClosingDiv] : null; + }, + results = [], + storeAreaPos = locateStoreArea(text); + if(storeAreaPos) { + var endOfDivRegExp = /(<\/div>\s*)/gi, + startPos = storeAreaPos[0]; + endOfDivRegExp.lastIndex = startPos; + var match = endOfDivRegExp.exec(text); + while(match && startPos < storeAreaPos[1]) { + var endPos = endOfDivRegExp.lastIndex, + tiddlerFields = parseTiddlerDiv(text.substring(startPos,endPos),fields); + tiddlerFields.text = utils.htmlDecode(tiddlerFields.text); + results.push(tiddlerFields); + startPos = endPos; + match = endOfDivRegExp.exec(text); + } + } + return results; +}; + +tiddlerInput.register = function(tiddlerConverters) { + tiddlerConverters.registerDeserializer(".txt","text/plain",inputTiddlerPlain); + tiddlerConverters.registerDeserializer(".tiddler","application/x-tiddler-html-div",inputTiddlerDiv); + tiddlerConverters.registerDeserializer(".tid","application/x-tiddler",inputTiddler); + tiddlerConverters.registerDeserializer(".json","application/json",inputTiddlerJSON); + tiddlerConverters.registerDeserializer(".tiddlywiki","application/x-tiddlywiki",inputTiddlyWiki); +}; diff --git a/js/TiddlerOutput.js b/js/TiddlerOutput.js index 2688650ad..6ca5a1b0d 100755 --- a/js/TiddlerOutput.js +++ b/js/TiddlerOutput.js @@ -5,14 +5,28 @@ Functions concerned with parsing representations of tiddlers /*jslint node: true */ "use strict"; -var utils = require("./Utils.js"); +var utils = require("./Utils.js"), + util = require("util"); var tiddlerOutput = exports; +// Utility function to convert a tags string array into a TiddlyWiki-style quoted tags string +var stringifyTags = function(tags) { + var results = []; + for(var t=0; t.html` and `.txt`. var Tiddler = require("./js/Tiddler.js").Tiddler, WikiStore = require("./js/WikiStore.js").WikiStore, WikiTextRenderer = require("./js/WikiTextRenderer.js").WikiTextRenderer, - tiddlerInput = require("./js/TiddlerInput"), + TiddlerConverters = require("./js/TiddlerConverters.js").TiddlerConverters, + tiddlerInput = require("./js/TiddlerInput.js"), utils = require("./js/Utils.js"), util = require("util"), fs = require("fs"), path = require("path"); var testdirectory = process.argv[2], + tiddlerConverters = new TiddlerConverters(), store = new WikiStore(), files = fs.readdirSync(testdirectory), titles = [], f,t,extname,basename; +tiddlerInput.register(tiddlerConverters); + for(f=0; f 1) { throw "Cannot use .JSON files"; }