plist 2.0.1 → 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/History.md CHANGED
@@ -1,3 +1,11 @@
1
+ 2.1.0 / 2017-05-04
2
+ ==================
3
+
4
+ * [[`e4f06669bb`]](https://github.com/TooTallNate/plist.js/commit/e4f06669bb51d2e65654df7c39aab52bc3bf4e8a) - update license (extend copyright term) (Mike Reinstein)
5
+ * [[`edc6e41035`]](https://github.com/TooTallNate/plist.js/commit/edc6e4103546b1d7518a577e7c202c305a8abec0) - update module deps (Mike Reinstein)
6
+ * [[`85d11c48ef`](https://github.com/TooTallNate/plist.js/commit/85d11c48eff02312cbdd67f46fd8e74b0d372ca1)] - Harden test-cases and implementation to align with other implementations (Björn Brauer)
7
+ * [[`7619537eaa`]](https://github.com/TooTallNate/plist.js/commit/7619537eaa9e3e5a80829e759c004d2e017a07d2) review feedback: early returns and constants for nodeTypes (Björn Brauer)
8
+
1
9
  2.0.1 / 2016-08-16
2
10
  ==================
3
11
 
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2010-2014 Nathan Rajlich <nathan@tootallnate.net>
3
+ Copyright (c) 2010-2017 Nathan Rajlich <nathan@tootallnate.net>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person
6
6
  obtaining a copy of this software and associated documentation
package/README.md CHANGED
@@ -69,7 +69,7 @@ Parsing a plist from string payload:
69
69
  ``` javascript
70
70
  var plist = require('plist');
71
71
 
72
- var xml =
72
+ var xml =
73
73
  '<?xml version="1.0" encoding="UTF-8"?>' +
74
74
  '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' +
75
75
  '<plist version="1.0">' +
@@ -138,27 +138,4 @@ console.log(plist.build(json));
138
138
 
139
139
  ## License
140
140
 
141
- (The MIT License)
142
-
143
- Copyright (c) 2010-2014 Nathan Rajlich <nathan@tootallnate.net>
144
-
145
- Permission is hereby granted, free of charge, to any person
146
- obtaining a copy of this software and associated documentation
147
- files (the "Software"), to deal in the Software without
148
- restriction, including without limitation the rights to use,
149
- copy, modify, merge, publish, distribute, sublicense, and/or sell
150
- copies of the Software, and to permit persons to whom the
151
- Software is furnished to do so, subject to the following
152
- conditions:
153
-
154
- The above copyright notice and this permission notice shall be
155
- included in all copies or substantial portions of the Software.
156
-
157
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
158
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
159
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
160
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
161
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
162
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
163
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
164
- OTHER DEALINGS IN THE SOFTWARE.
141
+ [(The MIT License)](LICENSE)
package/lib/parse.js CHANGED
@@ -10,6 +10,11 @@ var DOMParser = require('xmldom').DOMParser;
10
10
 
11
11
  exports.parse = parse;
12
12
 
13
+ var TEXT_NODE = 3;
14
+ var CDATA_NODE = 4;
15
+ var COMMENT_NODE = 8;
16
+
17
+
13
18
  /**
14
19
  * We ignore raw text (usually whitespace), <!-- xml comments -->,
15
20
  * and raw CDATA nodes.
@@ -20,9 +25,9 @@ exports.parse = parse;
20
25
  */
21
26
 
22
27
  function shouldIgnoreNode (node) {
23
- return node.nodeType === 3 // text
24
- || node.nodeType === 8 // comment
25
- || node.nodeType === 4; // cdata
28
+ return node.nodeType === TEXT_NODE
29
+ || node.nodeType === COMMENT_NODE
30
+ || node.nodeType === CDATA_NODE;
26
31
  }
27
32
 
28
33
  /**
@@ -43,6 +48,12 @@ function isEmptyNode(node){
43
48
  }
44
49
  }
45
50
 
51
+ function invariant(test, message) {
52
+ if (!test) {
53
+ throw new Error(message);
54
+ }
55
+ }
56
+
46
57
  /**
47
58
  * Parses a Plist XML string. Returns an Object.
48
59
  *
@@ -53,9 +64,10 @@ function isEmptyNode(node){
53
64
 
54
65
  function parse (xml) {
55
66
  var doc = new DOMParser().parseFromString(xml);
56
- if (doc.documentElement.nodeName !== 'plist') {
57
- throw new Error('malformed document. First element should be <plist>');
58
- }
67
+ invariant(
68
+ doc.documentElement.nodeName === 'plist',
69
+ 'malformed document. First element should be <plist>'
70
+ );
59
71
  var plist = parsePlistXML(doc.documentElement);
60
72
 
61
73
  // the root <plist> node gets interpreted as an Array,
@@ -74,41 +86,59 @@ function parse (xml) {
74
86
  */
75
87
 
76
88
  function parsePlistXML (node) {
77
- var i, new_obj, key, val, new_arr, res, d;
89
+ var i, new_obj, key, val, new_arr, res, counter, type;
78
90
 
79
91
  if (!node)
80
92
  return null;
81
93
 
82
94
  if (node.nodeName === 'plist') {
83
95
  new_arr = [];
96
+ if (isEmptyNode(node)) {
97
+ return new_arr;
98
+ }
84
99
  for (i=0; i < node.childNodes.length; i++) {
85
- // ignore comment nodes (text)
86
100
  if (!shouldIgnoreNode(node.childNodes[i])) {
87
101
  new_arr.push( parsePlistXML(node.childNodes[i]));
88
102
  }
89
103
  }
90
104
  return new_arr;
91
-
92
105
  } else if (node.nodeName === 'dict') {
93
106
  new_obj = {};
94
107
  key = null;
108
+ counter = 0;
109
+ if (isEmptyNode(node)) {
110
+ return new_obj;
111
+ }
95
112
  for (i=0; i < node.childNodes.length; i++) {
96
- // ignore comment nodes (text)
97
- if (!shouldIgnoreNode(node.childNodes[i])) {
98
- if (key === null) {
99
- key = parsePlistXML(node.childNodes[i]);
100
- } else {
101
- new_obj[key] = parsePlistXML(node.childNodes[i]);
102
- key = null;
103
- }
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]);
104
128
  }
129
+ counter += 1;
130
+ }
131
+ if (counter % 2 === 1) {
132
+ throw new Error('Missing value for "' + key + '" while parsing <dict/>');
105
133
  }
106
134
  return new_obj;
107
135
 
108
136
  } else if (node.nodeName === 'array') {
109
137
  new_arr = [];
138
+ if (isEmptyNode(node)) {
139
+ return new_arr;
140
+ }
110
141
  for (i=0; i < node.childNodes.length; i++) {
111
- // ignore comment nodes (text)
112
142
  if (!shouldIgnoreNode(node.childNodes[i])) {
113
143
  res = parsePlistXML(node.childNodes[i]);
114
144
  if (null != res) new_arr.push(res);
@@ -120,45 +150,60 @@ function parsePlistXML (node) {
120
150
  // TODO: what should we do with text types? (CDATA sections)
121
151
 
122
152
  } else if (node.nodeName === 'key') {
123
- if(isEmptyNode(node)) return null;
124
- res = '';
125
- if(node.childNodes[0]) {
126
- res = node.childNodes[0].nodeValue;
153
+ if (isEmptyNode(node)) {
154
+ return '';
127
155
  }
128
- return res;
156
+ return node.childNodes[0].nodeValue;
129
157
  } else if (node.nodeName === 'string') {
130
158
  res = '';
131
- if(isEmptyNode(node)) return null;
132
- for (d=0; d < node.childNodes.length; d++) {
133
- 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
+ }
134
167
  }
135
168
  return res;
136
169
 
137
170
  } else if (node.nodeName === 'integer') {
138
- // parse as base 10 integer
171
+ invariant(
172
+ !isEmptyNode(node),
173
+ 'Cannot parse "" as integer.'
174
+ );
139
175
  return parseInt(node.childNodes[0].nodeValue, 10);
140
176
 
141
177
  } else if (node.nodeName === 'real') {
178
+ invariant(
179
+ !isEmptyNode(node),
180
+ 'Cannot parse "" as real.'
181
+ );
142
182
  res = '';
143
- for (d=0; d < node.childNodes.length; d++) {
144
- if (node.childNodes[d].nodeType === 3) {
145
- 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;
146
186
  }
147
187
  }
148
188
  return parseFloat(res);
149
189
 
150
190
  } else if (node.nodeName === 'data') {
151
191
  res = '';
152
- for (d=0; d < node.childNodes.length; d++) {
153
- if (node.childNodes[d].nodeType === 3) {
154
- 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, '');
155
198
  }
156
199
  }
157
-
158
- // decode base64 data to a Buffer instance
159
200
  return new Buffer(res, 'base64');
160
201
 
161
202
  } else if (node.nodeName === 'date') {
203
+ invariant(
204
+ !isEmptyNode(node),
205
+ 'Cannot parse "" as Date.'
206
+ )
162
207
  return new Date(node.childNodes[0].nodeValue);
163
208
 
164
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": "2.0.1",
4
+ "version": "2.1.0",
5
5
  "author": "Nathan Rajlich <nathan@tootallnate.net>",
6
6
  "contributors": [
7
7
  "Hans Huebner <hans.huebner@gmail.com>",
@@ -25,15 +25,15 @@
25
25
  ],
26
26
  "main": "index.js",
27
27
  "dependencies": {
28
- "base64-js": "1.1.2",
28
+ "base64-js": "1.2.0",
29
29
  "xmlbuilder": "8.2.2",
30
30
  "xmldom": "0.1.x"
31
31
  },
32
32
  "devDependencies": {
33
- "browserify": "13.0.1",
34
- "mocha": "2.4.5",
35
- "multiline": "1.0.2",
36
- "zuul": "3.10.1"
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"