github.com/oam-dev/kubevela@v1.9.11/references/docgen/provider.go (about)

     1  /*
     2   Copyright 2023 The KubeVela Authors.
     3  
     4   Licensed under the Apache License, Version 2.0 (the "License");
     5   you may not use this file except in compliance with the License.
     6   You may obtain a copy of the License at
     7  
     8   	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10   Unless required by applicable law or agreed to in writing, software
    11   distributed under the License is distributed on an "AS IS" BASIS,
    12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   See the License for the specific language governing permissions and
    14   limitations under the License.
    15  */
    16  
    17  package docgen
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"io"
    24  	"strings"
    25  	"sync"
    26  
    27  	"cuelang.org/go/cue"
    28  	"cuelang.org/go/cue/cuecontext"
    29  	"golang.org/x/sync/errgroup"
    30  )
    31  
    32  // GenerateProvidersMarkdown generates markdown documentation for providers.
    33  func GenerateProvidersMarkdown(ctx context.Context, providers []io.Reader, w io.Writer) error {
    34  	docs := make([]string, len(providers))
    35  	mu := &sync.Mutex{}
    36  	wg, _ := errgroup.WithContext(ctx)
    37  
    38  	for i, provider := range providers {
    39  		i, provider := i, provider
    40  		wg.Go(func() error {
    41  			doc := bytes.NewBuffer(nil)
    42  
    43  			if err := GenerateProviderMarkdown(provider, doc); err != nil {
    44  				return err
    45  			}
    46  
    47  			mu.Lock()
    48  			docs[i] = doc.String() // stable order
    49  			mu.Unlock()
    50  
    51  			return nil
    52  		})
    53  	}
    54  
    55  	if err := wg.Wait(); err != nil {
    56  		return err
    57  	}
    58  
    59  	_, err := w.Write([]byte(strings.Join(docs, "\n")))
    60  	return err
    61  }
    62  
    63  // GenerateProviderMarkdown generates markdown documentation for a provider.
    64  func GenerateProviderMarkdown(provider io.Reader, w io.Writer) error {
    65  	const (
    66  		providerKey = "#provider"
    67  		paramsKey   = "$params"
    68  		returnsKey  = "$returns"
    69  	)
    70  
    71  	c := cuecontext.New()
    72  
    73  	content, err := io.ReadAll(provider)
    74  	if err != nil {
    75  		return fmt.Errorf("failed to read provider file: %w", err)
    76  	}
    77  
    78  	v := c.CompileBytes(content)
    79  	if v.Err() != nil {
    80  		return fmt.Errorf("failed to compile provider file: %w", v.Err())
    81  	}
    82  
    83  	// iter provider methods
    84  	iter, err := v.Fields(cue.Definitions(true))
    85  	if err != nil {
    86  		return fmt.Errorf("failed to get definition iterator: %w", err)
    87  	}
    88  
    89  	docs, ref, pkg := bytes.NewBuffer(nil), MarkdownReference{}, ""
    90  	for iter.Next() {
    91  		item := iter.Value()
    92  
    93  		// get package name. TODO(iyear): more elegant
    94  		if pkg == "" {
    95  			t, err := item.LookupPath(cue.ParsePath(providerKey)).String()
    96  			if err != nil {
    97  				return err
    98  			}
    99  			pkg = t
   100  		}
   101  
   102  		// header
   103  		fmt.Fprintf(docs, "## %s\n", iter.Label())
   104  
   105  		doc, _, err := ref.parseParameters("", item.LookupPath(cue.ParsePath(paramsKey)), "*Params*", 0, true)
   106  		if err != nil {
   107  			return err
   108  		}
   109  		docs.WriteString(doc)
   110  
   111  		doc, _, err = ref.parseParameters("", item.LookupPath(cue.ParsePath(returnsKey)), "*Returns*", 0, true)
   112  		if err != nil {
   113  			return err
   114  		}
   115  		docs.WriteString(doc)
   116  	}
   117  
   118  	doc := bytes.NewBuffer(nil)
   119  	fmt.Fprintf(doc, "# %s\n\n", pkg) // package name header
   120  	doc.Write(docs.Bytes())
   121  	doc.WriteString("------\n\n") // footer
   122  
   123  	_, err = w.Write(doc.Bytes())
   124  	return err
   125  }