1 |
|
2 | var self,
|
3 | hasProp = {}.hasOwnProperty;
|
4 |
|
5 | module.exports = self = {
|
6 | convert: function(obj) {
|
7 | return self._arrayToChildren(obj);
|
8 | },
|
9 | _arrayToChildren: function(a, parent) {
|
10 | var children, j, len, node, prev, v;
|
11 | if (parent == null) {
|
12 | parent = null;
|
13 | }
|
14 | children = [];
|
15 | prev = null;
|
16 | for (j = 0, len = a.length; j < len; j++) {
|
17 | v = a[j];
|
18 | if (typeof v === 'string') {
|
19 | node = self._getTextNodeFor(v);
|
20 | } else {
|
21 | node = self._objectToNode(v, parent);
|
22 | node.prev = null;
|
23 | node.next = null;
|
24 | node.parent = parent;
|
25 | if (prev != null) {
|
26 | node.prev = prev;
|
27 | prev.next = node;
|
28 | }
|
29 | prev = node;
|
30 | }
|
31 | children.push(node);
|
32 | }
|
33 | return children;
|
34 | },
|
35 | _objectToNode: function(o) {
|
36 | var attribs, children, i, k, key, name, node, ref, v, val;
|
37 | i = 0;
|
38 | for (k in o) {
|
39 | if (!hasProp.call(o, k)) continue;
|
40 | v = o[k];
|
41 | if (i > 0) {
|
42 | throw Error("_objectToNode() only accepts an object with one key/value");
|
43 | }
|
44 | key = k;
|
45 | val = v;
|
46 | i++;
|
47 | }
|
48 | node = {};
|
49 | if (typeof key !== 'string') {
|
50 | throw Error("_objectToNode()'s key must be a string of tag name and classes");
|
51 | }
|
52 | if (typeof val === 'string') {
|
53 | children = [self._getTextNodeFor(val)];
|
54 | } else if (Array.isArray(val)) {
|
55 | children = self._arrayToChildren(val, node);
|
56 | } else {
|
57 | inspect(o);
|
58 | throw Error("_objectToNode()'s key's value must only be a string or an array");
|
59 | }
|
60 | node.type = 'tag';
|
61 | ref = self._parseTag(key), name = ref.name, attribs = ref.attribs;
|
62 | node.name = name;
|
63 | node.attribs = attribs;
|
64 | node.children = children;
|
65 | return node;
|
66 | },
|
67 | _getTextNodeFor: function(s) {
|
68 | return {
|
69 | type: 'text',
|
70 | data: s
|
71 | };
|
72 | },
|
73 | _nameRx: /^[a-zA-Z\-\_]{1}[a-zA-Z0-9\-\_]*$/,
|
74 | _parseTag: function(k) {
|
75 | var attribs, classes, cls, id, m, name, parts;
|
76 | if (!k.match(/^[a-zA-Z0-9\#\-\_\.\[\]\"\'\=\,\s]+$/) || k.match(/^[0-9]+/)) {
|
77 | throw Error("cannot parse tag `" + k + "`");
|
78 | }
|
79 | attribs = {};
|
80 | parts = {
|
81 | name: '',
|
82 | attribs: attribs
|
83 | };
|
84 | if (m = k.match(/^([^\.#]+)/)) {
|
85 | name = m[1];
|
86 | if (!name.match(self._nameRx)) {
|
87 | throw Error("tag name `" + name + "` is not valid");
|
88 | }
|
89 | parts.name = name;
|
90 | k = k.substr(name.length, k.length);
|
91 | }
|
92 | if (m = k.match(/^#([a-zA-Z0-9\-]+)/)) {
|
93 | id = m[1];
|
94 | if (!id.match(self._nameRx)) {
|
95 | throw Error("tag id `" + id + "` is not valid");
|
96 | }
|
97 | attribs.id = id;
|
98 | k = k.substr(id.length + 1, k.length);
|
99 | }
|
100 | classes = [];
|
101 | while (m = k.match(/\.([a-zA-Z0-9\-\_]+)/)) {
|
102 | cls = m[1];
|
103 | if (!cls.match(self._nameRx)) {
|
104 | throw Error("tag class `" + cls + "` is not valid");
|
105 | }
|
106 | classes.push(cls);
|
107 | k = k.replace('.' + cls, '');
|
108 | }
|
109 | if (classes.length) {
|
110 | attribs["class"] = classes.join(" ");
|
111 | }
|
112 | return parts;
|
113 | }
|
114 | };
|