(function (tree) {
/*jshint loopfunc:true */
tree.extendFinderVisitor = function() {
this._visitor = new tree.visitor(this);
this.contexts = [];
this.allExtendsStack = [[]];
};
tree.extendFinderVisitor.prototype = {
run: function (root) {
root = this._visitor.visit(root);
root.allExtends = this.allExtendsStack[0];
return root;
},
visitRule: function (ruleNode, visitArgs) {
visitArgs.visitDeeper = false;
},
visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
visitArgs.visitDeeper = false;
},
visitRuleset: function (rulesetNode, visitArgs) {
if (rulesetNode.root) {
return;
}
var i, j, extend, allSelectorsExtendList = [], extendList;
// get &:extend(.a); rules which apply to all selectors in this ruleset
var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0;
for(i = 0; i < ruleCnt; i++) {
if (rulesetNode.rules[i] instanceof tree.Extend) {
allSelectorsExtendList.push(rules[i]);
rulesetNode.extendOnEveryPath = true;
}
}
// now find every selector and apply the extends that apply to all extends
// and the ones which apply to an individual extend
var paths = rulesetNode.paths;
for(i = 0; i < paths.length; i++) {
var selectorPath = paths[i],
selector = selectorPath[selectorPath.length - 1],
selExtendList = selector.extendList;
extendList = selExtendList ? selExtendList.slice(0).concat(allSelectorsExtendList)
: allSelectorsExtendList;
if (extendList) {
extendList = extendList.map(function(allSelectorsExtend) {
return allSelectorsExtend.clone();
});
}
for(j = 0; j < extendList.length; j++) {
this.foundExtends = true;
extend = extendList[j];
extend.findSelfSelectors(selectorPath);
extend.ruleset = rulesetNode;
if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
}
}
this.contexts.push(rulesetNode.selectors);
},
visitRulesetOut: function (rulesetNode) {
if (!rulesetNode.root) {
this.contexts.length = this.contexts.length - 1;
}
},
visitMedia: function (mediaNode, visitArgs) {
mediaNode.allExtends = [];
this.allExtendsStack.push(mediaNode.allExtends);
},
visitMediaOut: function (mediaNode) {
this.allExtendsStack.length = this.allExtendsStack.length - 1;
},
visitDirective: function (directiveNode, visitArgs) {
directiveNode.allExtends = [];
this.allExtendsStack.push(directiveNode.allExtends);
},
visitDirectiveOut: function (directiveNode) {
this.allExtendsStack.length = this.allExtendsStack.length - 1;
}
};
tree.processExtendsVisitor = function() {
this._visitor = new tree.visitor(this);
};
tree.processExtendsVisitor.prototype = {
run: function(root) {
var extendFinder = new tree.extendFinderVisitor();
extendFinder.run(root);
if (!extendFinder.foundExtends) { return root; }
root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
this.allExtendsStack = [root.allExtends];
return this._visitor.visit(root);
},
doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
//
// chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
// the selector we would do normally, but we are also adding an extend with the same target selector
// this means this new extend can then go and alter other extends
//
// this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
// this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
// we look at each selector at a time, as is done in visitRuleset
var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend;
iterationCount = iterationCount || 0;
//loop through comparing every extend with every target extend.
// a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
// e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
// and the second is the target.
// the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
// case when processing media queries
for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){
for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){
extend = extendsList[extendIndex];
targetExtend = extendsListTarget[targetExtendIndex];
// look for circular references
if( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ){ continue; }
// find a match in the target extends self selector (the bit before :extend)
selectorPath = [targetExtend.selfSelectors[0]];
matches = extendVisitor.findMatch(extend, selectorPath);
if (matches.length) {
// we found a match, so for each self selector..
extend.selfSelectors.forEach(function(selfSelector) {
// process the extend as usual
newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector);
// but now we create a new extend from it
newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0);
newExtend.selfSelectors = newSelector;
// add the extend onto the list of extends for that selector
newSelector[newSelector.length-1].extendList = [newExtend];
// record that we need to add it.
extendsToAdd.push(newExtend);
newExtend.ruleset = targetExtend.ruleset;
//remember its parents for circular references
newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids);
// only process the selector once.. if we have :extend(.a,.b) then multiple
// extends will look at the same selector path, so when extending
// we know that any others will be duplicates in terms of what is added to the css
if (targetExtend.firstExtendOnThisSelectorPath) {
newExtend.firstExtendOnThisSelectorPath = true;
targetExtend.ruleset.paths.push(newSelector);
}
});
}
}
}
if (extendsToAdd.length) {
// try to detect circular references to stop a stack overflow.
// may no longer be needed.
this.extendChainCount++;
if (iterationCount > 100) {
var selectorOne = "{unable to calculate}";
var selectorTwo = "{unable to calculate}";
try
{
selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
selectorTwo = extendsToAdd[0].selector.toCSS();
}
catch(e) {}
throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"};
}
// now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1));
} else {
return extendsToAdd;
}
},
visitRule: function (ruleNode, visitArgs) {
visitArgs.visitDeeper = false;
},
visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
visitArgs.visitDeeper = false;
},
visitSelector: function (selectorNode, visitArgs) {
visitArgs.visitDeeper = false;
},
visitRuleset: function (rulesetNode, visitArgs) {
if (rulesetNode.root) {
return;
}
var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath;
// look at each selector path in the ruleset, find any extend matches and then copy, find and replace
for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
selectorPath = rulesetNode.paths[pathIndex];
// extending extends happens initially, before the main pass
if (rulesetNode.extendOnEveryPath) { continue; }
var extendList = selectorPath[selectorPath.length-1].extendList;
if (extendList && extendList.length) { continue; }
matches = this.findMatch(allExtends[extendIndex], selectorPath);
if (matches.length) {
allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
});
}
}
}
rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
},
findMatch: function (extend, haystackSelectorPath) {
//
// look through the haystack selector path to try and find the needle - extend.selector
// returns an array of selector matches that can then be replaced
//
var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
targetCombinator, i,
extendVisitor = this,
needleElements = extend.selector.elements,
potentialMatches = [], potentialMatch, matches = [];
// loop through the haystack elements
for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
haystackElement = hackstackSelector.elements[hackstackElementIndex];
// if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});
}
for(i = 0; i < potentialMatches.length; i++) {
potentialMatch = potentialMatches[i];
// selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
// then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
// what the resulting combinator will be
targetCombinator = haystackElement.combinator.value;
if (targetCombinator === '' && hackstackElementIndex === 0) {
targetCombinator = ' ';
}
// if we don't match, null our match to indicate failure
if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
(potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
potentialMatch = null;
} else {
potentialMatch.matched++;
}
// if we are still valid and have finished, test whether we have elements after and whether these are allowed
if (potentialMatch) {
potentialMatch.finished = potentialMatch.matched === needleElements.length;
if (potentialMatch.finished &&
(!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) {
potentialMatch = null;
}
}
// if null we remove, if not, we are still valid, so either push as a valid match or continue
if (potentialMatch) {
if (potentialMatch.finished) {
potentialMatch.length = needleElements.length;
potentialMatch.endPathIndex = haystackSelectorIndex;
potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
matches.push(potentialMatch);
}
} else {
potentialMatches.splice(i, 1);
i--;
}
}
}
}
return matches;
},
isElementValuesEqual: function(elementValue1, elementValue2) {
if (typeof elementValue1 === "string" || typeof elementValue2 === "string") {
return elementValue1 === elementValue2;
}
if (elementValue1 instanceof tree.Attribute) {
if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
return false;
}
if (!elementValue1.value || !elementValue2.value) {
if (elementValue1.value || elementValue2.value) {
return false;
}
return true;
}
elementValue1 = elementValue1.value.value || elementValue1.value;
elementValue2 = elementValue2.value.value || elementValue2.value;
return elementValue1 === elementValue2;
}
elementValue1 = elementValue1.value;
elementValue2 = elementValue2.value;
if (elementValue1 instanceof tree.Selector) {
if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
return false;
}
for(var i = 0; i <elementValue1.elements.length; i++) {
if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
return false;
}
}
if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {
return false;
}
}
return true;
}
return false;
},
extendSelector:function (matches, selectorPath, replacementSelector) {
//for a set of matches, replace each match with the replacement selector
var currentSelectorPathIndex = 0,
currentSelectorPathElementIndex = 0,
path = [],
matchIndex,
selector,
firstElement,
match,
newElements;
for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
match = matches[matchIndex];
selector = selectorPath[match.pathIndex];
firstElement = new tree.Element(
match.initialCombinator,
replacementSelector.elements[0].value,
replacementSelector.elements[0].index,
replacementSelector.elements[0].currentFileInfo
);
if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
currentSelectorPathElementIndex = 0;
currentSelectorPathIndex++;
}
newElements = selector.elements
.slice(currentSelectorPathElementIndex, match.index)
.concat([firstElement])
.concat(replacementSelector.elements.slice(1));
if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
path[path.length - 1].elements =
path[path.length - 1].elements.concat(newElements);
} else {
path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
path.push(new tree.Selector(
newElements
));
}
currentSelectorPathIndex = match.endPathIndex;
currentSelectorPathElementIndex = match.endPathElementIndex;
if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
currentSelectorPathElementIndex = 0;
currentSelectorPathIndex++;
}
}
if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
currentSelectorPathIndex++;
}
path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
return path;
},
visitRulesetOut: function (rulesetNode) {
},
visitMedia: function (mediaNode, visitArgs) {
var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
this.allExtendsStack.push(newAllExtends);
},
visitMediaOut: function (mediaNode) {
this.allExtendsStack.length = this.allExtendsStack.length - 1;
},
visitDirective: function (directiveNode, visitArgs) {
var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
this.allExtendsStack.push(newAllExtends);
},
visitDirectiveOut: function (directiveNode) {
this.allExtendsStack.length = this.allExtendsStack.length - 1;
}
};
})(require('./tree'));
var es5_visitors = (function () {
var types = require("babel-types"),
defaultExtendDecoratorName = "JavaProxy",
columnOffset = 1,
ASTERISK_SEPARATOR = "*",
customExtendsArr = [],
normalExtendsArr = [],
interfacesArr = [],
UNSUPPORTED_TYPESCRIPT_EXTEND_FORMAT_MESSAGE = "[WARN] TypeScript-extended class has a super() call in an unsupported format.",
customExtendsArrGlobal = [];
/* ENTRY POINT!
* Traverses each passed node with several visitors.
* Result from visit can be got from static methods.
*
* Input parameters:
* path - node to visit
* config - filename, decorator name ...
*/
function es5Visitor(path, config) {
if (!config.filePath) {
config.filePath = "No file path provided";
}
if (path.node.skipMeOnVisit) {
return;
}
// ES5 Syntax
// anchor is extend (normal extend pattern + custom extend pattern)
if (types.isMemberExpression(path) && path.node.property.name === "extend") {
traverseEs5Extend(path, config);
}
//anchor is new keyword (interface pattern)
if (types.isNewExpression(path)) {
traverseInterface(path, config);
}
// // Parsed Typescript to ES5 Syntax (normal extend pattern + custom extend pattern)
// // anchor is __extends
if (types.isIdentifier(path) && path.node.name === "__extends") {
traverseTsExtend(path, config);
}
// Maybe it's not a good idea to expose this scenario because it can be explicitly covered
// //anchor is JavaProxy (optional)
// var customDecoratorName = config.extendDecoratorName === undefined ? defaultExtendDecoratorName : config.extendDecoratorName;
// if(t.isIdentifier(path) && path.node.name === customDecoratorName) {
// if(path.node.skipMeOnVisit) {
// return;
// }
// console.log("enters because there is a java proxy down the way")
// traverseJavaProxyExtend(path, config, customDecoratorName);
// }
}
/*
* Returns the custom extends array generated from visitor
*/
es5Visitor.getProxyExtendInfo = function () {
var res = customExtendsArr.slice();
customExtendsArr = [];
return res;
}
/*
* Returns the common extends array generated from visitor
*/
es5Visitor.getCommonExtendInfo = function () {
var res = [];
for (var index in normalExtendsArr) {
if (normalExtendsArr[index][0] !== "*") {
res.push(normalExtendsArr[index]);
}
}
normalExtendsArr = [];
return res;
}
/*
* Returns the extended interfaces array generated from visitor
*/
es5Visitor.getInterfaceInfo = function () {
var res = interfacesArr.slice();
interfacesArr = [];
return res;
}
/*
* Traverses the typescript extend case (__extends())
* Write results in "normalExtendsArr" or "customExtendsArr".
*/
function traverseTsExtend(path, config) {
// information for normal extend (unnamed)
var extendClass;
try {
extendClass = _getArgumentFromNodeAsString(path, 5, config)
} catch (e) {
config.logger.info(e.message)
return;
}
var overriddenMethodNames = _getOverriddenMethodsTypescript(path, 3);
var extendPath = _getParent(path, 3, config);
var declaredClassName = "";
var typescriptClassExtendSuperCallLocation = getTypeScriptExtendSuperCallLocation(extendPath, config);
var extendParent = _getParent(path, 1, config);
if (types.isCallExpression(extendParent)) {
declaredClassName = extendParent.node.arguments[0].name;
}
var decorateNodes = traverseForDecorate(path, config, 3);
var isDecoratedWithExtend = false,
customExtendDecoratorName,
customExtendDecoratorValue,
implementedInterfaces = [];
if (!decorateNodes) {
// 7 -> Takes 7 levels up to get to the scope where the class is declared
decorateNodes = traverseForDecorateSpecial(path, config, 7);
}
if (decorateNodes) {
for (var i in decorateNodes) {
var currentDecorator = decorateNodes[i];
if (types.isCallExpression(currentDecorator)) {
// Interfaces/Implements
if (currentDecorator.callee.name === config.interfacesDecoratorName) {
currentDecorator.callee.skipMeOnVisit = true;
var interfaces = currentDecorator.arguments[0].elements;
for (var i in interfaces) {
var interfaceName = _getWholeInterfaceNameFromInterfacesNode(interfaces[i]);
implementedInterfaces.push(interfaceName);
}
}
// JavaProxy
if (currentDecorator.callee.name === config.extendDecoratorName) {
currentDecorator.callee.skipMeOnVisit = true;
isDecoratedWithExtend = true;
customExtendDecoratorName = config.extendDecoratorName === undefined ? defaultExtendDecoratorName : config.extendDecoratorName;
customExtendDecoratorValue = currentDecorator.arguments[0].value;
}
}
}
}
if (isDecoratedWithExtend) {
traverseJavaProxyExtend(customExtendDecoratorValue, config, customExtendDecoratorName, extendClass, overriddenMethodNames, implementedInterfaces);
} else {
var lineToWrite;
lineToWrite = _generateLineToWrite("", extendClass, overriddenMethodNames, { file: config.filePath, line: typescriptClassExtendSuperCallLocation.line, column: typescriptClassExtendSuperCallLocation.column, className: declaredClassName }, "", implementedInterfaces);
if (config.logger) {
config.logger.info(lineToWrite)
}
normalExtendsArr.push(lineToWrite);
}
}
function getTypeScriptExtendSuperCallLocation(extendPath, config) {
var constructorFunctionName;
var returnIdentifierName;
var superCalleeStartColumn;
var superCalleeLine;
var locationAssigned = false;
// checks if constructor function and return identifiers match in a transpiled typescript class extend
if (extendPath.node.body && extendPath.node.body.length >= 3) {
if (types.isFunctionDeclaration(extendPath.node.body[1]) && extendPath.node.body[1].id)
constructorFunctionName = extendPath.node.body[1].id.name;
if (types.isReturnStatement(extendPath.node.body[extendPath.node.body.length - 1]))
returnIdentifierName = extendPath.node.body[extendPath.node.body.length - 1].argument.name;
}
// checks the typescript-extended class for a strict format, and a super call/apply inside
/**
* function MyBtn() {
var _this = _super.call(this) || this;
return global.__native(_this);
}
**UGLIFIED extended class**
function t(t) {
var r = e.call(this) || this;
r.textBase = t;
return global.__native(r);
}
*/
if (constructorFunctionName === returnIdentifierName && !!constructorFunctionName) {
var constructorFunctionScope = extendPath.node.body[1];
// the 'super' variable will always be passed as the second argument to the __extends call
// try to find the 'super' identifier which may be uglified
var superVariableIdentifier = getSuperVariableIdentifier(extendPath.node.body[0]);
//// helper functions to find the correct super.call(this) node
function getSuperVariableIdentifier(__extendsNode) {
if (types.isExpressionStatement(__extendsNode) && types.isCallExpression(__extendsNode.expression)) {
var __extendsCallArguments = __extendsNode.expression.arguments;
if (__extendsCallArguments.length == 2) {
return __extendsCallArguments[1].name;
}
}
}
/** Getting the super.call node from assignment
if expressionStatement => check possibleExpressionStatements[0]
if possibleExpressionStatements[0].expression is assignment expression
if possibleExpressionStatements[0].expression.right is logical expression
if possibleExpressionStatements[0].expression.right.left is Call expression
if possibleExpressionStatements[0].expression.right.left.callee.object.name === superVariableIdentifier
if the above is valid, then variableRHS = possibleVariableDeclarations[0].expression.right.left
*/
function getThisAssignmentSuperCallLineNode(nodes, superIdentifier) {
var matchingNodes = nodes.filter(
(node) => {
return types.isAssignmentExpression(node.expression)
&& types.isLogicalExpression(node.expression.right)
&& types.isCallExpression(node.expression.right.left)
&& node.expression.right.left.callee.object.name === superIdentifier;
});
return matchingNodes.length > 0 ? matchingNodes[0].expression.right.left : null;
}
/** Getting the super.call node from declaration
if variableDeclaration => check possibleVariableDeclarations[0].declarations[0].init isn't null
if possibleNodesForSuperCall[0].declarations[0].init is logical expression
if possibleNodesForSuperCall[0].declarations[0].init.left is Call Expression
if possibleNodesForSuperCall[0].declarations[0].init.left.callee.object.name === superVariableIdentifier
if the above is valid, then variableRHS = possibleVariableDeclarations[0].declarations[0].init.left
*/
function getThisDeclarationSuperCallLineNode(nodes, superIdentifier) {
var matchingNodes = nodes.filter(
(node) => {
return types.isLogicalExpression(node.declarations[0].init)
&& types.isCallExpression(node.declarations[0].init.left)
&& node.declarations[0].init.left.callee.object.name === superIdentifier;
});
return matchingNodes.length > 0 ? matchingNodes[0].declarations[0].init.left : null;
}
////
if (superVariableIdentifier) {
var possibleVariableDeclarations = [];
var possibleExpressionStatements = [];
constructorFunctionScope.body.body.forEach(node => {
if (types.isVariableDeclaration(node)) {
possibleVariableDeclarations.push(node);
} else if (types.isExpressionStatement(node)) {
possibleExpressionStatements.push(node);
}
});
if (possibleVariableDeclarations.length > 0 || possibleExpressionStatements.length > 0) {
var superCallRHS = getThisDeclarationSuperCallLineNode(possibleVariableDeclarations, superVariableIdentifier)
|| getThisAssignmentSuperCallLineNode(possibleExpressionStatements, superVariableIdentifier);
if (superCallRHS) {
var superCallee = superCallRHS.callee.property;
superCalleeStartColumn = superCallee.loc.start.column + 1;
superCalleeLine = superCallee.loc.start.line;
locationAssigned = true;
}
}
}
}
if (!locationAssigned) {
config.logger.info(UNSUPPORTED_TYPESCRIPT_EXTEND_FORMAT_MESSAGE + " ctor function name: " + constructorFunctionName);
}
return {
line: superCalleeLine,
column: superCalleeStartColumn
};
}
function traverseForDecorate(path, config, depth) {
var iifeRoot = _getParent(path, depth)
var body = iifeRoot.node.body;
for (var index in body) {
var ci = body[index];
if (isDecorateStatement(ci)) {
// returns the node of the decorate (node.expression.right.callee)
// __decorate([..])
return ci.expression.right.arguments[0].elements;
}
}
return null;
}
function traverseForDecorateSpecial(path, config, depth) {
var iifeRoot = _getParent(path, depth);
var sibling = iifeRoot.getSibling(iifeRoot.key + 1).node;
if (sibling) {
if (isDecorateStatement(sibling)) {
// returns the node of the decorate (node.expression.right.callee)
// __decorate([..])
return sibling.expression.right.arguments[0].elements;
}
}
return null;
}
function isDecorateStatement(node) {
return types.isExpressionStatement(node) &&
types.isAssignmentExpression(node.expression) &&
node.expression.right.callee &&
node.expression.right.callee.name === "__decorate" &&
node.expression.right.arguments &&
types.isArrayExpression(node.expression.right.arguments[0])
}
/*
* Traverses the node, which is a "new" expression and find if it's a native interface or not.
* Write results in "interfacesArr".
*/
function traverseInterface(path, config) {
if (!config.interfaceNames) {
throw "No interface names are provided! You can pass them in config.interfaceNames as an array!"
}
var o = path.node.callee,
interfaceArr = _getWholeName(o),
foundInterface = false,
interfaceNames = config.interfaceNames
var currentInterface = interfaceArr.reverse().join(".");
for (var i in interfaceNames) {
var interfaceName = interfaceNames[i].trim();
if (interfaceName === currentInterface) {
currentInterface = interfaceName;
foundInterface = true;
break;
}
}
if (foundInterface) {
var arg0 = "",
arg1;
if (path.node.arguments.length === 1) {
arg1 = path.node.arguments[0];
}
else if (path.node.arguments.length === 2) {
arg0 = path.node.arguments[0];
arg1 = path.node.arguments[1];
}
else {
throw {
message: "Not enough or too many arguments passed(" + path.node.arguments.length + ") when trying to extend interface in file: " + config.filePath,
errCode: 1
}
}
var isCorrectInterfaceName = _testClassName(arg0.value);
var overriddenInterfaceMethods = _getOverriddenMethods(arg1, config);
var extendInfo = {
file: config.filePath,
line: path.node.loc.start.line,
column: path.node.loc.start.column + columnOffset,
className: (isCorrectInterfaceName ? arg0.value : "")
}
var lineToWrite = _generateLineToWrite("", currentInterface, overriddenInterfaceMethods.join(","), extendInfo, "");
if (config.logger) {
config.logger.info(lineToWrite)
}
interfacesArr.push(lineToWrite)
}
}
/*
* Finds the java proxy name from custom class decorator.
* Write results in "customExtendsArr"
*/
function traverseJavaProxyExtend(path, config, customDecoratorName, extendClass, overriddenMethodNames, implementedInterfaces) {
if (config.logger) {
config.logger.info("\t+in " + customDecoratorName + " anchor");
}
var classNameFromDecorator = path;//_getDecoratorArgument(path, config, customDecoratorName);
var lineToWrite = _generateLineToWrite(classNameFromDecorator, extendClass, overriddenMethodNames, "", config.fullPathName, implementedInterfaces);
if (config.logger) {
config.logger.info(lineToWrite)
}
addCustomExtend(classNameFromDecorator, config.fullPathName, lineToWrite)
}
/*
* Finds the normal extend name, overridden methods and possibly java proxy name from passed node.
* Writes to "customExtendsArr" or "normalExtendsArr".
* Left whole for readability.
*/
function traverseEs5Extend(path, config) {
var callee = path.parent.callee;
if (callee) {
var o = callee.object
extendClass = _getWholeName(o);
var extendArguments = path.parent.arguments;
var arg0,
arg1;
if (extendArguments.length === 1 && types.isObjectExpression(arg0)) {
arg0 = extendArguments[0];
}
else if (types.isStringLiteral(arg0)) {
}
var arg0 = "",
arg1;
if (extendArguments.length) {
// Get implementation object when there is only 1 argument
if (extendArguments.length === 1 && types.isObjectExpression(extendArguments[0])) {
arg1 = extendArguments[0];
}
// Get the name of the extended class and the implementation object when both arguments are present
else if (extendArguments.length === 2) {
if (types.isStringLiteral(extendArguments[0]) && types.isObjectExpression(extendArguments[1])) {
arg0 = extendArguments[0];
arg1 = extendArguments[1];
}
}
else {
// don't throw here, because there can be a valid js extend that has nothing to do with NS
return;
throw {
message: "Not enough or too many arguments passed(" + extendArguments.length + ") when trying to extend class in file: " + config.filePath,
errCode: 1
}
}
}
else {
// don't throw here, because there can be a valid js extend that has nothing to do with NS
return;
throw {
message: "You need to call the extend with parameters. Example: '...extend(\"a.b.C\", {...overrides...})') in file: " + config.filePath,
errCode: 1
}
}
className = arg0.value ? arg0.value : "";
// Get all methods from the implementation object
var methodsAndInterfaces = _getOverridenMethodsAndImplementedInterfaces(arg1, config);
var overriddenMethodNames = methodsAndInterfaces[0];
var implementedInterfaces = methodsAndInterfaces[1];
var isCorrectExtendClassName = _testJavaProxyName(className);
var isCorrectClassName = _testClassName(className);
if (className && !isCorrectClassName && !isCorrectExtendClassName) {
throw {
message: "The 'extend' you are trying to make has an invalid name. Example: '...extend(\"a.b.C\", {...overrides...})'), file: " + config.filePath,
errCode: 1
}
}
var lineToWrite = "";
if (isCorrectExtendClassName) {
if (config.logger) {
config.logger.info(lineToWrite)
}
var classNameFromDecorator = isCorrectExtendClassName ? className : "";
lineToWrite = _generateLineToWrite(classNameFromDecorator, extendClass.reverse().join("."), overriddenMethodNames, "", config.fullPathName, implementedInterfaces);
addCustomExtend(classNameFromDecorator, config.fullPathName, lineToWrite);
return;
}
if (config.logger) {
config.logger.info(lineToWrite)
}
var extendInfo = {
file: config.filePath,
line: path.node.property.loc.start.line,
column: path.node.property.loc.start.column + columnOffset,
className: className
};
lineToWrite = _generateLineToWrite(isCorrectExtendClassName ? className : "", extendClass.reverse().join("."), overriddenMethodNames, extendInfo, "", implementedInterfaces);
normalExtendsArr.push(lineToWrite)
}
else {
// don't throw here, because there can be a valid js extend that has nothing to do with NS
return;
throw {
message: "You need to call the extend '...extend(\"extend_name\", {...overrides...})'), file: " + config.filePath,
errCode: 1
}
}
}
/*
* HELPER METHODS
*/
function _getOverriddenMethods(node, config) {
var overriddenMethodNames = [];
if (types.isObjectExpression(node)) {
var objectProperties = node.properties;
for (var index in objectProperties) {
overriddenMethodNames.push(objectProperties[index].key.name);
}
}
return overriddenMethodNames;
}
// NOTE: It's a near-identical method to _getOverridenMethods for optimisation reasons
// we do not want to check for interfaces while creating an interface
// and likewise, we do not want to iterate twice through the impl. object's properties to read the interfaces
function _getOverridenMethodsAndImplementedInterfaces(node, config) {
var result = [];
var overriddenMethodNames = [];
var implementedInterfaces = [];
var interfacesFound = false;
if (types.isObjectExpression(node)) {
var objectProperties = node.properties;
/*
Iterates through all properties of the implementation object, e.g.
{
method1: function() {
},
method3: function() {
}
}
will get 'method1' and 'method3'
*/
for (var index in objectProperties) {
// if the user has declared interfaces that he is implementing
if (!interfacesFound
&& objectProperties[index].key.name.toLowerCase() === "interfaces"
&& types.isArrayExpression(objectProperties[index].value)) {
interfacesFound = true;
var interfaces = objectProperties[index].value.elements;
for (var i in interfaces) {
var interfaceName = _getWholeInterfaceNameFromInterfacesNode(interfaces[i]);
implementedInterfaces.push(interfaceName);
}
} else {
overriddenMethodNames.push(objectProperties[index].key.name)
}
}
}
result.push(overriddenMethodNames);
result.push(implementedInterfaces);
return result;
}
function _getWholeInterfaceNameFromInterfacesNode(node) {
var interfaceName = "";
if (types.isMemberExpression(node)) {
interfaceName += _resolveInterfacePath(node.object);
interfaceName += node.property.name;
}
return interfaceName;
}
function _resolveInterfacePath(node) {
var subNode = "";
if (types.isMemberExpression(node)) {
if (types.isMemberExpression(node.object)) {
subNode += _resolveInterfacePath(node.object);
subNode += node.property.name + ".";
} else {
subNode += node.object.name + ".";
subNode += node.property.name + ".";
}
}
return subNode;
}
function _getWholeName(node) {
var arr = [],
isAndroidInterface = false;
while (node !== undefined) {
if (!types.isMemberExpression(node)) {
if (isAndroidInterface) {
arr.push(node.name)
}
break;
}
isAndroidInterface = true;
arr.push(node.property.name)
node = node.object
}
return arr;
}
function _getArgumentFromNodeAsString(path, count, config) {
var extClassArr = [];
var extendedClass = _getParent(path, count, config);
if (extendedClass) {
if (types.isCallExpression(extendedClass.node)) {
var o = extendedClass.node.arguments[0];
}
else {
throw {
message: "Node type is not a call expression. File=" + config.filePath + " line=" + path.node.loc.start.line,
errCode: 1
}
}
}
extClassArr = _getWholeName(o);
return extClassArr.reverse().join(".");
}
function _getDecoratorArgument(path, config, customDecoratorName) {
if (path.parent && types.isCallExpression(path.parent)) {
if (path.parent.arguments && path.parent.arguments.length > 0) {
var classNameFromDecorator = path.parent.arguments[0].value
var isCorrectExtendClassName = _testJavaProxyName(classNameFromDecorator);
if (isCorrectExtendClassName) {
return path.parent.arguments[0].value;
}
else {
throw {
message: "The first argument '" + classNameFromDecorator + "' of the " + customDecoratorName + " decorator is not following the right pattern which is: '[namespace.]ClassName'. Example: '" + customDecoratorName + "(\"a.b.ClassName\", {overrides...})', file: " + config.filePath,
errCode: 1
}
}
}
else {
throw {
message: "No arguments passed to " + customDecoratorName + " decorator. Example: '" + customDecoratorName + "(\"a.b.ClassName\", {overrides...})', file: " + config.filePath,
errCode: 1
}
}
}
else {
throw {
message: "Decorator " + customDecoratorName + " must be called with parameters: Example: '" + customDecoratorName + "(\"a.b.ClassName\", {overrides...})', file: " + config.filePath,
errCode: 1
}
}
return undefined;
}
function _getOverriddenMethodsTypescript(path, count) {
var overriddenMethods = [];
var cn = _getParent(path, count)
// this pattern follows typescript generated syntax
for (var item in cn.node.body) {
var ci = cn.node.body[item];
if (types.isExpressionStatement(ci)) {
if (types.isAssignmentExpression(ci.expression)) {
if (ci.expression.left.property) {
overriddenMethods.push(ci.expression.left.property.name)
}
}
}
}
return overriddenMethods;
}
function _getParent(node, numberOfParents, config) {
if (!node) {
throw {
message: "No parent found for node in file: " + config.filePath,
errCode: 1
}
}
if (numberOfParents === 0) {
return node;
}
return _getParent(node.parentPath, --numberOfParents)
}
function _testJavaProxyName(name) {
if (name) {
return /^((\w+\.)+\w+)$/.test(name)
}
return false;
}
function _testClassName(name) {
if (name && name != "") {
return /^(\w+)$/.test(name)
}
return false;
}
function _generateLineToWrite(classNameFromDecorator, extendClass, overriddenMethodNames, extendInfo, filePath, implementedInterfaces = "") {
const extendInfoFile = extendInfo.file ? extendInfo.file.replace(/[-\\/\\. ]/g, "_") : "";
const extendInfoLine = extendInfo.line ? extendInfo.line : "";
const extendInfoColumn = extendInfo.column ? extendInfo.column : "";
const extendInfoNewClassName = extendInfo.className ? extendInfo.className : "";
var lineToWrite = `${extendClass}${ASTERISK_SEPARATOR}`
+ `${extendInfoFile}${ASTERISK_SEPARATOR}`
+ `${extendInfoLine}${ASTERISK_SEPARATOR}`
+ `${extendInfoColumn}${ASTERISK_SEPARATOR}`
+ `${extendInfoNewClassName}${ASTERISK_SEPARATOR}`
+ `${overriddenMethodNames}${ASTERISK_SEPARATOR}`
+ `${classNameFromDecorator}${ASTERISK_SEPARATOR}`
+ `${filePath}${ASTERISK_SEPARATOR}`
+ `${implementedInterfaces}`
return lineToWrite;
}
function addCustomExtend(param, extendPath, lineToWrite) {
if (customExtendsArrGlobal.indexOf(param) === -1) {
customExtendsArr.push(lineToWrite)
customExtendsArrGlobal.push(param)
} else {
console.log("Warning: there already is an extend called " + param + ".")
if (extendPath.indexOf("tns_modules") === -1) {
// app folder will take precedence over tns_modules
console.log("Warning: The static binding generator will generate extend from:" + extendPath + " implementation")
customExtendsArr.push(lineToWrite)
customExtendsArrGlobal.push(param)
}
}
}
return {
es5Visitor: es5Visitor
}
})();
module.exports = es5_visitors;
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test suite is written using Jasmine -- see http://jasmine.github.io/
goog.require('goog.crypt.base64');
goog.require('goog.testing.asserts');
goog.require('jspb.Message');
// CommonJS-LoadFromFile: ../testbinary_pb proto.jspb.test
goog.require('proto.jspb.test.ExtendsWithMessage');
goog.require('proto.jspb.test.ForeignEnum');
goog.require('proto.jspb.test.ForeignMessage');
goog.require('proto.jspb.test.TestAllTypes');
goog.require('proto.jspb.test.TestExtendable');
goog.require('proto.jspb.test.extendOptionalBool');
goog.require('proto.jspb.test.extendOptionalBytes');
goog.require('proto.jspb.test.extendOptionalDouble');
goog.require('proto.jspb.test.extendOptionalFixed32');
goog.require('proto.jspb.test.extendOptionalFixed64');
goog.require('proto.jspb.test.extendOptionalFloat');
goog.require('proto.jspb.test.extendOptionalForeignEnum');
goog.require('proto.jspb.test.extendOptionalInt32');
goog.require('proto.jspb.test.extendOptionalInt64');
goog.require('proto.jspb.test.extendOptionalSfixed32');
goog.require('proto.jspb.test.extendOptionalSfixed64');
goog.require('proto.jspb.test.extendOptionalSint32');
goog.require('proto.jspb.test.extendOptionalSint64');
goog.require('proto.jspb.test.extendOptionalString');
goog.require('proto.jspb.test.extendOptionalUint32');
goog.require('proto.jspb.test.extendOptionalUint64');
goog.require('proto.jspb.test.extendPackedRepeatedBoolList');
goog.require('proto.jspb.test.extendPackedRepeatedDoubleList');
goog.require('proto.jspb.test.extendPackedRepeatedFixed32List');
goog.require('proto.jspb.test.extendPackedRepeatedFixed64List');
goog.require('proto.jspb.test.extendPackedRepeatedFloatList');
goog.require('proto.jspb.test.extendPackedRepeatedForeignEnumList');
goog.require('proto.jspb.test.extendPackedRepeatedInt32List');
goog.require('proto.jspb.test.extendPackedRepeatedInt64List');
goog.require('proto.jspb.test.extendPackedRepeatedSfixed32List');
goog.require('proto.jspb.test.extendPackedRepeatedSfixed64List');
goog.require('proto.jspb.test.extendPackedRepeatedSint32List');
goog.require('proto.jspb.test.extendPackedRepeatedSint64List');
goog.require('proto.jspb.test.extendPackedRepeatedUint32List');
goog.require('proto.jspb.test.extendPackedRepeatedUint64List');
goog.require('proto.jspb.test.extendRepeatedBoolList');
goog.require('proto.jspb.test.extendRepeatedBytesList');
goog.require('proto.jspb.test.extendRepeatedDoubleList');
goog.require('proto.jspb.test.extendRepeatedFixed32List');
goog.require('proto.jspb.test.extendRepeatedFixed64List');
goog.require('proto.jspb.test.extendRepeatedFloatList');
goog.require('proto.jspb.test.extendRepeatedForeignEnumList');
goog.require('proto.jspb.test.extendRepeatedInt32List');
goog.require('proto.jspb.test.extendRepeatedInt64List');
goog.require('proto.jspb.test.extendRepeatedSfixed32List');
goog.require('proto.jspb.test.extendRepeatedSfixed64List');
goog.require('proto.jspb.test.extendRepeatedSint32List');
goog.require('proto.jspb.test.extendRepeatedSint64List');
goog.require('proto.jspb.test.extendRepeatedStringList');
goog.require('proto.jspb.test.extendRepeatedUint32List');
goog.require('proto.jspb.test.extendRepeatedUint64List');
var suite = {};
var BYTES = new Uint8Array([1, 2, 8, 9]);
var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES);
/**
* Helper: fill all fields on a TestAllTypes message.
* @param {proto.jspb.test.TestAllTypes} msg
*/
function fillAllFields(msg) {
msg.setOptionalInt32(-42);
// can be exactly represented by JS number (64-bit double, i.e., 52-bit
// mantissa).
msg.setOptionalInt64(-0x7fffffff00000000);
msg.setOptionalUint32(0x80000000);
msg.setOptionalUint64(0xf000000000000000);
msg.setOptionalSint32(-100);
msg.setOptionalSint64(-0x8000000000000000);
msg.setOptionalFixed32(1234);
msg.setOptionalFixed64(0x1234567800000000);
msg.setOptionalSfixed32(-1234);
msg.setOptionalSfixed64(-0x1234567800000000);
msg.setOptionalFloat(1.5);
msg.setOptionalDouble(-1.5);
msg.setOptionalBool(true);
msg.setOptionalString('hello world');
msg.setOptionalBytes(BYTES);
msg.setOptionalGroup(new proto.jspb.test.TestAllTypes.OptionalGroup());
msg.getOptionalGroup().setA(100);
var submsg = new proto.jspb.test.ForeignMessage();
submsg.setC(16);
msg.setOptionalForeignMessage(submsg);
msg.setOptionalForeignEnum(proto.jspb.test.ForeignEnum.FOREIGN_FOO);
msg.setOneofString('oneof');
msg.setRepeatedInt32List([-42]);
msg.setRepeatedInt64List([-0x7fffffff00000000]);
msg.setRepeatedUint32List([0x80000000]);
msg.setRepeatedUint64List([0xf000000000000000]);
msg.setRepeatedSint32List([-100]);
msg.setRepeatedSint64List([-0x8000000000000000]);
msg.setRepeatedFixed32List([1234]);
msg.setRepeatedFixed64List([0x1234567800000000]);
msg.setRepeatedSfixed32List([-1234]);
msg.setRepeatedSfixed64List([-0x1234567800000000]);
msg.setRepeatedFloatList([1.5]);
msg.setRepeatedDoubleList([-1.5]);
msg.setRepeatedBoolList([true]);
msg.setRepeatedStringList(['hello world']);
msg.setRepeatedBytesList([BYTES, BYTES]);
msg.setRepeatedGroupList([new proto.jspb.test.TestAllTypes.RepeatedGroup()]);
msg.getRepeatedGroupList()[0].setA(100);
submsg = new proto.jspb.test.ForeignMessage();
submsg.setC(1000);
msg.setRepeatedForeignMessageList([submsg]);
msg.setRepeatedForeignEnumList([proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
msg.setPackedRepeatedInt32List([-42]);
msg.setPackedRepeatedInt64List([-0x7fffffff00000000]);
msg.setPackedRepeatedUint32List([0x80000000]);
msg.setPackedRepeatedUint64List([0xf000000000000000]);
msg.setPackedRepeatedSint32List([-100]);
msg.setPackedRepeatedSint64List([-0x8000000000000000]);
msg.setPackedRepeatedFixed32List([1234]);
msg.setPackedRepeatedFixed64List([0x1234567800000000]);
msg.setPackedRepeatedSfixed32List([-1234]);
msg.setPackedRepeatedSfixed64List([-0x1234567800000000]);
msg.setPackedRepeatedFloatList([1.5]);
msg.setPackedRepeatedDoubleList([-1.5]);
msg.setPackedRepeatedBoolList([true]);
}
/**
* Helper: compare a bytes field to an expected value
* @param {Uint8Array|string} arr
* @param {Uint8Array} expected
* @return {boolean}
*/
function bytesCompare(arr, expected) {
if (goog.isString(arr)) {
arr = goog.crypt.base64.decodeStringToUint8Array(arr);
}
if (arr.length != expected.length) {
return false;
}
for (var i = 0; i < arr.length; i++) {
if (arr[i] != expected[i]) {
return false;
}
}
return true;
}
/**
* Helper: verify contents of given TestAllTypes message as set by
* fillAllFields().
* @param {proto.jspb.test.TestAllTypes} original
* @param {proto.jspb.test.TestAllTypes} copy
*/
function checkAllFields(original, copy) {
assertTrue(jspb.Message.equals(original, copy));
assertEquals(copy.getOptionalInt32(), -42);
assertEquals(copy.getOptionalInt64(), -0x7fffffff00000000);
assertEquals(copy.getOptionalUint32(), 0x80000000);
assertEquals(copy.getOptionalUint64(), 0xf000000000000000);
assertEquals(copy.getOptionalSint32(), -100);
assertEquals(copy.getOptionalSint64(), -0x8000000000000000);
assertEquals(copy.getOptionalFixed32(), 1234);
assertEquals(copy.getOptionalFixed64(), 0x1234567800000000);
assertEquals(copy.getOptionalSfixed32(), -1234);
assertEquals(copy.getOptionalSfixed64(), -0x1234567800000000);
assertEquals(copy.getOptionalFloat(), 1.5);
assertEquals(copy.getOptionalDouble(), -1.5);
assertEquals(copy.getOptionalBool(), true);
assertEquals(copy.getOptionalString(), 'hello world');
assertEquals(true, bytesCompare(copy.getOptionalBytes(), BYTES));
assertEquals(true, bytesCompare(copy.getOptionalBytes_asU8(), BYTES));
assertEquals(
copy.getOptionalBytes_asB64(), goog.crypt.base64.encodeByteArray(BYTES));
assertEquals(copy.getOptionalGroup().getA(), 100);
assertEquals(copy.getOptionalForeignMessage().getC(), 16);
assertEquals(copy.getOptionalForeignEnum(),
proto.jspb.test.ForeignEnum.FOREIGN_FOO);
assertEquals(copy.getOneofString(), 'oneof');
assertEquals(copy.getOneofFieldCase(),
proto.jspb.test.TestAllTypes.OneofFieldCase.ONEOF_STRING);
assertElementsEquals(copy.getRepeatedInt32List(), [-42]);
assertElementsEquals(copy.getRepeatedInt64List(), [-0x7fffffff00000000]);
assertElementsEquals(copy.getRepeatedUint32List(), [0x80000000]);
assertElementsEquals(copy.getRepeatedUint64List(), [0xf000000000000000]);
assertElementsEquals(copy.getRepeatedSint32List(), [-100]);
assertElementsEquals(copy.getRepeatedSint64List(), [-0x8000000000000000]);
assertElementsEquals(copy.getRepeatedFixed32List(), [1234]);
assertElementsEquals(copy.getRepeatedFixed64List(), [0x1234567800000000]);
assertElementsEquals(copy.getRepeatedSfixed32List(), [-1234]);
assertElementsEquals(copy.getRepeatedSfixed64List(), [-0x1234567800000000]);
assertElementsEquals(copy.getRepeatedFloatList(), [1.5]);
assertElementsEquals(copy.getRepeatedDoubleList(), [-1.5]);
assertElementsEquals(copy.getRepeatedBoolList(), [true]);
assertElementsEquals(copy.getRepeatedStringList(), ['hello world']);
assertEquals(copy.getRepeatedBytesList().length, 2);
assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[0], BYTES));
assertEquals(true, bytesCompare(copy.getRepeatedBytesList()[0], BYTES));
assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[1], BYTES));
assertEquals(copy.getRepeatedBytesList_asB64()[0], BYTES_B64);
assertEquals(copy.getRepeatedBytesList_asB64()[1], BYTES_B64);
assertEquals(copy.getRepeatedGroupList().length, 1);
assertEquals(copy.getRepeatedGroupList()[0].getA(), 100);
assertEquals(copy.getRepeatedForeignMessageList().length, 1);
assertEquals(copy.getRepeatedForeignMessageList()[0].getC(), 1000);
assertElementsEquals(copy.getRepeatedForeignEnumList(),
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
assertElementsEquals(copy.getPackedRepeatedInt32List(), [-42]);
assertElementsEquals(copy.getPackedRepeatedInt64List(),
[-0x7fffffff00000000]);
assertElementsEquals(copy.getPackedRepeatedUint32List(), [0x80000000]);
assertElementsEquals(copy.getPackedRepeatedUint64List(),
[0xf000000000000000]);
assertElementsEquals(copy.getPackedRepeatedSint32List(), [-100]);
assertElementsEquals(copy.getPackedRepeatedSint64List(),
[-0x8000000000000000]);
assertElementsEquals(copy.getPackedRepeatedFixed32List(), [1234]);
assertElementsEquals(copy.getPackedRepeatedFixed64List(),
[0x1234567800000000]);
assertElementsEquals(copy.getPackedRepeatedSfixed32List(), [-1234]);
assertElementsEquals(copy.getPackedRepeatedSfixed64List(),
[-0x1234567800000000]);
assertElementsEquals(copy.getPackedRepeatedFloatList(), [1.5]);
assertElementsEquals(copy.getPackedRepeatedDoubleList(), [-1.5]);
}
/**
* Helper: verify that all expected extensions are present.
* @param {!proto.jspb.test.TestExtendable} msg
*/
function checkExtensions(msg) {
assertEquals(-42,
msg.getExtension(proto.jspb.test.extendOptionalInt32));
assertEquals(-0x7fffffff00000000,
msg.getExtension(proto.jspb.test.extendOptionalInt64));
assertEquals(0x80000000,
msg.getExtension(proto.jspb.test.extendOptionalUint32));
assertEquals(0xf000000000000000,
msg.getExtension(proto.jspb.test.extendOptionalUint64));
assertEquals(-100,
msg.getExtension(proto.jspb.test.extendOptionalSint32));
assertEquals(-0x8000000000000000,
msg.getExtension(proto.jspb.test.extendOptionalSint64));
assertEquals(1234,
msg.getExtension(proto.jspb.test.extendOptionalFixed32));
assertEquals(0x1234567800000000,
msg.getExtension(proto.jspb.test.extendOptionalFixed64));
assertEquals(-1234,
msg.getExtension(proto.jspb.test.extendOptionalSfixed32));
assertEquals(-0x1234567800000000,
msg.getExtension(proto.jspb.test.extendOptionalSfixed64));
assertEquals(1.5,
msg.getExtension(proto.jspb.test.extendOptionalFloat));
assertEquals(-1.5,
msg.getExtension(proto.jspb.test.extendOptionalDouble));
assertEquals(true,
msg.getExtension(proto.jspb.test.extendOptionalBool));
assertEquals('hello world',
msg.getExtension(proto.jspb.test.extendOptionalString));
assertEquals(
true, bytesCompare(
msg.getExtension(proto.jspb.test.extendOptionalBytes), BYTES));
assertEquals(16,
msg.getExtension(
proto.jspb.test.ExtendsWithMessage.optionalExtension).getFoo());
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedInt32List),
[-42]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedInt64List),
[-0x7fffffff00000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedUint32List),
[0x80000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedUint64List),
[0xf000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSint32List),
[-100]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSint64List),
[-0x8000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedFixed32List),
[1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedFixed64List),
[0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSfixed32List),
[-1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSfixed64List),
[-0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedFloatList),
[1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedDoubleList),
[-1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedBoolList),
[true]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedStringList),
['hello world']);
assertEquals(
true,
bytesCompare(
msg.getExtension(proto.jspb.test.extendRepeatedBytesList)[0], BYTES));
assertEquals(1000,
msg.getExtension(
proto.jspb.test.ExtendsWithMessage.repeatedExtensionList)[0]
.getFoo());
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedForeignEnumList),
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedInt32List),
[-42]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedInt64List),
[-0x7fffffff00000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedUint32List),
[0x80000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedUint64List),
[0xf000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSint32List),
[-100]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSint64List),
[-0x8000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed32List),
[1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed64List),
[0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed32List),
[-1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed64List),
[-0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedFloatList),
[1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedDoubleList),
[-1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedBoolList),
[true]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList),
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
}
describe('protoBinaryTest', function() {
/**
* Tests a basic serialization-deserializaton round-trip with all supported
* field types (on the TestAllTypes message type).
*/
it('testRoundTrip', function() {
var msg = new proto.jspb.test.TestAllTypes();
fillAllFields(msg);
var encoded = msg.serializeBinary();
var decoded = proto.jspb.test.TestAllTypes.deserializeBinary(encoded);
checkAllFields(msg, decoded);
});
/**
* Test that base64 string and Uint8Array are interchangeable in bytes fields.
*/
it('testBytesFieldsGettersInterop', function() {
var msg = new proto.jspb.test.TestAllTypes();
// Set from a base64 string and check all the getters work.
msg.setOptionalBytes(BYTES_B64);
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
// Test binary serialize round trip doesn't break it.
msg = proto.jspb.test.TestAllTypes.deserializeBinary(msg.serializeBinary());
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg = new proto.jspb.test.TestAllTypes();
// Set from a Uint8Array and check all the getters work.
msg.setOptionalBytes(BYTES);
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
});
/**
* Test that bytes setters will receive result of any of the getters.
*/
it('testBytesFieldsSettersInterop', function() {
var msg = new proto.jspb.test.TestAllTypes();
msg.setOptionalBytes(BYTES);
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg.setOptionalBytes(msg.getOptionalBytes());
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg.setOptionalBytes(msg.getOptionalBytes_asB64());
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg.setOptionalBytes(msg.getOptionalBytes_asU8());
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
});
/**
* Test that bytes setters will receive result of any of the getters.
*/
it('testRepeatedBytesGetters', function() {
var msg = new proto.jspb.test.TestAllTypes();
function assertGetters() {
assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[0]));
assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[1]));
assertTrue(msg.getRepeatedBytesList_asU8()[0] instanceof Uint8Array);
assertTrue(msg.getRepeatedBytesList_asU8()[1] instanceof Uint8Array);
assertTrue(bytesCompare(msg.getRepeatedBytesList()[0], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList()[1], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[0], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[1], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[0], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[1], BYTES));
}
msg.setRepeatedBytesList([BYTES, BYTES]);
assertGetters();
msg.setRepeatedBytesList([BYTES_B64, BYTES_B64]);
assertGetters();
msg.setRepeatedBytesList([]);
assertEquals(0, msg.getRepeatedBytesList().length);
assertEquals(0, msg.getRepeatedBytesList_asB64().length);
assertEquals(0, msg.getRepeatedBytesList_asU8().length);
});
/**
* Helper: fill all extension values.
* @param {proto.jspb.test.TestExtendable} msg
*/
function fillExtensions(msg) {
msg.setExtension(
proto.jspb.test.extendOptionalInt32, -42);
msg.setExtension(
proto.jspb.test.extendOptionalInt64, -0x7fffffff00000000);
msg.setExtension(
proto.jspb.test.extendOptionalUint32, 0x80000000);
msg.setExtension(
proto.jspb.test.extendOptionalUint64, 0xf000000000000000);
msg.setExtension(
proto.jspb.test.extendOptionalSint32, -100);
msg.setExtension(
proto.jspb.test.extendOptionalSint64, -0x8000000000000000);
msg.setExtension(
proto.jspb.test.extendOptionalFixed32, 1234);
msg.setExtension(
proto.jspb.test.extendOptionalFixed64, 0x1234567800000000);
msg.setExtension(
proto.jspb.test.extendOptionalSfixed32, -1234);
msg.setExtension(
proto.jspb.test.extendOptionalSfixed64, -0x1234567800000000);
msg.setExtension(
proto.jspb.test.extendOptionalFloat, 1.5);
msg.setExtension(
proto.jspb.test.extendOptionalDouble, -1.5);
msg.setExtension(
proto.jspb.test.extendOptionalBool, true);
msg.setExtension(
proto.jspb.test.extendOptionalString, 'hello world');
msg.setExtension(proto.jspb.test.extendOptionalBytes, BYTES);
var submsg = new proto.jspb.test.ExtendsWithMessage();
submsg.setFoo(16);
msg.setExtension(
proto.jspb.test.ExtendsWithMessage.optionalExtension, submsg);
msg.setExtension(
proto.jspb.test.extendOptionalForeignEnum,
proto.jspb.test.ForeignEnum.FOREIGN_FOO);
msg.setExtension(
proto.jspb.test.extendRepeatedInt32List, [-42]);
msg.setExtension(
proto.jspb.test.extendRepeatedInt64List, [-0x7fffffff00000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedUint32List, [0x80000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedUint64List, [0xf000000000000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedSint32List, [-100]);
msg.setExtension(
proto.jspb.test.extendRepeatedSint64List, [-0x8000000000000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedFixed32List, [1234]);
msg.setExtension(
proto.jspb.test.extendRepeatedFixed64List, [0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedSfixed32List, [-1234]);
msg.setExtension(
proto.jspb.test.extendRepeatedSfixed64List, [-0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedFloatList, [1.5]);
msg.setExtension(
proto.jspb.test.extendRepeatedDoubleList, [-1.5]);
msg.setExtension(
proto.jspb.test.extendRepeatedBoolList, [true]);
msg.setExtension(
proto.jspb.test.extendRepeatedStringList, ['hello world']);
msg.setExtension(proto.jspb.test.extendRepeatedBytesList, [BYTES]);
submsg = new proto.jspb.test.ExtendsWithMessage();
submsg.setFoo(1000);
msg.setExtension(
proto.jspb.test.ExtendsWithMessage.repeatedExtensionList, [submsg]);
msg.setExtension(proto.jspb.test.extendRepeatedForeignEnumList,
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedInt32List, [-42]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedInt64List, [-0x7fffffff00000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedUint32List, [0x80000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedUint64List, [0xf000000000000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSint32List, [-100]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSint64List, [-0x8000000000000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedFixed32List, [1234]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedFixed64List, [0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSfixed32List, [-1234]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSfixed64List,
[-0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedFloatList, [1.5]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedDoubleList, [-1.5]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedBoolList, [true]);
msg.setExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList,
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
}
/**
* Tests extension serialization and deserialization.
*/
it('testExtensions', function() {
var msg = new proto.jspb.test.TestExtendable();
fillExtensions(msg);
var encoded = msg.serializeBinary();
var decoded = proto.jspb.test.TestExtendable.deserializeBinary(encoded);
checkExtensions(decoded);
});
});
Accelerate Your Automation Test Cycles With LambdaTest
Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.