plist 1.1.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Parser functions.
3
+ */
4
+
5
+ var parserFunctions = require('./lib/parse');
6
+ Object.keys(parserFunctions).forEach(function (k) { exports[k] = parserFunctions[k]; });
7
+
8
+ /**
9
+ * Builder functions.
10
+ */
11
+
12
+ var builderFunctions = require('./lib/build');
13
+ Object.keys(builderFunctions).forEach(function (k) { exports[k] = builderFunctions[k]; });
package/lib/build.js CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -92,7 +91,9 @@ function walk_obj(next, next_child) {
92
91
  var tag_type, i, prop;
93
92
  var name = type(next);
94
93
 
95
- if (Array.isArray(next)) {
94
+ if ('Undefined' == name) {
95
+ return;
96
+ } else if (Array.isArray(next)) {
96
97
  next_child = next_child.ele('array');
97
98
  for (i = 0; i < next.length; i++) {
98
99
  walk_obj(next[i], next_child);
@@ -128,7 +129,7 @@ function walk_obj(next, next_child) {
128
129
  } else if ('ArrayBuffer' == name) {
129
130
  next_child.ele('data').raw(base64.fromByteArray(next));
130
131
 
131
- } else if (next.buffer && 'ArrayBuffer' == type(next.buffer)) {
132
+ } else if (next && next.buffer && 'ArrayBuffer' == type(next.buffer)) {
132
133
  // a typed array
133
134
  next_child.ele('data').raw(base64.fromByteArray(new Uint8Array(next.buffer), next_child));
134
135
 
package/lib/parse.js CHANGED
@@ -1,9 +1,7 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
5
4
 
6
- var deprecate = require('util-deprecate');
7
5
  var DOMParser = require('xmldom').DOMParser;
8
6
 
9
7
  /**
@@ -11,10 +9,11 @@ var DOMParser = require('xmldom').DOMParser;
11
9
  */
12
10
 
13
11
  exports.parse = parse;
14
- exports.parseString = deprecate(parseString, '`parseString()` is deprecated. ' +
15
- 'It\'s not actually async. Use `parse()` instead.');
16
- exports.parseStringSync = deprecate(parseStringSync, '`parseStringSync()` is ' +
17
- 'deprecated. Use `parse()` instead.');
12
+
13
+ var TEXT_NODE = 3;
14
+ var CDATA_NODE = 4;
15
+ var COMMENT_NODE = 8;
16
+
18
17
 
19
18
  /**
20
19
  * We ignore raw text (usually whitespace), <!-- xml comments -->,
@@ -26,77 +25,55 @@ exports.parseStringSync = deprecate(parseStringSync, '`parseStringSync()` is ' +
26
25
  */
27
26
 
28
27
  function shouldIgnoreNode (node) {
29
- return node.nodeType === 3 // text
30
- || node.nodeType === 8 // comment
31
- || node.nodeType === 4; // cdata
28
+ return node.nodeType === TEXT_NODE
29
+ || node.nodeType === COMMENT_NODE
30
+ || node.nodeType === CDATA_NODE;
32
31
  }
33
32
 
34
-
35
33
  /**
36
- * Parses a Plist XML string. Returns an Object.
34
+ * Check if the node is empty. Some plist file has such node:
35
+ * <key />
36
+ * this node shoud be ignored.
37
37
  *
38
- * @param {String} xml - the XML String to decode
39
- * @returns {Mixed} the decoded value from the Plist XML
40
- * @api public
38
+ * @see https://github.com/TooTallNate/plist.js/issues/66
39
+ * @param {Element} node
40
+ * @returns {Boolean}
41
+ * @api private
41
42
  */
42
-
43
- function parse (xml) {
44
- var doc = new DOMParser().parseFromString(xml);
45
- if (doc.documentElement.nodeName !== 'plist') {
46
- throw new Error('malformed document. First element should be <plist>');
43
+ function isEmptyNode(node){
44
+ if(!node.childNodes || node.childNodes.length === 0) {
45
+ return true;
46
+ } else {
47
+ return false;
47
48
  }
48
- var plist = parsePlistXML(doc.documentElement);
49
-
50
- // the root <plist> node gets interpreted as an Array,
51
- // so pull out the inner data first
52
- if (plist.length == 1) plist = plist[0];
53
-
54
- return plist;
55
49
  }
56
50
 
57
- /**
58
- * Parses a Plist XML string. Returns an Object. Takes a `callback` function.
59
- *
60
- * @param {String} xml - the XML String to decode
61
- * @param {Function} callback - callback function
62
- * @returns {Mixed} the decoded value from the Plist XML
63
- * @api public
64
- * @deprecated not actually async. use parse() instead
65
- */
66
-
67
- function parseString (xml, callback) {
68
- var doc, error, plist;
69
- try {
70
- doc = new DOMParser().parseFromString(xml);
71
- plist = parsePlistXML(doc.documentElement);
72
- } catch(e) {
73
- error = e;
51
+ function invariant(test, message) {
52
+ if (!test) {
53
+ throw new Error(message);
74
54
  }
75
- callback(error, plist);
76
55
  }
77
56
 
78
57
  /**
79
58
  * Parses a Plist XML string. Returns an Object.
80
59
  *
81
60
  * @param {String} xml - the XML String to decode
82
- * @param {Function} callback - callback function
83
61
  * @returns {Mixed} the decoded value from the Plist XML
84
62
  * @api public
85
- * @deprecated use parse() instead
86
63
  */
87
64
 
88
- function parseStringSync (xml) {
65
+ function parse (xml) {
89
66
  var doc = new DOMParser().parseFromString(xml);
90
- var plist;
91
- if (doc.documentElement.nodeName !== 'plist') {
92
- throw new Error('malformed document. First element should be <plist>');
93
- }
94
- plist = parsePlistXML(doc.documentElement);
67
+ invariant(
68
+ doc.documentElement.nodeName === 'plist',
69
+ 'malformed document. First element should be <plist>'
70
+ );
71
+ var plist = parsePlistXML(doc.documentElement);
72
+
73
+ // the root <plist> node gets interpreted as an Array,
74
+ // so pull out the inner data first
75
+ if (plist.length == 1) plist = plist[0];
95
76
 
96
- // if the plist is an array with 1 element, pull it out of the array
97
- if (plist.length == 1) {
98
- plist = plist[0];
99
- }
100
77
  return plist;
101
78
  }
102
79
 
@@ -109,41 +86,59 @@ function parseStringSync (xml) {
109
86
  */
110
87
 
111
88
  function parsePlistXML (node) {
112
- var i, new_obj, key, val, new_arr, res, d;
89
+ var i, new_obj, key, val, new_arr, res, counter, type;
113
90
 
114
91
  if (!node)
115
92
  return null;
116
93
 
117
94
  if (node.nodeName === 'plist') {
118
95
  new_arr = [];
96
+ if (isEmptyNode(node)) {
97
+ return new_arr;
98
+ }
119
99
  for (i=0; i < node.childNodes.length; i++) {
120
- // ignore comment nodes (text)
121
100
  if (!shouldIgnoreNode(node.childNodes[i])) {
122
101
  new_arr.push( parsePlistXML(node.childNodes[i]));
123
102
  }
124
103
  }
125
104
  return new_arr;
126
-
127
105
  } else if (node.nodeName === 'dict') {
128
106
  new_obj = {};
129
107
  key = null;
108
+ counter = 0;
109
+ if (isEmptyNode(node)) {
110
+ return new_obj;
111
+ }
130
112
  for (i=0; i < node.childNodes.length; i++) {
131
- // ignore comment nodes (text)
132
- if (!shouldIgnoreNode(node.childNodes[i])) {
133
- if (key === null) {
134
- key = parsePlistXML(node.childNodes[i]);
135
- } else {
136
- new_obj[key] = parsePlistXML(node.childNodes[i]);
137
- key = null;
138
- }
113
+ if (shouldIgnoreNode(node.childNodes[i])) continue;
114
+ if (counter % 2 === 0) {
115
+ invariant(
116
+ node.childNodes[i].nodeName === 'key',
117
+ 'Missing key while parsing <dict/>.'
118
+ );
119
+ key = parsePlistXML(node.childNodes[i]);
120
+ } else {
121
+ invariant(
122
+ node.childNodes[i].nodeName !== 'key',
123
+ 'Unexpected key "'
124
+ + parsePlistXML(node.childNodes[i])
125
+ + '" while parsing <dict/>.'
126
+ );
127
+ new_obj[key] = parsePlistXML(node.childNodes[i]);
139
128
  }
129
+ counter += 1;
130
+ }
131
+ if (counter % 2 === 1) {
132
+ throw new Error('Missing value for "' + key + '" while parsing <dict/>');
140
133
  }
141
134
  return new_obj;
142
135
 
143
136
  } else if (node.nodeName === 'array') {
144
137
  new_arr = [];
138
+ if (isEmptyNode(node)) {
139
+ return new_arr;
140
+ }
145
141
  for (i=0; i < node.childNodes.length; i++) {
146
- // ignore comment nodes (text)
147
142
  if (!shouldIgnoreNode(node.childNodes[i])) {
148
143
  res = parsePlistXML(node.childNodes[i]);
149
144
  if (null != res) new_arr.push(res);
@@ -155,40 +150,60 @@ function parsePlistXML (node) {
155
150
  // TODO: what should we do with text types? (CDATA sections)
156
151
 
157
152
  } else if (node.nodeName === 'key') {
153
+ if (isEmptyNode(node)) {
154
+ return '';
155
+ }
158
156
  return node.childNodes[0].nodeValue;
159
-
160
157
  } else if (node.nodeName === 'string') {
161
158
  res = '';
162
- for (d=0; d < node.childNodes.length; d++) {
163
- res += node.childNodes[d].nodeValue;
159
+ if (isEmptyNode(node)) {
160
+ return res;
161
+ }
162
+ for (i=0; i < node.childNodes.length; i++) {
163
+ var type = node.childNodes[i].nodeType;
164
+ if (type === TEXT_NODE || type === CDATA_NODE) {
165
+ res += node.childNodes[i].nodeValue;
166
+ }
164
167
  }
165
168
  return res;
166
169
 
167
170
  } else if (node.nodeName === 'integer') {
168
- // parse as base 10 integer
171
+ invariant(
172
+ !isEmptyNode(node),
173
+ 'Cannot parse "" as integer.'
174
+ );
169
175
  return parseInt(node.childNodes[0].nodeValue, 10);
170
176
 
171
177
  } else if (node.nodeName === 'real') {
178
+ invariant(
179
+ !isEmptyNode(node),
180
+ 'Cannot parse "" as real.'
181
+ );
172
182
  res = '';
173
- for (d=0; d < node.childNodes.length; d++) {
174
- if (node.childNodes[d].nodeType === 3) {
175
- res += node.childNodes[d].nodeValue;
183
+ for (i=0; i < node.childNodes.length; i++) {
184
+ if (node.childNodes[i].nodeType === TEXT_NODE) {
185
+ res += node.childNodes[i].nodeValue;
176
186
  }
177
187
  }
178
188
  return parseFloat(res);
179
189
 
180
190
  } else if (node.nodeName === 'data') {
181
191
  res = '';
182
- for (d=0; d < node.childNodes.length; d++) {
183
- if (node.childNodes[d].nodeType === 3) {
184
- res += node.childNodes[d].nodeValue.replace(/\s+/g, '');
192
+ if (isEmptyNode(node)) {
193
+ return new Buffer(res, 'base64');
194
+ }
195
+ for (i=0; i < node.childNodes.length; i++) {
196
+ if (node.childNodes[i].nodeType === TEXT_NODE) {
197
+ res += node.childNodes[i].nodeValue.replace(/\s+/g, '');
185
198
  }
186
199
  }
187
-
188
- // decode base64 data to a Buffer instance
189
200
  return new Buffer(res, 'base64');
190
201
 
191
202
  } else if (node.nodeName === 'date') {
203
+ invariant(
204
+ !isEmptyNode(node),
205
+ 'Cannot parse "" as Date.'
206
+ )
192
207
  return new Date(node.childNodes[0].nodeValue);
193
208
 
194
209
  } else if (node.nodeName === 'true') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "plist",
3
3
  "description": "Mac OS X Plist parser/builder for Node.js and browsers",
4
- "version": "1.1.0",
4
+ "version": "2.1.0",
5
5
  "author": "Nathan Rajlich <nathan@tootallnate.net>",
6
6
  "contributors": [
7
7
  "Hans Huebner <hans.huebner@gmail.com>",
@@ -14,6 +14,7 @@
14
14
  "type": "git",
15
15
  "url": "git://github.com/TooTallNate/node-plist.git"
16
16
  },
17
+ "license": "MIT",
17
18
  "keywords": [
18
19
  "apple",
19
20
  "browser",
@@ -22,18 +23,17 @@
22
23
  "parser",
23
24
  "xml"
24
25
  ],
25
- "main": "lib/plist.js",
26
+ "main": "index.js",
26
27
  "dependencies": {
27
- "base64-js": "0.0.6",
28
- "xmlbuilder": "2.2.1",
29
- "xmldom": "0.1.x",
30
- "util-deprecate": "1.0.0"
28
+ "base64-js": "1.2.0",
29
+ "xmlbuilder": "8.2.2",
30
+ "xmldom": "0.1.x"
31
31
  },
32
32
  "devDependencies": {
33
- "browserify": "5.10.1",
34
- "mocha": "1.18.2",
35
- "multiline": "0.3.4",
36
- "zuul": "1.10.2"
33
+ "browserify": "^14.3.0",
34
+ "mocha": "^3.3.0",
35
+ "multiline": "^1.0.2",
36
+ "zuul": "^3.10.1"
37
37
  },
38
38
  "scripts": {
39
39
  "test": "make test"
package/lib/node.js DELETED
@@ -1,49 +0,0 @@
1
- /**
2
- * Module dependencies.
3
- */
4
-
5
- var fs = require('fs');
6
- var parse = require('./parse');
7
- var deprecate = require('util-deprecate');
8
-
9
- /**
10
- * Module exports.
11
- */
12
-
13
- exports.parseFile = deprecate(parseFile, '`parseFile()` is deprecated. ' +
14
- 'Use `parseString()` instead.');
15
- exports.parseFileSync = deprecate(parseFileSync, '`parseFileSync()` is deprecated. ' +
16
- 'Use `parseStringSync()` instead.');
17
-
18
- /**
19
- * Parses file `filename` as a .plist file.
20
- * Invokes `fn` callback function when done.
21
- *
22
- * @param {String} filename - name of the file to read
23
- * @param {Function} fn - callback function
24
- * @api public
25
- * @deprecated use parseString() instead
26
- */
27
-
28
- function parseFile (filename, fn) {
29
- fs.readFile(filename, { encoding: 'utf8' }, onread);
30
- function onread (err, inxml) {
31
- if (err) return fn(err);
32
- parse.parseString(inxml, fn);
33
- }
34
- }
35
-
36
- /**
37
- * Parses file `filename` as a .plist file.
38
- * Returns a when done.
39
- *
40
- * @param {String} filename - name of the file to read
41
- * @param {Function} fn - callback function
42
- * @api public
43
- * @deprecated use parseStringSync() instead
44
- */
45
-
46
- function parseFileSync (filename) {
47
- var inxml = fs.readFileSync(filename, 'utf8');
48
- return parse.parseStringSync(inxml);
49
- }
package/lib/plist.js DELETED
@@ -1,23 +0,0 @@
1
-
2
- var i;
3
-
4
- /**
5
- * Parser functions.
6
- */
7
-
8
- var parserFunctions = require('./parse');
9
- for (i in parserFunctions) exports[i] = parserFunctions[i];
10
-
11
- /**
12
- * Builder functions.
13
- */
14
-
15
- var builderFunctions = require('./build');
16
- for (i in builderFunctions) exports[i] = builderFunctions[i];
17
-
18
- /**
19
- * Add Node.js-specific functions (they're deprecated…).
20
- */
21
-
22
- var nodeFunctions = require('./node');
23
- for (i in nodeFunctions) exports[i] = nodeFunctions[i];
package/test/build.js DELETED
@@ -1,133 +0,0 @@
1
-
2
- var assert = require('assert');
3
- var build = require('../').build;
4
- var multiline = require('multiline');
5
-
6
- describe('plist', function () {
7
-
8
- describe('build()', function () {
9
-
10
- it('should create a plist XML string from a String', function () {
11
- var xml = build('test');
12
- assert.strictEqual(xml, multiline(function () {/*
13
- <?xml version="1.0" encoding="UTF-8"?>
14
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
15
- <plist version="1.0">
16
- <string>test</string>
17
- </plist>
18
- */}));
19
- });
20
-
21
- it('should create a plist XML integer from a whole Number', function () {
22
- var xml = build(3);
23
- assert.strictEqual(xml, multiline(function () {/*
24
- <?xml version="1.0" encoding="UTF-8"?>
25
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
26
- <plist version="1.0">
27
- <integer>3</integer>
28
- </plist>
29
- */}));
30
- });
31
-
32
- it('should create a plist XML real from a fractional Number', function () {
33
- var xml = build(Math.PI);
34
- assert.strictEqual(xml, multiline(function () {/*
35
- <?xml version="1.0" encoding="UTF-8"?>
36
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
37
- <plist version="1.0">
38
- <real>3.141592653589793</real>
39
- </plist>
40
- */}));
41
- });
42
-
43
- it('should create a plist XML date from a Date', function () {
44
- var xml = build(new Date('2010-02-08T21:41:23Z'));
45
- assert.strictEqual(xml, multiline(function () {/*
46
- <?xml version="1.0" encoding="UTF-8"?>
47
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
48
- <plist version="1.0">
49
- <date>2010-02-08T21:41:23Z</date>
50
- </plist>
51
- */}));
52
- });
53
-
54
- it('should create a plist XML date from a Buffer', function () {
55
- var xml = build(new Buffer('☃'));
56
- assert.strictEqual(xml, multiline(function () {/*
57
- <?xml version="1.0" encoding="UTF-8"?>
58
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
59
- <plist version="1.0">
60
- <data>4piD</data>
61
- </plist>
62
- */}));
63
- });
64
-
65
- it('should create a plist XML true from a `true` Boolean', function () {
66
- var xml = build(true);
67
- assert.strictEqual(xml, multiline(function () {/*
68
- <?xml version="1.0" encoding="UTF-8"?>
69
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
70
- <plist version="1.0">
71
- <true/>
72
- </plist>
73
- */}));
74
- });
75
-
76
- it('should create a plist XML false from a `false` Boolean', function () {
77
- var xml = build(false);
78
- assert.strictEqual(xml, multiline(function () {/*
79
- <?xml version="1.0" encoding="UTF-8"?>
80
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
81
- <plist version="1.0">
82
- <false/>
83
- </plist>
84
- */}));
85
- });
86
-
87
- it('should create a plist XML dict from an Object', function () {
88
- var xml = build({ foo: 'bar' });
89
- assert.strictEqual(xml, multiline(function () {/*
90
- <?xml version="1.0" encoding="UTF-8"?>
91
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
92
- <plist version="1.0">
93
- <dict>
94
- <key>foo</key>
95
- <string>bar</string>
96
- </dict>
97
- </plist>
98
- */}));
99
- });
100
-
101
- it('should create a plist XML array from an Array', function () {
102
- var xml = build([ 1, 'foo', false, new Date(1234) ]);
103
- assert.strictEqual(xml, multiline(function () {/*
104
- <?xml version="1.0" encoding="UTF-8"?>
105
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
106
- <plist version="1.0">
107
- <array>
108
- <integer>1</integer>
109
- <string>foo</string>
110
- <false/>
111
- <date>1970-01-01T00:00:01Z</date>
112
- </array>
113
- </plist>
114
- */}));
115
- });
116
-
117
- it('should properly encode an empty string', function () {
118
- var xml = build({ a: '' });
119
- assert.strictEqual(xml, multiline(function () {/*
120
- <?xml version="1.0" encoding="UTF-8"?>
121
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
122
- <plist version="1.0">
123
- <dict>
124
- <key>a</key>
125
- <string></string>
126
- </dict>
127
- </plist>
128
- */}));
129
- });
130
-
131
- });
132
-
133
- });