plist 2.0.1 → 3.0.2

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/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 Buffer.from(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
- return new Buffer(res, 'base64');
200
+ return Buffer.from(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": "3.0.2",
5
5
  "author": "Nathan Rajlich <nathan@tootallnate.net>",
6
6
  "contributors": [
7
7
  "Hans Huebner <hans.huebner@gmail.com>",
@@ -25,17 +25,20 @@
25
25
  ],
26
26
  "main": "index.js",
27
27
  "dependencies": {
28
- "base64-js": "1.1.2",
29
- "xmlbuilder": "8.2.2",
30
- "xmldom": "0.1.x"
28
+ "base64-js": "^1.5.1",
29
+ "xmlbuilder": "^9.0.7",
30
+ "xmldom": "^0.5.0"
31
31
  },
32
32
  "devDependencies": {
33
- "browserify": "13.0.1",
34
- "mocha": "2.4.5",
35
- "multiline": "1.0.2",
33
+ "browserify": "^16.5.2",
34
+ "mocha": "^5.2.0",
35
+ "multiline": "^1.0.2",
36
36
  "zuul": "3.10.1"
37
37
  },
38
38
  "scripts": {
39
39
  "test": "make test"
40
+ },
41
+ "engines": {
42
+ "node": ">=6"
40
43
  }
41
44
  }