chore: In gno doc, use JSONDocumentation (like from vm/qdoc)
PR https://github.com/gnolang/gno/pull/3851 makes gnoweb use vm/qdoc which returns a JSONDocumentation. This PR makes gno doc use a JSONDocumentation to print the docs. Currently, this is obtained from the local gno code, but this opens to way for gno doc to make a remote call to vm/qdoc when needed.
In general, this PR separates two processes which are currently intertwined: Figuring out what information needs to be printed and extracting that information from the go/doc AST. Now, we first extract all information from the go/doc AST into a JSONDocumentation, and then we figure out what needs to be printed.
As a follow-on to PR https://github.com/gnolang/gno/pull/3459, add more information in JSONDocumentation:
- In
JSONDocumentation, addBugs - In
JSONType, changeSignaturetoType(breaking change) - In
JSONType, addAliasfortype A = B - In
JSONType, addKindto handle struct, interface, etc. - In
JSONType, addInterElemsandFieldsto include information about interface elements (methods, embedded types) and struct fields - In
JSONField, addDocwhich is useful for struct fields - In
JSONFunc, addCrossing - Update tests accordingly
Make gno doc use a JSONDocumentation:
- In
WriteJSONDocumentation, add a param forWriteDocumentationOptionsso that we can setSource - In
pkgPrinter, change the type ofdoctoJSONDocumentation. Get it fromWriteJSONDocumentation - In
pkgPrinter, remove unused fieldspkg,fileandfs - In
pkgPrinter, changetypedValueandconstructorto use the symbol strings instead of the specific go/doc AST types (which are not inJSONDocumentation) - Change
pkgPrintermethods to useJSONDocumentationinstead of the go/doc AST - In
pkgPrinter.ToText, use a default Parser and Printer so that we don't need the go/doc package AST. Make it a non-method function - In
pkgPrinter.symbolDoc, remove the unused bool return
For example. gno doc valopers prints:
package valopers // import "valopers"
Package valopers is designed around the permissionless lifecycle of valoper
profiles.
const MonikerMaxLength
var ErrValoperExists
func AddToAuthList(cur realm, address_XXX std.Address, member std.Address)
func Auth() *authz.Authorizer
func DeleteFromAuthList(cur realm, address_XXX std.Address, member std.Address)
func NewInstructionsProposalCallback(newInstructions string) func() error
func NewMinFeeProposalCallback(newMinFee int64) func() error
func Register(cur realm, moniker string, description string, address_XXX std.Address, pubKey string)
func Render(fullPath string) string
func UpdateDescription(cur realm, address_XXX std.Address, description string)
func UpdateKeepRunning(cur realm, address_XXX std.Address, keepRunning bool)
func UpdateMoniker(cur realm, address_XXX std.Address, moniker string)
type Valoper struct{ ... }
func GetByAddr(address_XXX std.Address) Valoper
BREAKING CHANGE: In JSONType, changed Signature to Type. The signature can be easily constructed with "type " + Name + " " + Type. (Should be minimal impact. This doesn't affect gnoweb which doesn't show types.)
🛠 PR Checks Summary
All Automated Checks passed. ✅
Manual Checks (for Reviewers):
- [ ] IGNORE the bot requirements for this PR (force green CI check)
Read More
🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.
✅ Automated Checks (for Contributors):
🟢 Maintainers must be able to edit this pull request (more info) 🟢 Pending initial approval by a review team member, or review from tech-staff
☑️ Contributor Actions:
- Fix any issues flagged by automated checks.
- Follow the Contributor Checklist to ensure your PR is ready for review.
- Add new tests, or document why they are unnecessary.
- Provide clear examples/screenshots, if necessary.
- Update documentation, if required.
- Ensure no breaking changes, or include
BREAKING CHANGEnotes. - Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
- Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Automated Checks
Maintainers must be able to edit this pull request (more info)
If
🟢 Condition met └── 🟢 And ├── 🟢 The base branch matches this pattern: ^master$ └── 🟢 The pull request was created from a fork (head branch repo: jefft0/gno)Then
🟢 Requirement satisfied └── 🟢 Maintainer can modify this pull requestPending initial approval by a review team member, or review from tech-staff
If
🟢 Condition met └── 🟢 And ├── 🟢 The base branch matches this pattern: ^master$ └── 🟢 Not (🔴 Pull request author is a member of the team: tech-staff)Then
🟢 Requirement satisfied └── 🟢 If ├── 🟢 Condition │ └── 🟢 Or │ ├── 🟢 At least 1 user(s) of the organization reviewed the pull request (with state "APPROVED") │ ├── 🟢 At least 1 user(s) of the team tech-staff reviewed pull request │ └── 🔴 This pull request is a draft └── 🟢 Then └── 🟢 And ├── 🟢 Not (🔴 This label is applied to pull request: review/triage-pending) └── 🟢 At least 1 user(s) of the team tech-staff reviewed pull requestManual Checks
**IGNORE** the bot requirements for this PR (force green CI check)
If
🟢 Condition met └── 🟢 On every pull requestCan be checked by
- Any user with comment edit permission
Codecov Report
:x: Patch coverage is 76.72584% with 118 lines in your changes missing coverage. Please review.
:loudspeaker: Thoughts on this report? Let us know!
- If
JSONTypeis an interface, it doesn't include the methods. We can add to theFieldswhere Name is the method name and Type is afunc. For exampletype Test interface { Meth(int x) string}is aJSONFieldwhere Name isMethand Type isfunc (int x) string. Does that sound good?
I would separate Fields and Methods, for structs and interfaces respectively, rather than overloading them. We can use omitempty to only include them for one. (We could use omitzero to print an empty JSON array using a non-nil slice, so show Fields OR Methods even when they're empty, but it's available only in 1.24 which is released in August :cry: ).
- Should
JSONDocumentationinclude the package BUGS?
If it's trivial, yes.
I would separate
FieldsandMethods, for structs and interfaces respectively
That would work. Alternatively, in JSONDocumentation, we can keep Types []*JSONType only for struct types, and add Interfaces []*JSONInterface where JSONInterface has Methods (and no Fields). What do you think?
That would work. Alternatively, in
JSONDocumentation, we can keepTypes []*JSONTypeonly for struct types, and addInterfaces []*JSONInterfacewhereJSONInterfacehasMethods(and noFields). What do you think?
No, I think it makes sense to keep them together - Types can actually have not just struct and interfaces, but all kinds of declared types, no? Like type A int. So maybe instead of "interface": true/false we need a "kind" field, like reflect.Kind. Seeing as we work on the AST, though, it should be different.
Here's how I propose we make it:
type JSONType struct {
Name string `json:"name"` // JSONType
Type string `json:"type"` // struct { ... }
Doc string `json:"doc"` // godoc documentation...
Alias bool `json:"alias"` // true if Assign != 0; ie. if an alias like `type A = B`
Kind string `json:"kind"` // struct | interface | array | slice | map | channel | func | pointer | ident
Methods []JSONField `json:"methods,omitzero"` // interface methods (kind == "struct")
Fields []JSONField `json:"fields,omitzero"` // struct fields (kind == "interface")
}
- Remove
Signaturein favor ofType(it can be easily constructed with"type " + Name + " " + Type) - Add Alias to indicate type aliases
- Add Kind; allows a reader to quickly "peek" into the kind of the type. We may extend this to put this in other places, but let's start with JSONType. This should be based on a simple AST type switch on the value of TypeSpec.Type;
SelectorExprandIdentshould both be considered idents,ParenExprshould be de-parenthesized before generating the JSONType. - Methods and Fields have
omitzero; useomitemptyfor now and add a comment noting to switch when possible.
Here's how I propose we make it
Sounds good. A detail question about struct field comments. Consider the struct
type MyStruct struct {
// Above comment
X int // line comment
}
In the AST Field type, the above comment and line comment are separated as Doc and Comment . In JSONField, should we combine these into one Doc string? (Same question for interface methods.)
In the AST
Fieldtype, the above comment and line comment are separated asDocandComment. InJSONField, should we combine these into oneDocstring? (Same question for interface methods.)
Sounds good.
@thehowl , in JSONType, you suggest Methods []JSONField. Instead, I suggest to use JSONFunc which will allow us to separate out parameters and return types. Sound good?
- Remove
Signaturein favor ofType(it can be easily constructed with"type " + Name + " " + Type)- Add Alias to indicate type aliases
- Add Kind; allows a reader to quickly "peek" into the kind of the type. We may extend this to put this in other places, but let's start with JSONType. This should be based on a simple AST type switch on the value of TypeSpec.Type;
SelectorExprandIdentshould both be considered idents,ParenExprshould be de-parenthesized before generating the JSONType.- Methods and Fields have
omitzero; useomitemptyfor now and add a comment noting to switch when possible.
Hi @thehowl . These changes are complete. Ready for review again.
On some thought, let's merge this after #4316.
The syntax to cross will be different again, so we'll have to update how this works regardless.
@jefft0 xform2 is merged. Can you update this so that cur realm as a first parameter is identified as crossing, rather than using the crossing() statement?
I think we can still call it a "crossing function", so only the detection system should change.
@jefft0 xform2 is merged. Can you update this so that
cur realmas a first parameter is identified as crossing, rather than using thecrossing()statement?
Hi @thehowl . Done. https://github.com/gnolang/gno/pull/3931/commits/977b1d6bb27a74ef75a1403226c3677d2a9641a9
Overall, it looks good. @jefft0 Just before approval, what is the point of detecting and retaining the
BUGkeyword? I understand its relevance to the current package, but once we reach themainnet, I don't think we should encourage people to retain functionality withBUG. Since the contract cannot be updated, I don't see the value in deploying a buggy feature.
I included BUGS because @thehowl asked me to. https://github.com/gnolang/gno/pull/3931#issuecomment-2810044808
Overall, it looks good. @jefft0 Just before approval, what is the point of detecting and retaining the
BUGkeyword? I understand its relevance to the current package, but once we reach themainnet, I don't think we should encourage people to retain functionality withBUG. Since the contract cannot be updated, I don't see the value in deploying a buggy feature.
// BUG can be used to mention even rare bug conditions: https://pkg.go.dev/reflect#pkg-note-BUG
Gno realms specifically will likely have some form of evolution, and bugs may be kept in packages for many reasons, chief among which backwards compatibility, so I would say it's sometimes desirable to have them, and having a mechanism to clearly mark bugs is better IMO than not having one.
We can also remove it as less important, but even Go does ship packages with bugs. Admittedly, this bug feature is more useful if package documentation can be updated (even if the rest of the program can't), but I don't think this is a wrong feature to have itself