...

Source file src/github.com/playwright-community/playwright-go/helpers.go

Documentation: github.com/playwright-community/playwright-go

     1  package playwright
     2  
     3  import (
     4  	"reflect"
     5  	"regexp"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/danwakefield/fnmatch"
    10  )
    11  
    12  type (
    13  	routeHandler = func(Route, Request)
    14  )
    15  
    16  func skipFieldSerialization(val reflect.Value) bool {
    17  	typ := val.Type()
    18  	return (typ.Kind() == reflect.Ptr ||
    19  		typ.Kind() == reflect.Interface ||
    20  		typ.Kind() == reflect.Map ||
    21  		typ.Kind() == reflect.Slice) && val.IsNil() || (val.Kind() == reflect.Interface && val.Elem().Kind() == reflect.Ptr && val.Elem().IsNil())
    22  }
    23  
    24  func transformStructValues(in interface{}) interface{} {
    25  	v := reflect.ValueOf(in)
    26  	if v.Kind() == reflect.Ptr {
    27  		v = v.Elem()
    28  	}
    29  	if _, ok := in.(*channel); ok {
    30  		return in
    31  	}
    32  	if v.Kind() == reflect.Map || v.Kind() == reflect.Struct {
    33  		return transformStructIntoMapIfNeeded(in)
    34  	}
    35  	if v.Kind() == reflect.Slice {
    36  		outSlice := []interface{}{}
    37  		for i := 0; i < v.Len(); i++ {
    38  			if !skipFieldSerialization(v.Index(i)) {
    39  				outSlice = append(outSlice, transformStructValues(v.Index(i).Interface()))
    40  			}
    41  		}
    42  		return outSlice
    43  	}
    44  	if v.Interface() == Null() || (v.Kind() == reflect.String && v.String() == Null().(string)) {
    45  		return "null"
    46  	}
    47  	return in
    48  }
    49  
    50  func transformStructIntoMapIfNeeded(inStruct interface{}) map[string]interface{} {
    51  	out := make(map[string]interface{})
    52  	v := reflect.ValueOf(inStruct)
    53  	if v.Kind() == reflect.Ptr {
    54  		v = v.Elem()
    55  	}
    56  	typ := v.Type()
    57  	if v.Kind() == reflect.Struct {
    58  		// Merge into the base map by the JSON struct tag
    59  		for i := 0; i < v.NumField(); i++ {
    60  			fi := typ.Field(i)
    61  			// Skip the values when the field is a pointer (like *string) and nil.
    62  			if !skipFieldSerialization(v.Field(i)) {
    63  				// We use the JSON struct fields for getting the original names
    64  				// out of the field.
    65  				tagv := fi.Tag.Get("json")
    66  				key := strings.Split(tagv, ",")[0]
    67  				if key == "" {
    68  					key = fi.Name
    69  				}
    70  				out[key] = transformStructValues(v.Field(i).Interface())
    71  			}
    72  		}
    73  	} else if v.Kind() == reflect.Map {
    74  		// Merge into the base map
    75  		for _, key := range v.MapKeys() {
    76  			if !skipFieldSerialization(v.MapIndex(key)) {
    77  				out[key.String()] = transformStructValues(v.MapIndex(key).Interface())
    78  			}
    79  		}
    80  	}
    81  	return out
    82  }
    83  
    84  // transformOptions handles the parameter data transformation
    85  func transformOptions(options ...interface{}) map[string]interface{} {
    86  	var base map[string]interface{}
    87  	var option interface{}
    88  	// Case 1: No options are given
    89  	if len(options) == 0 {
    90  		return make(map[string]interface{})
    91  	}
    92  	if len(options) == 1 {
    93  		// Case 2: a single value (either struct or map) is given.
    94  		base = make(map[string]interface{})
    95  		option = options[0]
    96  	} else if len(options) == 2 {
    97  		// Case 3: two values are given. The first one needs to be a map and the
    98  		// second one can be a struct or map. It will be then get merged into the first
    99  		// base map.
   100  		base = transformStructIntoMapIfNeeded(options[0])
   101  		option = options[1]
   102  	}
   103  	v := reflect.ValueOf(option)
   104  	if v.Kind() == reflect.Slice {
   105  		if v.Len() == 0 {
   106  			return base
   107  		}
   108  		option = v.Index(0).Interface()
   109  	}
   110  
   111  	if option == nil {
   112  		return base
   113  	}
   114  	v = reflect.ValueOf(option)
   115  
   116  	if v.Kind() == reflect.Ptr {
   117  		v = v.Elem()
   118  	}
   119  
   120  	optionMap := transformStructIntoMapIfNeeded(v.Interface())
   121  	for key, value := range optionMap {
   122  		base[key] = value
   123  	}
   124  	return base
   125  }
   126  
   127  func remapValue(inMapValue reflect.Value, outStructValue reflect.Value) {
   128  	switch outStructValue.Type().Kind() {
   129  	case reflect.Bool:
   130  		outStructValue.SetBool(inMapValue.Bool())
   131  	case reflect.String:
   132  		outStructValue.SetString(inMapValue.String())
   133  	case reflect.Float64:
   134  		outStructValue.SetFloat(inMapValue.Float())
   135  	case reflect.Int:
   136  		outStructValue.SetInt(int64(inMapValue.Float()))
   137  	case reflect.Slice:
   138  		outStructValue.Set(reflect.MakeSlice(outStructValue.Type(), inMapValue.Len(), inMapValue.Cap()))
   139  		for i := 0; i < inMapValue.Len(); i++ {
   140  			remapValue(inMapValue.Index(i).Elem(), outStructValue.Index(i))
   141  		}
   142  	case reflect.Struct:
   143  		structTyp := outStructValue.Type()
   144  		for i := 0; i < outStructValue.NumField(); i++ {
   145  			fi := structTyp.Field(i)
   146  			key := strings.Split(fi.Tag.Get("json"), ",")[0]
   147  			structField := outStructValue.Field(i)
   148  			structFieldDeref := outStructValue.Field(i)
   149  			if structField.Type().Kind() == reflect.Ptr {
   150  				structField.Set(reflect.New(structField.Type().Elem()))
   151  				structFieldDeref = structField.Elem()
   152  			}
   153  			for _, e := range inMapValue.MapKeys() {
   154  				if key == e.String() {
   155  					value := inMapValue.MapIndex(e)
   156  					remapValue(value.Elem(), structFieldDeref)
   157  				}
   158  			}
   159  		}
   160  	default:
   161  		panic(inMapValue.Interface())
   162  	}
   163  }
   164  
   165  func remapMapToStruct(inputMap interface{}, outStruct interface{}) {
   166  	remapValue(reflect.ValueOf(inputMap), reflect.ValueOf(outStruct).Elem())
   167  }
   168  
   169  func isFunctionBody(expression string) bool {
   170  	expression = strings.TrimSpace(expression)
   171  	return strings.HasPrefix(expression, "function") ||
   172  		strings.HasPrefix(expression, "async ") ||
   173  		strings.Contains(expression, "=> ")
   174  }
   175  
   176  type urlMatcher struct {
   177  	urlOrPredicate interface{}
   178  }
   179  
   180  func newURLMatcher(urlOrPredicate interface{}) *urlMatcher {
   181  	return &urlMatcher{
   182  		urlOrPredicate: urlOrPredicate,
   183  	}
   184  }
   185  
   186  func (u *urlMatcher) Matches(url string) bool {
   187  	switch v := u.urlOrPredicate.(type) {
   188  	case *regexp.Regexp:
   189  		return v.MatchString(url)
   190  	case string:
   191  		return fnmatch.Match(v, url, 0)
   192  	}
   193  	if reflect.TypeOf(u.urlOrPredicate).Kind() == reflect.Func {
   194  		function := reflect.ValueOf(u.urlOrPredicate)
   195  		result := function.Call([]reflect.Value{reflect.ValueOf(url)})
   196  		return result[0].Bool()
   197  	}
   198  	panic(u.urlOrPredicate)
   199  }
   200  
   201  type routeHandlerEntry struct {
   202  	matcher *urlMatcher
   203  	handler routeHandler
   204  }
   205  
   206  func newRouteHandlerEntry(matcher *urlMatcher, handler routeHandler) *routeHandlerEntry {
   207  	return &routeHandlerEntry{
   208  		matcher: matcher,
   209  		handler: handler,
   210  	}
   211  }
   212  
   213  type safeStringSet struct {
   214  	sync.Mutex
   215  	v []string
   216  }
   217  
   218  func (s *safeStringSet) Has(expected string) bool {
   219  	s.Lock()
   220  	defer s.Unlock()
   221  	for _, v := range s.v {
   222  		if v == expected {
   223  			return true
   224  		}
   225  	}
   226  	return false
   227  }
   228  
   229  func (s *safeStringSet) Add(v string) {
   230  	if s.Has(v) {
   231  		return
   232  	}
   233  	s.Lock()
   234  	s.v = append(s.v, v)
   235  	s.Unlock()
   236  }
   237  
   238  func (s *safeStringSet) Remove(remove string) {
   239  	s.Lock()
   240  	defer s.Unlock()
   241  	newSlice := make([]string, 0)
   242  	for _, v := range s.v {
   243  		if v != remove {
   244  			newSlice = append(newSlice, v)
   245  		}
   246  	}
   247  	if len(s.v) != len(newSlice) {
   248  		s.v = newSlice
   249  	}
   250  }
   251  
   252  func newSafeStringSet(v []string) *safeStringSet {
   253  	return &safeStringSet{
   254  		v: v,
   255  	}
   256  }
   257  
   258  const defaultTimeout = 30 * 1000
   259  
   260  type timeoutSettings struct {
   261  	parent            *timeoutSettings
   262  	timeout           float64
   263  	navigationTimeout float64
   264  }
   265  
   266  func (t *timeoutSettings) SetTimeout(timeout float64) {
   267  	t.timeout = timeout
   268  }
   269  
   270  func (t *timeoutSettings) Timeout() float64 {
   271  	if t.timeout != 0 {
   272  		return t.timeout
   273  	}
   274  	if t.parent != nil {
   275  		return t.parent.Timeout()
   276  	}
   277  	return defaultTimeout
   278  }
   279  
   280  func (t *timeoutSettings) SetNavigationTimeout(navigationTimeout float64) {
   281  	t.navigationTimeout = navigationTimeout
   282  }
   283  
   284  func (t *timeoutSettings) NavigationTimeout() float64 {
   285  	if t.navigationTimeout != 0 {
   286  		return t.navigationTimeout
   287  	}
   288  	if t.parent != nil {
   289  		return t.parent.NavigationTimeout()
   290  	}
   291  	return defaultTimeout
   292  }
   293  
   294  func newTimeoutSettings(parent *timeoutSettings) *timeoutSettings {
   295  	return &timeoutSettings{
   296  		parent:            parent,
   297  		timeout:           defaultTimeout,
   298  		navigationTimeout: defaultTimeout,
   299  	}
   300  }
   301  
   302  func waitForEvent(emitter EventEmitter, event string, predicate ...interface{}) <-chan interface{} {
   303  	evChan := make(chan interface{}, 1)
   304  	removeHandler := make(chan bool, 1)
   305  	handler := func(ev ...interface{}) {
   306  		if len(predicate) == 0 {
   307  			if len(ev) == 1 {
   308  				evChan <- ev[0]
   309  			} else {
   310  				evChan <- nil
   311  			}
   312  			removeHandler <- true
   313  		} else if len(predicate) == 1 {
   314  			result := reflect.ValueOf(predicate[0]).Call([]reflect.Value{reflect.ValueOf(ev[0])})
   315  			if result[0].Bool() {
   316  				evChan <- ev[0]
   317  				removeHandler <- true
   318  			}
   319  		}
   320  	}
   321  	go func() {
   322  		<-removeHandler
   323  		emitter.RemoveListener(event, handler)
   324  	}()
   325  	emitter.On(event, handler)
   326  	return evChan
   327  }
   328  
   329  // SelectOptionValues is the option struct for ElementHandle.Select() etc.
   330  type SelectOptionValues struct {
   331  	Values   *[]string
   332  	Indexes  *[]int
   333  	Labels   *[]string
   334  	Elements *[]ElementHandle
   335  }
   336  
   337  func convertSelectOptionSet(values SelectOptionValues) map[string]interface{} {
   338  	out := make(map[string]interface{})
   339  	if values == (SelectOptionValues{}) {
   340  		return out
   341  	}
   342  
   343  	var o []map[string]interface{}
   344  	if values.Values != nil {
   345  		for _, v := range *values.Values {
   346  			m := map[string]interface{}{"value": v}
   347  			o = append(o, m)
   348  		}
   349  	}
   350  	if values.Indexes != nil {
   351  		for _, i := range *values.Indexes {
   352  			m := map[string]interface{}{"index": i}
   353  			o = append(o, m)
   354  		}
   355  	}
   356  	if values.Labels != nil {
   357  		for _, l := range *values.Labels {
   358  			m := map[string]interface{}{"label": l}
   359  			o = append(o, m)
   360  		}
   361  	}
   362  	if o != nil {
   363  		out["options"] = o
   364  	}
   365  
   366  	var e []*channel
   367  	if values.Elements != nil {
   368  		for _, eh := range *values.Elements {
   369  			e = append(e, eh.(*elementHandleImpl).channel)
   370  		}
   371  	}
   372  	if e != nil {
   373  		out["elements"] = e
   374  	}
   375  
   376  	return out
   377  }
   378  
   379  func unroute(channel *channel, inRoutes []*routeHandlerEntry, url interface{}, handlers ...routeHandler) ([]*routeHandlerEntry, error) {
   380  	var handler routeHandler
   381  	if len(handlers) == 1 {
   382  		handler = handlers[0]
   383  	}
   384  	handlerPtr := reflect.ValueOf(handler).Pointer()
   385  
   386  	routes := make([]*routeHandlerEntry, 0)
   387  
   388  	for _, route := range inRoutes {
   389  		routeHandlerPtr := reflect.ValueOf(route.handler).Pointer()
   390  		if route.matcher.urlOrPredicate != url ||
   391  			(handler != nil && routeHandlerPtr != handlerPtr) {
   392  			routes = append(routes, route)
   393  		}
   394  	}
   395  
   396  	if len(routes) == 0 {
   397  		_, err := channel.Send("setNetworkInterceptionEnabled", map[string]interface{}{
   398  			"enabled": false,
   399  		})
   400  		if err != nil {
   401  			return nil, err
   402  		}
   403  	}
   404  	return routes, nil
   405  }
   406  
   407  func serializeMapToNameAndValue(headers map[string]string) []map[string]string {
   408  	serialized := make([]map[string]string, 0)
   409  	for name, value := range headers {
   410  		serialized = append(serialized, map[string]string{
   411  			"name":  name,
   412  			"value": value,
   413  		})
   414  	}
   415  	return serialized
   416  }
   417  

View as plain text