apache / cordova-common

Compare 642d381 ... +0 ... 185b326

Showing 1 of 1 files from the diff.

@@ -17,6 +17,8 @@
Loading
17 17
    under the License.
18 18
*/
19 19
20 +
// @ts-check
21 +
20 22
/**
21 23
 * contains XML utility functions, some of which are specific to elementtree
22 24
 */
@@ -27,20 +29,40 @@
Loading
27 29
const et = require('elementtree');
28 30
const stripBom = require('strip-bom');
29 31
32 +
/**
33 +
 * The part of the <edit-config> interface that is used here
34 +
 * @typedef {{oldAttrib?: et.Attributes}} EditConfigMunge
35 +
 */
36 +
30 37
module.exports = {
31 -
    // compare two et.XML nodes, see if they match
32 -
    // compares tagName, text, attributes and children (recursively)
33 -
    equalNodes: function (one, two) {
38 +
    /**
39 +
     * Compares two et.XML nodes, see if they match.
40 +
     *
41 +
     * Compares tagName, text, attributes and children (recursively)
42 +
     *
43 +
     * @param {et.Element} one
44 +
     * @param {et.Element} two
45 +
     * @return {boolean} true iff one and two are equal
46 +
     */
47 +
    equalNodes (one, two) {
34 48
        return one.tag === two.tag &&
35 49
            one.len() === two.len() &&
36 -
            one.text.trim() === two.text.trim() &&
50 +
            String(one.text).trim() === String(two.text).trim() &&
37 51
            attribMatch(one, two) &&
38 52
            _.zip(one.getchildren(), two.getchildren())
39 53
                .every(([c1, c2]) => module.exports.equalNodes(c1, c2));
40 54
    },
41 55
42 -
    // adds node to doc at selector, creating parent if it doesn't exist
43 -
    graftXML: function (doc, nodes, selector, after) {
56 +
    /**
57 +
     * Adds node to doc at selector, creating parent if it doesn't exist
58 +
     *
59 +
     * @param {et.ElementTree} doc
60 +
     * @param {et.Element[]} nodes
61 +
     * @param {string} selector
62 +
     * @param {string | undefined} [after]
63 +
     * @return {boolean}
64 +
     */
65 +
    graftXML (doc, nodes, selector, after) {
44 66
        let parent = module.exports.resolveParent(doc, selector);
45 67
46 68
        if (!parent) {
@@ -73,20 +95,45 @@
Loading
73 95
        return true;
74 96
    },
75 97
76 -
    // adds new attributes to doc at selector
77 -
    // Will only merge if attribute has not been modified already or --force is used
78 -
    graftXMLMerge: function (doc, nodes, selector, xml) {
98 +
    /**
99 +
     * Adds new attributes to doc at selector.
100 +
     *
101 +
     * Will only merge if attribute has not been modified already or --force is used
102 +
     *
103 +
     * @param {et.ElementTree} doc
104 +
     * @param {et.Element[]} nodes
105 +
     * @param {string} selector
106 +
     * @param {EditConfigMunge} xml
107 +
     * @return {boolean}
108 +
     */
109 +
    graftXMLMerge (doc, nodes, selector, xml) {
79 110
        return graftXMLAttrs(doc, nodes, selector, xml);
80 111
    },
81 112
82 -
    // overwrite all attributes to doc at selector with new attributes
83 -
    // Will only overwrite if attribute has not been modified already or --force is used
84 -
    graftXMLOverwrite: function (doc, nodes, selector, xml) {
113 +
    /**
114 +
     * Overwrites all attributes to doc at selector with new attributes.
115 +
     *
116 +
     * Will only overwrite if attribute has not been modified already or --force is used
117 +
     *
118 +
     * @param {et.ElementTree} doc
119 +
     * @param {et.Element[]} nodes
120 +
     * @param {string} selector
121 +
     * @param {EditConfigMunge} xml
122 +
     * @return {boolean}
123 +
     */
124 +
    graftXMLOverwrite (doc, nodes, selector, xml) {
85 125
        return graftXMLAttrs(doc, nodes, selector, xml, { overwrite: true });
86 126
    },
87 127
88 -
    // removes node from doc at selector
89 -
    pruneXML: function (doc, nodes, selector) {
128 +
    /**
129 +
     * Removes node from doc at selector.
130 +
     *
131 +
     * @param {et.ElementTree} doc
132 +
     * @param {et.Element[]} nodes
133 +
     * @param {string} selector
134 +
     * @return {boolean}
135 +
     */
136 +
    pruneXML (doc, nodes, selector) {
90 137
        const parent = module.exports.resolveParent(doc, selector);
91 138
        if (!parent) return false;
92 139
@@ -98,8 +145,15 @@
Loading
98 145
        return true;
99 146
    },
100 147
101 -
    // restores attributes from doc at selector
102 -
    pruneXMLRestore: function (doc, selector, xml) {
148 +
    /**
149 +
     * Restores attributes from doc at selector.
150 +
     *
151 +
     * @param {et.ElementTree} doc
152 +
     * @param {string} selector
153 +
     * @param {EditConfigMunge} xml
154 +
     * @return {boolean}
155 +
     */
156 +
    pruneXMLRestore (doc, selector, xml) {
103 157
        const target = module.exports.resolveParent(doc, selector);
104 158
        if (!target) return false;
105 159
@@ -110,7 +164,13 @@
Loading
110 164
        return true;
111 165
    },
112 166
113 -
    pruneXMLRemove: function (doc, selector, nodes) {
167 +
    /**
168 +
     * @param {et.ElementTree} doc
169 +
     * @param {string} selector
170 +
     * @param {et.Element[]} nodes
171 +
     * @return {boolean}
172 +
     */
173 +
    pruneXMLRemove (doc, selector, nodes) {
114 174
        const target = module.exports.resolveParent(doc, selector);
115 175
        if (!target) return false;
116 176
@@ -123,11 +183,20 @@
Loading
123 183
        return true;
124 184
    },
125 185
126 -
    parseElementtreeSync: function (filename) {
186 +
    /**
187 +
     * @param {string} filename
188 +
     * @return {et.ElementTree}
189 +
     */
190 +
    parseElementtreeSync (filename) {
127 191
        return et.parse(stripBom(fs.readFileSync(filename, 'utf-8')));
128 192
    },
129 193
130 -
    resolveParent: function (doc, selector) {
194 +
    /**
195 +
     * @param {et.ElementTree} doc
196 +
     * @param {string} selector
197 +
     * @return {et.Element | null}
198 +
     */
199 +
    resolveParent (doc, selector) {
131 200
        if (!selector.startsWith('/')) return doc.find(selector);
132 201
133 202
        // elementtree does not implement absolute selectors so we build an
@@ -138,6 +207,13 @@
Loading
138 207
    }
139 208
};
140 209
210 +
/**
211 +
 * @param {et.ElementTree} doc
212 +
 * @param {et.Element[]} nodes
213 +
 * @param {string} selector
214 +
 * @param {EditConfigMunge} xml
215 +
 * @return {boolean}
216 +
 */
141 217
function graftXMLAttrs (doc, nodes, selector, xml, { overwrite = false } = {}) {
142 218
    const target = module.exports.resolveParent(doc, selector);
143 219
    if (!target) return false;
@@ -151,15 +227,25 @@
Loading
151 227
    return true;
152 228
}
153 229
230 +
/**
231 +
 * @param {et.Element} node
232 +
 * @param {et.Element | et.ElementTree} parent
233 +
 * @return {et.Element | undefined}
234 +
 */
154 235
function findChild (node, parent) {
155 -
    const matches = parent.findall(node.tag);
236 +
    const matches = parent.findall(String(node.tag));
156 237
    return matches.find(m => module.exports.equalNodes(node, m));
157 238
}
158 239
159 -
// Find the index at which to insert an entry. After is a ;-separated priority list
160 -
// of tags after which the insertion should be made. E.g. If we need to
161 -
// insert an element C, and the rule is that the order of children has to be
162 -
// As, Bs, Cs. After will be equal to "C;B;A".
240 +
/**
241 +
 * Find the index at which to insert an entry.
242 +
 *
243 +
 * @param {et.Element[]} children
244 +
 * @param {string} after a ;-separated priority list of tags after which the
245 +
 *  insertion should be made. E.g. if we need to insert an element C, and the
246 +
 *  order of children has to be As, Bs, Cs then `after` will be equal to "C;B;A".
247 +
 * @return {number}
248 +
 */
163 249
function findInsertIdx (children, after) {
164 250
    const childrenTags = children.map(child => child.tag);
165 251
    const foundIndex = after.split(';')
@@ -173,9 +259,15 @@
Loading
173 259
const BLACKLIST = ['platform', 'feature', 'plugin', 'engine'];
174 260
const SINGLETONS = ['content', 'author', 'name'];
175 261
262 +
/**
263 +
 * @param {et.Element} src
264 +
 * @param {et.Element} dest
265 +
 * @param {string} platform
266 +
 * @param {boolean} clobber
267 +
 */
176 268
function mergeXml (src, dest, platform, clobber) {
177 269
    // Do nothing for blacklisted tags.
178 -
    if (BLACKLIST.includes(src.tag)) return;
270 +
    if (BLACKLIST.includes(String(src.tag))) return;
179 271
180 272
    // Handle attributes
181 273
    const omitAttrs = new Set(clobber ? [] : dest.keys());
@@ -199,8 +291,9 @@
Loading
199 291
    // Handle duplicate preference tags (by name attribute)
200 292
    removeDuplicatePreferences(dest);
201 293
294 +
    /** @param {et.Element} srcChild */
202 295
    function mergeChild (srcChild) {
203 -
        const srcTag = srcChild.tag;
296 +
        const srcTag = String(srcChild.tag);
204 297
        const query = srcTag + '';
205 298
        let destChild;
206 299
        let shouldMerge = true;
@@ -220,12 +313,13 @@
Loading
220 313
        if (destChild) {
221 314
            dest.remove(destChild);
222 315
        } else {
223 -
            destChild = new et.Element(srcTag);
316 +
            destChild = et.Element(srcTag);
224 317
        }
225 318
        mergeXml(srcChild, destChild, platform, clobber && shouldMerge);
226 319
        dest.append(destChild);
227 320
    }
228 321
322 +
    /** @param {et.Element} xml */
229 323
    function removeDuplicatePreferences (xml) {
230 324
        const prefs = xml.findall('preference[@name][@value]');
231 325
@@ -247,13 +341,24 @@
Loading
247 341
// Expose for testing.
248 342
module.exports.mergeXml = mergeXml;
249 343
344 +
/**
345 +
 * @param {et.Element} elm1
346 +
 * @param {et.Element} elm2
347 +
 * @return {boolean}
348 +
 */
250 349
function textMatch (elm1, elm2) {
251 -
    const format = text => text ? text.replace(/\s+/, '') : '';
350 +
    /** @param {et.ElementText | null} text */
351 +
    const format = text => text ? String(text).replace(/\s+/, '') : '';
252 352
    const text1 = format(elm1.text);
253 353
    const text2 = format(elm2.text);
254 354
    return (text1 === '' || text1 === text2);
255 355
}
256 356
357 +
/**
358 +
 * @param {et.Element} a
359 +
 * @param {et.Element} b
360 +
 * @return {boolean} true iff attributes on a and b are equal
361 +
 */
257 362
function attribMatch (a, b) {
258 363
    const aKeys = a.keys();
259 364
    return aKeys.length === b.keys().length &&

Everything is accounted for!

No changes detected that need to be reviewed.
What changes does Codecov check for?
Lines, not adjusted in diff, that have changed coverage data.
Files that introduced coverage data that had none before.
Files that have missing coverage data that once were tracked.
Files Coverage
src 89.55%
cordova-common.js 0.00%
Project Totals (20 files) 88.26%
Loading