mirror of
https://github.com/TiddlyWiki/TiddlyWiki5.git
synced 2026-04-27 06:34:36 +00:00
First pass at bibtex importer
This commit is contained in:
342
plugins/tiddlywiki/bibtex/files/bibtexParse.js
Executable file
342
plugins/tiddlywiki/bibtex/files/bibtexParse.js
Executable file
@@ -0,0 +1,342 @@
|
||||
/* start bibtexParse 0.0.22 */
|
||||
|
||||
//Original work by Henrik Muehe (c) 2010
|
||||
//
|
||||
//CommonJS port by Mikola Lysenko 2013
|
||||
//
|
||||
//Port to Browser lib by ORCID / RCPETERS
|
||||
//
|
||||
//Issues:
|
||||
//no comment handling within strings
|
||||
//no string concatenation
|
||||
//no variable values yet
|
||||
//Grammar implemented here:
|
||||
//bibtex -> (string | preamble | comment | entry)*;
|
||||
//string -> '@STRING' '{' key_equals_value '}';
|
||||
//preamble -> '@PREAMBLE' '{' value '}';
|
||||
//comment -> '@COMMENT' '{' value '}';
|
||||
//entry -> '@' key '{' key ',' key_value_list '}';
|
||||
//key_value_list -> key_equals_value (',' key_equals_value)*;
|
||||
//key_equals_value -> key '=' value;
|
||||
//value -> value_quotes | value_braces | key;
|
||||
//value_quotes -> '"' .*? '"'; // not quite
|
||||
//value_braces -> '{' .*? '"'; // not quite
|
||||
(function(exports) {
|
||||
|
||||
function BibtexParser() {
|
||||
|
||||
this.months = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
||||
this.notKey = [',','{','}',' ','='];
|
||||
this.pos = 0;
|
||||
this.input = "";
|
||||
this.entries = new Array();
|
||||
|
||||
this.currentEntry = "";
|
||||
|
||||
this.setInput = function(t) {
|
||||
this.input = t;
|
||||
};
|
||||
|
||||
this.getEntries = function() {
|
||||
return this.entries;
|
||||
};
|
||||
|
||||
this.isWhitespace = function(s) {
|
||||
return (s == ' ' || s == '\r' || s == '\t' || s == '\n');
|
||||
};
|
||||
|
||||
this.match = function(s, canCommentOut) {
|
||||
if (canCommentOut == undefined || canCommentOut == null)
|
||||
canCommentOut = true;
|
||||
this.skipWhitespace(canCommentOut);
|
||||
if (this.input.substring(this.pos, this.pos + s.length) == s) {
|
||||
this.pos += s.length;
|
||||
} else {
|
||||
throw "Token mismatch, expected " + s + ", found "
|
||||
+ this.input.substring(this.pos);
|
||||
};
|
||||
this.skipWhitespace(canCommentOut);
|
||||
};
|
||||
|
||||
this.tryMatch = function(s, canCommentOut) {
|
||||
if (canCommentOut == undefined || canCommentOut == null)
|
||||
canCommentOut = true;
|
||||
this.skipWhitespace(canCommentOut);
|
||||
if (this.input.substring(this.pos, this.pos + s.length) == s) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
this.skipWhitespace(canCommentOut);
|
||||
};
|
||||
|
||||
/* when search for a match all text can be ignored, not just white space */
|
||||
this.matchAt = function() {
|
||||
while (this.input.length > this.pos && this.input[this.pos] != '@') {
|
||||
this.pos++;
|
||||
};
|
||||
|
||||
if (this.input[this.pos] == '@') {
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
this.skipWhitespace = function(canCommentOut) {
|
||||
while (this.isWhitespace(this.input[this.pos])) {
|
||||
this.pos++;
|
||||
};
|
||||
if (this.input[this.pos] == "%" && canCommentOut == true) {
|
||||
while (this.input[this.pos] != "\n") {
|
||||
this.pos++;
|
||||
};
|
||||
this.skipWhitespace(canCommentOut);
|
||||
};
|
||||
};
|
||||
|
||||
this.value_braces = function() {
|
||||
var bracecount = 0;
|
||||
this.match("{", false);
|
||||
var start = this.pos;
|
||||
var escaped = false;
|
||||
while (true) {
|
||||
if (!escaped) {
|
||||
if (this.input[this.pos] == '}') {
|
||||
if (bracecount > 0) {
|
||||
bracecount--;
|
||||
} else {
|
||||
var end = this.pos;
|
||||
this.match("}", false);
|
||||
return this.input.substring(start, end);
|
||||
};
|
||||
} else if (this.input[this.pos] == '{') {
|
||||
bracecount++;
|
||||
} else if (this.pos >= this.input.length - 1) {
|
||||
throw "Unterminated value";
|
||||
};
|
||||
};
|
||||
if (this.input[this.pos] == '\\' && escaped == false)
|
||||
escaped = true;
|
||||
else
|
||||
escaped = false;
|
||||
this.pos++;
|
||||
};
|
||||
};
|
||||
|
||||
this.value_comment = function() {
|
||||
var str = '';
|
||||
var brcktCnt = 0;
|
||||
while (!(this.tryMatch("}", false) && brcktCnt == 0)) {
|
||||
str = str + this.input[this.pos];
|
||||
if (this.input[this.pos] == '{')
|
||||
brcktCnt++;
|
||||
if (this.input[this.pos] == '}')
|
||||
brcktCnt--;
|
||||
if (this.pos >= this.input.length - 1) {
|
||||
throw "Unterminated value:" + this.input.substring(start);
|
||||
};
|
||||
this.pos++;
|
||||
};
|
||||
return str;
|
||||
};
|
||||
|
||||
this.value_quotes = function() {
|
||||
this.match('"', false);
|
||||
var start = this.pos;
|
||||
var escaped = false;
|
||||
while (true) {
|
||||
if (!escaped) {
|
||||
if (this.input[this.pos] == '"') {
|
||||
var end = this.pos;
|
||||
this.match('"', false);
|
||||
return this.input.substring(start, end);
|
||||
} else if (this.pos >= this.input.length - 1) {
|
||||
throw "Unterminated value:" + this.input.substring(start);
|
||||
};
|
||||
}
|
||||
if (this.input[this.pos] == '\\' && escaped == false)
|
||||
escaped = true;
|
||||
else
|
||||
escaped = false;
|
||||
this.pos++;
|
||||
};
|
||||
};
|
||||
|
||||
this.single_value = function() {
|
||||
var start = this.pos;
|
||||
if (this.tryMatch("{")) {
|
||||
return this.value_braces();
|
||||
} else if (this.tryMatch('"')) {
|
||||
return this.value_quotes();
|
||||
} else {
|
||||
var k = this.key();
|
||||
if (k.match("^[0-9]+$"))
|
||||
return k;
|
||||
else if (this.months.indexOf(k.toLowerCase()) >= 0)
|
||||
return k.toLowerCase();
|
||||
else
|
||||
throw "Value expected:" + this.input.substring(start) + ' for key: ' + k;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
this.value = function() {
|
||||
var values = [];
|
||||
values.push(this.single_value());
|
||||
while (this.tryMatch("#")) {
|
||||
this.match("#");
|
||||
values.push(this.single_value());
|
||||
};
|
||||
return values.join("");
|
||||
};
|
||||
|
||||
this.key = function(optional) {
|
||||
var start = this.pos;
|
||||
while (true) {
|
||||
if (this.pos >= this.input.length) {
|
||||
throw "Runaway key";
|
||||
};
|
||||
// а-яА-Я is Cyrillic
|
||||
//console.log(this.input[this.pos]);
|
||||
if (this.notKey.indexOf(this.input[this.pos]) >= 0) {
|
||||
if (optional && this.input[this.pos] != ',') {
|
||||
this.pos = start;
|
||||
return null;
|
||||
};
|
||||
return this.input.substring(start, this.pos);
|
||||
} else {
|
||||
this.pos++;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
this.key_equals_value = function() {
|
||||
var key = this.key();
|
||||
if (this.tryMatch("=")) {
|
||||
this.match("=");
|
||||
var val = this.value();
|
||||
return [ key, val ];
|
||||
} else {
|
||||
throw "... = value expected, equals sign missing:"
|
||||
+ this.input.substring(this.pos);
|
||||
};
|
||||
};
|
||||
|
||||
this.key_value_list = function() {
|
||||
var kv = this.key_equals_value();
|
||||
this.currentEntry['entryTags'] = {};
|
||||
this.currentEntry['entryTags'][kv[0]] = kv[1];
|
||||
while (this.tryMatch(",")) {
|
||||
this.match(",");
|
||||
// fixes problems with commas at the end of a list
|
||||
if (this.tryMatch("}")) {
|
||||
break;
|
||||
}
|
||||
;
|
||||
kv = this.key_equals_value();
|
||||
this.currentEntry['entryTags'][kv[0]] = kv[1];
|
||||
};
|
||||
};
|
||||
|
||||
this.entry_body = function(d) {
|
||||
this.currentEntry = {};
|
||||
this.currentEntry['citationKey'] = this.key(true);
|
||||
this.currentEntry['entryType'] = d.substring(1);
|
||||
if (this.currentEntry['citationKey'] != null) {
|
||||
this.match(",");
|
||||
}
|
||||
this.key_value_list();
|
||||
this.entries.push(this.currentEntry);
|
||||
};
|
||||
|
||||
this.directive = function() {
|
||||
this.match("@");
|
||||
return "@" + this.key();
|
||||
};
|
||||
|
||||
this.preamble = function() {
|
||||
this.currentEntry = {};
|
||||
this.currentEntry['entryType'] = 'PREAMBLE';
|
||||
this.currentEntry['entry'] = this.value_comment();
|
||||
this.entries.push(this.currentEntry);
|
||||
};
|
||||
|
||||
this.comment = function() {
|
||||
this.currentEntry = {};
|
||||
this.currentEntry['entryType'] = 'COMMENT';
|
||||
this.currentEntry['entry'] = this.value_comment();
|
||||
this.entries.push(this.currentEntry);
|
||||
};
|
||||
|
||||
this.entry = function(d) {
|
||||
this.entry_body(d);
|
||||
};
|
||||
|
||||
this.alernativeCitationKey = function () {
|
||||
this.entries.forEach(function (entry) {
|
||||
if (!entry.citationKey && entry.entryTags) {
|
||||
entry.citationKey = '';
|
||||
if (entry.entryTags.author) {
|
||||
entry.citationKey += entry.entryTags.author.split(',')[0] += ', ';
|
||||
}
|
||||
entry.citationKey += entry.entryTags.year;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.bibtex = function() {
|
||||
while (this.matchAt()) {
|
||||
var d = this.directive();
|
||||
this.match("{");
|
||||
if (d == "@STRING") {
|
||||
this.string();
|
||||
} else if (d == "@PREAMBLE") {
|
||||
this.preamble();
|
||||
} else if (d == "@COMMENT") {
|
||||
this.comment();
|
||||
} else {
|
||||
this.entry(d);
|
||||
}
|
||||
this.match("}");
|
||||
};
|
||||
|
||||
this.alernativeCitationKey();
|
||||
};
|
||||
};
|
||||
|
||||
exports.toJSON = function(bibtex) {
|
||||
var b = new BibtexParser();
|
||||
b.setInput(bibtex);
|
||||
b.bibtex();
|
||||
return b.entries;
|
||||
};
|
||||
|
||||
/* added during hackathon don't hate on me */
|
||||
exports.toBibtex = function(json) {
|
||||
var out = '';
|
||||
for ( var i in json) {
|
||||
out += "@" + json[i].entryType;
|
||||
out += '{';
|
||||
if (json[i].citationKey)
|
||||
out += json[i].citationKey + ', ';
|
||||
if (json[i].entry)
|
||||
out += json[i].entry ;
|
||||
if (json[i].entryTags) {
|
||||
var tags = '';
|
||||
for (var jdx in json[i].entryTags) {
|
||||
if (tags.length != 0)
|
||||
tags += ', ';
|
||||
tags += jdx + '= {' + json[i].entryTags[jdx] + '}';
|
||||
}
|
||||
out += tags;
|
||||
}
|
||||
out += '}\n\n';
|
||||
}
|
||||
return out;
|
||||
|
||||
};
|
||||
|
||||
})(typeof exports === 'undefined' ? this['bibtexParse'] = {} : exports);
|
||||
|
||||
/* end bibtexParse */
|
||||
Reference in New Issue
Block a user