Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

parser optimizations

  • Loading branch information...
commit 52584d055f090e7d7c507a3ba0290fd0291ed15a 1 parent 9e0c160
Gabriel Llamas authored
1  .gitignore
View
@@ -0,0 +1 @@
+node_modules
10 CHANGES
View
@@ -1,11 +1,13 @@
v1.0.0 (xx Jul 2013)
Complete refactor.
- This new version only iterates the data one time, while the previous version
- was a direct port from the Java source code and was iterating four times
- over the same data.
+ Improved speed by ~37%. This new version only iterates the data one time,
+ while the previous version was a direct port from the Java source code and
+ was iterating four times over the same data.
All the dependencies have been removed.
+ "load()" and "store" have been removed and "parse()" and "stringify()" can
+ read and write to files with the "path" setting.
Added "json" parameter. When it is enabled stringified json arrays and objects
- are parsed.
+ are parsed into javascript arrays and objects.
Removed "bufferSize" and "encoding" parameters. Files are read using a 16KB
buffer size and utf8 encoding.
Fixed some unusual bugs with escaped backslashes.
2  MIGRATION-v0.3-v1
View
@@ -0,0 +1,2 @@
+- Se elimina "load()" y "store()" y "parse()" y "stringify()" leen o escriben
+ a archivo usando el parámetro "path".
8 bench.js
View
@@ -12,7 +12,7 @@ speedy.run ({
pOld.parse (data, { sections: true });
},
"new": function (){
- pNew.parse (data, { data: true, sections: true }, function (){});
+ pNew.parse (data, { sections: true });
}
});
@@ -32,9 +32,9 @@ Total time: ~6000ms (6s 0ms)
Higher is better (ops/sec)
old
- 11,980 ± 0.2%
+ 11,132 ± 0.0%
new
- 12,130 ± 0.4%
+ 17,670 ± 0.2%
-Elapsed time: 6112ms (6s 112ms)
+Elapsed time: 6131ms (6s 131ms)
*/
42 benchmark/ini-vs-properties.js
View
@@ -0,0 +1,42 @@
+"use strict";
+
+var speedy = require ("speedy");
+var fs = require ("fs");
+var ini = require ("ini");
+var properties = require ("../lib");
+
+var data = fs.readFileSync ("properties", { encoding: "utf8" });
+
+speedy.run ({
+ ini: function (){
+ ini.parse (data);
+ },
+ properties: function (){
+ properties.parse (data, { sections: true });
+ }
+});
+
+//Note: ini doesn't convert the values to numbers
+
+/*
+File: ini-vs-properties.js
+
+Node v0.10.13
+V8 v3.14.5.9
+Speedy v0.0.8
+
+Benchmarks: 2
+Timeout: 1000ms (1s 0ms)
+Samples: 3
+Total time per benchmark: ~3000ms (3s 0ms)
+Total time: ~6000ms (6s 0ms)
+
+Higher is better (ops/sec)
+
+ini
+ 24,815 ± 0.3%
+properties
+ 22,449 ± 0.2%
+
+Elapsed time: 6140ms (6s 140ms)
+*/
27 benchmark/json
View
@@ -0,0 +1,27 @@
+{
+ "strings": {
+ "s1": "v",
+ "s2": "v",
+ "s3": "v",
+ "s4": "v",
+ "s5": "v"
+ },
+ "numbers": {
+ "n1": 1,
+ "n2": 1,
+ "n3": 1,
+ "n4": 123.123,
+ "n5": 123.123,
+ "n6": 123.123
+ },
+ "arrays": {
+ "a1": ["1", 1, 123.123]
+ },
+ "objects": {
+ "o1": {
+ "a": "1",
+ "b": 1,
+ "c": 123.123
+ }
+ }
+}
42 benchmark/json-vs-properties.js
View
@@ -0,0 +1,42 @@
+"use strict";
+
+var speedy = require ("speedy");
+var properties = require ("../lib");
+var fs = require ("fs");
+
+var jsonData = fs.readFileSync ("json", { encoding: "utf8" });
+var propertiesData = fs.readFileSync ("properties", { encoding: "utf8" });
+
+speedy.run ({
+ json: function (){
+ JSON.parse (jsonData);
+ },
+ properties: function (){
+ properties.parse (propertiesData, { sections: true, json: true });
+ }
+});
+
+//Note: JSON.parse is written in native by the people that made the V8 engine!
+
+/*
+File: json-vs-properties.js
+
+Node v0.10.13
+V8 v3.14.5.9
+Speedy v0.0.8
+
+Benchmarks: 2
+Timeout: 1000ms (1s 0ms)
+Samples: 3
+Total time per benchmark: ~3000ms (3s 0ms)
+Total time: ~6000ms (6s 0ms)
+
+Higher is better (ops/sec)
+
+json
+ 374,519 ± 0.0%
+properties
+ 21,360 ± 0.2%
+
+Elapsed time: 6131ms (6s 131ms)
+*/
24 benchmark/properties
View
@@ -0,0 +1,24 @@
+[strings]
+s1 = v
+s2 = v
+s3 = v
+s4 = v
+s5 = v
+
+[numbers]
+n1 = 1
+n2 = 1
+n3 = 1
+n4 = 123.123
+n5 = 123.123
+n6 = 123.123
+
+[arrays]
+a1 = ["1", 1, 123.123]
+a2 = ["1", 1, 123.123]
+a3 = ["1", 1, 123.123]
+
+[objects]
+o1 = { "a": "1", "b": 1, "c": 123.123 }
+o2 = { "a": "1", "b": 1, "c": 123.123 }
+o3 = { "a": "1", "b": 1, "c": 123.123 }
6 lib/index.js
View
@@ -1,4 +1,6 @@
"use strict";
-module.exports.parse = require ("./parse");
-module.exports.stringify = require ("./stringify");
+module.exports = {
+ parse: require ("./read"),
+ stringify: require ("./write")
+};
360 lib/parse.js
View
@@ -1,205 +1,201 @@
"use strict";
-var fs = require ("fs");
-var reader = require ("./reader");
-
-var convertType = function (value, cb){
- if (value === null) return cb (null, null);
- var lower = value.toLowerCase ();
- if (lower === "true") return cb (null, true);
- if (lower === "false") return cb (null, false);
- var v = Number (value);
- if (!isNaN (value)) return cb (null, v);
- cb (null, value);
-};
-
-var convertJson = function (value, cb){
- if (value === null) return cb (null, null);
-
- if (value[0] === "{" || value[0] === "["){
- try{
- cb (null, JSON.parse (value));
- }catch (error){
- cb (error);
- }
- }else{
- convertType (value, cb);
+var hex = function (c){
+ switch (c){
+ case "0": return 0;
+ case "1": return 1;
+ case "2": return 2;
+ case "3": return 3;
+ case "4": return 4;
+ case "5": return 5;
+ case "6": return 6;
+ case "7": return 7;
+ case "8": return 8;
+ case "9": return 9;
+ case "a": case "A": return 10;
+ case "b": case "B": return 11;
+ case "c": case "C": return 12;
+ case "d": case "D": return 13;
+ case "e": case "E": return 14;
+ case "f": case "F": return 15;
}
};
-var expand = function (o, str, settings, cb){
- if (!settings.variables || !str) return cb (null, str);
-
- var stack = [];
+module.exports = function (data, options, handlers, control){
var c;
- var cp;
+ var escape;
+ var skipSpace = true;
+ var isCommentLine;
+ var isSectionLine;
+ var newLine = true;
+ var multiLine;
+ var isKey = true;
var key = "";
- var section = null;
- var v;
- var holder;
- var t;
+ var value = "";
+ var section;
+ var unicode;
+ var unicodeRemaining;
+ var escapingUnicode;
+ var keySpace;
+ var sep;
+ var ignoreLine;
- for (var i=0, ii=str.length; i<ii; i++){
- c = str[i];
-
- if (cp === "$" && c === "{"){
- key = key.substring (0, key.length - 1);
- stack.push ({
- key: key,
- section: section
- });
+ var line = function (){
+ if (key || value || sep){
+ handlers.line (key, value);
key = "";
- section = null;
+ value = "";
+ sep = false;
+ }
+ };
+
+ var escapeString = function (key, c){
+ if (escapingUnicode && unicodeRemaining){
+ unicode = (unicode<<4) + hex (c);
+ if (--unicodeRemaining) return key;
+ escape = false;
+ escapingUnicode = false;
+ return key + String.fromCharCode (unicode);
+ }
+
+ if (c === "u"){
+ unicode = 0;
+ escapingUnicode = true;
+ unicodeRemaining = 4;
+ return key;
+ }
+
+ escape = false;
+
+ if (c === "t") return key + "\t";
+ else if (c === "r") return key + "\r";
+ else if (c === "n") return key + "\n";
+ else if (c === "f") return key + "\f";
+
+ return key + c;
+ };
+
+ for (var i=0, ii=data.length; i<ii; i++){
+ if (control.abort) return;
+ c = data[i];
+
+ if (c === "\r") continue;
+
+ if (isCommentLine){
+ if (c === "\n"){
+ isCommentLine = false;
+ newLine = true;
+ skipSpace = true;
+ }
+ continue;
+ }
+
+ if (isSectionLine && c === "]"){
+ handlers.section (section);
+ //Ignore chars after the section in the same line
+ ignoreLine = true;
continue;
- }else if (stack.length){
- if (settings.sections && c === "|"){
- section = key;
- key = "";
+ }
+
+ if (skipSpace){
+ if (c === " " || c === "\t" || c === "\f"){
continue;
- }else if (c === "}"){
- holder = section !== null ? o[section] : o;
- if (!holder){
- return cb (new Error ("Cannot found the section \"" + section + "\""),
- null);
- }
- if (!(key in holder)){
- return cb (new Error ("Cannot found the property \"" + key + "\""),
- null);
- }
- v = holder[key];
- t = stack.pop ();
- section = t.section;
- key = t.key + (v === null ? "" : v);
+ }
+ if (!multiLine && c === "\n"){
+ //Empty line or key w/ separator and w/o value
+ isKey = true;
+ keySpace = false;
+ line ();
continue;
}
+ skipSpace = false;
+ multiLine = false;
}
- cp = c;
- key += c;
- }
-
- if (stack.length !== 0){
- return cb (new Error ("Malformed variable: " + str), null);
- }
-
- cb (null, key);
-};
-
-var build = function (data, settings, cb){
- var o = {};
- var convert = settings.json ? convertJson : convertType;
- var currentSection = null;
-
- //Line handler
- var line;
- if (settings.reviver){
- settings.reviver.isProperty = true;
- settings.reviver.isSection = false;
-
- if (settings.sections){
- line = function (error, key, value){
- value = settings.reviver (key, value, currentSection);
- if (value !== undefined){
- if (currentSection === null) o[key] = value;
- else (o[currentSection])[key] = value;
- }
- };
- }else{
- line = function (error, key, value){
- value = settings.reviver (key, value);
- if (value !== undefined) o[key] = value;
- };
- }
- }else{
- if (settings.sections){
- line = function (error, key, value){
- if (currentSection === null) o[key] = value;
- else o[currentSection][key] = value;
- };
- }else{
- line = function (error, key, value){
- o[key] = value;
- };
+ if (newLine){
+ newLine = false;
+ if (c === "#" || c === "!" || options.comments[c]){
+ isCommentLine = true;
+ continue;
+ }
+ if (options.sections && c === "["){
+ section = "";
+ isSectionLine = true;
+ control.skipSection = false;
+ continue;
+ }
}
- }
-
- //Section handler
- var section;
- if (settings.reviver){
- settings.reviver.isProperty = false;
- settings.reviver.isSection = true;
- section = function (section){
- var add = settings.reviver (null, null, section);
- if (add){
- currentSection = section;
- o[currentSection] = {};
+ if (c !== "\n"){
+ if (control.skipSection || ignoreLine) continue;
+
+ if (!isSectionLine){
+ if (!escape && (c === "=" || c === ":" || options.separators[c])){
+ if (isKey){
+ //sep is needed to detect empty key and empty value with a
+ //non-whitespace separator
+ sep = true;
+ isKey = false;
+ keySpace = false;
+ //Skip whitespace between separator and value
+ skipSpace = true;
+ continue;
+ }
+ }
+
+ if (keySpace){
+ //Line with whitespace separator
+ keySpace = false;
+ isKey = false;
+ }
+ }
+
+ if (c === "\\"){
+ if (escape){
+ if (isSectionLine) section += "\\";
+ else if (isKey) key += "\\";
+ else value += "\\";
+ }
+ escape = !escape;
}else{
- r.skipSection ();
+ if (isSectionLine){
+ if (escape) section = escapeString (section, c);
+ else section += c;
+ }else if (isKey){
+ if (escape){
+ key = escapeString (key, c);
+ }else{
+ if (c === " " || c === "\t" || c === "\f"){
+ keySpace = true;
+ //Skip whitespace between key and separator
+ skipSpace = true;
+ continue;
+ }
+ key += c;
+ }
+ }else{
+ if (escape) value = escapeString (value, c);
+ else value += c;
+ }
}
- };
- }else{
- section = function (section){
- currentSection = section;
- o[currentSection] = {};
- };
- }
-
- var abort = function (error){
- r.abort ();
- cb (error);
- };
-
- var r = reader.create (data, settings)
- .on ("line", function (key, value){
- //Variable expansion
- expand (o, key, settings, function (error, key){
- if (error) return abort (error);
-
- expand (o, value, settings, function (error, value){
- if (error) return abort (error);
-
- //Type conversion
- convert (value || null, function (error, value){
- if (error) return abort (error);
-
- line (error, key, value);
- });
- });
- });
- })
- .on ("section", function (s){
- expand (o, s, settings, function (error, s){
- if (error) return abort (error);
-
- section (s);
- });
- })
- .on ("end", function (){
- if (settings.reviver){
- delete settings.reviver.isProperty;
- delete settings.reviver.isSection;
+ }else{
+ if (escape){
+ escape = false;
+ skipSpace = true;
+ multiLine = true;
+ }else{
+ if (isSectionLine){
+ isSectionLine = false;
+ ignoreLine = false;
}
- cb (null, o);
- });
-};
-
-module.exports = function (p, settings, cb){
- if (arguments.length === 2){
- cb = settings;
- settings = {
- json: true
- };
+ newLine = true;
+ skipSpace = true;
+ isKey = true;
+
+ line ();
+ }
+ }
}
- if (settings.json === undefined) settings.json = true;
-
- if (!settings.data){
- fs.readFile (p, { encoding: "utf8" }, function (error, data){
- if (error) return cb (error);
- build (data, settings, cb);
- });
- }else{
- build (p, settings, cb);
- }
+ line ();
};
254 lib/read.js
View
@@ -0,0 +1,254 @@
+"use strict";
+
+var fs = require ("fs");
+var parse = require ("./parse");
+
+var convertType = function (value, cb){
+ if (value === null) return cb (null, null);
+ if (value === "null") return cb (null, null);
+ if (value === "true") return cb (null, true);
+ if (value === "false") return cb (null, false);
+ var v = Number (value);
+ if (!isNaN (value)) return cb (null, v);
+ cb (null, value);
+};
+
+var convertJson = function (value, cb){
+ if (value === null) return cb (null, null);
+
+ if (value[0] === "{" || value[0] === "["){
+ try{
+ cb (null, JSON.parse (value));
+ }catch (error){
+ cb (error);
+ }
+ }else{
+ convertType (value, cb);
+ }
+};
+
+var expand = function (o, str, options, cb){
+ if (!options.variables || !str) return cb (null, str);
+
+ var stack = [];
+ var c;
+ var cp;
+ var key = "";
+ var section = null;
+ var v;
+ var holder;
+ var t;
+
+ for (var i=0, ii=str.length; i<ii; i++){
+ c = str[i];
+
+ if (cp === "$" && c === "{"){
+ key = key.substring (0, key.length - 1);
+ stack.push ({
+ key: key,
+ section: section
+ });
+ key = "";
+ section = null;
+ continue;
+ }else if (stack.length){
+ if (options.sections && c === "|"){
+ section = key;
+ key = "";
+ continue;
+ }else if (c === "}"){
+ holder = section !== null ? o[section] : o;
+ if (!holder){
+ return cb (new Error ("Cannot found the section \"" + section +
+ "\""));
+ }
+ if (!(key in holder)){
+ return cb (new Error ("Cannot found the property \"" + key + "\""));
+ }
+ v = holder[key];
+ t = stack.pop ();
+ section = t.section;
+ key = t.key + (v === null ? "" : v);
+ continue;
+ }
+ }
+
+ cp = c;
+ key += c;
+ }
+
+ if (stack.length !== 0){
+ return cb (new Error ("Malformed variable: " + str));
+ }
+
+ cb (null, key);
+};
+
+var build = function (data, options, cb){
+ var o = {};
+ var convert = options.json ? convertJson : convertType;
+ var currentSection = null;
+
+ var abort = function (error){
+ control.abort = true;
+ if (cb) return cb (error);
+ throw error;
+ };
+
+ var handlers = {};
+
+ //Line handler
+ var line;
+ if (options.reviver){
+ options.reviver.isProperty = true;
+ options.reviver.isSection = false;
+
+ if (options.sections){
+ line = function (error, key, value){
+ value = options.reviver (key, value, currentSection);
+ if (value !== undefined){
+ if (currentSection === null) o[key] = value;
+ else o[currentSection][key] = value;
+ }
+ };
+ }else{
+ line = function (error, key, value){
+ value = options.reviver (key, value);
+ if (value !== undefined) o[key] = value;
+ };
+ }
+ }else{
+ if (options.sections){
+ line = function (error, key, value){
+ if (currentSection === null) o[key] = value;
+ else o[currentSection][key] = value;
+ };
+ }else{
+ line = function (error, key, value){
+ o[key] = value;
+ };
+ }
+ }
+
+ //Section handler
+ var section;
+ if (options.sections){
+ if (options.reviver){
+ options.reviver.isProperty = false;
+ options.reviver.isSection = true;
+
+ section = function (section){
+ var add = options.reviver (null, null, section);
+ if (add){
+ currentSection = section;
+ o[currentSection] = {};
+ }else{
+ control.skipSection = true;
+ }
+ };
+ }else{
+ section = function (section){
+ currentSection = section;
+ o[currentSection] = {};
+ };
+ }
+ }
+
+ //Variables
+ if (options.variables){
+ handlers.line = function (key, value){
+ expand (o, key, options, function (error, key){
+ if (error) return abort (error);
+
+ expand (o, value, options, function (error, value){
+ if (error) return abort (error);
+
+ convert (value || null, function (error, value){
+ if (error) return abort (error);
+
+ line (error, key, value);
+ });
+ });
+ });
+ };
+
+ if (options.sections){
+ handlers.section = function (s){
+ expand (o, s, options, function (error, s){
+ if (error) return abort (error);
+
+ section (s);
+ });
+ };
+ }
+ }else{
+ handlers.line = function (key, value){
+ convert (value || null, function (error, value){
+ if (error) return abort (error);
+
+ line (error, key, value);
+ });
+ };
+
+ if (options.sections){
+ handlers.section = section;
+ }
+ }
+
+ var control = {
+ abort: false,
+ skipSection: false
+ };
+
+ parse (data, options, handlers, control);
+
+ if (options.reviver){
+ delete options.reviver.isProperty;
+ delete options.reviver.isSection;
+ }
+
+ if (cb) return cb (null, o);
+ return o;
+};
+
+module.exports = function (data, options, cb){
+ if (arguments.length === 2 && typeof options === "function"){
+ cb = options;
+ options = {};
+ }
+
+ var comments = options.comments || [];
+ if (!Array.isArray (comments)) comments = [comments];
+ var c = {};
+ comments.forEach (function (comment){
+ c[comment] = true;
+ });
+
+ var separators = options.separators || [];
+ if (!Array.isArray (separators)) separators = [separators];
+ var s = {};
+ separators.forEach (function (separator){
+ s[separator] = true;
+ });
+
+ options = {
+ json: options.json,
+ path: options.path,
+ sections: options.sections,
+ variables: options.variables,
+ reviver: options.reviver,
+ comments: c,
+ separators: s
+ };
+
+ if (options.path){
+ if (!cb) throw new TypeError ("A callback must be passed if the data is " +
+ "a path");
+ fs.readFile (data, { encoding: "utf8" }, function (error, data){
+ if (error) return cb (error);
+ build (data, options, cb);
+ });
+ }else{
+ return build (data, options, cb);
+ }
+};
239 lib/reader.js
View
@@ -1,239 +0,0 @@
-"use strict";
-
-var events = require ("events");
-var util = require ("util");
-
-module.exports.create = function (data, settings){
- return new Reader (data, settings);
-};
-
-var Reader = function (data, settings){
- events.EventEmitter.call (this);
-
- var me = this;
-
- var comments = settings.comments || [];
- if (!Array.isArray (comments)) comments = [comments];
- this._comments = {};
- comments.forEach (function (comment){
- me._comments[comment] = true;
- });
-
- var separators = settings.separators || [];
- if (!Array.isArray (separators)) separators = [separators];
- this._separators = {};
- separators.forEach (function (separator){
- me._separators[separator] = true;
- });
-
- this._sections = settings.sections;
- this._abort = false;
-
- process.nextTick (function (){
- me._parse (data);
- });
-};
-
-util.inherits (Reader, events.EventEmitter);
-
-Reader.prototype._isComment = function (c){
- //User defined comment tokens
- return !!this._comments[c];
-};
-
-Reader.prototype._isSeparator = function (c){
- //User defined separator tokens
- return !!this._separators[c];
-};
-
-Reader.prototype._parse = function (data){
- var c;
- var escape;
- var skipSpace = true;
- var isCommentLine;
- var isSectionLine;
- var newLine = true;
- var multiLine;
- var isKey = true;
- var key = "";
- var value = "";
- var section;
- var unicode;
- var unicodeRemaining;
- var escapingUnicode;
- var keySpace;
- var sep;
- var ignoreLine;
-
- var me = this;
-
- var line = function (){
- if (key || value || sep){
- me.emit ("line", key, value);
- key = "";
- value = "";
- sep = false;
- }
- };
-
- var escapeString = function (key, c){
- if (escapingUnicode && unicodeRemaining){
- unicode += c;
- if (--unicodeRemaining) return key;
- escape = false;
- escapingUnicode = false;
- return key + String.fromCharCode (parseInt (unicode[0] + unicode[1] +
- unicode[2] + unicode[3], 16));
- }
-
- if (c === "u"){
- unicode = "";
- escapingUnicode = true;
- unicodeRemaining = 4;
- return key;
- }
-
- escape = false;
-
- if (c === "t") return key + "\t";
- else if (c === "r") return key + "\r";
- else if (c === "n") return key + "\n";
- else if (c === "f") return key + "\f";
-
- return key + c;
- };
-
- for (var i=0, ii=data.length; i<ii; i++){
- if (this._abort) return;
- c = data[i];
-
- if (c === "\r") continue;
-
- if (isCommentLine){
- if (c === "\n"){
- isCommentLine = false;
- newLine = true;
- skipSpace = true;
- }
- continue;
- }
-
- if (isSectionLine && c === "]"){
- this.emit ("section", section);
- //Ignore chars after the section in the same line
- ignoreLine = true;
- continue;
- }
-
- if (skipSpace){
- if (c === " " || c === "\t" || c === "\f"){
- continue;
- }
- if (!multiLine && c === "\n"){
- //Empty line or key w/ separator and w/o value
- isKey = true;
- keySpace = false;
- line ();
- continue;
- }
- skipSpace = false;
- multiLine = false;
- }
-
- if (newLine){
- newLine = false;
- if (c === "#" || c === "!" || this._isComment (c)){
- isCommentLine = true;
- continue;
- }
- if (this._sections && c === "["){
- section = "";
- isSectionLine = true;
- this._skipSection = false;
- continue;
- }
- }
-
- if (c !== "\n"){
- if (this._skipSection || ignoreLine) continue;
-
- if (!isSectionLine){
- if (!escape && (c === "=" || c === ":" || this._isSeparator (c))){
- if (isKey){
- //sep is needed to detect empty key and empty value with a
- //non-whitespace separator
- sep = true;
- isKey = false;
- keySpace = false;
- //Skip whitespace between separator and value
- skipSpace = true;
- continue;
- }
- }
-
- if (keySpace){
- //Line with whitespace separator
- keySpace = false;
- isKey = false;
- }
- }
-
- if (c === "\\"){
- if (escape){
- if (isSectionLine) section += "\\";
- else if (isKey) key += "\\";
- else value += "\\";
- }
- escape = !escape;
- }else{
- if (isSectionLine){
- if (escape) section = escapeString (section, c);
- else section += c;
- }else if (isKey){
- if (escape){
- key = escapeString (key, c);
- }else{
- if (c === " " || c === "\t" || c === "\f"){
- keySpace = true;
- //Skip whitespace between key and separator
- skipSpace = true;
- continue;
- }
- key += c;
- }
- }else{
- if (escape) value = escapeString (value, c);
- else value += c;
- }
- }
- }else{
- if (escape){
- escape = false;
- skipSpace = true;
- multiLine = true;
- }else{
- if (isSectionLine){
- isSectionLine = false;
- ignoreLine = false;
- }
- newLine = true;
- skipSpace = true;
- isKey = true;
-
- line ();
- }
- }
- }
-
- line ();
-
- this.emit ("end");
-};
-
-Reader.prototype.abort = function (){
- this._abort = true;
-};
-
-Reader.prototype.skipSection = function (){
- this._skipSection = true;
-};
0  lib/stringify.js → lib/write.js
View
File renamed without changes
3  package.json
View
@@ -14,6 +14,9 @@
"engines": {
"node": ">=0.10"
},
+ "devDependencies": {
+ "ini": "*"
+ },
"license": "MIT",
"main": "lib"
}
48 test/index.js
View
@@ -5,7 +5,9 @@ var properties = require ("../lib");
var tests = {
"load properties": function (done){
- properties.parse ("properties", function (error, p){
+ var options = { path: true, json: true };
+
+ properties.parse ("properties", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -40,14 +42,15 @@ var tests = {
a22: 123,
a23: [1, 2, 3],
a24: { "1": { "2": 3 }},
- "[a]": null
+ "[a]": null,
+ a25: null
});
done ();
});
},
"load properties (empty key, empty value)": function (done){
- properties.parse (":", { data: true }, function (error, p){
+ properties.parse (":", function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -59,8 +62,7 @@ var tests = {
},
"load properties (no json)": function (done){
properties.parse ("a1 true\na2 false\na3 123\na4 [1, 2, \\\n " +
- "3]\na5 : { \"1\"\\\n : { \"2\": 3 }}", { data: true, json: false },
- function (error, p){
+ "3]\na5 : { \"1\"\\\n : { \"2\": 3 }}", function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -78,9 +80,9 @@ var tests = {
var reviver = function (key, value){
if (key === "a") return 1;
};
+ var options = { reviver: reviver };
- properties.parse ("a b\nc d", { data: true, reviver: reviver },
- function (error, p){
+ properties.parse ("a b\nc d", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -91,7 +93,7 @@ var tests = {
});
},
"empty data": function (done){
- properties.parse ("", { data: true }, function (error, p){
+ properties.parse ("", function (error, p){
assert.ifError (error);
assert.deepEqual (p, {});
@@ -100,8 +102,9 @@ var tests = {
});
},
"custom separator and comment tokens": function (done){
- var settings = { comments: ";", separators: "", data: true };
- properties.parse (";a\n!a\na1:b\na2→b", settings, function (error, p){
+ var options = { comments: ";", separators: "" };
+
+ properties.parse (";a\n!a\na1:b\na2→b", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -113,7 +116,9 @@ var tests = {
});
},
"sections": function (done){
- properties.parse ("sections", { sections: true }, function (error, p){
+ var options = { sections: true, path: true };
+
+ properties.parse ("sections", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -144,9 +149,9 @@ var tests = {
if (reviver.isSection) return section !== "a=1";
return value;
};
+ var options = { sections: true, reviver: reviver, path: true };
- properties.parse ("sections", { sections: true, reviver: reviver },
- function (error, p){
+ properties.parse ("sections", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -170,8 +175,9 @@ var tests = {
});
},
"variables": function (done){
- var settings = { variables: true, json: false };
- properties.parse ("variables", settings, function (error, p){
+ var options = { variables: true, json: false, path: true };
+
+ properties.parse ("variables", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -188,8 +194,9 @@ var tests = {
});
},
"variables with sections": function (done){
- var settings = { variables: true, sections: true, json: false };
- properties.parse ("variables-sections", settings, function (error, p){
+ var options = { variables: true, sections: true, json: false, path: true };
+
+ properties.parse ("variables-sections", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
@@ -219,12 +226,13 @@ var tests = {
});
},
"variables with json": function (done){
- var settings = { variables: true, sections: true };
- properties.parse ("variables-json", settings, function (error, p){
+ var options = { variables: true, sections: true, path: true, json: true };
+
+ properties.parse ("variables-json", options, function (error, p){
assert.ifError (error);
assert.deepEqual (p, {
- Me: {
+ profile: {
what: "mail",
name: "me",
email: "me@me.com",
1  test/properties
View
@@ -45,6 +45,7 @@ a23 [1, 2, \
3]
a24 : { "1"\
: { "2": 3 }}
+a25 null
#No sections
[a]
10 test/variables-json
View
@@ -1,10 +1,10 @@
-[Me]
+[profile]
what = mail
name = me
-e${Me|what} = me@me.com
+e${profile|what} = me@me.com
user = {\
"num": 1,\
- "friends": ["${Me|name}"],\
- "name": "${Me|name}",\
- "e${Me|what}": "${Me|email}"\
+ "friends": ["${profile|name}"],\
+ "name": "${profile|name}",\
+ "e${profile|what}": "${profile|email}"\
}
Please sign in to comment.
Something went wrong with that request. Please try again.