| // Copyright 2018 Google LLC |
| // |
| // 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 common defines types and utilities common to expression parsing, |
| // checking, and interpretation |
| package common |
| |
| import ( |
| "strings" |
| "unicode" |
| ) |
| |
| // DocKind indicates the type of documentation element. |
| type DocKind int |
| |
| const ( |
| // DocEnv represents environment variable documentation. |
| DocEnv DocKind = iota + 1 |
| // DocFunction represents function documentation. |
| DocFunction |
| // DocOverload represents function overload documentation. |
| DocOverload |
| // DocVariable represents variable documentation. |
| DocVariable |
| // DocMacro represents macro documentation. |
| DocMacro |
| // DocExample represents example documentation. |
| DocExample |
| // DocField represents documentation for a struct field. |
| DocField |
| ) |
| |
| // Doc holds the documentation details for a specific program element like |
| // a variable, function, macro, or example. |
| type Doc struct { |
| // Kind specifies the type of documentation element (e.g., Function, Variable). |
| Kind DocKind |
| |
| // Name is the identifier of the documented element (e.g., function name, variable name). |
| Name string |
| |
| // Type is the data type associated with the element, primarily used for variables. |
| Type string |
| |
| // Signature represents the function or overload signature. |
| Signature string |
| |
| // Description holds the textual description of the element, potentially spanning multiple lines. |
| Description string |
| |
| // Children holds nested documentation elements, such as overloads for a function |
| // or examples for a function/macro. |
| Children []*Doc |
| } |
| |
| // MultilineDescription combines multiple lines into a newline separated string. |
| func MultilineDescription(lines ...string) string { |
| return strings.Join(lines, "\n") |
| } |
| |
| // ParseDescription takes a single string containing newline characters and splits |
| // it into a multiline description. All empty lines will be skipped. |
| // |
| // Returns an empty string if the input string is empty. |
| func ParseDescription(doc string) string { |
| var lines []string |
| if len(doc) != 0 { |
| // Split the input string by newline characters. |
| for _, line := range strings.Split(doc, "\n") { |
| l := strings.TrimRightFunc(line, unicode.IsSpace) |
| if len(l) == 0 { |
| continue |
| } |
| lines = append(lines, l) |
| } |
| } |
| // Return an empty slice if the input is empty. |
| return MultilineDescription(lines...) |
| } |
| |
| // ParseDescriptions splits a documentation string into multiple multi-line description |
| // sections, using blank lines as delimiters. |
| func ParseDescriptions(doc string) []string { |
| var examples []string |
| if len(doc) != 0 { |
| lines := strings.Split(doc, "\n") |
| lineStart := 0 |
| for i, l := range lines { |
| // Trim trailing whitespace to identify effectively blank lines. |
| l = strings.TrimRightFunc(l, unicode.IsSpace) |
| // If a line is blank, it marks the end of the current section. |
| if len(l) == 0 { |
| // Start the next section after the blank line. |
| ex := lines[lineStart:i] |
| if len(ex) != 0 { |
| examples = append(examples, MultilineDescription(ex...)) |
| } |
| lineStart = i + 1 |
| } |
| } |
| // Append the last section if it wasn't terminated by a blank line. |
| if lineStart < len(lines) { |
| examples = append(examples, MultilineDescription(lines[lineStart:]...)) |
| } |
| } |
| return examples |
| } |
| |
| // NewVariableDoc creates a new Doc struct specifically for documenting a variable. |
| func NewVariableDoc(name, celType, description string) *Doc { |
| return &Doc{ |
| Kind: DocVariable, |
| Name: name, |
| Type: celType, |
| Description: ParseDescription(description), |
| } |
| } |
| |
| // NewFunctionDoc creates a new Doc struct for documenting a function. |
| func NewFunctionDoc(name, description string, overloads ...*Doc) *Doc { |
| return &Doc{ |
| Kind: DocFunction, |
| Name: name, |
| Description: ParseDescription(description), |
| Children: overloads, |
| } |
| } |
| |
| // NewOverloadDoc creates a new Doc struct for a function example. |
| func NewOverloadDoc(id, signature string, examples ...*Doc) *Doc { |
| return &Doc{ |
| Kind: DocOverload, |
| Name: id, |
| Signature: signature, |
| Children: examples, |
| } |
| } |
| |
| // NewMacroDoc creates a new Doc struct for documenting a macro. |
| func NewMacroDoc(name, description string, examples ...*Doc) *Doc { |
| return &Doc{ |
| Kind: DocMacro, |
| Name: name, |
| Description: ParseDescription(description), |
| Children: examples, |
| } |
| } |
| |
| // NewExampleDoc creates a new Doc struct specifically for holding an example. |
| func NewExampleDoc(ex string) *Doc { |
| return &Doc{ |
| Kind: DocExample, |
| Description: ex, |
| } |
| } |
| |
| // NewFieldDoc creates a new Doc struct for documenting a struct field. |
| func NewFieldDoc(name, celType, description string, examples ...*Doc) *Doc { |
| return &Doc{ |
| Kind: DocField, |
| Name: name, |
| Type: celType, |
| Description: description, |
| Children: examples, |
| } |
| } |
| |
| // Documentor is an interface for types that can provide their own documentation. |
| type Documentor interface { |
| // Documentation returns the documentation coded by the DocKind to assist |
| // with text formatting. |
| Documentation() *Doc |
| } |