Skip to content

Commit

Permalink
Small improvements to parser and validator.
Browse files Browse the repository at this point in the history
  • Loading branch information
tdecaluwe committed Mar 11, 2016
1 parent 47e25e2 commit 5ac5797
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 46 deletions.
63 changes: 30 additions & 33 deletions parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ var Tokenizer = require('./tokenizer.js');

var EventEmitter = require('events');

var opensegment = function (parser) {
parser._validator.onopensegment(parser._tokenizer.buffer);
parser.onopensegment(parser._tokenizer.buffer);
parser._tokenizer.buffer = '';
}

var closecomponent = function (parser) {
parser._validator.onclosecomponent(parser._tokenizer);
parser.oncomponent(parser._tokenizer.buffer);
parser._tokenizer.buffer = '';
}

var closesegment = function (parser) {
parser._validator.onclosesegment();
parser.onclosesegment();
parser.state = Parser.states.segment;
}

/**
* The `Parser` class encapsulates an online parsing algorithm, similar to a
* SAX-parser. By itself it doesn't do anything useful, however several
Expand Down Expand Up @@ -118,33 +136,27 @@ Parser.prototype.write = function (chunk) {
// want the parser to detect another UNA header in such a case, we put it
// in the segment state.
this.state = Parser.states.segment;
// Continue to read the first segment, otherwise the index increment add
// Fall through to read the next segment, otherwise the index increment at
// the end of the loop would cause the parser to skip the first character.
case Parser.states.unb:
case Parser.states.segment:
index = this._tokenizer.segment(chunk, index);
// Determine the next parser state.
switch (chunk.charCodeAt(index) || this._configuration.EOT) {
case this._configuration.DES:
this._validator.onopensegment(this._tokenizer.buffer);
this.onopensegment(this._tokenizer.buffer);
opensegment(this);
this.state = Parser.states.element;
this._tokenizer.buffer = '';
break;
case this._configuration.ST:
this._validator.onopensegment(this._tokenizer.buffer);
this.onopensegment(this._tokenizer.buffer);
this._validator.onclosesegment(this);
this.onclosesegment();
this.state = Parser.states.segment;
this._tokenizer.buffer = '';
opensegment(this);
closesegment(this);
break;
case this._configuration.EOT:
case this._configuration.CR:
case this._configuration.LF:
break;
default:
throw Parser.errors.invalidControlAfterSegment(this._tokenizer.buffer, chunk.charAt(index));
throw Parser.errors.invalidCharacter(chunk.charAt(index), index);
}
break;
case Parser.states.element:
Expand All @@ -156,44 +168,35 @@ Parser.prototype.write = function (chunk) {
// Start reading a new component.
this._validator.onopencomponent(this._tokenizer);
// Fall through to process the available component data.
case Parser.states.continued:
case Parser.states.data:
index = this._tokenizer.data(chunk, index);
// Avoid opening a new component if the component data is interrupted by
// a control character, like a decimal mark.
this.state = Parser.states.data;
// Determine the next parser state.
switch (chunk.charCodeAt(index) || this._configuration.EOT) {
case this._configuration.CDS:
this._validator.onclosecomponent(this._tokenizer);
this.oncomponent(this._tokenizer.buffer);
closecomponent(this);
this.state = Parser.states.component;
this._tokenizer.buffer = '';
break;
case this._configuration.DES:
this._validator.onclosecomponent(this._tokenizer);
this.oncomponent(this._tokenizer.buffer);
closecomponent(this);
this.state = Parser.states.element;
this._tokenizer.buffer = '';
break;
case this._configuration.ST:
this._validator.onclosecomponent(this._tokenizer);
this.oncomponent(this._tokenizer.buffer);
this._validator.onclosesegment();
this.onclosesegment();
this.state = Parser.states.segment;
this._tokenizer.buffer = '';
closecomponent(this);
closesegment(this);
break;
case this._configuration.DM:
this._tokenizer.decimal(chunk, index);
this.state = Parser.states.data;
break;
case this._configuration.RC:
index++;
this._tokenizer.release(chunk, index);
this.state = Parser.states.data;
break;
case this._configuration.EOT:
case this._configuration.CR:
case this._configuration.LF:
this.state = Parser.states.data;
break;
default:
throw Parser.errors.invalidCharacter(chunk.charAt(index), index);
Expand Down Expand Up @@ -224,12 +227,6 @@ Parser.errors = {
message += 'Invalid character ' + character;
message += ' at position ' + index;
return new Error(message);
},
invalidControlAfterSegment: function (segment, character) {
var message = '';
message += 'Invalid character ' + character;
message += ' after reading segment name ' + segment;
return new Error(message);
}
}

Expand Down
25 changes: 12 additions & 13 deletions validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@

'use strict'

var checkComponents = function (validator) {
var name;

if (validator._counts.component < validator._element.requires || validator._counts.component > validator._element.components.length) {
name = validator._segment.elements[validator._counts.element];
throw Validator.errors.countError('Element', name, validator._element, validator._counts.component);
}
}

/**
* The `Validator` can be used as an add-on to `Parser` class, to enable
* validation of segments, elements and components. This class implements a
Expand Down Expand Up @@ -141,15 +150,11 @@ Validator.prototype.onopensegment = function (segment) {
* @summary Start validation for a new element.
*/
Validator.prototype.onelement = function () {
var name;

switch (this._state) {
case Validator.states.all:
// Check component count of the previous enter.
if (this._counts.component < this._element.requires || this._counts.component > this._element.components.length) {
name = this._segment.elements[this._counts.element];
throw Validator.errors.countError('Element', name, this._element, this._counts.component);
}
checkComponents(this);
// Fall through to continue with element count validation.
case Validator.states.enter:
// Skip component count checks for the first element.
Expand Down Expand Up @@ -217,19 +222,13 @@ Validator.prototype.onclosecomponent = function (buffer) {
* @summary Finish validation for the current segment.
*/
Validator.prototype.onclosesegment = function (segment) {
var name;

switch (this._state) {
case Validator.states.all:
if (this._counts.component < this._element.requires || this._counts.component > this._element.components.length) {
name = this._segment.elements[this._counts.element];
throw Validator.errors.countError('Element', name, this._element, this._counts.component);
}
checkComponents(this);
// Fall through to continue with element count validation.
case Validator.states.elements:
if (this._counts.element < this._segment.requires || this._counts.element > this._segment.elements.length) {
name = segment;
throw Validator.errors.countError('Segment', name, this._segment, this._counts.element);
throw Validator.errors.countError('Segment', segment, this._segment, this._counts.element);
}
}
}
Expand Down

0 comments on commit 5ac5797

Please sign in to comment.