Current File : //usr/local/share/.config/yarn/global/node_modules/js-git/lib/object-codec.js |
"use strict";
var bodec = require('bodec');
var modes = require('./modes');
// (body) -> raw-buffer
var encoders = exports.encoders = {
blob: encodeBlob,
tree: encodeTree,
commit: encodeCommit,
tag: encodeTag
};
// ({type:type, body:raw-buffer}) -> buffer
exports.frame = frame;
// (raw-buffer) -> body
var decoders = exports.decoders ={
blob: decodeBlob,
tree: decodeTree,
commit: decodeCommit,
tag: decodeTag
};
// (buffer) -> {type:type, body:raw-buffer}
exports.deframe = deframe;
// Export git style path sort in case it's wanted.
exports.treeMap = treeMap;
exports.treeSort = treeSort;
function encodeBlob(body) {
if (!bodec.isBinary(body)) throw new TypeError("Blobs must be binary values");
return body;
}
function treeMap(key) {
/*jshint validthis:true*/
var entry = this[key];
return {
name: key,
mode: entry.mode,
hash: entry.hash
};
}
function treeSort(a, b) {
var aa = (a.mode === modes.tree) ? a.name + "/" : a.name;
var bb = (b.mode === modes.tree) ? b.name + "/" : b.name;
return aa > bb ? 1 : aa < bb ? -1 : 0;
}
function encodeTree(body) {
var tree = "";
if (Array.isArray(body)) throw new TypeError("Tree must be in object form");
var list = Object.keys(body).map(treeMap, body).sort(treeSort);
for (var i = 0, l = list.length; i < l; i++) {
var entry = list[i];
tree += entry.mode.toString(8) + " " + bodec.encodeUtf8(entry.name) +
"\0" + bodec.decodeHex(entry.hash);
}
return bodec.fromRaw(tree);
}
function encodeTag(body) {
var str = "object " + body.object +
"\ntype " + body.type +
"\ntag " + body.tag +
"\ntagger " + formatPerson(body.tagger) +
"\n\n" + body.message;
return bodec.fromUnicode(str);
}
function encodeCommit(body) {
var str = "tree " + body.tree;
for (var i = 0, l = body.parents.length; i < l; ++i) {
str += "\nparent " + body.parents[i];
}
str += "\nauthor " + formatPerson(body.author) +
"\ncommitter " + formatPerson(body.committer) +
"\n\n" + body.message;
return bodec.fromUnicode(str);
}
function formatPerson(person) {
return safe(person.name) +
" <" + safe(person.email) + "> " +
formatDate(person.date);
}
function safe(string) {
return string.replace(/(?:^[\.,:;<>"']+|[\0\n<>]+|[\.,:;<>"']+$)/gm, "");
}
function two(num) {
return (num < 10 ? "0" : "") + num;
}
function formatDate(date) {
var seconds, offset;
if (date.seconds) {
seconds = date.seconds;
offset = date.offset;
}
// Also accept Date instances
else {
seconds = Math.floor(date.getTime() / 1000);
offset = date.getTimezoneOffset();
}
var neg = "+";
if (offset <= 0) offset = -offset;
else neg = "-";
offset = neg + two(Math.floor(offset / 60)) + two(offset % 60);
return seconds + " " + offset;
}
function frame(obj) {
var type = obj.type;
var body = obj.body;
if (!bodec.isBinary(body)) body = encoders[type](body);
return bodec.join([
bodec.fromRaw(type + " " + body.length + "\0"),
body
]);
}
function decodeBlob(body) {
return body;
}
function decodeTree(body) {
var i = 0;
var length = body.length;
var start;
var mode;
var name;
var hash;
var tree = {};
while (i < length) {
start = i;
i = indexOf(body, 0x20, start);
if (i < 0) throw new SyntaxError("Missing space");
mode = parseOct(body, start, i++);
start = i;
i = indexOf(body, 0x00, start);
name = bodec.toUnicode(body, start, i++);
hash = bodec.toHex(body, i, i += 20);
tree[name] = {
mode: mode,
hash: hash
};
}
return tree;
}
function decodeCommit(body) {
var i = 0;
var start;
var key;
var parents = [];
var commit = {
tree: "",
parents: parents,
author: "",
committer: "",
message: ""
};
while (body[i] !== 0x0a) {
start = i;
i = indexOf(body, 0x20, start);
if (i < 0) throw new SyntaxError("Missing space");
key = bodec.toRaw(body, start, i++);
start = i;
i = indexOf(body, 0x0a, start);
if (i < 0) throw new SyntaxError("Missing linefeed");
var value = bodec.toUnicode(body, start, i++);
if (key === "parent") {
parents.push(value);
}
else {
if (key === "author" || key === "committer") {
value = decodePerson(value);
}
commit[key] = value;
}
}
i++;
commit.message = bodec.toUnicode(body, i, body.length);
return commit;
}
function decodeTag(body) {
var i = 0;
var start;
var key;
var tag = {};
while (body[i] !== 0x0a) {
start = i;
i = indexOf(body, 0x20, start);
if (i < 0) throw new SyntaxError("Missing space");
key = bodec.toRaw(body, start, i++);
start = i;
i = indexOf(body, 0x0a, start);
if (i < 0) throw new SyntaxError("Missing linefeed");
var value = bodec.toUnicode(body, start, i++);
if (key === "tagger") value = decodePerson(value);
tag[key] = value;
}
i++;
tag.message = bodec.toUnicode(body, i, body.length);
return tag;
}
function decodePerson(string) {
var match = string.match(/^([^<]*) <([^>]*)> ([^ ]*) (.*)$/);
if (!match) throw new Error("Improperly formatted person string");
return {
name: match[1],
email: match[2],
date: {
seconds: parseInt(match[3], 10),
offset: parseInt(match[4], 10) / 100 * -60
}
};
}
function deframe(buffer, decode) {
var space = indexOf(buffer, 0x20);
if (space < 0) throw new Error("Invalid git object buffer");
var nil = indexOf(buffer, 0x00, space);
if (nil < 0) throw new Error("Invalid git object buffer");
var body = bodec.slice(buffer, nil + 1);
var size = parseDec(buffer, space + 1, nil);
if (size !== body.length) throw new Error("Invalid body length.");
var type = bodec.toRaw(buffer, 0, space);
return {
type: type,
body: decode ? decoders[type](body) : body
};
}
function indexOf(buffer, byte, i) {
i |= 0;
var length = buffer.length;
for (;;i++) {
if (i >= length) return -1;
if (buffer[i] === byte) return i;
}
}
function parseOct(buffer, start, end) {
var val = 0;
while (start < end) {
val = (val << 3) + buffer[start++] - 0x30;
}
return val;
}
function parseDec(buffer, start, end) {
var val = 0;
while (start < end) {
val = val * 10 + buffer[start++] - 0x30;
}
return val;
}