github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/common/types/convert.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package types
    15  
    16  import (
    17  	"encoding/json"
    18  	"fmt"
    19  	"html/template"
    20  	"reflect"
    21  	"time"
    22  
    23  	"github.com/spf13/cast"
    24  )
    25  
    26  // ToDuration converts v to time.Duration.
    27  // See ToDurationE if you need to handle errors.
    28  func ToDuration(v interface{}) time.Duration {
    29  	d, _ := ToDurationE(v)
    30  	return d
    31  }
    32  
    33  // ToDurationE converts v to time.Duration.
    34  func ToDurationE(v interface{}) (time.Duration, error) {
    35  	if n := cast.ToInt(v); n > 0 {
    36  		return time.Duration(n) * time.Millisecond, nil
    37  	}
    38  	d, err := time.ParseDuration(cast.ToString(v))
    39  	if err != nil {
    40  		return 0, fmt.Errorf("cannot convert %v to time.Duration", v)
    41  	}
    42  	return d, nil
    43  }
    44  
    45  // ToStringSlicePreserveString is the same as ToStringSlicePreserveStringE,
    46  // but it never fails.
    47  func ToStringSlicePreserveString(v interface{}) []string {
    48  	vv, _ := ToStringSlicePreserveStringE(v)
    49  	return vv
    50  }
    51  
    52  // ToStringSlicePreserveStringE converts v to a string slice.
    53  // If v is a string, it will be wrapped in a string slice.
    54  func ToStringSlicePreserveStringE(v interface{}) ([]string, error) {
    55  	if v == nil {
    56  		return nil, nil
    57  	}
    58  	if sds, ok := v.(string); ok {
    59  		return []string{sds}, nil
    60  	}
    61  	result, err := cast.ToStringSliceE(v)
    62  	if err == nil {
    63  		return result, nil
    64  	}
    65  
    66  	// Probably []int or similar. Fall back to reflect.
    67  	vv := reflect.ValueOf(v)
    68  
    69  	switch vv.Kind() {
    70  	case reflect.Slice, reflect.Array:
    71  		result = make([]string, vv.Len())
    72  		for i := 0; i < vv.Len(); i++ {
    73  			s, err := cast.ToStringE(vv.Index(i).Interface())
    74  			if err != nil {
    75  				return nil, err
    76  			}
    77  			result[i] = s
    78  		}
    79  		return result, nil
    80  	default:
    81  		return nil, fmt.Errorf("failed to convert %T to a string slice", v)
    82  	}
    83  
    84  }
    85  
    86  // TypeToString converts v to a string if it's a valid string type.
    87  // Note that this will not try to convert numeric values etc.,
    88  // use ToString for that.
    89  func TypeToString(v interface{}) (string, bool) {
    90  	switch s := v.(type) {
    91  	case string:
    92  		return s, true
    93  	case template.HTML:
    94  		return string(s), true
    95  	case template.CSS:
    96  		return string(s), true
    97  	case template.HTMLAttr:
    98  		return string(s), true
    99  	case template.JS:
   100  		return string(s), true
   101  	case template.JSStr:
   102  		return string(s), true
   103  	case template.URL:
   104  		return string(s), true
   105  	case template.Srcset:
   106  		return string(s), true
   107  	}
   108  
   109  	return "", false
   110  }
   111  
   112  // ToString converts v to a string.
   113  func ToString(v interface{}) string {
   114  	s, _ := ToStringE(v)
   115  	return s
   116  }
   117  
   118  // ToStringE converts v to a string.
   119  func ToStringE(v interface{}) (string, error) {
   120  	if s, ok := TypeToString(v); ok {
   121  		return s, nil
   122  	}
   123  
   124  	switch s := v.(type) {
   125  	case json.RawMessage:
   126  		return string(s), nil
   127  	default:
   128  		return cast.ToStringE(v)
   129  	}
   130  }