plist 3.1.1 → 4.0.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/README.md CHANGED
@@ -20,33 +20,44 @@ and vice-versa.
20
20
  Install using `npm`:
21
21
 
22
22
  ``` bash
23
- $ npm install --save plist
23
+ $ npm install plist
24
24
  ```
25
25
 
26
- Then `require()` the _plist_ module in your file:
26
+ Then import the `parse()` and `build()` functions:
27
27
 
28
28
  ``` js
29
- var plist = require('plist');
29
+ import { parse, build } from 'plist';
30
30
 
31
- // now use the `parse()` and `build()` functions
32
- var val = plist.parse('<plist><string>Hello World!</string></plist>');
31
+ const val = parse('<plist><string>Hello World!</string></plist>');
33
32
  console.log(val); // "Hello World!"
34
33
  ```
35
34
 
36
35
 
37
36
  ### Browser
38
37
 
39
- Include the `dist/plist.js` in a `<script>` tag in your HTML file:
38
+ Use an [import map](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap)
39
+ to resolve the bare module specifiers used by plist and its dependencies,
40
+ then import directly from the source:
40
41
 
41
42
  ``` html
42
- <script src="plist.js"></script>
43
- <script>
44
- // now use the `parse()` and `build()` functions
45
- var val = plist.parse('<plist><string>Hello World!</string></plist>');
43
+ <script type="importmap">
44
+ {
45
+ "imports": {
46
+ "@xmldom/xmldom": "https://esm.sh/@xmldom/xmldom",
47
+ "xmlbuilder": "https://esm.sh/xmlbuilder"
48
+ }
49
+ }
50
+ </script>
51
+ <script type="module">
52
+ import { parse, build } from './node_modules/plist/index.js';
53
+
54
+ const val = parse('<plist><string>Hello World!</string></plist>');
46
55
  console.log(val); // "Hello World!"
47
56
  </script>
48
57
  ```
49
58
 
59
+ See the [browser example](./examples/browser/) for a drag-and-drop demo.
60
+
50
61
 
51
62
  ## API
52
63
 
@@ -54,20 +65,20 @@ Include the `dist/plist.js` in a `<script>` tag in your HTML file:
54
65
 
55
66
  Parsing a plist from filename:
56
67
 
57
- ``` javascript
58
- var fs = require('fs');
59
- var plist = require('plist');
68
+ ``` js
69
+ import { readFileSync } from 'node:fs';
70
+ import { parse } from 'plist';
60
71
 
61
- var obj = plist.parse(fs.readFileSync('myPlist.plist', 'utf8'));
72
+ const obj = parse(readFileSync('myPlist.plist', 'utf8'));
62
73
  console.log(JSON.stringify(obj));
63
74
  ```
64
75
 
65
76
  Parsing a plist from string payload:
66
77
 
67
- ``` javascript
68
- var plist = require('plist');
78
+ ``` js
79
+ import { parse } from 'plist';
69
80
 
70
- var xml =
81
+ const xml =
71
82
  '<?xml version="1.0" encoding="UTF-8"?>' +
72
83
  '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' +
73
84
  '<plist version="1.0">' +
@@ -84,7 +95,7 @@ var xml =
84
95
  '</dict>' +
85
96
  '</plist>';
86
97
 
87
- console.log(plist.parse(xml));
98
+ console.log(parse(xml));
88
99
 
89
100
  // [
90
101
  // "metadata",
@@ -102,10 +113,10 @@ console.log(plist.parse(xml));
102
113
  Given an existing JavaScript Object, you can turn it into an XML document
103
114
  that complies with the plist DTD:
104
115
 
105
- ``` javascript
106
- var plist = require('plist');
116
+ ``` js
117
+ import { build } from 'plist';
107
118
 
108
- var json = [
119
+ const obj = [
109
120
  "metadata",
110
121
  {
111
122
  "bundle-identifier": "com.company.app",
@@ -115,7 +126,7 @@ var json = [
115
126
  }
116
127
  ];
117
128
 
118
- console.log(plist.build(json));
129
+ console.log(build(obj));
119
130
 
120
131
  // <?xml version="1.0" encoding="UTF-8"?>
121
132
  // <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -134,12 +145,6 @@ console.log(plist.build(json));
134
145
  // </plist>
135
146
  ```
136
147
 
