mirror of
https://github.com/apache/cordova-android.git
synced 2026-04-04 00:02:03 +08:00
CB-9782 Check in cordova-common dependency
This commit is contained in:
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2013 Brett Rudd
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// contains PLIST utility functions
|
||||
var __ = require('underscore');
|
||||
var plist = require('plist');
|
||||
|
||||
// adds node to doc at selector
|
||||
module.exports.graftPLIST = graftPLIST;
|
||||
function graftPLIST(doc, xml, selector) {
|
||||
var obj = plist.parse('<plist>'+xml+'</plist>');
|
||||
|
||||
var node = doc[selector];
|
||||
if (node && Array.isArray(node) && Array.isArray(obj)){
|
||||
node = node.concat(obj);
|
||||
for (var i =0;i<node.length; i++){
|
||||
for (var j=i+1; j<node.length; ++j) {
|
||||
if (nodeEqual(node[i], node[j]))
|
||||
node.splice(j--,1);
|
||||
}
|
||||
}
|
||||
doc[selector] = node;
|
||||
} else {
|
||||
//plist uses objects for <dict>. If we have two dicts we merge them instead of
|
||||
// overriding the old one. See CB-6472
|
||||
if (node && __.isObject(node) && __.isObject(obj) && !__.isDate(node) && !__.isDate(obj)){//arrays checked above
|
||||
__.extend(obj,node);
|
||||
}
|
||||
doc[selector] = obj;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// removes node from doc at selector
|
||||
module.exports.prunePLIST = prunePLIST;
|
||||
function prunePLIST(doc, xml, selector) {
|
||||
var obj = plist.parse('<plist>'+xml+'</plist>');
|
||||
|
||||
pruneOBJECT(doc, selector, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function pruneOBJECT(doc, selector, fragment) {
|
||||
if (Array.isArray(fragment) && Array.isArray(doc[selector])) {
|
||||
var empty = true;
|
||||
for (var i in fragment) {
|
||||
for (var j in doc[selector]) {
|
||||
empty = pruneOBJECT(doc[selector], j, fragment[i]) && empty;
|
||||
}
|
||||
}
|
||||
if (empty)
|
||||
{
|
||||
delete doc[selector];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (nodeEqual(doc[selector], fragment)) {
|
||||
delete doc[selector];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function nodeEqual(node1, node2) {
|
||||
if (typeof node1 != typeof node2)
|
||||
return false;
|
||||
else if (typeof node1 == 'string') {
|
||||
node2 = escapeRE(node2).replace(new RegExp('\\$[a-zA-Z0-9-_]+','gm'),'(.*?)');
|
||||
return new RegExp('^' + node2 + '$').test(node1);
|
||||
}
|
||||
else {
|
||||
for (var key in node2) {
|
||||
if (!nodeEqual(node1[key], node2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// escape string for use in regex
|
||||
function escapeRE(str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '$&');
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2013 Anis Kadri
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* jshint sub:true, laxcomma:true */
|
||||
|
||||
/**
|
||||
* contains XML utility functions, some of which are specific to elementtree
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, path = require('path')
|
||||
, _ = require('underscore')
|
||||
, et = require('elementtree')
|
||||
;
|
||||
|
||||
module.exports = {
|
||||
// compare two et.XML nodes, see if they match
|
||||
// compares tagName, text, attributes and children (recursively)
|
||||
equalNodes: function(one, two) {
|
||||
if (one.tag != two.tag) {
|
||||
return false;
|
||||
} else if (one.text.trim() != two.text.trim()) {
|
||||
return false;
|
||||
} else if (one._children.length != two._children.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var oneAttribKeys = Object.keys(one.attrib),
|
||||
twoAttribKeys = Object.keys(two.attrib),
|
||||
i = 0, attribName;
|
||||
|
||||
if (oneAttribKeys.length != twoAttribKeys.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i; i < oneAttribKeys.length; i++) {
|
||||
attribName = oneAttribKeys[i];
|
||||
|
||||
if (one.attrib[attribName] != two.attrib[attribName]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (i; i < one._children.length; i++) {
|
||||
if (!module.exports.equalNodes(one._children[i], two._children[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// adds node to doc at selector, creating parent if it doesn't exist
|
||||
graftXML: function(doc, nodes, selector, after) {
|
||||
var parent = resolveParent(doc, selector);
|
||||
if (!parent) {
|
||||
//Try to create the parent recursively if necessary
|
||||
try {
|
||||
var parentToCreate = et.XML('<' + path.basename(selector) + '>'),
|
||||
parentSelector = path.dirname(selector);
|
||||
|
||||
this.graftXML(doc, [parentToCreate], parentSelector);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
parent = resolveParent(doc, selector);
|
||||
if (!parent) return false;
|
||||
}
|
||||
|
||||
nodes.forEach(function (node) {
|
||||
// check if child is unique first
|
||||
if (uniqueChild(node, parent)) {
|
||||
var children = parent.getchildren();
|
||||
var insertIdx = after ? findInsertIdx(children, after) : children.length;
|
||||
|
||||
//TODO: replace with parent.insert after the bug in ElementTree is fixed
|
||||
parent.getchildren().splice(insertIdx, 0, node);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// removes node from doc at selector
|
||||
pruneXML: function(doc, nodes, selector) {
|
||||
var parent = resolveParent(doc, selector);
|
||||
if (!parent) return false;
|
||||
|
||||
nodes.forEach(function (node) {
|
||||
var matchingKid = null;
|
||||
if ((matchingKid = findChild(node, parent)) !== null) {
|
||||
// stupid elementtree takes an index argument it doesn't use
|
||||
// and does not conform to the python lib
|
||||
parent.remove(matchingKid);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
parseElementtreeSync: function (filename) {
|
||||
var contents = fs.readFileSync(filename, 'utf-8');
|
||||
if(contents) {
|
||||
//Windows is the BOM. Skip the Byte Order Mark.
|
||||
contents = contents.substring(contents.indexOf('<'));
|
||||
}
|
||||
return new et.ElementTree(et.XML(contents));
|
||||
}
|
||||
};
|
||||
|
||||
function findChild(node, parent) {
|
||||
var matchingKids = parent.findall(node.tag)
|
||||
, i, j;
|
||||
|
||||
for (i = 0, j = matchingKids.length ; i < j ; i++) {
|
||||
if (module.exports.equalNodes(node, matchingKids[i])) {
|
||||
return matchingKids[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function uniqueChild(node, parent) {
|
||||
var matchingKids = parent.findall(node.tag)
|
||||
, i = 0;
|
||||
|
||||
if (matchingKids.length === 0) {
|
||||
return true;
|
||||
} else {
|
||||
for (i; i < matchingKids.length; i++) {
|
||||
if (module.exports.equalNodes(node, matchingKids[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var ROOT = /^\/([^\/]*)/,
|
||||
ABSOLUTE = /^\/([^\/]*)\/(.*)/;
|
||||
|
||||
function resolveParent(doc, selector) {
|
||||
var parent, tagName, subSelector;
|
||||
|
||||
// handle absolute selector (which elementtree doesn't like)
|
||||
if (ROOT.test(selector)) {
|
||||
tagName = selector.match(ROOT)[1];
|
||||
// test for wildcard "any-tag" root selector
|
||||
if (tagName == '*' || tagName === doc._root.tag) {
|
||||
parent = doc._root;
|
||||
|
||||
// could be an absolute path, but not selecting the root
|
||||
if (ABSOLUTE.test(selector)) {
|
||||
subSelector = selector.match(ABSOLUTE)[2];
|
||||
parent = parent.find(subSelector);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
parent = doc.find(selector);
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
// Find the index at which to insert an entry. After is a ;-separated priority list
|
||||
// of tags after which the insertion should be made. E.g. If we need to
|
||||
// insert an element C, and the rule is that the order of children has to be
|
||||
// As, Bs, Cs. After will be equal to "C;B;A".
|
||||
function findInsertIdx(children, after) {
|
||||
var childrenTags = children.map(function(child) { return child.tag; });
|
||||
var afters = after.split(';');
|
||||
var afterIndexes = afters.map(function(current) { return childrenTags.lastIndexOf(current); });
|
||||
var foundIndex = _.find(afterIndexes, function(index) { return index != -1; });
|
||||
|
||||
//add to the beginning if no matching nodes are found
|
||||
return typeof foundIndex === 'undefined' ? 0 : foundIndex+1;
|
||||
}
|
||||
|
||||
var BLACKLIST = ['platform', 'feature','plugin','engine'];
|
||||
var SINGLETONS = ['content', 'author'];
|
||||
function mergeXml(src, dest, platform, clobber) {
|
||||
// Do nothing for blacklisted tags.
|
||||
if (BLACKLIST.indexOf(src.tag) != -1) return;
|
||||
|
||||
//Handle attributes
|
||||
Object.getOwnPropertyNames(src.attrib).forEach(function (attribute) {
|
||||
if (clobber || !dest.attrib[attribute]) {
|
||||
dest.attrib[attribute] = src.attrib[attribute];
|
||||
}
|
||||
});
|
||||
//Handle text
|
||||
if (src.text && (clobber || !dest.text)) {
|
||||
dest.text = src.text;
|
||||
}
|
||||
//Handle platform
|
||||
if (platform) {
|
||||
src.findall('platform[@name="' + platform + '"]').forEach(function (platformElement) {
|
||||
platformElement.getchildren().forEach(mergeChild);
|
||||
});
|
||||
}
|
||||
|
||||
//Handle children
|
||||
src.getchildren().forEach(mergeChild);
|
||||
|
||||
function mergeChild (srcChild) {
|
||||
var srcTag = srcChild.tag,
|
||||
destChild = new et.Element(srcTag),
|
||||
foundChild,
|
||||
query = srcTag + '',
|
||||
shouldMerge = true;
|
||||
|
||||
if (BLACKLIST.indexOf(srcTag) === -1) {
|
||||
if (SINGLETONS.indexOf(srcTag) !== -1) {
|
||||
foundChild = dest.find(query);
|
||||
if (foundChild) {
|
||||
destChild = foundChild;
|
||||
dest.remove(destChild);
|
||||
}
|
||||
} else {
|
||||
//Check for an exact match and if you find one don't add
|
||||
Object.getOwnPropertyNames(srcChild.attrib).forEach(function (attribute) {
|
||||
query += '[@' + attribute + '="' + srcChild.attrib[attribute] + '"]';
|
||||
});
|
||||
var foundChildren = dest.findall(query);
|
||||
for(var i = 0; i < foundChildren.length; i++) {
|
||||
foundChild = foundChildren[i];
|
||||
if (foundChild && textMatch(srcChild, foundChild) && (Object.keys(srcChild.attrib).length==Object.keys(foundChild.attrib).length)) {
|
||||
destChild = foundChild;
|
||||
dest.remove(destChild);
|
||||
shouldMerge = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mergeXml(srcChild, destChild, platform, clobber && shouldMerge);
|
||||
dest.append(destChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expose for testing.
|
||||
module.exports.mergeXml = mergeXml;
|
||||
|
||||
function textMatch(elm1, elm2) {
|
||||
var text1 = elm1.text ? elm1.text.replace(/\s+/, '') : '',
|
||||
text2 = elm2.text ? elm2.text.replace(/\s+/, '') : '';
|
||||
return (text1 === '' || text1 === text2);
|
||||
}
|
||||
Reference in New Issue
Block a user