github.com/klaytn/klaytn@v1.12.1/console/jsre/completion.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2016 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from internal/jsre/completion.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package jsre
    22  
    23  import (
    24  	"regexp"
    25  	"sort"
    26  	"strings"
    27  
    28  	"github.com/dop251/goja"
    29  )
    30  
    31  // JS numerical token
    32  var numerical = regexp.MustCompile(`^(NaN|-?((\d*\.\d+|\d+)([Ee][+-]?\d+)?|Infinity))$`)
    33  
    34  // CompleteKeywords returns potential continuations for the given line. Since line is
    35  // evaluated, callers need to make sure that evaluating line does not have side effects.
    36  func (jsre *JSRE) CompleteKeywords(line string) []string {
    37  	var results []string
    38  	jsre.Do(func(vm *goja.Runtime) {
    39  		results = getCompletions(vm, line)
    40  	})
    41  	return results
    42  }
    43  
    44  func getCompletions(vm *goja.Runtime, line string) (results []string) {
    45  	parts := strings.Split(line, ".")
    46  	if len(parts) == 0 {
    47  		return nil
    48  	}
    49  
    50  	// Find the right-most fully named object in the line. e.g. if line = "x.y.z"
    51  	// and "x.y" is an object, obj will reference "x.y".
    52  	obj := vm.GlobalObject()
    53  	for i := 0; i < len(parts)-1; i++ {
    54  		if numerical.MatchString(parts[i]) {
    55  			return nil
    56  		}
    57  		v := obj.Get(parts[i])
    58  		if v == nil || goja.IsNull(v) || goja.IsUndefined(v) {
    59  			return nil // No object was found
    60  		}
    61  		obj = v.ToObject(vm)
    62  	}
    63  
    64  	// Go over the keys of the object and retain the keys matching prefix.
    65  	// Example: if line = "x.y.z" and "x.y" exists and has keys "zebu", "zebra"
    66  	// and "platypus", then "x.y.zebu" and "x.y.zebra" will be added to results.
    67  	prefix := parts[len(parts)-1]
    68  	iterOwnAndConstructorKeys(vm, obj, func(k string) {
    69  		if strings.HasPrefix(k, prefix) {
    70  			if len(parts) == 1 {
    71  				results = append(results, k)
    72  			} else {
    73  				results = append(results, strings.Join(parts[:len(parts)-1], ".")+"."+k)
    74  			}
    75  		}
    76  	})
    77  
    78  	// Append opening parenthesis (for functions) or dot (for objects)
    79  	// if the line itself is the only completion.
    80  	if len(results) == 1 && results[0] == line {
    81  		// Accessing the property will cause it to be evaluated.
    82  		// This can cause an error, e.g. in case of web3.eth.protocolVersion
    83  		// which has been dropped from geth. Ignore the error for autocompletion
    84  		// purposes.
    85  		obj := SafeGet(obj, parts[len(parts)-1])
    86  		if obj != nil {
    87  			if _, isfunc := goja.AssertFunction(obj); isfunc {
    88  				results[0] += "("
    89  			} else {
    90  				results[0] += "."
    91  			}
    92  		}
    93  	}
    94  
    95  	sort.Strings(results)
    96  	return results
    97  }