137
- ## Cross Platform Testing Credits
138
-
139
- Much thanks to Sauce Labs for providing free resources that enable cross-browser testing on this project!
140
-
141
- [![Testing Powered By SauceLabs](https://opensource.saucelabs.com/images/opensauce/powered-by-saucelabs-badge-red.png?sanitize=true "Testing Powered By SauceLabs")](https://saucelabs.com)
142
-
143
148
 
144
149
  ## License
145
150
 
package/index.js CHANGED
@@ -1,13 +1,2 @@
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]; });
1
+ export { parse } from './lib/parse.js';
2
+ export { build } from './lib/build.js';
package/lib/build.js CHANGED
@@ -1,15 +1,20 @@
1
- /**
2
- * Module dependencies.
3
- */
4
-
5
- var base64 = require('base64-js');
6
- var xmlbuilder = require('xmlbuilder');
1
+ import xmlbuilder from 'xmlbuilder';
7
2
 
8
3
  /**
9
- * Module exports.
4
+ * Encode a Uint8Array into a base64 string.
5
+ *
6
+ * @param {Uint8Array} bytes
7
+ * @returns {String} base64 encoded string
8
+ * @api private
10
9
  */
11
10
 
12
- exports.build = build;
11
+ function uint8ArrayToBase64(bytes) {
12
+ let binary = '';
13
+ for (let i = 0; i < bytes.length; i++) {
14
+ binary += String.fromCharCode(bytes[i]);
15
+ }
16
+ return btoa(binary);
17
+ }
13
18
 
14
19
  /**
15
20
  * Accepts a `Date` instance and returns an ISO date string.
@@ -40,9 +45,9 @@ function ISODateString(d){
40
45
  * @api private
41
46
  */
42
47
 
43
- var toString = Object.prototype.toString;
48
+ const toString = Object.prototype.toString;
44
49
  function type (obj) {
45
- var m = toString.call(obj).match(/\[object (.*)\]/);
50
+ const m = toString.call(obj).match(/\[object (.*)\]/);
46
51
  return m ? m[1] : m;
47
52
  }
48
53
 
