forked from krakenjs/spud
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.js
97 lines (87 loc) · 5.02 KB
/
parse.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/***@@@ BEGIN LICENSE @@@***/
/*───────────────────────────────────────────────────────────────────────────*\
│ Copyright (C) 2013 eBay Software Foundation │
│ │
│hh ,'""`. │
│ / _ _ \ Licensed under the Apache License, Version 2.0 (the "License"); │
│ |(@)(@)| you may not use this file except in compliance with the License. │
│ ) __ ( You may obtain a copy of the License at │
│ /,'))((`.\ │
│(( (( )) )) http://www.apache.org/licenses/LICENSE-2.0 │
│ `\ `)(' /' │
│ │
│ Unless required by applicable law or agreed to in writing, software │
│ distributed under the License is distributed on an "AS IS" BASIS, │
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
│ See the License for the specific language governing permissions and │
│ limitations under the License. │
\*───────────────────────────────────────────────────────────────────────────*/
/***@@@ END LICENSE @@@***/
'use strict';
var util = require('util'),
codePointAt = require('string.fromcodepoint');
function getEscapedChar(match) {
match = match.substring(2).replace(/[\{\}]/g, '');
return String.fromCodePoint(parseInt(match, 16));
}
function parse(data) {
var result = {};
data.split(/\r?\n/).forEach(function (line) {
var kvp = line.match(/^(?!\s*#)([^=]+)=(.+)$/),
key = null,
value = null;
if (Array.isArray(kvp) && kvp.length > 1) {
key = kvp[1].trim();
value = kvp[2];
if (key.indexOf('\\u') !== -1) {
//ES6 format: \u{xxxxxx}
if (key.indexOf('\\u{') !== -1) {
key = key.replace(/(\\u\{[A-Z0-9]{1,6}})/gi, getEscapedChar);
} else {
key = key.replace(/(\\u[A-Z0-9]{4})/gi, getEscapedChar);
}
}
var tail = result;
key.split(/\./).forEach(function (prop, index, arr) {
// Sanitize key
prop = prop.replace(/\s/g, '');
// Change to allow most any chars for name and map key
var arrMap = prop.match(/^([^\[]+)\[(.*)\]$/);
if ( Array.isArray(arrMap) && arrMap.length > 1 ) {
var arrKey = arrMap[1];
if ( arrMap[2] !== '' ) {
// If previous value is present for this key, use it, otherwise new object
arrMap[2].split(/\]\[/).forEach(function (arrProp, arrIndex, subArr) {
// Iterate over the property keys
if ( arrProp.match(/^[0-9]+$/) ) {
if ( arrIndex === 0 ) {
tail = tail[arrKey] = (typeof tail[arrKey] !== 'undefined' && typeof tail[arrKey] === 'object') ? tail[arrKey] : [];
}
// Assign the value if it's the last key in the set
tail[arrProp] = ( arrIndex === subArr.length - 1 ) ? value : tail[arrProp] || [];
} else {
if ( arrIndex === 0 ) {
tail = tail[arrKey] = (typeof tail[arrKey] !== 'undefined' && typeof tail[arrKey] === 'object') ? tail[arrKey] : {};
}
// Assign the value if it's the last key in the set
tail[arrProp] = ( arrIndex === subArr.length - 1 ) ? value : tail[arrProp] || {};
}
tail = tail[arrProp];
});
}
} else if (index === arr.length - 1) {
// On the final property in the namespace
// Property wasn't yet defined, so just set a value
tail[prop] = value;
} else {
// Continue through the namespace. If a property
// was defined in a previous iteration, use it,
// otherwise, create an empty object and move on.
tail = tail[prop] = (tail[prop] || {});
}
});
}
});
return result;
}
module.exports = parse;