Update schema-based docs generator (#4035)
* Update properties.tmpl to render property comment as-is. WIP splitting out properties to lang-specific tables. * Generate the constructor dynamically from the resource per language. * Add doc functions in each language generator package for getting doc links for types..and later other functions too. * Render the constructor params in the Go code and inject into the template. * Generate nodejs types using the nodejs lang generator. * Add a templates bundler. Added a new Make target for autogenerating a static bundle for the resource docs generator. * Generate type links for all languages based on their schema type. Render the property type with a link if the underlying elements have a supporting type. Fix word-breaks for Python type names. * Various changes including the introduction of an interface type under the codegen package to help with generating some language-specific information for the resource docs generator. * Add a function to explicitly generate links for input types of nested types. Fix the resource doc link generator for Go. Don't replace the module name from the nodejs language type. * Fix bug with C# property type html encoding. * Fix some template formatting. Pass the state inputs for Python to generate the lookup function for it. * Do not generate the examples section if there are none. * Generating the property types per language. * Formatting. Rename function for readability. * Add comments. Update README. * Use relative URLs for doc links within the main site
This commit is contained in:
parent
2a24470135
commit
edbb05dddd
6
Makefile
6
Makefile
|
@ -12,6 +12,12 @@ TESTPARALLELISM := 10
|
|||
build-proto::
|
||||
cd sdk/proto && ./generate.sh
|
||||
|
||||
.PHONY: generate
|
||||
generate::
|
||||
$(call STEP_MESSAGE)
|
||||
echo "Generate static assets bundle for docs generator"
|
||||
go generate ./pkg/codegen/docs/
|
||||
|
||||
build::
|
||||
go install -ldflags "-X github.com/pulumi/pulumi/pkg/version.Version=${VERSION}" ${PROJECT}
|
||||
|
||||
|
|
27
pkg/codegen/docs.go
Normal file
27
pkg/codegen/docs.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"github.com/pulumi/pulumi/pkg/codegen/schema"
|
||||
)
|
||||
|
||||
// DocLanguageHelper is an interface for extracting language-specific information from a Pulumi schema.
|
||||
// See the implementation for this interface under each of the language code generators.
|
||||
type DocLanguageHelper interface {
|
||||
GetDocLinkForResourceType(packageName, moduleName, typeName string) string
|
||||
GetDocLinkForInputType(packageName, moduleName, typeName string) string
|
||||
GetLanguageTypeString(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string
|
||||
}
|
1
pkg/codegen/docs/.gitignore
vendored
Normal file
1
pkg/codegen/docs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
packaged.go
|
40
pkg/codegen/docs/README.md
Normal file
40
pkg/codegen/docs/README.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Docs generator
|
||||
|
||||
This generator generates resource-level docs by utilizing the Pulumi schema.
|
||||
|
||||
## Crash course on templates
|
||||
|
||||
The templates use Go's built-in `html/template` package to process templates with data. The driver for this doc generator (e.g. tfbridge for TF-based providers) then persists each file from memory onto the disk as `.md` files.
|
||||
|
||||
Although we are using the `html/template` package, it has the same exact interface as the [`text/template`](https://golang.org/pkg/text/template) package, except for some HTML specific things. Therefore, all of the functions available in the `text/template` package are also available with the `html/template` package.
|
||||
|
||||
* Data can be injected using `{{.PropertyName}}`.
|
||||
* Nested properties can be accessed using the dot notation, i.e. `{{.Property1.Property2}}`.
|
||||
* Templates can inject other templates using the `{{template "template_name"}}` directive.
|
||||
* For this to work, you will need to first define the named template using `{{define "template_name"}}`.
|
||||
* You can pass data to nested templates by simply passing an argument after the template's name.
|
||||
* To remove whitespace from injected values, use the `-` in the template tags.
|
||||
* For example, `{{if .SomeBool}} some text {{- else}} some other text {{- end}}`. Note the use of `-` to eliminate whitespace from the enclosing text.
|
||||
* Read more [here](https://golang.org/pkg/text/template/#hdr-Text_and_spaces).
|
||||
* To render un-encoded content use the custom global function `htmlSafe`.
|
||||
* **Note**: This should only be used if you know for sure you are not injecting any user-generated content, as it by-passes the HTML encoding.
|
||||
* To print regular strings, that share the same syntax as the Go templating engine, use the built-in global function `print` [function](https://golang.org/pkg/text/template/#hdr-Functions).
|
||||
* For example, if you need to render `{{% md %}}`, you will instead need to do `{{print "{{% md %}}"}}`.
|
||||
|
||||
Learn more from here: https://curtisvermeeren.github.io/2017/09/14/Golang-Templates-Cheatsheet
|
||||
|
||||
## `bundler.go`
|
||||
|
||||
This file contains a `main` function and is part of the `main` package. We run it using the `go generate` command (see the `Makefile` and the starting comment in `pkg/codegen/gen.go`).
|
||||
|
||||
> This file is ignored using a `+build ignore` comment at the top of the file, so it is not ignored during a `go build ...`.
|
||||
|
||||
## `packaged.go`
|
||||
|
||||
A file generated by `bundler.go` that contains formatted byte strings, that represent the string templates from the `./templates/` folder. This file is also git-ignored as it is intended to only be generated by the `docs` repo and is not used during runtime of the main Pulumi CLI. In fact, this whole package is not used during the runtime of the CLI itself.
|
||||
|
||||
## `go:generate`
|
||||
|
||||
> Read more [here](https://blog.golang.org/generate).
|
||||
|
||||
`go:generate` is a special code comment that can be used to run custom commands by simply running `go generate <package>`, which then scans for `go:generate` comments in all sources in the package `<package>`. It also serves as a way to document, that a certain file relies on a command to have been executed before it can be used.
|
128
pkg/codegen/docs/bundler.go
Normal file
128
pkg/codegen/docs/bundler.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
//+build ignore
|
||||
|
||||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Pulling out some of the repeated strings tokens into constants would harm readability, so we just ignore the
|
||||
// goconst linter's warning.
|
||||
//
|
||||
// nolint: lll, goconst
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const (
|
||||
basePath = "."
|
||||
docsTemplatesPath = basePath + "/templates"
|
||||
generatedFileName = basePath + "/packaged.go"
|
||||
)
|
||||
|
||||
var conv = map[string]interface{}{"conv": fmtByteSlice}
|
||||
var tmpl = template.Must(template.New("").Funcs(conv).Parse(`
|
||||
// AUTO-GENERATED FILE! DO NOT EDIT THIS FILE MANUALLY.
|
||||
|
||||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Pulling out some of the repeated strings tokens into constants would harm readability, so we just ignore the
|
||||
// goconst linter's warning.
|
||||
//
|
||||
// nolint: lll, goconst
|
||||
package docs
|
||||
|
||||
func init() {
|
||||
packagedTemplates = make(map[string][]byte)
|
||||
{{ range $key, $value := . }}
|
||||
packagedTemplates["{{ $key }}"] = []byte{ {{ conv $value }} }
|
||||
{{ println }}
|
||||
{{- end }}
|
||||
}
|
||||
`))
|
||||
|
||||
// fmtByteSlice returns a formatted byte string for a given slice of bytes.
|
||||
// We embed the raw bytes to avoid any formatting errors that can occur due to saving
|
||||
// raw strings in a file.
|
||||
func fmtByteSlice(s []byte) string {
|
||||
builder := strings.Builder{}
|
||||
|
||||
for _, v := range s {
|
||||
builder.WriteString(fmt.Sprintf("%d,", int(v)))
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// main reads files under the templates directory, and builds a map of filename to byte slice.
|
||||
// Each file's contents are then written to a generated file.
|
||||
//
|
||||
// NOTE: Sub-directories are currently not supported.
|
||||
func main() {
|
||||
files, err := ioutil.ReadDir(docsTemplatesPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading the templates dir: %v", err)
|
||||
}
|
||||
|
||||
contents := make(map[string][]byte)
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
fmt.Printf("%q is a dir. Skipping...", f.Name())
|
||||
}
|
||||
b, err := ioutil.ReadFile(docsTemplatesPath + "/" + f.Name())
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading file %s: %v", f.Name(), err)
|
||||
}
|
||||
contents[f.Name()] = b
|
||||
}
|
||||
|
||||
// We overwrite the file every time the `go generate ...` command is run.
|
||||
f, err := os.Create(generatedFileName)
|
||||
if err != nil {
|
||||
log.Fatal("Error creating blob file:", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
builder := &bytes.Buffer{}
|
||||
if err = tmpl.Execute(builder, contents); err != nil {
|
||||
log.Fatal("Error executing template", err)
|
||||
}
|
||||
|
||||
data, err := format.Source(builder.Bytes())
|
||||
if err != nil {
|
||||
log.Fatal("Error formatting generated code", err)
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(generatedFileName, data, os.ModePerm); err != nil {
|
||||
log.Fatal("Error writing file", err)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//go:generate go run bundler.go
|
||||
|
||||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -21,17 +23,100 @@ package docs
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"io"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/codegen"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/dotnet"
|
||||
go_gen "github.com/pulumi/pulumi/pkg/codegen/go"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/nodejs"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/python"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/schema"
|
||||
"github.com/pulumi/pulumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
var supportedLanguages = []string{"csharp", "go", "nodejs", "python"}
|
||||
|
||||
var templates *template.Template
|
||||
var packagedTemplates map[string][]byte
|
||||
|
||||
// Header represents the header of each resource markdown file.
|
||||
type Header struct {
|
||||
Title string
|
||||
}
|
||||
|
||||
type exampleUsage struct {
|
||||
Heading string
|
||||
Code string
|
||||
}
|
||||
|
||||
// Property represents an input or an output property.
|
||||
type Property struct {
|
||||
Name string
|
||||
Comment string
|
||||
Type PropertyType
|
||||
DeprecationMessage string
|
||||
|
||||
IsRequired bool
|
||||
// IsInput is a flag to indicate if a property is an input
|
||||
// property.
|
||||
IsInput bool
|
||||
}
|
||||
|
||||
// DocNestedType represents a complex type.
|
||||
type DocNestedType struct {
|
||||
Name string
|
||||
APIDocLinks map[string]string
|
||||
Properties map[string][]Property
|
||||
}
|
||||
|
||||
// PropertyType represents the type of a property.
|
||||
type PropertyType struct {
|
||||
Name string
|
||||
// Link can be a link to an anchor tag on the same
|
||||
// page, or to another page/site.
|
||||
Link string
|
||||
}
|
||||
|
||||
// ConstructorParam represents the formal parameters of a constructor.
|
||||
type ConstructorParam struct {
|
||||
Name string
|
||||
Type PropertyType
|
||||
|
||||
// This is the language specific optional type indicator.
|
||||
// For example, in nodejs this is the character "?" and in Go
|
||||
// it's "*".
|
||||
OptionalFlag string
|
||||
|
||||
DefaultValue string
|
||||
}
|
||||
|
||||
type resourceArgs struct {
|
||||
Header
|
||||
|
||||
Comment string
|
||||
Examples []exampleUsage
|
||||
|
||||
ConstructorParams map[string]string
|
||||
// ConstructorResource is the resource that is being constructed or
|
||||
// is the result of a constructor-like function.
|
||||
ConstructorResource map[string]PropertyType
|
||||
ArgsRequired bool
|
||||
|
||||
InputProperties map[string][]Property
|
||||
OutputProperties map[string][]Property
|
||||
StateInputs map[string][]Property
|
||||
StateParam string
|
||||
|
||||
NestedTypes []DocNestedType
|
||||
}
|
||||
|
||||
type stringSet map[string]struct{}
|
||||
|
||||
func (ss stringSet) add(s string) {
|
||||
|
@ -44,32 +129,6 @@ type typeDetails struct {
|
|||
functionType bool
|
||||
}
|
||||
|
||||
// wbr inserts HTML <wbr> in between case changes, e.g. "fooBar" becomes "foo<wbr>Bar".
|
||||
func wbr(s string) string {
|
||||
var runes []rune
|
||||
var prev rune
|
||||
for i, r := range s {
|
||||
if i != 0 && unicode.IsLower(prev) && unicode.IsUpper(r) {
|
||||
runes = append(runes, []rune("<wbr>")...)
|
||||
}
|
||||
runes = append(runes, r)
|
||||
prev = r
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func title(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
runes := []rune(s)
|
||||
return string(append([]rune{unicode.ToUpper(runes[0])}, runes[1:]...))
|
||||
}
|
||||
|
||||
func lower(s string) string {
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
|
||||
type modContext struct {
|
||||
pkg *schema.Package
|
||||
mod string
|
||||
|
@ -80,6 +139,13 @@ type modContext struct {
|
|||
tool string
|
||||
}
|
||||
|
||||
func resourceName(r *schema.Resource) string {
|
||||
if r.IsProvider {
|
||||
return "Provider"
|
||||
}
|
||||
return tokenToName(r.Token)
|
||||
}
|
||||
|
||||
func (mod *modContext) details(t *schema.ObjectType) *typeDetails {
|
||||
details, ok := mod.typeDetails[t]
|
||||
if !ok {
|
||||
|
@ -92,336 +158,384 @@ func (mod *modContext) details(t *schema.ObjectType) *typeDetails {
|
|||
return details
|
||||
}
|
||||
|
||||
func tokenToName(tok string) string {
|
||||
components := strings.Split(tok, ":")
|
||||
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
||||
return title(components[2])
|
||||
}
|
||||
func (mod *modContext) typeString(t schema.Type, lang string, input, optional bool, insertWordBreaks bool) PropertyType {
|
||||
var langType string
|
||||
|
||||
func resourceName(r *schema.Resource) string {
|
||||
if r.IsProvider {
|
||||
return "Provider"
|
||||
}
|
||||
return tokenToName(r.Token)
|
||||
}
|
||||
|
||||
func (mod *modContext) typeStringPulumi(t schema.Type, link bool) string {
|
||||
var br string
|
||||
lt := "<"
|
||||
gt := ">"
|
||||
|
||||
// If we're linking, we're including HTML, so also include word breaks,
|
||||
// and escape < and >.
|
||||
if link {
|
||||
br = "<wbr>"
|
||||
lt = "<<wbr>"
|
||||
gt = "<wbr>>"
|
||||
var docLanguageHelper codegen.DocLanguageHelper
|
||||
switch lang {
|
||||
case "nodejs":
|
||||
docLanguageHelper = nodejs.DocLanguageHelper{}
|
||||
case "go":
|
||||
docLanguageHelper = go_gen.DocLanguageHelper{}
|
||||
case "csharp":
|
||||
docLanguageHelper = dotnet.DocLanguageHelper{}
|
||||
case "python":
|
||||
docLanguageHelper = python.DocLanguageHelper{}
|
||||
default:
|
||||
panic(errors.Errorf("Unknown language (%q) passed!", lang))
|
||||
}
|
||||
|
||||
var typ string
|
||||
langType = docLanguageHelper.GetLanguageTypeString(mod.pkg, mod.mod, t, input, optional)
|
||||
|
||||
// If the type is an object type, let's also wrap it with a link to the supporting type
|
||||
// on the same page using an anchor tag.
|
||||
var href string
|
||||
switch t := t.(type) {
|
||||
case *schema.ArrayType:
|
||||
|
||||
typ = fmt.Sprintf("Array%s%s%s", lt, mod.typeStringPulumi(t.ElementType, link), gt)
|
||||
case *schema.MapType:
|
||||
typ = fmt.Sprintf("Map%s%s%s", lt, mod.typeStringPulumi(t.ElementType, link), gt)
|
||||
elementLangType := mod.typeString(t.ElementType, lang, input, optional, false)
|
||||
href = elementLangType.Link
|
||||
case *schema.ObjectType:
|
||||
if link {
|
||||
typ = fmt.Sprintf("<a href=\"#%s\">%s</a>", lower(tokenToName(t.Token)), wbr(tokenToName(t.Token)))
|
||||
} else {
|
||||
typ = tokenToName(t.Token)
|
||||
}
|
||||
case *schema.TokenType:
|
||||
typ = tokenToName(t.Token)
|
||||
case *schema.UnionType:
|
||||
var elements []string
|
||||
for _, e := range t.ElementTypes {
|
||||
elements = append(elements, mod.typeStringPulumi(e, link))
|
||||
}
|
||||
sep := fmt.Sprintf(", %s", br)
|
||||
return fmt.Sprintf("Union%s%s%s", lt, strings.Join(elements, sep), gt)
|
||||
default:
|
||||
switch t {
|
||||
case schema.BoolType:
|
||||
typ = "boolean"
|
||||
case schema.IntType, schema.NumberType:
|
||||
typ = "number"
|
||||
case schema.StringType:
|
||||
typ = "string"
|
||||
case schema.ArchiveType:
|
||||
typ = "Archive"
|
||||
case schema.AssetType:
|
||||
typ = fmt.Sprintf("Union%sAsset, %sArchive%s", lt, br, gt)
|
||||
case schema.AnyType:
|
||||
typ = "any"
|
||||
}
|
||||
tokenName := tokenToName(t.Token)
|
||||
// Links to anchor targs on the same page must be lower-cased.
|
||||
href = "#" + lower(tokenName)
|
||||
}
|
||||
|
||||
if insertWordBreaks {
|
||||
if lang == "csharp" {
|
||||
langType = html.EscapeString(langType)
|
||||
}
|
||||
langType = wbr(langType)
|
||||
}
|
||||
return PropertyType{
|
||||
Link: href,
|
||||
Name: langType,
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
func (mod *modContext) genConstructorTS(w io.Writer, r *schema.Resource) {
|
||||
name := resourceName(r)
|
||||
|
||||
allOptionalInputs := true
|
||||
for _, prop := range r.InputProperties {
|
||||
allOptionalInputs = allOptionalInputs && !prop.IsRequired
|
||||
}
|
||||
|
||||
var argsFlags string
|
||||
if allOptionalInputs {
|
||||
// If the number of required input properties was zero, we can make the args object optional.
|
||||
argsFlags = "?"
|
||||
}
|
||||
argsType := name + "Args"
|
||||
|
||||
// TODO: The link to the class name and args type needs to factor in the package and module. Right now it's hardcoded to aws and s3.
|
||||
fmt.Fprintf(w, "<span class=\"k\">new</span> <span class=\"nx\"><a href=/docs/reference/pkg/nodejs/pulumi/aws/s3/#%s>%s</a></span><span class=\"p\">(</span><span class=\"nx\">name</span>: <span class=\"kt\"><a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String>string</a></span><span class=\"p\">,</span> <span class=\"nx\">args%s</span>: <span class=\"kt\"><a href=/docs/reference/pkg/nodejs/pulumi/aws/s3/#%s>%s</a></span><span class=\"p\">,</span> <span class=\"nx\">opts?</span>: <span class=\"kt\"><a href=/docs/reference/pkg/nodejs/pulumi/pulumi/#CustomResourceOptions>pulumi.CustomResourceOptions</a></span><span class=\"p\">);</span>", name, name, argsFlags, argsType, argsType)
|
||||
}
|
||||
|
||||
func (mod *modContext) genConstructorPython(w io.Writer, r *schema.Resource) {
|
||||
fmt.Fprintf(w, "def __init__(__self__, resource_name, opts=None")
|
||||
for _, prop := range r.InputProperties {
|
||||
fmt.Fprintf(w, ", %s=None", python.PyName(prop.Name))
|
||||
}
|
||||
// Note: We're excluding __name__ and __opts__ as those are only there for backwards compatibility and are
|
||||
// deliberately not included in doc strings.
|
||||
fmt.Fprintf(w, ", __props__=None)")
|
||||
}
|
||||
|
||||
func (mod *modContext) genConstructorGo(w io.Writer, r *schema.Resource) {
|
||||
func (mod *modContext) genConstructorTS(r *schema.Resource, argsOptional bool) []ConstructorParam {
|
||||
name := resourceName(r)
|
||||
argsType := name + "Args"
|
||||
fmt.Fprintf(w, "func New%s(ctx *pulumi.Context, name string, args *%s, opts ...pulumi.ResourceOption) (*%s, error)\n", name, argsType, name)
|
||||
argsFlag := ""
|
||||
if argsOptional {
|
||||
argsFlag = "?"
|
||||
}
|
||||
|
||||
docLangHelper := nodejs.DocLanguageHelper{}
|
||||
return []ConstructorParam{
|
||||
{
|
||||
Name: "name",
|
||||
Type: PropertyType{
|
||||
Name: "string",
|
||||
Link: nodejs.GetDocLinkForBuiltInType("string"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "args",
|
||||
OptionalFlag: argsFlag,
|
||||
Type: PropertyType{
|
||||
Name: argsType,
|
||||
Link: docLangHelper.GetDocLinkForResourceType(mod.pkg.Name, mod.mod, argsType),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "opts",
|
||||
OptionalFlag: "?",
|
||||
Type: PropertyType{
|
||||
Name: "pulumi.CustomResourceOptions",
|
||||
Link: docLangHelper.GetDocLinkForResourceType("pulumi", "pulumi", "CustomResourceOptions"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *modContext) genConstructorCS(w io.Writer, r *schema.Resource) {
|
||||
func (mod *modContext) genConstructorGo(r *schema.Resource, argsOptional bool) []ConstructorParam {
|
||||
name := resourceName(r)
|
||||
argsType := name + "Args"
|
||||
argsFlag := ""
|
||||
if argsOptional {
|
||||
argsFlag = "*"
|
||||
}
|
||||
|
||||
docLangHelper := go_gen.DocLanguageHelper{}
|
||||
// return fmt.Sprintf("func New%s(ctx *pulumi.Context, name string, args *%s, opts ...pulumi.ResourceOption) (*%s, error)\n", name, argsType, name)
|
||||
return []ConstructorParam{
|
||||
{
|
||||
Name: "ctx",
|
||||
OptionalFlag: "*",
|
||||
Type: PropertyType{
|
||||
Name: "pulumi.Context",
|
||||
Link: "https://pkg.go.dev/github.com/pulumi/pulumi/sdk/go/pulumi?tab=doc#Context",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "name",
|
||||
Type: PropertyType{
|
||||
Name: "string",
|
||||
Link: go_gen.GetDocLinkForBuiltInType("string"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "args",
|
||||
OptionalFlag: argsFlag,
|
||||
Type: PropertyType{
|
||||
Name: argsType,
|
||||
Link: docLangHelper.GetDocLinkForResourceType(mod.pkg.Name, mod.mod, argsType),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "opts",
|
||||
OptionalFlag: "...",
|
||||
Type: PropertyType{
|
||||
Name: "pulumi.ResourceOption",
|
||||
Link: "https://pkg.go.dev/github.com/pulumi/pulumi/sdk/go/pulumi?tab=doc#ResourceOption",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *modContext) genConstructorCS(r *schema.Resource, argsOptional bool) []ConstructorParam {
|
||||
name := resourceName(r)
|
||||
argsType := name + "Args"
|
||||
argsSchemaType := &schema.ObjectType{
|
||||
Token: r.Token,
|
||||
}
|
||||
argLangType := mod.typeString(argsSchemaType, "csharp", true, argsOptional, false)
|
||||
|
||||
var argsFlag string
|
||||
var argsDefault string
|
||||
allOptionalInputs := true
|
||||
for _, prop := range r.InputProperties {
|
||||
allOptionalInputs = allOptionalInputs && !prop.IsRequired
|
||||
}
|
||||
if allOptionalInputs {
|
||||
if argsOptional {
|
||||
// If the number of required input properties was zero, we can make the args object optional.
|
||||
argsDefault = " = null"
|
||||
argsType += "?"
|
||||
argsFlag = "?"
|
||||
}
|
||||
|
||||
optionsType := "CustomResourceOptions"
|
||||
optionsType := "Pulumi.CustomResourceOptions"
|
||||
if r.IsProvider {
|
||||
optionsType = "ResourceOptions"
|
||||
optionsType = "Pulumi.ResourceOptions"
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "public %s(string name, %s args%s, %s? options = null)\n", name, argsType, argsDefault, optionsType)
|
||||
docLangHelper := dotnet.DocLanguageHelper{}
|
||||
return []ConstructorParam{
|
||||
{
|
||||
Name: "name",
|
||||
Type: PropertyType{
|
||||
Name: "string",
|
||||
Link: "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "args",
|
||||
OptionalFlag: argsFlag,
|
||||
DefaultValue: argsDefault,
|
||||
Type: PropertyType{
|
||||
Name: argsType,
|
||||
Link: docLangHelper.GetDocLinkForResourceType(mod.pkg.Name, "", argLangType.Name),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "opts",
|
||||
OptionalFlag: "?",
|
||||
DefaultValue: " = null",
|
||||
Type: PropertyType{
|
||||
Name: optionsType,
|
||||
Link: docLangHelper.GetDocLinkForResourceType("", "", optionsType),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *modContext) genProperties(w io.Writer, properties []*schema.Property, input bool) {
|
||||
if len(properties) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "<table class=\"ml-6\">\n")
|
||||
fmt.Fprintf(w, " <thead>\n")
|
||||
fmt.Fprintf(w, " <tr>\n")
|
||||
fmt.Fprintf(w, " <th>Argument</th>\n")
|
||||
fmt.Fprintf(w, " <th>Type</th>\n")
|
||||
fmt.Fprintf(w, " <th>Description</th>\n")
|
||||
fmt.Fprintf(w, " </tr>\n")
|
||||
fmt.Fprintf(w, " </thead>\n")
|
||||
fmt.Fprintf(w, " <tbody>\n")
|
||||
|
||||
for _, prop := range properties {
|
||||
var required string
|
||||
if input {
|
||||
required = "(Optional) "
|
||||
if prop.IsRequired {
|
||||
required = "(Required) "
|
||||
}
|
||||
}
|
||||
|
||||
// The comment contains markdown, so we must wrap it in our `{{% md %}}`` shortcode, which enables markdown
|
||||
// to be rendered inside HTML tags (otherwise, Hugo's markdown renderer won't render it as markdown).
|
||||
// Unfortunately, this injects an extra `<p>...</p>` around the rendered markdown content, which adds some margin
|
||||
// to the top and bottom of the content which we don't want. So we inject some styles to remove the margins from
|
||||
// those `p` tags.
|
||||
fmt.Fprintf(w, " <tr>\n")
|
||||
fmt.Fprintf(w, " <td class=\"align-top\">%s</td>\n", wbr(prop.Name))
|
||||
fmt.Fprintf(w, " <td class=\"align-top\"><code>%s</code></td>\n", mod.typeStringPulumi(prop.Type, true))
|
||||
fmt.Fprintf(w, " <td class=\"align-top\">{{%% md %%}}\n%s%s\n{{%% /md %%}}</td>\n", required, prop.Comment)
|
||||
fmt.Fprintf(w, " </tr>\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, " </tbody>\n")
|
||||
fmt.Fprintf(w, "</table>\n\n")
|
||||
}
|
||||
|
||||
func (mod *modContext) genNestedTypes(w io.Writer, properties []*schema.Property, input bool) {
|
||||
func (mod *modContext) genNestedTypes(properties []*schema.Property, input bool) []DocNestedType {
|
||||
tokens := stringSet{}
|
||||
mod.getTypes(properties, tokens)
|
||||
var objs []*schema.ObjectType
|
||||
|
||||
var objs []DocNestedType
|
||||
for token := range tokens {
|
||||
for _, t := range mod.pkg.Types {
|
||||
if obj, ok := t.(*schema.ObjectType); ok && obj.Token == token {
|
||||
objs = append(objs, obj)
|
||||
if len(obj.Properties) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Create maps to hold the per-language properties of this object and links to
|
||||
// the API doc fpr each language.
|
||||
props := make(map[string][]Property)
|
||||
apiDocLinks := make(map[string]string)
|
||||
for _, lang := range supportedLanguages {
|
||||
var docLangHelper codegen.DocLanguageHelper
|
||||
|
||||
inputObjLangType := mod.typeString(t, lang, true /*input*/, true /*optional*/, false /*insertWordBreaks*/)
|
||||
switch lang {
|
||||
case "csharp":
|
||||
docLangHelper = dotnet.DocLanguageHelper{}
|
||||
case "go":
|
||||
docLangHelper = go_gen.DocLanguageHelper{}
|
||||
case "nodejs":
|
||||
docLangHelper = nodejs.DocLanguageHelper{}
|
||||
case "python":
|
||||
docLangHelper = python.DocLanguageHelper{}
|
||||
default:
|
||||
panic(errors.Errorf("cannot generate nested type doc link for unhandled language %q", lang))
|
||||
}
|
||||
apiDocLinks[lang] = docLangHelper.GetDocLinkForInputType(mod.pkg.Name, mod.mod, inputObjLangType.Name)
|
||||
props[lang] = mod.getProperties(obj.Properties, lang, true)
|
||||
}
|
||||
|
||||
objs = append(objs, DocNestedType{
|
||||
Name: tokenToName(obj.Token),
|
||||
APIDocLinks: apiDocLinks,
|
||||
Properties: props,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(objs, func(i, j int) bool {
|
||||
return tokenToName(objs[i].Token) < tokenToName(objs[j].Token)
|
||||
return objs[i].Name < objs[j].Name
|
||||
})
|
||||
for _, obj := range objs {
|
||||
fmt.Fprintf(w, "#### %s\n\n", tokenToName(obj.Token))
|
||||
|
||||
mod.genProperties(w, obj.Properties, input)
|
||||
}
|
||||
return objs
|
||||
}
|
||||
|
||||
func (mod *modContext) genGet(w io.Writer, r *schema.Resource) {
|
||||
name := resourceName(r)
|
||||
|
||||
stateType := name + "State"
|
||||
|
||||
var stateParam string
|
||||
if r.StateInputs != nil {
|
||||
stateParam = fmt.Sprintf("state?: %s, ", stateType)
|
||||
// getProperties returns a slice of properties that can be rendered for docs for
|
||||
// the provided slice of properties in the schema.
|
||||
func (mod *modContext) getProperties(properties []*schema.Property, lang string, isInput bool) []Property {
|
||||
if len(properties) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "{{< langchoose csharp >}}\n\n")
|
||||
|
||||
fmt.Fprintf(w, "```typescript\n")
|
||||
fmt.Fprintf(w, "public static get(name: string, id: pulumi.Input<pulumi.ID>, %sopts?: pulumi.CustomResourceOptions): %s;\n", stateParam, name)
|
||||
fmt.Fprintf(w, "```\n\n")
|
||||
|
||||
// TODO: This is currently hard coded for Bucket. Need to generalize for all resources.
|
||||
fmt.Fprintf(w, "```python\n")
|
||||
fmt.Fprintf(w, "def get(resource_name, id, opts=None, acceleration_status=None, acl=None, arn=None, bucket=None, bucket_domain_name=None, bucket_prefix=None, bucket_regional_domain_name=None, cors_rules=None, force_destroy=None, hosted_zone_id=None, lifecycle_rules=None, loggings=None, object_lock_configuration=None, policy=None, region=None, replication_configuration=None, request_payer=None, server_side_encryption_configuration=None, tags=None, versioning=None, website=None, website_domain=None, website_endpoint=None)\n")
|
||||
fmt.Fprintf(w, "```\n\n")
|
||||
|
||||
// TODO: This is currently hard coded for Bucket. Need to generalize for all resources.
|
||||
fmt.Fprintf(w, "```go\n")
|
||||
fmt.Fprintf(w, "func GetBucket(ctx *pulumi.Context, name string, id pulumi.IDInput, state *BucketState, opts ...pulumi.ResourceOption) (*Bucket, error)\n")
|
||||
fmt.Fprintf(w, "```\n\n")
|
||||
|
||||
// TODO: This is currently hard coded for Bucket. Need to generalize for all resources.
|
||||
fmt.Fprintf(w, "```csharp\n")
|
||||
fmt.Fprintf(w, "public static Bucket Get(string name, Input<string> id, BucketState? state = null, CustomResourceOptions? options = null);\n")
|
||||
fmt.Fprintf(w, "```\n\n")
|
||||
|
||||
fmt.Fprintf(w, "Get an existing %s resource's state with the given name, ID, and optional extra\n", name)
|
||||
fmt.Fprintf(w, "properties used to qualify the lookup.\n\n")
|
||||
|
||||
for _, lang := range []string{"nodejs", "go", "csharp"} {
|
||||
fmt.Fprintf(w, "{{%% lang %s %%}}\n", lang)
|
||||
fmt.Fprintf(w, "<ul class=\"pl-10\">\n")
|
||||
fmt.Fprintf(w, " <li><strong>name</strong> – (Required) The unique name of the resulting resource.</li>\n")
|
||||
fmt.Fprintf(w, " <li><strong>id</strong> – (Required) The _unique_ provider ID of the resource to lookup.</li>\n")
|
||||
if stateParam != "" {
|
||||
fmt.Fprintf(w, " <li><strong>state</strong> – (Optional) Any extra arguments used during the lookup.</li>\n")
|
||||
docProperties := make([]Property, 0, len(properties))
|
||||
for _, prop := range properties {
|
||||
if prop == nil {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, " <li><strong>opts</strong> – (Optional) A bag of options that control this resource's behavior.</li>\n")
|
||||
fmt.Fprintf(w, "</ul>\n")
|
||||
fmt.Fprintf(w, "{{%% /lang %%}}\n\n")
|
||||
docProperties = append(docProperties, Property{
|
||||
Name: getLanguagePropertyName(prop.Name, lang, true),
|
||||
Comment: prop.Comment,
|
||||
DeprecationMessage: prop.DeprecationMessage,
|
||||
IsRequired: prop.IsRequired,
|
||||
IsInput: isInput,
|
||||
Type: mod.typeString(prop.Type, lang, isInput, !prop.IsRequired, true),
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: Unlike the other languages, Python does not have a separate state object. The state args are all just
|
||||
// named parameters of the get function. Consider injecting `resource_name`, `id`, and `opts` as the first three
|
||||
// items in the table of state input properties.
|
||||
|
||||
if r.StateInputs != nil {
|
||||
fmt.Fprintf(w, "The following state arguments are supported:\n\n")
|
||||
|
||||
mod.genProperties(w, r.StateInputs.Properties, true)
|
||||
}
|
||||
return docProperties
|
||||
}
|
||||
|
||||
func (mod *modContext) genResource(w io.Writer, r *schema.Resource) {
|
||||
func (mod *modContext) genConstructors(r *schema.Resource, allOptionalInputs bool) map[string]string {
|
||||
constructorParams := make(map[string]string)
|
||||
for _, lang := range supportedLanguages {
|
||||
var (
|
||||
paramTemplate string
|
||||
params []ConstructorParam
|
||||
)
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
switch lang {
|
||||
case "nodejs":
|
||||
params = mod.genConstructorTS(r, allOptionalInputs)
|
||||
paramTemplate = "ts_constructor_param"
|
||||
case "go":
|
||||
params = mod.genConstructorGo(r, allOptionalInputs)
|
||||
paramTemplate = "go_constructor_param"
|
||||
case "csharp":
|
||||
params = mod.genConstructorCS(r, allOptionalInputs)
|
||||
paramTemplate = "csharp_constructor_param"
|
||||
}
|
||||
|
||||
n := len(params)
|
||||
for i, p := range params {
|
||||
if err := templates.ExecuteTemplate(b, paramTemplate, p); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if i != n-1 {
|
||||
if err := templates.ExecuteTemplate(b, "param_separator", nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
constructorParams[lang] = b.String()
|
||||
}
|
||||
return constructorParams
|
||||
}
|
||||
|
||||
// getConstructorResourceInfo returns a map of per-language information about
|
||||
// the resource being constructed.
|
||||
func (mod *modContext) getConstructorResourceInfo(resourceTypeName string) map[string]PropertyType {
|
||||
resourceMap := make(map[string]PropertyType)
|
||||
resourceDisplayName := resourceTypeName
|
||||
|
||||
for _, lang := range supportedLanguages {
|
||||
// Reset the type name back to the display name.
|
||||
resourceTypeName = resourceDisplayName
|
||||
|
||||
var docLangHelper codegen.DocLanguageHelper
|
||||
switch lang {
|
||||
case "nodejs":
|
||||
docLangHelper = nodejs.DocLanguageHelper{}
|
||||
case "go":
|
||||
docLangHelper = go_gen.DocLanguageHelper{}
|
||||
case "csharp":
|
||||
docLangHelper = dotnet.DocLanguageHelper{}
|
||||
resourceTypeName = fmt.Sprintf("Pulumi.%s.%s.%s", strings.Title(mod.pkg.Name), strings.Title(mod.mod), resourceTypeName)
|
||||
case "python":
|
||||
// Pulumi's Python language SDK does not have "types" yet, so we will skip it for now.
|
||||
continue
|
||||
default:
|
||||
panic(errors.Errorf("cannot generate constructor info for unhandled language %q", lang))
|
||||
}
|
||||
|
||||
resourceMap[lang] = PropertyType{
|
||||
Name: resourceDisplayName,
|
||||
Link: docLangHelper.GetDocLinkForResourceType(mod.pkg.Name, mod.mod, resourceTypeName),
|
||||
}
|
||||
}
|
||||
|
||||
return resourceMap
|
||||
}
|
||||
|
||||
// genResource is the entrypoint for generating a doc for a resource
|
||||
// from its Pulumi schema.
|
||||
func (mod *modContext) genResource(r *schema.Resource) resourceArgs {
|
||||
// Create a resource module file into which all of this resource's types will go.
|
||||
name := resourceName(r)
|
||||
|
||||
fmt.Fprintf(w, "%s\n\n", r.Comment)
|
||||
|
||||
// TODO: Remove this - it's just temporary to include some data we don't have available yet.
|
||||
mod.genMockupExamples(w, r)
|
||||
|
||||
fmt.Fprintf(w, "## Create a %s Resource\n\n", name)
|
||||
|
||||
// TODO: In the examples on the page, we only want to show TypeScript and Python tabs for now, as initially
|
||||
// we'll only have examples in those languages.
|
||||
// However, lower on the page, we will be showing declarations and types in all of the supported languages.
|
||||
// The default behavior of the lang chooser is to switch all lang tabs on the page when a tab is selected.
|
||||
// This means, if Go is selected lower in the page, then the chooser tabs for the examples will try to show
|
||||
// Go content, which won't be present. We should fix this somehow such that selecting Go lower in the page
|
||||
// doesn't cause the example tabs to change. But if Python is selected, the example tabs should change since
|
||||
// Python is available there.
|
||||
fmt.Fprintf(w, "{{< langchoose csharp >}}\n\n")
|
||||
|
||||
fmt.Fprintf(w, "<div class=\"highlight\"><pre class=\"chroma\"><code class=\"language-typescript\" data-lang=\"typescript\">")
|
||||
mod.genConstructorTS(w, r)
|
||||
fmt.Fprintf(w, "</code></pre></div>\n\n")
|
||||
|
||||
fmt.Fprintf(w, "```python\n")
|
||||
mod.genConstructorPython(w, r)
|
||||
fmt.Fprintf(w, "\n```\n\n")
|
||||
|
||||
fmt.Fprintf(w, "```go\n")
|
||||
mod.genConstructorGo(w, r)
|
||||
fmt.Fprintf(w, "\n```\n\n")
|
||||
|
||||
fmt.Fprintf(w, "```csharp\n")
|
||||
mod.genConstructorCS(w, r)
|
||||
fmt.Fprintf(w, "\n```\n\n")
|
||||
|
||||
fmt.Fprintf(w, "Creates a %s resource with the given unique name, arguments, and options.\n\n", name)
|
||||
// TODO: Unlike the other languages, Python does not have a separate Args object for inputs.
|
||||
// The args are all just named parameters of the constructor. Consider injecting
|
||||
// `resource_name` and `opts` as the first two items in the table of properties.
|
||||
inputProps := make(map[string][]Property)
|
||||
outputProps := make(map[string][]Property)
|
||||
stateInputs := make(map[string][]Property)
|
||||
for _, lang := range supportedLanguages {
|
||||
inputProps[lang] = mod.getProperties(r.InputProperties, lang, true)
|
||||
if r.IsProvider {
|
||||
continue
|
||||
}
|
||||
outputProps[lang] = mod.getProperties(r.Properties, lang, false)
|
||||
if r.StateInputs != nil {
|
||||
stateInputs[lang] = mod.getProperties(r.StateInputs.Properties, lang, true)
|
||||
}
|
||||
}
|
||||
|
||||
allOptionalInputs := true
|
||||
for _, prop := range r.InputProperties {
|
||||
allOptionalInputs = allOptionalInputs && !prop.IsRequired
|
||||
// If at least one prop is required, then break.
|
||||
if prop.IsRequired {
|
||||
allOptionalInputs = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
argsRequired := "Required"
|
||||
if allOptionalInputs {
|
||||
argsRequired = "Optional"
|
||||
data := resourceArgs{
|
||||
Header: Header{
|
||||
Title: name,
|
||||
},
|
||||
|
||||
Comment: r.Comment,
|
||||
// TODO: This is just temporary to include some data we don't have available yet.
|
||||
Examples: mod.getMockupExamples(r),
|
||||
|
||||
ConstructorParams: mod.genConstructors(r, allOptionalInputs),
|
||||
ConstructorResource: mod.getConstructorResourceInfo(name),
|
||||
ArgsRequired: !allOptionalInputs,
|
||||
|
||||
InputProperties: inputProps,
|
||||
OutputProperties: outputProps,
|
||||
StateInputs: stateInputs,
|
||||
StateParam: name + "State",
|
||||
NestedTypes: mod.genNestedTypes(r.InputProperties, true),
|
||||
}
|
||||
|
||||
for _, lang := range []string{"nodejs", "go", "csharp"} {
|
||||
fmt.Fprintf(w, "{{%% lang %s %%}}\n", lang)
|
||||
fmt.Fprintf(w, "<ul class=\"pl-10\">\n")
|
||||
fmt.Fprintf(w, " <li><strong>name</strong> – (Required) The unique name of the resulting resource.</li>\n")
|
||||
fmt.Fprintf(w, " <li><strong>args</strong> – (%s) The arguments to use to populate this resource's properties.</li>\n", argsRequired)
|
||||
fmt.Fprintf(w, " <li><strong>opts</strong> – (Optional) A bag of options that control this resource's behavior.</li>\n")
|
||||
fmt.Fprintf(w, "</ul>\n")
|
||||
fmt.Fprintf(w, "{{%% /lang %%}}\n\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "The following arguments are supported:\n\n")
|
||||
|
||||
// TODO: Unlike the other languages, Python does not have a separate Args object. The args are all just
|
||||
// named parameters of the constructor. Consider injecting `resource_name` and `opts` as the first two items
|
||||
// in the table of properties.
|
||||
|
||||
mod.genProperties(w, r.InputProperties, true)
|
||||
|
||||
fmt.Fprintf(w, "## %s Output Properties\n\n", name)
|
||||
|
||||
fmt.Fprintf(w, "The following output properties are available:\n\n")
|
||||
|
||||
mod.genProperties(w, r.Properties, false)
|
||||
|
||||
fmt.Fprintf(w, "## Look up an Existing %s Resource\n\n", name)
|
||||
|
||||
mod.genGet(w, r)
|
||||
|
||||
fmt.Fprintf(w, "## Import an Existing %s Resource\n\n", name)
|
||||
|
||||
// TODO: How do we want to show import? It will take a paragraph or two of explanation plus example, similar
|
||||
// to the content at https://www.pulumi.com/docs/intro/concepts/programming-model/#import
|
||||
fmt.Fprintf(w, "TODO\n\n")
|
||||
|
||||
fmt.Fprintf(w, "## Support Types\n\n")
|
||||
|
||||
mod.genNestedTypes(w, r.InputProperties, true)
|
||||
return data
|
||||
}
|
||||
|
||||
func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) {
|
||||
|
@ -543,12 +657,15 @@ func (mod *modContext) gen(fs fs) error {
|
|||
|
||||
// Resources
|
||||
for _, r := range mod.resources {
|
||||
data := mod.genResource(r)
|
||||
|
||||
title := resourceName(r)
|
||||
buffer := &bytes.Buffer{}
|
||||
mod.genHeader(buffer, resourceName(r))
|
||||
|
||||
mod.genResource(buffer, r)
|
||||
|
||||
addFile(lower(resourceName(r))+".md", buffer.String())
|
||||
err := templates.ExecuteTemplate(buffer, "resource.tmpl", data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
addFile(lower(title)+".md", buffer.String())
|
||||
}
|
||||
|
||||
// Functions
|
||||
|
@ -636,7 +753,23 @@ func (mod *modContext) genIndex(exports []string) string {
|
|||
return w.String()
|
||||
}
|
||||
|
||||
// GeneratePackage generates the docs package with docs for each resource given the Pulumi
|
||||
// schema.
|
||||
func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error) {
|
||||
templates = template.New("").Funcs(template.FuncMap{
|
||||
"htmlSafe": func(html string) template.HTML {
|
||||
// Markdown fragments in the templates need to be rendered as-is,
|
||||
// so that html/template package doesn't try to inject data into it,
|
||||
// which will most certainly fail.
|
||||
// nolint gosec
|
||||
return template.HTML(html)
|
||||
},
|
||||
})
|
||||
|
||||
for name, b := range packagedTemplates {
|
||||
template.Must(templates.New(name).Parse(string(b)))
|
||||
}
|
||||
|
||||
// group resources, types, and functions into modules
|
||||
modules := map[string]*modContext{}
|
||||
|
||||
|
@ -723,18 +856,13 @@ func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error
|
|||
}
|
||||
|
||||
// TODO: Remove this when we have real examples available.
|
||||
func (mod *modContext) genMockupExamples(w io.Writer, r *schema.Resource) {
|
||||
func (mod *modContext) getMockupExamples(r *schema.Resource) []exampleUsage {
|
||||
|
||||
if resourceName(r) != "Bucket" {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "## Example Usage\n\n")
|
||||
|
||||
examples := []struct {
|
||||
Heading string
|
||||
Code string
|
||||
}{
|
||||
examples := []exampleUsage{
|
||||
{
|
||||
Heading: "Private Bucket w/ Tags",
|
||||
Code: `import * as pulumi from "@pulumi/pulumi";
|
||||
|
@ -1003,15 +1131,5 @@ const mybucket = new aws.s3.Bucket("mybucket", {
|
|||
},
|
||||
}
|
||||
|
||||
for _, example := range examples {
|
||||
fmt.Fprintf(w, "### %s\n\n", example.Heading)
|
||||
|
||||
fmt.Fprintf(w, "{{< langchoose nojavascript nogo >}}\n\n")
|
||||
|
||||
fmt.Fprintf(w, "```typescript\n")
|
||||
fmt.Fprintf(w, example.Code)
|
||||
fmt.Fprintf(w, "```\n\n")
|
||||
|
||||
fmt.Fprintf(w, "```python\nComing soon\n```\n\n")
|
||||
}
|
||||
return examples
|
||||
}
|
||||
|
|
7
pkg/codegen/docs/templates/constructor_args.tmpl
vendored
Normal file
7
pkg/codegen/docs/templates/constructor_args.tmpl
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{{ define "constructor_args" }}
|
||||
<ul class="pl-10">
|
||||
<li><strong>name</strong> – (Required) The unique name of the resulting resource.</li>
|
||||
<li><strong>args</strong> – {{ if . }} (Required) {{ else }} (Optional) {{ end }} The arguments to use to populate this resource's properties.</li>
|
||||
<li><strong>opts</strong> – (Optional) A bag of options that control this resource's behavior.</li>
|
||||
</ul>
|
||||
{{ end }}
|
9
pkg/codegen/docs/templates/constructor_params.tmpl
vendored
Normal file
9
pkg/codegen/docs/templates/constructor_params.tmpl
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{{ define "param_separator" }}<span class="p">, </span>{{ end }}
|
||||
|
||||
{{ define "go_constructor_param" }}<span class="nx">{{ .Name }}</span> {{ .OptionalFlag }}{{ template "linkify_param" .Type }}{{ end }}
|
||||
|
||||
{{ define "ts_constructor_param" }}<span class="nx">{{ .Name }}</span>{{ .OptionalFlag }}: {{ template "linkify_param" .Type }}{{ end }}
|
||||
|
||||
{{ define "csharp_constructor_param" }}{{ template "linkify_param" .Type }}{{ .OptionalFlag }} <span class="nx">{{ .Name }}{{ .DefaultValue }}{{ end }}
|
||||
|
||||
{{ define "py_param" }}{{ range . }}, {{ htmlSafe .Name }}=None{{ end }}{{ end }}
|
25
pkg/codegen/docs/templates/examples.tmpl
vendored
Normal file
25
pkg/codegen/docs/templates/examples.tmpl
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
{{ define "examples" }}
|
||||
## Example Usage
|
||||
|
||||
{{ range . }}
|
||||
### {{ .Heading }}
|
||||
|
||||
{{ htmlSafe "{{< langchoose nojavascript >}}" }}
|
||||
|
||||
```typescript
|
||||
{{ htmlSafe .Code }}
|
||||
```
|
||||
|
||||
```csharp
|
||||
Coming soon!
|
||||
```
|
||||
|
||||
```go
|
||||
Coming soon!
|
||||
```
|
||||
|
||||
```python
|
||||
Coming soon!
|
||||
```
|
||||
{{ end }}
|
||||
{{ end }}
|
8
pkg/codegen/docs/templates/header.tmpl
vendored
Normal file
8
pkg/codegen/docs/templates/header.tmpl
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{{ define "header" }}
|
||||
---
|
||||
title: "{{ .Title }}"
|
||||
---
|
||||
<style>
|
||||
table td p { margin-top: 0; margin-bottom: 0; }
|
||||
</style>
|
||||
{{ end }}
|
49
pkg/codegen/docs/templates/properties.tmpl
vendored
Normal file
49
pkg/codegen/docs/templates/properties.tmpl
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
{{ define "propIsRequired" }}
|
||||
{{ if . }} (Required) {{- else }} (Optional){{- end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "properties_table" }}
|
||||
<table class="ml-6">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Argument</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range . }}
|
||||
<tr>
|
||||
<td class="align-top">{{ htmlSafe .Name }}</td>
|
||||
<td class="align-top">
|
||||
{{ if eq .Type.Link "#" "" }}
|
||||
<code>{{ htmlSafe .Type.Name }}</code>
|
||||
{{- else }}
|
||||
<code>{{ template "linkify" .Type }}</code>
|
||||
{{- end }}
|
||||
</td>
|
||||
<td class="align-top">
|
||||
{{- htmlSafe "{{% md %}}" }} {{ if .IsInput }}{{ template "propIsRequired" .IsRequired }}{{- end }} {{- .Comment }} {{ htmlSafe "{{% /md %}}" }}
|
||||
|
||||
{{ .DeprecationMessage }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ end }}
|
||||
|
||||
{{ define "properties" }}
|
||||
|
||||
{{ htmlSafe "{{< langchoose csharp nojavascript >}}" }}
|
||||
|
||||
{{ range $lang, $props := . }}
|
||||
{{ print "{{% lang" }} {{ print $lang }} {{ print "%}}" }}
|
||||
|
||||
{{ template "properties_table" $props }}
|
||||
|
||||
{{ print "{{% /lang %}}" }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
8
pkg/codegen/docs/templates/read_inputs.tmpl
vendored
Normal file
8
pkg/codegen/docs/templates/read_inputs.tmpl
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{{ define "read_inputs" }}
|
||||
<ul class="pl-10">
|
||||
<li><strong>name</strong> – (Required) The unique name of the resulting resource.</li>
|
||||
<li><strong>id</strong> – (Required) The _unique_ provider ID of the resource to lookup.</li>
|
||||
<li><strong>state</strong> – (Optional) Any extra arguments used during the lookup.</li>
|
||||
<li><strong>opts</strong> – (Optional) A bag of options that control this resource's behavior.</li>
|
||||
</ul>
|
||||
{{ end }}
|
110
pkg/codegen/docs/templates/resource.tmpl
vendored
Normal file
110
pkg/codegen/docs/templates/resource.tmpl
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
{{ template "header" .Header }}
|
||||
|
||||
{{ htmlSafe .Comment }}
|
||||
|
||||
<!-- Examples -->
|
||||
{{ if ne (len .Examples) 0 }}{{ template "examples" .Examples }}{{ end }}
|
||||
|
||||
<!-- Create resource -->
|
||||
## Create a {{ .Header.Title }} Resource
|
||||
|
||||
{{ htmlSafe "{{< langchoose csharp nojavascript >}}" }}
|
||||
|
||||
<div class="highlight"><pre class="chroma"><code class="language-typescript" data-lang="typescript"><span class="k">new </span>{{ template "linkify_param" .ConstructorResource.nodejs }}<span class="p">(</span>{{ htmlSafe .ConstructorParams.nodejs }}<span class="p">);</span></code></pre></div>
|
||||
|
||||
```python
|
||||
def {{ .Header.Title}}(resource_name, id, opts=None{{ template "py_param" .InputProperties.python }}, __props__=None)
|
||||
```
|
||||
|
||||
<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="k">func </span>New{{ .Header.Title }}<span class="p">(</span>{{ htmlSafe .ConstructorParams.go }}<span class="p">) (*{{ template "linkify_param" .ConstructorResource.go }}, error)</span></code></pre></div>
|
||||
|
||||
<div class="highlight"><pre class="chroma"><code class="language-csharp" data-lang="csharp"><span class="k">public </span>{{ template "linkify_param" .ConstructorResource.csharp }}<span class="p">(</span>{{ htmlSafe .ConstructorParams.csharp }}<span class="p">)</span></code></pre></div>
|
||||
|
||||
Creates a {{ .Header.Title }} resource with the given unique name, arguments, and options.
|
||||
|
||||
{{ htmlSafe "{{% lang nodejs %}}" }}
|
||||
{{ template "constructor_args" }}
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
{{ htmlSafe "{{% lang go %}}" }}
|
||||
{{ template "constructor_args" }}
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
{{ htmlSafe "{{% lang csharp %}}" }}
|
||||
{{ template "constructor_args" }}
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
The following arguments are supported:
|
||||
{{ template "properties" .InputProperties }}
|
||||
|
||||
<!-- Output properties -->
|
||||
{{ if ne (len .OutputProperties) 0 }}
|
||||
## {{.Header.Title}} Output Properties
|
||||
|
||||
The following output properties are available:
|
||||
|
||||
{{ template "properties" .OutputProperties }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Read resource -->
|
||||
{{ if ne (len .StateInputs) 0 }}
|
||||
## Look up an Existing {{.Header.Title}} Resource
|
||||
|
||||
{{ htmlSafe "{{< langchoose csharp nojavascript >}}" }}
|
||||
|
||||
```typescript
|
||||
public static get(name: string, id: pulumi.Input<pulumi.ID>, state?: {{ .StateParam }}, opts?: pulumi.CustomResourceOptions): {{ .Header.Title }};
|
||||
```
|
||||
|
||||
```python
|
||||
def get(resource_name, id, opts=None{{ template "py_param" .StateInputs.python }})
|
||||
```
|
||||
|
||||
```go
|
||||
func Get{{.Header.Title}}(ctx *pulumi.Context, name string, id pulumi.IDInput, state *{{ .StateParam }}, opts ...pulumi.ResourceOption) (*Bucket, error)
|
||||
```
|
||||
|
||||
```csharp
|
||||
public static {{ .Header.Title }} Get(string name, Input<string> id, {{ .StateParam }}? state = null, CustomResourceOptions? options = null);
|
||||
```
|
||||
|
||||
Get an existing {{.Header.Title}} resource's state with the given name, ID, and optional extra properties used to qualify the lookup.
|
||||
|
||||
{{ htmlSafe "{{% lang nodejs %}}" }}
|
||||
{{ template "read_inputs" }}
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
{{ htmlSafe "{{% lang go %}}" }}
|
||||
{{ template "read_inputs" }}
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
{{ htmlSafe "{{% lang csharp %}}" }}
|
||||
{{ template "read_inputs" }}
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
The following state arguments are supported:
|
||||
{{ template "properties" .StateInputs }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
<!-- Supporting types -->
|
||||
{{ if ne (len .NestedTypes) 0 }}
|
||||
## Supporting Types
|
||||
{{ range .NestedTypes }}
|
||||
#### {{ .Name }}
|
||||
{{ htmlSafe "{{% lang nodejs %}}" }}
|
||||
> See the <a href="{{ .APIDocLinks.nodejs }}">input</a> API doc.
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
{{ htmlSafe "{{% lang go %}}" }}
|
||||
> See the <a href="{{ .APIDocLinks.go }}">input</a> API doc.
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
{{ htmlSafe "{{% lang csharp %}}" }}
|
||||
> See the <a href="{{ .APIDocLinks.csharp }}">input</a> API doc.
|
||||
{{ htmlSafe "{{% /lang %}}" }}
|
||||
|
||||
{{ template "properties" .Properties }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
3
pkg/codegen/docs/templates/utils.tmpl
vendored
Normal file
3
pkg/codegen/docs/templates/utils.tmpl
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{{ define "linkify_param" }}<span class="nx"><a href="{{ .Link }}">{{ .Name }}</a></span>{{ end }}
|
||||
|
||||
{{ define "linkify" }}<a href="{{ .Link }}">{{ htmlSafe .Name }}</a>{{ end }}
|
82
pkg/codegen/docs/utils.go
Normal file
82
pkg/codegen/docs/utils.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Pulling out some of the repeated strings tokens into constants would harm readability, so we just ignore the
|
||||
// goconst linter's warning.
|
||||
//
|
||||
// nolint: lll, goconst
|
||||
package docs
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/codegen/python"
|
||||
"github.com/pulumi/pulumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
func isDotNetTypeNameBoundary(prev rune, next rune) bool {
|
||||
// For C# type names, which are PascalCase are qualified using "." as the separator.
|
||||
return prev == rune('.') && unicode.IsUpper(next)
|
||||
}
|
||||
|
||||
func isPythonTypeNameBoundary(prev rune, next rune) bool {
|
||||
// For Python, names are snake_cased (Duh?).
|
||||
return (prev == rune('_') && unicode.IsLower(next))
|
||||
}
|
||||
|
||||
// wbr inserts HTML <wbr> in between case changes, e.g. "fooBar" becomes "foo<wbr>Bar".
|
||||
func wbr(s string) string {
|
||||
var runes []rune
|
||||
var prev rune
|
||||
for i, r := range s {
|
||||
if i != 0 &&
|
||||
// For TS, JS and Go, property names are camelCase and types are PascalCase.
|
||||
((unicode.IsLower(prev) && unicode.IsUpper(r)) ||
|
||||
isDotNetTypeNameBoundary(prev, r) ||
|
||||
isPythonTypeNameBoundary(prev, r)) {
|
||||
runes = append(runes, []rune("<wbr>")...)
|
||||
}
|
||||
runes = append(runes, r)
|
||||
prev = r
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func lower(s string) string {
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
|
||||
// tokenToName returns the resource name from a Pulumi token.
|
||||
func tokenToName(tok string) string {
|
||||
components := strings.Split(tok, ":")
|
||||
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
||||
return strings.Title(components[2])
|
||||
}
|
||||
|
||||
// getLanguagePropertyName returns a language-specific representation of a given
|
||||
// property name.
|
||||
func getLanguagePropertyName(name string, lang string, insertWordBreak bool) string {
|
||||
switch lang {
|
||||
case "python":
|
||||
name = python.PyName(name)
|
||||
case "go", "csharp":
|
||||
name = strings.Title(name)
|
||||
}
|
||||
|
||||
if !insertWordBreak {
|
||||
return name
|
||||
}
|
||||
return wbr(name)
|
||||
}
|
54
pkg/codegen/dotnet/doc.go
Normal file
54
pkg/codegen/dotnet/doc.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// nolint: lll
|
||||
package dotnet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/codegen"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/schema"
|
||||
)
|
||||
|
||||
// DocLanguageHelper is the DotNet-specific implementation of the DocLanguageHelper.
|
||||
type DocLanguageHelper struct{}
|
||||
|
||||
var _ codegen.DocLanguageHelper = DocLanguageHelper{}
|
||||
|
||||
// GetDocLinkForResourceType returns the .NET API doc URL for a type belonging to a resource provider.
|
||||
func (d DocLanguageHelper) GetDocLinkForResourceType(packageName, _, typeName string) string {
|
||||
typeName = strings.ReplaceAll(typeName, "?", "")
|
||||
var packageNamespace string
|
||||
if packageName != "" {
|
||||
packageNamespace = "." + title(packageName)
|
||||
}
|
||||
return fmt.Sprintf("/docs/reference/pkg/dotnet/Pulumi%s/%s.html", packageNamespace, typeName)
|
||||
}
|
||||
|
||||
// GetDocLinkForInputType is not implemented at this time for Python.
|
||||
func (d DocLanguageHelper) GetDocLinkForInputType(packageName, moduleName, typeName string) string {
|
||||
return d.GetDocLinkForResourceType(packageName, moduleName, typeName)
|
||||
}
|
||||
|
||||
// GetLanguageTypeString returns the DotNet-specific type given a Pulumi schema type.
|
||||
func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string {
|
||||
typeDetails := map[*schema.ObjectType]*typeDetails{}
|
||||
mod := &modContext{
|
||||
pkg: pkg,
|
||||
typeDetails: typeDetails,
|
||||
}
|
||||
return mod.typeString(t, "", input, false /*state*/, false /*wrapInput*/, true /*requireInitializers*/, optional)
|
||||
}
|
59
pkg/codegen/go/doc.go
Normal file
59
pkg/codegen/go/doc.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Pulling out some of the repeated strings tokens into constants would harm readability, so we just ignore the
|
||||
// goconst linter's warning.
|
||||
//
|
||||
// nolint: lll, goconst
|
||||
package gen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/codegen"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/schema"
|
||||
)
|
||||
|
||||
// DocLanguageHelper is the Go-specific implementation of the DocLanguageHelper.
|
||||
type DocLanguageHelper struct{}
|
||||
|
||||
var _ codegen.DocLanguageHelper = DocLanguageHelper{}
|
||||
|
||||
// GetDocLinkForResourceType returns the godoc URL for a type belonging to a resource provider.
|
||||
func (d DocLanguageHelper) GetDocLinkForResourceType(packageName string, moduleName string, typeName string) string {
|
||||
path := fmt.Sprintf("%s/%s", packageName, moduleName)
|
||||
typeNameParts := strings.Split(typeName, ".")
|
||||
typeName = typeNameParts[len(typeNameParts)-1]
|
||||
return fmt.Sprintf("https://pkg.go.dev/github.com/pulumi/pulumi-%s/sdk/go/%s?tab=doc#%s", packageName, path, typeName)
|
||||
}
|
||||
|
||||
// GetDocLinkForInputType returns the godoc URL for an input type.
|
||||
func (d DocLanguageHelper) GetDocLinkForInputType(packageName, moduleName, typeName string) string {
|
||||
name := d.GetDocLinkForResourceType(packageName, moduleName, typeName)
|
||||
return name + "Args"
|
||||
}
|
||||
|
||||
// GetDocLinkForBuiltInType returns the godoc URL for a built-in type.
|
||||
func GetDocLinkForBuiltInType(typeName string) string {
|
||||
return fmt.Sprintf("https://golang.org/pkg/builtin/#%s", typeName)
|
||||
}
|
||||
|
||||
// GetLanguageTypeString returns the Go-specific type given a Pulumi schema type.
|
||||
func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string {
|
||||
mod := &pkgContext{
|
||||
pkg: pkg,
|
||||
}
|
||||
return mod.plainType(t, optional)
|
||||
}
|
73
pkg/codegen/nodejs/doc.go
Normal file
73
pkg/codegen/nodejs/doc.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2016-2020, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Pulling out some of the repeated strings tokens into constants would harm readability, so we just ignore the
|
||||
// goconst linter's warning.
|
||||
//
|
||||
// nolint: lll, goconst
|
||||
package nodejs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/codegen"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/schema"
|
||||
)
|
||||
|
||||
// DocLanguageHelper is the NodeJS-specific implementation of the DocLanguageHelper.
|
||||
type DocLanguageHelper struct{}
|
||||
|
||||
var _ codegen.DocLanguageHelper = DocLanguageHelper{}
|
||||
|
||||
// GetDocLinkForResourceType returns the NodeJS API doc for a type belonging to a resource provider.
|
||||
func (d DocLanguageHelper) GetDocLinkForResourceType(packageName, modName, typeName string) string {
|
||||
path := fmt.Sprintf("%s/%s", packageName, modName)
|
||||
typeName = strings.ReplaceAll(typeName, "?", "")
|
||||
return fmt.Sprintf("/docs/reference/pkg/nodejs/pulumi/%s/#%s", path, typeName)
|
||||
}
|
||||
|
||||
// GetDocLinkForInputType returns the doc link for an input type.
|
||||
func (d DocLanguageHelper) GetDocLinkForInputType(packageName, modName, typeName string) string {
|
||||
typeName = strings.ReplaceAll(typeName, "?", "")
|
||||
return fmt.Sprintf("/docs/reference/pkg/nodejs/pulumi/%s/types/input/#%s", packageName, typeName)
|
||||
}
|
||||
|
||||
// GetDocLinkForBuiltInType returns the URL for a built-in type.
|
||||
func GetDocLinkForBuiltInType(typeName string) string {
|
||||
return fmt.Sprintf("https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/%s", typeName)
|
||||
}
|
||||
|
||||
// GetLanguageTypeString returns the language-specific type given a Pulumi schema type.
|
||||
func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string {
|
||||
modCtx := &modContext{
|
||||
pkg: pkg,
|
||||
mod: moduleName,
|
||||
}
|
||||
typeName := modCtx.typeString(t, input, false, optional)
|
||||
|
||||
// Remove any package qualifiers from the type name.
|
||||
typeQualifierPackage := "inputs"
|
||||
if !input {
|
||||
typeQualifierPackage = "outputs"
|
||||
}
|
||||
typeName = strings.ReplaceAll(typeName, typeQualifierPackage+".", "")
|
||||
|
||||
// Remove the union with `undefined` for optional types,
|
||||
// since we will show that information separately anyway.
|
||||
if optional {
|
||||
typeName = strings.ReplaceAll(typeName, " | undefined", "?")
|
||||
}
|
||||
return typeName
|
||||
}
|
91
pkg/codegen/python/doc.go
Normal file
91
pkg/codegen/python/doc.go
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2016-2018, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Pulling out some of the repeated strings tokens into constants would harm readability,
|
||||
// so we just ignore the goconst linter's warning.
|
||||
//
|
||||
// nolint: lll, goconst
|
||||
package python
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/codegen"
|
||||
"github.com/pulumi/pulumi/pkg/codegen/schema"
|
||||
)
|
||||
|
||||
// DocLanguageHelper is the Python-specific implementation of the DocLanguageHelper.
|
||||
type DocLanguageHelper struct{}
|
||||
|
||||
var _ codegen.DocLanguageHelper = DocLanguageHelper{}
|
||||
|
||||
// GetDocLinkForResourceType is not implemented at this time for Python.
|
||||
func (d DocLanguageHelper) GetDocLinkForResourceType(packageName, modName, typeName string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetDocLinkForInputType is not implemented at this time for Python.
|
||||
func (d DocLanguageHelper) GetDocLinkForInputType(packageName, modName, typeName string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetLanguageTypeString returns the Python-specific type given a Pulumi schema type.
|
||||
func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string {
|
||||
name := pyType(t)
|
||||
|
||||
// The Python language generator will simply return
|
||||
// "list" or "dict" for certain enumerables. Once the generator
|
||||
// is updated with "types", the following code block ideally
|
||||
// wouldn't run anymore.
|
||||
switch name {
|
||||
case "list":
|
||||
arrTy := t.(*schema.ArrayType)
|
||||
elType := arrTy.ElementType.String()
|
||||
return getListWithTypeName(elementTypeToName(elType))
|
||||
case "dict":
|
||||
switch dictionaryTy := t.(type) {
|
||||
case *schema.MapType:
|
||||
elType := dictionaryTy.ElementType.String()
|
||||
return getDictWithTypeName(elementTypeToName(elType))
|
||||
case *schema.ObjectType:
|
||||
return getDictWithTypeName(tokenToName(dictionaryTy.Token))
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// elementTypeToName returns the type name from an element type of the form
|
||||
// package:module:_type, with its leading "_" stripped.
|
||||
func elementTypeToName(el string) string {
|
||||
parts := strings.Split(el, ":")
|
||||
if len(parts) == 3 {
|
||||
el = parts[2]
|
||||
}
|
||||
el = strings.TrimPrefix(el, "_")
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
// getListWithTypeName returns a Python representation of a list containing
|
||||
// items of `t`.
|
||||
func getListWithTypeName(t string) string {
|
||||
return fmt.Sprintf("list[%s]", PyName(t))
|
||||
}
|
||||
|
||||
// getDictWithTypeName returns the Python representation of a dictionary
|
||||
// where each item is of type `t`.
|
||||
func getDictWithTypeName(t string) string {
|
||||
return fmt.Sprintf("dict{%s}", PyName(t))
|
||||
}
|
Loading…
Reference in a new issue