add well known extensions#93
Conversation
| messages: MessageFormatter.IMessageModel[]; | ||
| extensions: ExtensionFormatter.IExtensionModel[]; | ||
| enums: EnumFormatter.IEnumModel[]; | ||
| wellKnownDeclarations: string[]; |
There was a problem hiding this comment.
We need Dedicated Types here rather than string type
There was a problem hiding this comment.
Okay got it, thanks. Do you have a suggestion on what those would be? I was modeling this after the imports field, since they are roughly equivalent (static strings that simply need to be inserted at the bottom of the file), but this could also be aliased like type WellKnownDeclaration = string; if that's preferable.
| "Timestamp": [ | ||
| "toDate(): Date;", | ||
| "fromDate(date: Date): null;", | ||
| "static fromDate(date: Date): Timestamp;", |
There was a problem hiding this comment.
I think we need move those functions into templates
There was a problem hiding this comment.
Could you advise on the best structure for that? Are you imagining partials for each of the messages within each of the well known types? I could imagine for example:
template
partial
wellKnown
timestamp
declarations.hbs
extensions
[messageName].hbs
I was primarily concerned about how these would be passed conditionally into the messages in a way that is not too obscenely complicated.
| {{{render 'partial/enum' this}}} | ||
| {{/each}} | ||
| {{#each wellKnownDeclarations}} | ||
| {{{this}}} |
There was a problem hiding this comment.
I think we need partial/xxx sub templates for well known types
There was a problem hiding this comment.
Cool, I'll wait to hear back on whether you prefer a sub template setup from elsewhere before implementing just so I know we're on the same page.
| }); | ||
|
|
||
| if (fileName in WellKnownExtensionsMap) { | ||
| WellKnownExtensionsMap[fileName]?.declarations?.forEach(declaration => { |
There was a problem hiding this comment.
I didn't get here. fileName here is the proto file user provided, like the examples/book.proto. It will never match the WellKnownExtensionsMap.
There was a problem hiding this comment.
Yes, that's expected! In that scenario, the Google generator will also not match, and therefore those functions will not be present. (The current example does not actually generate descriptors for any well known types.)
Those fields are strictly available when you're translating a well known type with that file path — see my original PR description for links to where/when this happens in Google protoc. I will add an example here to illustrate, though.
|
|
||
| descriptor.getMessageTypeList().forEach((enumType) => { | ||
| messages.push(MessageFormatter.format(fileName, exportMap, enumType, "", descriptor)); | ||
| messages.push(MessageFormatter.format(fileName, exportMap, enumType, "", descriptor, WellKnownExtensionsMap[fileName]?.extensions)); |
There was a problem hiding this comment.
Same here, file name is user provided like examples/book.proto. It won't be in the WellKnownExtensionsMap.
|
Could you please share me some use cases of I added the message TimestampType {
google.protobuf.Timestamp time = 1;
}in the if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.com.book.TimestampType.prototype.toObject = function(opt_includeInstance) {
return proto.com.book.TimestampType.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.com.book.TimestampType} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.com.book.TimestampType.toObject = function(includeInstance, msg) {
var f, obj = {
time: (f = msg.getTime()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f)
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.com.book.TimestampType}
*/
proto.com.book.TimestampType.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.com.book.TimestampType;
return proto.com.book.TimestampType.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.com.book.TimestampType} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.com.book.TimestampType}
*/
proto.com.book.TimestampType.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = new google_protobuf_timestamp_pb.Timestamp;
reader.readMessage(value,google_protobuf_timestamp_pb.Timestamp.deserializeBinaryFromReader);
msg.setTime(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.com.book.TimestampType.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.com.book.TimestampType.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.com.book.TimestampType} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.com.book.TimestampType.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getTime();
if (f != null) {
writer.writeMessage(
1,
f,
google_protobuf_timestamp_pb.Timestamp.serializeBinaryToWriter
);
}
};
/**
* optional google.protobuf.Timestamp time = 1;
* @return {?proto.google.protobuf.Timestamp}
*/
proto.com.book.TimestampType.prototype.getTime = function() {
return /** @type{?proto.google.protobuf.Timestamp} */ (
jspb.Message.getWrapperField(this, google_protobuf_timestamp_pb.Timestamp, 1));
};
/**
* @param {?proto.google.protobuf.Timestamp|undefined} value
* @return {!proto.com.book.TimestampType} returns this
*/
proto.com.book.TimestampType.prototype.setTime = function(value) {
return jspb.Message.setWrapperField(this, 1, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.com.book.TimestampType} returns this
*/
proto.com.book.TimestampType.prototype.clearTime = function() {
return this.setTime(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.com.book.TimestampType.prototype.hasTime = function() {
return jspb.Message.getField(this, 1) != null;
};I didn't find the |
|
@agreatfool I just added an example of how this gets triggered for illustration. I would certainly appreciate any input you have on how you'd prefer this functionality to be architected! In particular, it sounds like you'd prefer these to exist as partials, so I suggested an example directory structure for this that could use your input. |
This PR creates a mechanism for including extended methods for well known types, and adds those extensions for the
Timestamptype as well asListValue(in Struct), just to prove out the concept beyond the immediate need. It does so by echoing the logic ingoogle-protobuf, which should provide exact logical parity:google-protobufconsiders it a well known type if its path starts withgoogle/protobuf/, so well known extension filenames should include that prefix (https://github.com/protocolbuffers/protobuf/blob/d16bf914bc5ba569d2b70376051d15f68ce4322d/src/google/protobuf/compiler/js/js_generator.cc#L1634-L1636)Note that the embeds are copied over from DefinitelyTyped.
Happy to write out the rest of the embeds generated by the Google compiler, but let me know if this is a reasonable approach.
Addresses #92