aboutsummaryrefslogtreecommitdiffhomepage
path: root/js
diff options
context:
space:
mode:
authorGravatar Adam Cozzette <acozzette@google.com>2018-03-13 16:37:29 -0700
committerGravatar Adam Cozzette <acozzette@google.com>2018-03-13 16:37:29 -0700
commit0400cca3236de1ca303af38bf81eab332d042b7c (patch)
treea8a9b19853f64567c96750a1c7d253926471daa5 /js
parent96b535cc2f4f7b7e22a1b8622149f7c26a5a3f63 (diff)
Integrated internal changes from Google
Diffstat (limited to 'js')
-rw-r--r--js/binary/constants.js19
-rw-r--r--js/binary/decoder.js2
-rw-r--r--js/binary/writer.js6
-rw-r--r--js/binary/writer_test.js12
-rw-r--r--js/debug.js2
-rw-r--r--js/map.js16
-rw-r--r--js/message.js82
-rw-r--r--js/message_test.js12
8 files changed, 100 insertions, 51 deletions
diff --git a/js/binary/constants.js b/js/binary/constants.js
index 75a8a52c..21c5889c 100644
--- a/js/binary/constants.js
+++ b/js/binary/constants.js
@@ -60,14 +60,25 @@ goog.forwardDeclare('jsproto.BinaryExtension');
/**
- * Base interface class for all const messages. Does __not__ define any
- * methods, as doing so on a widely-used interface defeats dead-code
- * elimination.
+ * Base interface class for all const messages.
* @interface
*/
jspb.ConstBinaryMessage = function() {};
+/**
+ * Generate a debug string for this proto that is in proto2 text format.
+ * @return {string} The debug string.
+ */
+jspb.ConstBinaryMessage.prototype.toDebugString;
+/**
+ * Helper to generate a debug string for this proto at some indent level. The
+ * first line is not indented.
+ * @param {number} indentLevel The number of spaces by which to indent lines.
+ * @return {string} The debug string.
+ * @protected
+ */
+jspb.ConstBinaryMessage.prototype.toDebugStringInternal;
/**
* Base interface class for all messages. Does __not__ define any methods, as
@@ -97,6 +108,7 @@ jspb.ScalarFieldType;
* A repeated field in jspb is an array of scalars, blobs, or messages.
* @typedef {!Array<jspb.ScalarFieldType>|
!Array<!Uint8Array>|
+ !Array<!jspb.ConstBinaryMessage>|
!Array<!jspb.BinaryMessage>}
*/
jspb.RepeatedFieldType;
@@ -108,6 +120,7 @@ jspb.RepeatedFieldType;
* @typedef {jspb.ScalarFieldType|
jspb.RepeatedFieldType|
!Uint8Array|
+ !jspb.ConstBinaryMessage|
!jspb.BinaryMessage|
!jsproto.BinaryExtension}
*/
diff --git a/js/binary/decoder.js b/js/binary/decoder.js
index d0c0bc17..e33bf1be 100644
--- a/js/binary/decoder.js
+++ b/js/binary/decoder.js
@@ -986,7 +986,7 @@ jspb.BinaryDecoder.prototype.readString = function(length) {
codeUnits.push(high, low);
}
- // Avoid exceeding the maximum stack size when calling {@code apply}.
+ // Avoid exceeding the maximum stack size when calling `apply`.
if (codeUnits.length >= 8192) {
result += String.fromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
diff --git a/js/binary/writer.js b/js/binary/writer.js
index 8a018058..287d29c3 100644
--- a/js/binary/writer.js
+++ b/js/binary/writer.js
@@ -236,10 +236,12 @@ jspb.BinaryWriter.prototype.getResultBuffer = function() {
/**
* Converts the encoded data into a base64-encoded string.
+ * @param {boolean=} opt_webSafe True indicates we should use a websafe
+ * alphabet, which does not require escaping for use in URLs.
* @return {string}
*/
-jspb.BinaryWriter.prototype.getResultBase64String = function() {
- return goog.crypt.base64.encodeByteArray(this.getResultBuffer());
+jspb.BinaryWriter.prototype.getResultBase64String = function(opt_webSafe) {
+ return goog.crypt.base64.encodeByteArray(this.getResultBuffer(), opt_webSafe);
};
diff --git a/js/binary/writer_test.js b/js/binary/writer_test.js
index 118eecfc..8a9a1bb0 100644
--- a/js/binary/writer_test.js
+++ b/js/binary/writer_test.js
@@ -118,4 +118,16 @@ describe('binaryWriterTest', function() {
var buffer = writer.getResultBuffer();
assertEquals(expected, goog.crypt.byteArrayToHex(buffer));
});
+
+
+ /**
+ * Tests websafe encodings for base64 strings.
+ */
+ it('testWebSafeOption', function() {
+ var writer = new jspb.BinaryWriter();
+ writer.writeBytes(1, new Uint8Array([127]));
+ assertEquals('CgF/', writer.getResultBase64String());
+ assertEquals('CgF/', writer.getResultBase64String(false));
+ assertEquals('CgF_', writer.getResultBase64String(true));
+ });
});
diff --git a/js/debug.js b/js/debug.js
index 4ae3c2a2..ba51bbe0 100644
--- a/js/debug.js
+++ b/js/debug.js
@@ -42,7 +42,7 @@ goog.require('jspb.Message');
/**
* Turns a proto into a human readable object that can i.e. be written to the
- * console: {@code console.log(jspb.debug.dump(myProto))}.
+ * console: `console.log(jspb.debug.dump(myProto))`.
* This function makes a best effort and may not work in all cases. It will not
* work in obfuscated and or optimized code.
* Use this in environments where {@see jspb.Message.prototype.toObject} is
diff --git a/js/map.js b/js/map.js
index d423499f..7b5b2c38 100644
--- a/js/map.js
+++ b/js/map.js
@@ -48,9 +48,9 @@ goog.forwardDeclare('jspb.BinaryWriter');
*
* @template K, V
*
- * @param {!Array<!Array<!Object>>} arr
+ * @param {!Array<!Array<?>>} arr
*
- * @param {?function(new:V)|function(new:V,?)=} opt_valueCtor
+ * @param {?function(new:V, ?=)=} opt_valueCtor
* The constructor for type V, if type V is a message type.
*
* @constructor
@@ -118,7 +118,7 @@ jspb.Map.prototype.toArray = function() {
strKeys.sort();
for (var i = 0; i < strKeys.length; i++) {
var entry = this.map_[strKeys[i]];
- var valueWrapper = /** @type {!Object} */ (entry.valueWrapper);
+ var valueWrapper = /** @type {?jspb.Message} */ (entry.valueWrapper);
if (valueWrapper) {
valueWrapper.toArray();
}
@@ -165,7 +165,7 @@ jspb.Map.prototype.toObject = function(includeInstance, valueToObject) {
*
* @template K, V
* @param {!Array<!Array<!Object>>} entries
- * @param {!function(new:V)|function(new:V,?)} valueCtor
+ * @param {!function(new:V,?=)} valueCtor
* The constructor for type V.
* @param {!function(!Object):V} valueFromObject
* The fromObject function for type V.
@@ -432,7 +432,8 @@ jspb.Map.prototype.serializeBinary = function(
valueWriterFn.call(writer, 2, this.wrapEntry_(entry),
opt_valueWriterCallback);
} else {
- valueWriterFn.call(writer, 2, entry.value);
+ /** @type {function(this:jspb.BinaryWriter,number,?)} */ (valueWriterFn)
+ .call(writer, 2, entry.value);
}
writer.endSubMessage();
}
@@ -475,10 +476,13 @@ jspb.Map.deserializeBinary = function(map, reader, keyReaderFn, valueReaderFn,
} else if (field == 2) {
// Value.
if (map.valueCtor_) {
+ goog.asserts.assert(opt_valueReaderCallback);
value = new map.valueCtor_();
valueReaderFn.call(reader, value, opt_valueReaderCallback);
} else {
- value = valueReaderFn.call(reader);
+ value =
+ (/** @type {function(this:jspb.BinaryReader):?} */ (valueReaderFn))
+ .call(reader);
}
}
}
diff --git a/js/message.js b/js/message.js
index 8f68cbb4..04d43339 100644
--- a/js/message.js
+++ b/js/message.js
@@ -216,17 +216,6 @@ goog.define('jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS', true);
/**
- * @define {boolean} Turning on this flag does NOT change the behavior of JSPB
- * and only affects private internal state. It may, however, break some
- * tests that use naive deeply-equals algorithms, because using a proto
- * mutates its internal state.
- * Projects are advised to turn this flag always on.
- */
-goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', true);
-// TODO(b/19419436): Delete this flag.
-
-
-/**
* Does this JavaScript environment support Uint8Aray typed arrays?
* @type {boolean}
* @private
@@ -369,7 +358,7 @@ jspb.Message.getFieldNumber_ = function(msg, index) {
*/
jspb.Message.initialize = function(
msg, data, messageId, suggestedPivot, repeatedFields, opt_oneofFields) {
- msg.wrappers_ = jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ? null : {};
+ msg.wrappers_ = null;
if (!data) {
data = messageId ? [messageId] : [];
}
@@ -394,17 +383,12 @@ jspb.Message.initialize = function(
var fieldNumber = repeatedFields[i];
if (fieldNumber < msg.pivot_) {
var index = jspb.Message.getIndex_(msg, fieldNumber);
- msg.array[index] = msg.array[index] ||
- (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
- jspb.Message.EMPTY_LIST_SENTINEL_ :
- []);
+ msg.array[index] =
+ msg.array[index] || jspb.Message.EMPTY_LIST_SENTINEL_;
} else {
jspb.Message.maybeInitEmptyExtensionObject_(msg);
- msg.extensionObject_[fieldNumber] =
- msg.extensionObject_[fieldNumber] ||
- (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
- jspb.Message.EMPTY_LIST_SENTINEL_ :
- []);
+ msg.extensionObject_[fieldNumber] = msg.extensionObject_[fieldNumber] ||
+ jspb.Message.EMPTY_LIST_SENTINEL_;
}
}
}
@@ -517,8 +501,7 @@ jspb.Message.toObjectList = function(field, toObjectFn, opt_includeInstance) {
// And not using it here to avoid a function call.
var result = [];
for (var i = 0; i < field.length; i++) {
- result[i] = toObjectFn.call(field[i], opt_includeInstance,
- /** @type {!jspb.Message} */ (field[i]));
+ result[i] = toObjectFn.call(field[i], opt_includeInstance, field[i]);
}
return result;
};
@@ -551,10 +534,11 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions,
} else {
if (fieldInfo.isRepeated) {
obj[name] = jspb.Message.toObjectList(
- /** @type {!Array<jspb.Message>} */ (value),
+ /** @type {!Array<!jspb.Message>} */ (value),
fieldInfo.toObjectFn, opt_includeInstance);
} else {
- obj[name] = fieldInfo.toObjectFn(opt_includeInstance, value);
+ obj[name] = fieldInfo.toObjectFn(
+ opt_includeInstance, /** @type {!jspb.Message} */ (value));
}
}
}
@@ -1419,7 +1403,7 @@ jspb.Message.prototype.setExtension = function(fieldInfo, value) {
if (fieldInfo.isMessageType()) {
self.wrappers_[fieldNumber] = value;
self.extensionObject_[fieldNumber] = goog.array.map(
- /** @type {Array<jspb.Message>} */ (value), function(msg) {
+ /** @type {!Array<!jspb.Message>} */ (value), function(msg) {
return msg.toArray();
});
} else {
@@ -1428,7 +1412,8 @@ jspb.Message.prototype.setExtension = function(fieldInfo, value) {
} else {
if (fieldInfo.isMessageType()) {
self.wrappers_[fieldNumber] = value;
- self.extensionObject_[fieldNumber] = value ? value.toArray() : value;
+ self.extensionObject_[fieldNumber] =
+ value ? /** @type {!jspb.Message} */ (value).toArray() : value;
} else {
self.extensionObject_[fieldNumber] = value;
}
@@ -1530,9 +1515,15 @@ jspb.Message.compareFields = function(field1, field2) {
// If the fields are trivially equal, they're equal.
if (field1 == field2) return true;
- // If the fields aren't trivially equal and one of them isn't an object,
- // they can't possibly be equal.
if (!goog.isObject(field1) || !goog.isObject(field2)) {
+ // NaN != NaN so we cover this case.
+ if ((goog.isNumber(field1) && isNaN(field1)) ||
+ (goog.isNumber(field2) && isNaN(field2))) {
+ // One of the fields might be a string 'NaN'.
+ return String(field1) == String(field2);
+ }
+ // If the fields aren't trivially equal and one of them isn't an object,
+ // they can't possibly be equal.
return false;
}
@@ -1555,24 +1546,26 @@ jspb.Message.compareFields = function(field1, field2) {
// If they're both Arrays, compare them element by element except for the
// optional extension objects at the end, which we compare separately.
if (field1.constructor === Array) {
+ var typedField1 = /** @type {!Array<?>} */ (field1);
+ var typedField2 = /** @type {!Array<?>} */ (field2);
var extension1 = undefined;
var extension2 = undefined;
- var length = Math.max(field1.length, field2.length);
+ var length = Math.max(typedField1.length, typedField2.length);
for (var i = 0; i < length; i++) {
- var val1 = field1[i];
- var val2 = field2[i];
+ var val1 = typedField1[i];
+ var val2 = typedField2[i];
if (val1 && (val1.constructor == Object)) {
goog.asserts.assert(extension1 === undefined);
- goog.asserts.assert(i === field1.length - 1);
+ goog.asserts.assert(i === typedField1.length - 1);
extension1 = val1;
val1 = undefined;
}
if (val2 && (val2.constructor == Object)) {
goog.asserts.assert(extension2 === undefined);
- goog.asserts.assert(i === field2.length - 1);
+ goog.asserts.assert(i === typedField2.length - 1);
extension2 = val2;
val2 = undefined;
}
@@ -1695,8 +1688,13 @@ jspb.Message.clone_ = function(obj) {
var clonedArray = new Array(obj.length);
// Use array iteration where possible because it is faster than for-in.
for (var i = 0; i < obj.length; i++) {
- if ((o = obj[i]) != null) {
- clonedArray[i] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
+ o = obj[i];
+ if (o != null) {
+ // NOTE:redundant null check existing for NTI compatibility.
+ // see b/70515949
+ clonedArray[i] = (typeof o == 'object') ?
+ jspb.Message.clone_(goog.asserts.assert(o)) :
+ o;
}
}
return clonedArray;
@@ -1706,8 +1704,13 @@ jspb.Message.clone_ = function(obj) {
}
var clone = {};
for (var key in obj) {
- if ((o = obj[key]) != null) {
- clone[key] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
+ o = obj[key];
+ if (o != null) {
+ // NOTE:redundant null check existing for NTI compatibility.
+ // see b/70515949
+ clone[key] = (typeof o == 'object') ?
+ jspb.Message.clone_(goog.asserts.assert(o)) :
+ o;
}
}
return clone;
@@ -1723,6 +1726,9 @@ jspb.Message.registerMessageType = function(id, constructor) {
jspb.Message.registry_[id] = constructor;
// This is needed so we can later access messageId directly on the contructor,
// otherwise it is not available due to 'property collapsing' by the compiler.
+ /**
+ * @suppress {strictMissingProperties} messageId is not defined on Function
+ */
constructor.messageId = id;
};
diff --git a/js/message_test.js b/js/message_test.js
index 0acebb75..1be41093 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -418,6 +418,18 @@ describe('Message test suite', function() {
['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
});
+ it('testEqualsNonFinite', function() {
+ assertTrue(jspb.Message.compareFields(NaN, NaN));
+ assertTrue(jspb.Message.compareFields(NaN, 'NaN'));
+ assertTrue(jspb.Message.compareFields('NaN', NaN));
+ assertTrue(jspb.Message.compareFields(Infinity, Infinity));
+ assertTrue(jspb.Message.compareFields(Infinity, 'Infinity'));
+ assertTrue(jspb.Message.compareFields('-Infinity', -Infinity));
+ assertTrue(jspb.Message.compareFields([NaN], ['NaN']));
+ assertFalse(jspb.Message.compareFields(undefined, NaN));
+ assertFalse(jspb.Message.compareFields(NaN, undefined));
+ });
+
it('testToMap', function() {
var p1 = new proto.jspb.test.Simple1(['k', ['v']]);
var p2 = new proto.jspb.test.Simple1(['k1', ['v1', 'v2']]);