@@ -55,18 +60,18 @@ function type (obj) {
55
60
  * @api public
56
61
  */
57
62
 
58
- function build (obj, opts) {
59
- var XMLHDR = {
63
+ export function build (obj, opts) {
64
+ const XMLHDR = {
60
65
  version: '1.0',
61
66
  encoding: 'UTF-8'
62
67
  };
63
68
 
64
- var XMLDTD = {
69
+ const XMLDTD = {
65
70
  pubid: '-//Apple//DTD PLIST 1.0//EN',
66
71
  sysid: 'http://www.apple.com/DTDs/PropertyList-1.0.dtd'
67
72
  };
68
73
 
69
- var doc = xmlbuilder.create('plist');
74
+ const doc = xmlbuilder.create('plist');
70
75
 
71
76
  doc.dec(XMLHDR.version, XMLHDR.encoding, XMLHDR.standalone);
72
77
  doc.dtd(XMLDTD.pubid, XMLDTD.sysid);
@@ -88,23 +93,29 @@ function build (obj, opts) {
88
93
  */
89
94
 
90
95
  function walk_obj(next, next_child) {
91
- var tag_type, i, prop;
92
- var name = type(next);
96
+ const name = type(next);
93
97
 
94
98
  if ('Undefined' == name) {
95
99
  return;
96
100
  } else if (Array.isArray(next)) {
97
101
  next_child = next_child.ele('array');
98
- for (i = 0; i < next.length; i++) {
102
+ for (let i = 0; i < next.length; i++) {
99
103
  walk_obj(next[i], next_child);
100
104
  }
101
105
 
102
- } else if (Buffer.isBuffer(next)) {
103
- next_child.ele('data').raw(next.toString('base64'));
106
+ } else if (next instanceof ArrayBuffer) {
107
+ next_child.ele('data').raw(uint8ArrayToBase64(new Uint8Array(next)));
108
+
109
+ } else if (ArrayBuffer.isView(next)) {
110
+ // Handles Uint8Array, Buffer, and all typed arrays
111
+ const bytes = next instanceof Uint8Array
112
+ ? next
113
+ : new Uint8Array(next.buffer, next.byteOffset, next.byteLength);
114
+ next_child.ele('data').raw(uint8ArrayToBase64(bytes));
104
115
 
105
116
  } else if ('Object' == name) {
106
117
  next_child = next_child.ele('dict');
107
- for (prop in next) {
118
+ for (const prop in next) {
108
119
  if (next.hasOwnProperty(prop)) {
109
120
  next_child.ele('key').txt(prop);
110
121
  walk_obj(next[prop], next_child);
@@ -114,7 +125,7 @@ function walk_obj(next, next_child) {
114
125
  } else if ('Number' == name) {
115
126
  // detect if this is an integer or real
116
127
  // TODO: add an ability to force one way or another via a "cast"
117
- tag_type = (next % 1 === 0) ? 'integer' : 'real';
128
+ const tag_type = (next % 1 === 0) ? 'integer' : 'real';
118
129
  next_child.ele(tag_type).txt(next.toString());
119
130
 
120
131
  } else if ('BigInt' == name) {
@@ -129,13 +140,6 @@ function walk_obj(next, next_child) {
129
140
  } else if ('String' == name) {
130
141
  next_child.ele('string').txt(next);
131
142
 
132
- } else if ('ArrayBuffer' == name) {
133
- next_child.ele('data').raw(base64.fromByteArray(next));
134
-
135
- } else if (next && next.buffer && 'ArrayBuffer' == type(next.buffer)) {
136
- // a typed array
137
- next_child.ele('data').raw(base64.fromByteArray(new Uint8Array(next.buffer), next_child));
138
-
139
143
  } else if ('Null' === name) {
140
144
  next_child.ele('null').txt('');
141
145
 
package/lib/parse.js CHANGED
@@ -1,18 +1,25 @@
1
- /**
2
- * Module dependencies.
3
- */
4
-
5
- const { DOMParser } = require("@xmldom/xmldom");
1
+ import { DOMParser } from '@xmldom/xmldom';
6
2
 
7
3
  /**
8
- * Module exports.
4
+ * Decode a base64 string into a Uint8Array.
5
+ *
6
+ * @param {String} base64 - base64 encoded string
7
+ * @returns {Uint8Array}
8
+ * @api private
9
9
  */
10
10
 
11
- exports.parse = parse;
11
+ function base64ToUint8Array(base64) {
12
+ const binary = atob(base64);
13
+ const bytes = new Uint8Array(binary.length);
14
+ for (let i = 0; i < binary.length; i++) {
15
+ bytes[i] = binary.charCodeAt(i);
16
+ }
17
+ return bytes;
18
+ }
12
19
 
13
- var TEXT_NODE = 3;
14
- var CDATA_NODE = 4;
15
- var COMMENT_NODE = 8;
20
+ const TEXT_NODE = 3;
21
+ const CDATA_NODE = 4;
22
+ const COMMENT_NODE = 8;
16
23
 
17
24
  /**
18
25
  * We ignore raw text (usually whitespace), <!-- xml comments -->,
@@ -63,13 +70,13 @@ function invariant(test, message) {
63
70
  * @api public
64
71
  */
65
72
 
66
- function parse(xml) {
67
- var doc = new DOMParser().parseFromString(xml, "text/xml");
73
+ export function parse(xml) {
74
+ const doc = new DOMParser().parseFromString(xml, "text/xml");
68
75
  invariant(
69
76
  doc.documentElement.nodeName === "plist",
70
77
  "malformed document. First element should be <plist>",
71
78
  );
72
- var plist = parsePlistXML(doc.documentElement);
79
+ let plist = parsePlistXML(doc.documentElement);
73
80
 
74
81
  // the root <plist> node gets interpreted as an Array,
75
82
  // so pull out the inner data first
@@ -87,29 +94,27 @@ function parse(xml) {
87
94
  */
88
95
 
89
96
  function parsePlistXML(node) {
90
- var i, new_obj, key, val, new_arr, res, counter, type;
91
-
92
97
  if (!node) return null;
93
98
 
94
99
  if (node.nodeName === "plist") {
95
- new_arr = [];
100
+ const new_arr = [];
96
101
  if (isEmptyNode(node)) {
97
102
  return new_arr;
98
103
  }
99
- for (i = 0; i < node.childNodes.length; i++) {
104
+ for (let i = 0; i < node.childNodes.length; i++) {
100
105
  if (!shouldIgnoreNode(node.childNodes[i])) {
101
106
  new_arr.push(parsePlistXML(node.childNodes[i]));
102
107
  }
103
108
  }
104
109
  return new_arr;
105
110
  } else if (node.nodeName === "dict") {
106
- new_obj = {};
107
- key = null;
108
- counter = 0;
111
+ const new_obj = {};
112
+ let key = null;
113
+ let counter = 0;
109
114
  if (isEmptyNode(node)) {
110
115
  return new_obj;
111
116
  }
112
- for (i = 0; i < node.childNodes.length; i++) {
117
+ for (let i = 0; i < node.childNodes.length; i++) {
113
118
  if (shouldIgnoreNode(node.childNodes[i])) continue;
114
119
  if (counter % 2 === 0) {
115
120
  invariant(
@@ -134,13 +139,13 @@ function parsePlistXML(node) {
134
139
 
135
140
  return new_obj;
136
141
  } else if (node.nodeName === "array") {
137
- new_arr = [];
142
+ const new_arr = [];
138
143
  if (isEmptyNode(node)) {
139
144
  return new_arr;
140
145
  }
141
- for (i = 0; i < node.childNodes.length; i++) {
146
+ for (let i = 0; i < node.childNodes.length; i++) {
142
147
  if (!shouldIgnoreNode(node.childNodes[i])) {
143
- res = parsePlistXML(node.childNodes[i]);
148
+ const res = parsePlistXML(node.childNodes[i]);
144
149
  if (null != res) new_arr.push(res);
145
150
  }
146
151
  }
@@ -159,12 +164,12 @@ function parsePlistXML(node) {
159
164
 
160
165
  return node.childNodes[0].nodeValue;
161
166
  } else if (node.nodeName === "string") {
162
- res = "";
167
+ let res = "";
163
168
  if (isEmptyNode(node)) {
164
169
  return res;
165
170
  }
166
- for (i = 0; i < node.childNodes.length; i++) {
167
- var type = node.childNodes[i].nodeType;
171
+ for (let i = 0; i < node.childNodes.length; i++) {
172
+ const type = node.childNodes[i].nodeType;
168
173
  if (type === TEXT_NODE || type === CDATA_NODE) {
169
174
  res += node.childNodes[i].nodeValue;
170
175
  }
@@ -175,24 +180,24 @@ function parsePlistXML(node) {
175
180
  return parseInt(node.childNodes[0].nodeValue, 10);
176
181
  } else if (node.nodeName === "real") {
177
182
  invariant(!isEmptyNode(node), 'Cannot parse "" as real.');
178
- res = "";
179
- for (i = 0; i < node.childNodes.length; i++) {
183
+ let res = "";
184
+ for (let i = 0; i < node.childNodes.length; i++) {
180
185
  if (node.childNodes[i].nodeType === TEXT_NODE) {
181
186
  res += node.childNodes[i].nodeValue;
182
187
  }
183
188
  }
184
189
  return parseFloat(res);
185
190
  } else if (node.nodeName === "data") {
186
- res = "";
191
+ let res = "";
187
192
  if (isEmptyNode(node)) {
188
- return Buffer.from(res, "base64");
193
+ return base64ToUint8Array(res);
189
194
  }
190
- for (i = 0; i < node.childNodes.length; i++) {
195
+ for (let i = 0; i < node.childNodes.length; i++) {
191
196
  if (node.childNodes[i].nodeType === TEXT_NODE) {
192
197
  res += node.childNodes[i].nodeValue.replace(/\s+/g, "");
193
198
  }
194
199
  }
195
- return Buffer.from(res, "base64");
200
+ return base64ToUint8Array(res);
196
201
  } else if (node.nodeName === "date") {
197
202
  invariant(!isEmptyNode(node), 'Cannot parse "" as Date.');
198
203
  return new Date(node.childNodes[0].nodeValue);
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "plist",
3
3
  "description": "Apple's property list parser/builder for Node.js and browsers",
4
- "version": "3.1.1",
4
+ "version": "4.0.0",
5
+ "type": "module",
5
6
  "author": "Nathan Rajlich <nathan@tootallnate.net>",
6
7
  "contributors": [
7
8
  "Hans Huebner <hans.huebner@gmail.com>",
@@ -23,21 +24,19 @@
23
24
  "parser",
24
25
  "xml"
25
26
  ],
26
- "main": "index.js",
27
+ "exports": "./index.js",
28
+ "files": [
29
+ "index.js",
30
+ "lib"
31
+ ],
27
32
  "dependencies": {
28
33
  "@xmldom/xmldom": "^0.9.10",
29
- "base64-js": "^1.5.1",
30
34
  "xmlbuilder": "^15.1.1"
31
35
  },
32
- "devDependencies": {
33
- "browserify": "^17.0.0",
34
- "mocha": "^10.2.0",
35
- "zuul": "3.12.0"
36
- },
37
36
  "scripts": {
38
- "test": "make test"
37
+ "test": "node --test test/*.js"
39
38
  },
40
39
  "engines": {
41
- "node": ">=10.4.0"
40
+ "node": ">=18"
42
41
  }
43
42
  }
@@ -1,24 +0,0 @@
1
- name: ci
2
-
3
- on:
4
- push:
5
- pull_request:
6
-
7
- jobs:
8
- build:
9
- runs-on: ubuntu-latest
10
-
11
- strategy:
12
- matrix:
13
- node-version: [ '14', '16', '18' ]
14
-
15
- steps:
16
- - uses: actions/checkout@v2
17
-
18
- - name: Use Node.js ${{ matrix.node-version }}
19
- uses: actions/setup-node@v1
20
- with:
21
- node-version: ${{ matrix.node-version }}
22
-
23
- - run: npm install
24
- - run: npm test
package/.jshintrc DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "laxbreak": true,
3
- "laxcomma": true
4
- }