Permalink
Browse files

Add PrettyPrint capability, debug settings

- Initial version of PrettyPrint capability added to genx core
- Add flag to Writer constructor to turn on PrettyPrint
- Add basic tests to validate PrettyPrint works and formats correctly
- Add "clean" and "cmake / cmake debug" scripts to package.json
  • Loading branch information...
PMLavigne committed Dec 29, 2015
1 parent aa49f87 commit ced2105a78063a01de64271a6a999dc644e03db9
Showing with 168 additions and 31 deletions.
  1. +4 −4 examples/atom.js
  2. +5 −2 lib/genx.js
  3. +3 −0 package.json
  4. +71 −20 src/genx.cc
  5. +1 −1 src/genx.h
  6. +16 −3 src/writer.cc
  7. +1 −1 src/writer.h
  8. +67 −0 test/writer_test.js
View
@@ -1,10 +1,10 @@
var genx = require('genx');
var genx = require('../lib/genx');
var w = new genx.Writer();
var w = new genx.Writer(true);
w.on('data', function(data) {
process.stdout.write(data);
})
});
// Declare the elements and attributes up-front
var ns = w.declareNamespace('http://www.w3.org/2005/Atom', '');
@@ -17,7 +17,7 @@ var name = w.declareElement(ns, 'name');
var id = w.declareElement(ns, 'id');
var entry = w.declareElement(ns, 'entry');
var summary = w.declareElement(ns, 'summary');
var href = w.declareAttribute('href');
// This is not a processing instruction and as such can't be generated by Genx
View
@@ -1,5 +1,8 @@
var EventEmitter = require('events').EventEmitter,
genx = require('../build/Release/genx');
// Check if we're in debug mode
var genxDir = (typeof v8debug !== 'undefined') ? '../build/Debug/genx' : '../build/Release/genx',
EventEmitter = require('events').EventEmitter,
genx = require(genxDir);
genx.Writer.prototype.__proto__ = EventEmitter.prototype;
module.exports = genx;
View
@@ -23,6 +23,9 @@
}
],
"scripts": {
"clean": "(mkdir build || rm -rf build) && mkdir -p build",
"cmake": "cd build && cmake .. && make -j6",
"cmake-debug": "source ~/.nvm/nvm.sh && nvm use 4.2.3 && cd build && cmake -DCMAKE_BUILD_TYPE=Debug .. && make -j6",
"test": "mocha"
},
"optionalDependencies": {
View
@@ -15,6 +15,8 @@
#define False 0
#define STRLEN_XMLNS_COLON 6
#define NEWLINE "\n"
#define SPACER "\t"
/*******************************
* writer state
@@ -122,6 +124,9 @@ struct genxWriter_rec
const char * etext[100];
void * (* alloc)(void * userData, int bytes);
void (* dealloc)(void * userData, void * data);
unsigned int depth;
Boolean shouldNewline;
Boolean prettyPrint;
};
/*******************************
@@ -510,7 +515,7 @@ static Boolean isNameChar(genxWriter w, int c)
*/
genxWriter genxNew(void * (* alloc)(void * userData, int bytes),
void (* dealloc)(void * userData, void * data),
void * userData)
void * userData, Boolean prettyPrint)
{
genxWriter w;
genxNamespace xml;
@@ -586,6 +591,10 @@ genxWriter genxNew(void * (* alloc)(void * userData, int bytes),
xml->declCount = 1;
xml->declaration = xml->defaultDecl;
w->depth = 0;
w->shouldNewline = 0;
w->prettyPrint = prettyPrint;
return w;
}
@@ -1152,6 +1161,17 @@ static genxStatus writeStartTag(genxWriter w, bool inlineTag = 0)
unsetDefaultNamespace(w);
w->status = GENX_SUCCESS;
if(w->prettyPrint)
{
SendCheck(w, NEWLINE);
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
}
w->depth++;
w->shouldNewline = 0;
}
SendCheck(w, "<");
if (e->ns && (e->ns->declaration != w->xmlnsEquals))
{
@@ -1538,6 +1558,20 @@ genxStatus genxEndElement(genxWriter w)
;
e = (genxElement) w->stack.pointers[--i];
if(w->prettyPrint)
{
w->depth--;
// We only need to add a newline to closing tags that come right after other closing tags
if(w->shouldNewline)
{
SendCheck(w, NEWLINE);
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
}
}
w->shouldNewline = 1;
}
SendCheck(w, "</");
if (e->ns && e->ns->declaration != w->xmlnsEquals)
{
@@ -1567,29 +1601,29 @@ genxStatus genxEndElement(genxWriter w)
*/
if (ns->baroque)
{
i = w->stack.count;
while (i > 0)
{
while (w->stack.pointers[i] != NULL)
{
genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--];
genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--];
if (otherNs == ns)
{
ns->declaration = otherDecl;
i = 0;
break;
}
}
i = w->stack.count;
while (i > 0)
{
while (w->stack.pointers[i] != NULL)
{
genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--];
genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--];
/* skip NULL & element */
i -= 2;
}
if (otherNs == ns)
{
ns->declaration = otherDecl;
i = 0;
break;
}
}
/* skip NULL & element */
i -= 2;
}
}
ns->declCount--;
if (ns->declCount == 0)
ns->baroque = False;
ns->baroque = False;
}
}
@@ -1771,6 +1805,14 @@ genxStatus genxAddText(genxWriter w, constUtf8 start)
if (w->sequence != SEQUENCE_CONTENT)
return w->status = GENX_SEQUENCE_ERROR;
if(w->prettyPrint && w->shouldNewline)
{
SendCheck(w, NEWLINE);
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
}
}
while (*start)
{
int c = genxNextUnicodeChar(&start);
@@ -1912,6 +1954,15 @@ genxStatus genxComment(genxWriter w, constUtf8 text)
if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS)
return w->status;
if(w->prettyPrint && w->shouldNewline)
{
SendCheck(w, NEWLINE);
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
}
}
if ((w->status = sendx(w, (utf8) "<!--")) != GENX_SUCCESS)
return w->status;
if ((w->status = sendx(w, (utf8) text)) != GENX_SUCCESS)
View
@@ -78,7 +78,7 @@ typedef struct genxAttribute_rec * genxAttribute;
*/
genxWriter genxNew(void * (*alloc)(void * userData, int bytes),
void (* dealloc)(void * userData, void * data),
void * userData);
void * userData, int prettyPrint);
/*
* Dispose of a writer, freeing all associated memory
View
@@ -87,10 +87,10 @@ void Writer::Initialize(Local<Object> exports)
exports->Set(Nan::New("Writer").ToLocalChecked(), tpl->GetFunction());
}
Writer::Writer()
Writer::Writer(const bool prettyPrint)
{
// alloc, free, userData
writer = genxNew(NULL, NULL, this);
writer = genxNew(NULL, NULL, this, prettyPrint);
sender.send = sender_send;
sender.sendBounded = sender_sendBounded;
sender.flush = sender_flush;
@@ -103,7 +103,20 @@ Writer::~Writer()
void Writer::New(const Nan::FunctionCallbackInfo <Value> &args)
{
Writer* writer = new Writer();
bool prettyPrint = false;
switch(args.Length()) {
case 0: break;
case 1:
if(args[0]->IsBoolean()) {
prettyPrint = args[0]->ToBoolean()->Value();
break;
}
default:
Nan::ThrowTypeError("Constructor for Writer expects no arguments, or 1 argument of type Boolean");
return;
}
Writer* writer = new Writer(prettyPrint);
writer->Wrap(args.This());
args.GetReturnValue().Set(args.This());
}
View
@@ -52,7 +52,7 @@ class Writer: public Nan::ObjectWrap
public:
static void Initialize(v8::Local<v8::Object> target);
Writer();
Writer(const bool prettyPrint);
~Writer();
View
@@ -379,6 +379,73 @@ describe('genx', function(){
});
});
describe('generating a prettyprinted document', function() {
beforeEach(function() {
w = new genx.Writer(true);
});
describe('using literal nodes', function(){
it('generates the correct XML', function() {
var result = '';
w.on('data', function(data) {
result += data;
});
w.startDocument()
.addComment(' Testing ')
.startElementLiteral('http://www.w3.org/2005/Atom', 'feed')
.startElementLiteral('title').addAttributeLiteral('type', 'text')
.addText('Testing').endElement().endElement().endDocument();
result.should.equal("<!-- Testing -->\n\n<g1:feed xmlns:g1=\"http://www.w3.org/2005/Atom\">\n\t<title type=\"text\">Testing</title>\n</g1:feed>");
});
it('correctly spaces trailing text nodes', function() {
var result = '';
w.on('data', function(data) {
result += data;
});
w.startDocument()
.addComment(' Testing ')
.startElementLiteral('http://www.w3.org/2005/Atom', 'feed')
.startElementLiteral('title').addAttributeLiteral('type', 'text')
.addText('Testing')
.endElement()
.addText('Trailing Text')
.endElement()
.endDocument();
result.should.equal("<!-- Testing -->\n\n<g1:feed xmlns:g1=\"http://www.w3.org/2005/Atom\">\n\t" +
"<title type=\"text\">Testing</title>\n\tTrailing Text\n</g1:feed>");
});
it('correctly spaces comments', function() {
var result = '';
w.on('data', function(data) {
result += data;
});
w.startDocument()
.startElementLiteral('http://www.w3.org/2005/Atom', 'feed')
.startElementLiteral('title').addAttributeLiteral('type', 'text')
.addText('Testing')
.endElement()
.addComment(' Testing ')
.addText('Trailing Text')
.startElementLiteral('comment-only')
.addComment(' Testing ')
.endElement()
.endElement()
.endDocument();
result.should.equal("\n<g1:feed xmlns:g1=\"http://www.w3.org/2005/Atom\">\n\t" +
"<title type=\"text\">Testing</title>\n\t<!-- Testing -->\n\t" +
"Trailing Text\n\t<comment-only><!-- Testing --></comment-only>\n</g1:feed>");
});
});
});
it('can generate multiple documents', function() {
var result = '';

0 comments on commit ced2105

Please sign in to comment.