mirror of
				https://github.com/MontFerret/ferret.git
				synced 2025-10-30 23:37:40 +02:00 
			
		
		
		
	Added possibility to use FOR loop in ternary expression
This commit is contained in:
		
							
								
								
									
										24
									
								
								docs/examples/input.fql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								docs/examples/input.fql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| LET g = DOCUMENT("https://www.google.com/", true) | ||||
| LET inputBox = ELEMENT(g, 'input[name="q"]') | ||||
|  | ||||
| INPUT(inputBox, "ferrer") | ||||
|  | ||||
| LET searchBtn = ELEMENT(g, 'input[name="btnK"]') | ||||
|  | ||||
| CLICK(searchBtn) | ||||
|  | ||||
| WAIT_NAVIGATION(g) | ||||
|  | ||||
| LET result = ELEMENTS(g, '.g') | ||||
|  | ||||
| LOG(result ? 'element' : 'no element') | ||||
|  | ||||
| RETURN result ? ( | ||||
|     FOR result IN ELEMENTS(g, '.g') | ||||
|         LOG('iterate') | ||||
|         RETURN { | ||||
|             title: ELEMENT(result, 'h3 > a'), | ||||
|             description: ELEMENT(result, '.st'), | ||||
|             url: ELEMENT(result, 'cite') | ||||
|         } | ||||
| ) : 'no results' | ||||
| @@ -90,3 +90,13 @@ func (c *FqlCompiler) Compile(query string) (program *runtime.Program, err error | ||||
|  | ||||
| 	return program, err | ||||
| } | ||||
|  | ||||
| func (c *FqlCompiler) CompileP(query string) *runtime.Program { | ||||
| 	program, err := c.Compile(query) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	return program | ||||
| } | ||||
|   | ||||
| @@ -1602,6 +1602,92 @@ func TestInOperator(t *testing.T) { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestForTernaryExpression(t *testing.T) { | ||||
| 	Convey("RETURN foo ? TRUE : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.CompileP(` | ||||
| 			LET foo = FALSE | ||||
| 			RETURN foo ? TRUE : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.CompileP(` | ||||
| 			LET foo = TRUE | ||||
| 			RETURN foo ? TRUE : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `true`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("RETURN foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.CompileP(` | ||||
| 			LET foo = FALSE | ||||
| 			RETURN foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.CompileP(` | ||||
| 			LET foo = TRUE | ||||
| 			RETURN foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `[1,2,3,4,5]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("LET res =  foo ? TRUE : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.CompileP(` | ||||
| 			LET foo = FALSE | ||||
| 			LET res = foo ? TRUE : (FOR i IN 1..5 RETURN i*2)  | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.CompileP(` | ||||
| 			LET foo = TRUE | ||||
| 			LET res = foo ? TRUE : (FOR i IN 1..5 RETURN i*2) | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `true`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("LET res = foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.CompileP(` | ||||
| 			LET foo = FALSE | ||||
| 			LET res = foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.CompileP(` | ||||
| 			LET foo = TRUE | ||||
| 			LET res = foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `[1,2,3,4,5]`) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| //func TestHtml(t *testing.T) { | ||||
| //	Convey("Should load a document", t, func() { | ||||
| //		c := compiler.New() | ||||
|   | ||||
| @@ -117,7 +117,13 @@ func (v *visitor) doVisitReturnExpression(ctx *fql.ReturnExpressionContext, scop | ||||
| 		} | ||||
|  | ||||
| 		exp = out | ||||
| 	} else { | ||||
|  | ||||
| 		return expressions.NewReturnExpression(v.getSourceMap(ctx), exp) | ||||
| 	} | ||||
|  | ||||
| 	forIn := ctx.ForExpression() | ||||
|  | ||||
| 	if forIn != nil { | ||||
| 		out, err := v.doVisitForExpression(ctx.ForExpression().(*fql.ForExpressionContext), scope.Fork()) | ||||
|  | ||||
| 		if err != nil { | ||||
| @@ -125,9 +131,23 @@ func (v *visitor) doVisitReturnExpression(ctx *fql.ReturnExpressionContext, scop | ||||
| 		} | ||||
|  | ||||
| 		exp = out | ||||
|  | ||||
| 		return expressions.NewReturnExpression(v.getSourceMap(ctx), exp) | ||||
| 	} | ||||
|  | ||||
| 	return expressions.NewReturnExpression(v.getSourceMap(ctx), exp) | ||||
| 	forInTernary := ctx.ForTernaryExpression() | ||||
|  | ||||
| 	if forInTernary != nil { | ||||
| 		out, err := v.doVisitForTernaryExpression(forInTernary.(*fql.ForTernaryExpressionContext), scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		return expressions.NewReturnExpression(v.getSourceMap(ctx), out) | ||||
| 	} | ||||
|  | ||||
| 	return nil, ErrNotImplemented | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitForExpression(ctx *fql.ForExpressionContext, scope *scope) (core.Expression, error) { | ||||
| @@ -609,7 +629,9 @@ func (v *visitor) doVisitVariableDeclaration(ctx *fql.VariableDeclarationContext | ||||
|  | ||||
| 	if exp != nil { | ||||
| 		init, err = v.doVisitExpression(ctx.Expression().(*fql.ExpressionContext), scope) | ||||
| 	} else { | ||||
| 	} | ||||
|  | ||||
| 	if init == nil && err == nil { | ||||
| 		forIn := ctx.ForExpression() | ||||
|  | ||||
| 		if forIn != nil { | ||||
| @@ -617,6 +639,14 @@ func (v *visitor) doVisitVariableDeclaration(ctx *fql.VariableDeclarationContext | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if init == nil && err == nil { | ||||
| 		forTer := ctx.ForTernaryExpression() | ||||
|  | ||||
| 		if forTer != nil { | ||||
| 			init, err = v.doVisitForTernaryExpression(forTer.(*fql.ForTernaryExpressionContext), scope) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -661,16 +691,22 @@ func (v *visitor) doVisitChildren(node antlr.RuleNode, scope *scope) ([]core.Exp | ||||
| 		return make([]core.Expression, 0, 0), nil | ||||
| 	} | ||||
|  | ||||
| 	result := make([]core.Expression, len(children)) | ||||
| 	result := make([]core.Expression, 0, len(children)) | ||||
|  | ||||
| 	for _, child := range children { | ||||
| 		_, ok := child.(antlr.TerminalNode) | ||||
|  | ||||
| 		if ok { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 	for idx, child := range children { | ||||
| 		out, err := v.visit(child, scope) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		result[idx] = out | ||||
| 		result = append(result, out) | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| @@ -794,24 +830,10 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		var test core.Expression | ||||
| 		var consequent core.Expression | ||||
| 		var alternate core.Expression | ||||
|  | ||||
| 		if len(exps) == 3 { | ||||
| 			test = exps[0] | ||||
| 			consequent = exps[1] | ||||
| 			alternate = exps[2] | ||||
| 		} else { | ||||
| 			test = exps[0] | ||||
| 			alternate = exps[1] | ||||
| 		} | ||||
|  | ||||
| 		return expressions.NewConditionExpression( | ||||
| 		return v.createTernaryOperator( | ||||
| 			v.getSourceMap(ctx), | ||||
| 			test, | ||||
| 			consequent, | ||||
| 			alternate, | ||||
| 			exps, | ||||
| 			scope, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| @@ -860,14 +882,6 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c | ||||
| 		return v.doVisitRangeOperator(rangeOp.(*fql.RangeOperatorContext), scope) | ||||
| 	} | ||||
|  | ||||
| 	seq := ctx.ExpressionSequence() | ||||
|  | ||||
| 	if seq != nil { | ||||
| 		// seq := seq.(*fql.ExpressionSequenceContext) | ||||
|  | ||||
| 		return nil, core.Error(ErrNotImplemented, "expression sequence") | ||||
| 	} | ||||
|  | ||||
| 	// TODO: Complete it | ||||
| 	return nil, ErrNotImplemented | ||||
| } | ||||
| @@ -981,6 +995,42 @@ func (v *visitor) visit(node antlr.Tree, scope *scope) (core.Expression, error) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (v *visitor) doVisitForTernaryExpression(ctx *fql.ForTernaryExpressionContext, scope *scope) (*expressions.ConditionExpression, error) { | ||||
| 	exps, err := v.doVisitChildren(ctx, scope) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return v.createTernaryOperator( | ||||
| 		v.getSourceMap(ctx), | ||||
| 		exps, | ||||
| 		scope, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (v *visitor) createTernaryOperator(src core.SourceMap, exps []core.Expression, scope *scope) (*expressions.ConditionExpression, error) { | ||||
| 	var test core.Expression | ||||
| 	var consequent core.Expression | ||||
| 	var alternate core.Expression | ||||
|  | ||||
| 	if len(exps) == 3 { | ||||
| 		test = exps[0] | ||||
| 		consequent = exps[1] | ||||
| 		alternate = exps[2] | ||||
| 	} else { | ||||
| 		test = exps[0] | ||||
| 		alternate = exps[1] | ||||
| 	} | ||||
|  | ||||
| 	return expressions.NewConditionExpression( | ||||
| 		src, | ||||
| 		test, | ||||
| 		consequent, | ||||
| 		alternate, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (v *visitor) unexpectedToken(node antlr.Tree) error { | ||||
| 	name := "undefined" | ||||
| 	ctx, ok := node.(antlr.RuleContext) | ||||
|   | ||||
| @@ -23,6 +23,7 @@ bodyExpression | ||||
| returnExpression | ||||
|     : Return (Distinct)? expression | ||||
|     | Return (Distinct)? OpenParen forExpression CloseParen | ||||
|     | Return forTernaryExpression | ||||
|     ; | ||||
|  | ||||
| forExpression | ||||
| @@ -124,6 +125,7 @@ forExpressionReturn | ||||
| variableDeclaration | ||||
|     : Let Identifier Assign expression | ||||
|     | Let Identifier Assign OpenParen forExpression CloseParen | ||||
|     | Let Identifier Assign forTernaryExpression | ||||
|     ; | ||||
|  | ||||
| variable | ||||
| @@ -225,6 +227,12 @@ expression | ||||
|     | noneLiteral | ||||
|     ; | ||||
|  | ||||
| forTernaryExpression | ||||
|     : expression QuestionMark expression? Colon OpenParen forExpression CloseParen | ||||
|     | expression QuestionMark OpenParen forExpression CloseParen Colon expression | ||||
|     | expression QuestionMark OpenParen forExpression CloseParen Colon OpenParen forExpression CloseParen | ||||
|     ; | ||||
|  | ||||
| equalityOperator | ||||
|     : Gt | ||||
|     | Lt | ||||
| @@ -249,7 +257,7 @@ mathOperator | ||||
|  | ||||
| unaryOperator | ||||
|     : Not | ||||
|     | Plus  | ||||
|     | Plus | ||||
|     | Minus | ||||
|     | Like | ||||
|     ; | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -288,6 +288,12 @@ func (s *BaseFqlParserListener) EnterExpression(ctx *ExpressionContext) {} | ||||
| // ExitExpression is called when production expression is exited. | ||||
| func (s *BaseFqlParserListener) ExitExpression(ctx *ExpressionContext) {} | ||||
|  | ||||
| // EnterForTernaryExpression is called when production forTernaryExpression is entered. | ||||
| func (s *BaseFqlParserListener) EnterForTernaryExpression(ctx *ForTernaryExpressionContext) {} | ||||
|  | ||||
| // ExitForTernaryExpression is called when production forTernaryExpression is exited. | ||||
| func (s *BaseFqlParserListener) ExitForTernaryExpression(ctx *ForTernaryExpressionContext) {} | ||||
|  | ||||
| // EnterEqualityOperator is called when production equalityOperator is entered. | ||||
| func (s *BaseFqlParserListener) EnterEqualityOperator(ctx *EqualityOperatorContext) {} | ||||
|  | ||||
|   | ||||
| @@ -183,6 +183,10 @@ func (v *BaseFqlParserVisitor) VisitExpression(ctx *ExpressionContext) interface | ||||
| 	return v.VisitChildren(ctx) | ||||
| } | ||||
|  | ||||
| func (v *BaseFqlParserVisitor) VisitForTernaryExpression(ctx *ForTernaryExpressionContext) interface{} { | ||||
| 	return v.VisitChildren(ctx) | ||||
| } | ||||
|  | ||||
| func (v *BaseFqlParserVisitor) VisitEqualityOperator(ctx *EqualityOperatorContext) interface{} { | ||||
| 	return v.VisitChildren(ctx) | ||||
| } | ||||
|   | ||||
| @@ -139,6 +139,9 @@ type FqlParserListener interface { | ||||
| 	// EnterExpression is called when entering the expression production. | ||||
| 	EnterExpression(c *ExpressionContext) | ||||
|  | ||||
| 	// EnterForTernaryExpression is called when entering the forTernaryExpression production. | ||||
| 	EnterForTernaryExpression(c *ForTernaryExpressionContext) | ||||
|  | ||||
| 	// EnterEqualityOperator is called when entering the equalityOperator production. | ||||
| 	EnterEqualityOperator(c *EqualityOperatorContext) | ||||
|  | ||||
| @@ -283,6 +286,9 @@ type FqlParserListener interface { | ||||
| 	// ExitExpression is called when exiting the expression production. | ||||
| 	ExitExpression(c *ExpressionContext) | ||||
|  | ||||
| 	// ExitForTernaryExpression is called when exiting the forTernaryExpression production. | ||||
| 	ExitForTernaryExpression(c *ForTernaryExpressionContext) | ||||
|  | ||||
| 	// ExitEqualityOperator is called when exiting the equalityOperator production. | ||||
| 	ExitEqualityOperator(c *EqualityOperatorContext) | ||||
|  | ||||
|   | ||||
| @@ -139,6 +139,9 @@ type FqlParserVisitor interface { | ||||
| 	// Visit a parse tree produced by FqlParser#expression. | ||||
| 	VisitExpression(ctx *ExpressionContext) interface{} | ||||
|  | ||||
| 	// Visit a parse tree produced by FqlParser#forTernaryExpression. | ||||
| 	VisitForTernaryExpression(ctx *ForTernaryExpressionContext) interface{} | ||||
|  | ||||
| 	// Visit a parse tree produced by FqlParser#equalityOperator. | ||||
| 	VisitEqualityOperator(ctx *EqualityOperatorContext) interface{} | ||||
|  | ||||
|   | ||||
| @@ -40,3 +40,13 @@ func (p *Program) Run(ctx context.Context, setters ...Option) ([]byte, error) { | ||||
|  | ||||
| 	return out.MarshalJSON() | ||||
| } | ||||
|  | ||||
| func (p *Program) RunP(ctx context.Context, setters ...Option) []byte { | ||||
| 	out, err := p.Run(ctx, setters...) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	return out | ||||
| } | ||||
|   | ||||
| @@ -67,6 +67,14 @@ func GetIn(from core.Value, byPath []core.Value) (core.Value, error) { | ||||
| 					result = el.GetChildNodes() | ||||
| 				case "length": | ||||
| 					result = el.Length() | ||||
| 				case "url": | ||||
| 					if result.Type() == core.HtmlDocumentType { | ||||
| 						doc, ok := result.(HtmlDocument) | ||||
|  | ||||
| 						if ok { | ||||
| 							result = doc.Url() | ||||
| 						} | ||||
| 					} | ||||
| 				default: | ||||
| 					result = None | ||||
| 				} | ||||
|   | ||||
| @@ -2,30 +2,38 @@ package values | ||||
|  | ||||
| import "github.com/MontFerret/ferret/pkg/runtime/core" | ||||
|  | ||||
| type HtmlNode interface { | ||||
| 	core.Value | ||||
| type ( | ||||
| 	HtmlNode interface { | ||||
| 		core.Value | ||||
|  | ||||
| 	NodeType() Int | ||||
| 		NodeType() Int | ||||
|  | ||||
| 	NodeName() String | ||||
| 		NodeName() String | ||||
|  | ||||
| 	Length() Int | ||||
| 		Length() Int | ||||
|  | ||||
| 	InnerText() String | ||||
| 		InnerText() String | ||||
|  | ||||
| 	InnerHtml() String | ||||
| 		InnerHtml() String | ||||
|  | ||||
| 	Value() core.Value | ||||
| 		Value() core.Value | ||||
|  | ||||
| 	GetAttributes() core.Value | ||||
| 		GetAttributes() core.Value | ||||
|  | ||||
| 	GetAttribute(name String) core.Value | ||||
| 		GetAttribute(name String) core.Value | ||||
|  | ||||
| 	GetChildNodes() core.Value | ||||
| 		GetChildNodes() core.Value | ||||
|  | ||||
| 	GetChildNode(idx Int) core.Value | ||||
| 		GetChildNode(idx Int) core.Value | ||||
|  | ||||
| 	QuerySelector(selector String) core.Value | ||||
| 		QuerySelector(selector String) core.Value | ||||
|  | ||||
| 	QuerySelectorAll(selector String) core.Value | ||||
| } | ||||
| 		QuerySelectorAll(selector String) core.Value | ||||
| 	} | ||||
|  | ||||
| 	HtmlDocument interface { | ||||
| 		HtmlNode | ||||
|  | ||||
| 		Url() core.Value | ||||
| 	} | ||||
| ) | ||||
|   | ||||
| @@ -91,3 +91,32 @@ func Navigate(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
|  | ||||
| 	return values.None, doc.Navigate(args[1].(values.String)) | ||||
| } | ||||
|  | ||||
| func Input(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 2, 3) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	// TYPE(el, "foobar") | ||||
| 	if len(args) == 2 { | ||||
| 		arg1 := args[0] | ||||
|  | ||||
| 		err := core.ValidateType(arg1, core.HtmlElementType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return values.False, err | ||||
| 		} | ||||
|  | ||||
| 		el, ok := arg1.(*dynamic.HtmlElement) | ||||
|  | ||||
| 		if !ok { | ||||
| 			return values.False, core.Error(core.ErrInvalidType, "expected dynamic element") | ||||
| 		} | ||||
|  | ||||
| 		return values.None, el.Input(args[1], values.NewInt(100)) | ||||
| 	} | ||||
|  | ||||
| 	return values.None, nil | ||||
| } | ||||
|   | ||||
| @@ -15,7 +15,6 @@ import ( | ||||
| 	"github.com/mafredri/cdp/protocol/page" | ||||
| 	"github.com/mafredri/cdp/rpcc" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
| @@ -25,7 +24,7 @@ type HtmlDocument struct { | ||||
| 	conn    *rpcc.Conn | ||||
| 	client  *cdp.Client | ||||
| 	events  *events.EventBroker | ||||
| 	url     string | ||||
| 	url     values.String | ||||
| 	element *HtmlElement | ||||
| } | ||||
|  | ||||
| @@ -132,7 +131,7 @@ func NewHtmlDocument( | ||||
| 	doc.url = "" | ||||
|  | ||||
| 	if root.BaseURL != nil { | ||||
| 		doc.url = *root.BaseURL | ||||
| 		doc.url = values.NewString(*root.BaseURL) | ||||
| 	} | ||||
|  | ||||
| 	broker.AddEventListener("load", func(_ interface{}) { | ||||
| @@ -154,7 +153,7 @@ func NewHtmlDocument( | ||||
| 		doc.url = "" | ||||
|  | ||||
| 		if updated.BaseURL != nil { | ||||
| 			doc.url = *updated.BaseURL | ||||
| 			doc.url = values.NewString(*updated.BaseURL) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| @@ -176,7 +175,7 @@ func (doc *HtmlDocument) String() string { | ||||
| 	doc.Lock() | ||||
| 	defer doc.Unlock() | ||||
|  | ||||
| 	return doc.url | ||||
| 	return doc.url.String() | ||||
| } | ||||
|  | ||||
| func (doc *HtmlDocument) Unwrap() interface{} { | ||||
| @@ -213,7 +212,7 @@ func (doc *HtmlDocument) Compare(other core.Value) int { | ||||
| 	case core.HtmlDocumentType: | ||||
| 		other := other.(*HtmlDocument) | ||||
|  | ||||
| 		return strings.Compare(doc.url, other.url) | ||||
| 		return doc.url.Compare(other.url) | ||||
| 	default: | ||||
| 		if other.Type() > core.HtmlDocumentType { | ||||
| 			return -1 | ||||
| @@ -320,6 +319,10 @@ func (doc *HtmlDocument) QuerySelectorAll(selector values.String) core.Value { | ||||
| 	return doc.element.QuerySelectorAll(selector) | ||||
| } | ||||
|  | ||||
| func (doc *HtmlDocument) Url() core.Value { | ||||
| 	return doc.url | ||||
| } | ||||
|  | ||||
| func (doc *HtmlDocument) ClickBySelector(selector values.String) (values.Boolean, error) { | ||||
| 	res, err := eval.Eval( | ||||
| 		doc.client, | ||||
|   | ||||
| @@ -164,11 +164,17 @@ func (el *HtmlElement) MarshalJSON() ([]byte, error) { | ||||
| 	el.Lock() | ||||
| 	defer el.Unlock() | ||||
|  | ||||
| 	return json.Marshal(el.innerHtml) | ||||
| 	val, err := el.innerText.Value() | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return json.Marshal(val.String()) | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) String() string { | ||||
| 	return el.value.String() | ||||
| 	return el.InnerHtml().String() | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) Compare(other core.Value) int { | ||||
| @@ -372,6 +378,13 @@ func (el *HtmlElement) Click() (values.Boolean, error) { | ||||
| 	return events.DispatchEvent(ctx, el.client, el.id, "click") | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) Input(value core.Value, timeout values.Int) error { | ||||
| 	ctx, cancel := contextWithTimeout() | ||||
| 	defer cancel() | ||||
|  | ||||
| 	return el.client.DOM.SetAttributeValue(ctx, dom.NewSetAttributeValueArgs(el.id, "value", value.String())) | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) IsConnected() values.Boolean { | ||||
| 	el.Lock() | ||||
| 	defer el.Unlock() | ||||
|   | ||||
| @@ -2,12 +2,13 @@ package static | ||||
|  | ||||
| import ( | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"github.com/PuerkitoBio/goquery" | ||||
| ) | ||||
|  | ||||
| type HtmlDocument struct { | ||||
| 	*HtmlElement | ||||
| 	url string | ||||
| 	url values.String | ||||
| } | ||||
|  | ||||
| func NewHtmlDocument( | ||||
| @@ -28,7 +29,7 @@ func NewHtmlDocument( | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &HtmlDocument{el, url}, nil | ||||
| 	return &HtmlDocument{el, values.NewString(url)}, nil | ||||
| } | ||||
|  | ||||
| func (el *HtmlDocument) Type() core.Type { | ||||
| @@ -38,8 +39,9 @@ func (el *HtmlDocument) Type() core.Type { | ||||
| func (el *HtmlDocument) Compare(other core.Value) int { | ||||
| 	switch other.Type() { | ||||
| 	case core.HtmlDocumentType: | ||||
| 		// TODO: complete the comparison | ||||
| 		return -1 | ||||
| 		otherDoc := other.(values.HtmlDocument) | ||||
|  | ||||
| 		return el.url.Compare(otherDoc.Url()) | ||||
| 	default: | ||||
| 		if other.Type() > core.HtmlDocumentType { | ||||
| 			return -1 | ||||
| @@ -48,3 +50,7 @@ func (el *HtmlDocument) Compare(other core.Value) int { | ||||
| 		return 1 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (el *HtmlDocument) Url() core.Value { | ||||
| 	return el.url | ||||
| } | ||||
|   | ||||
| @@ -24,13 +24,7 @@ func NewHtmlElement(node *goquery.Selection) (*HtmlElement, error) { | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) MarshalJSON() ([]byte, error) { | ||||
| 	html, err := el.selection.Html() | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return json.Marshal(html) | ||||
| 	return json.Marshal(el.InnerText().String()) | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) Type() core.Type { | ||||
| @@ -38,7 +32,7 @@ func (el *HtmlElement) Type() core.Type { | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) String() string { | ||||
| 	return el.selection.Text() | ||||
| 	return el.InnerHtml().String() | ||||
| } | ||||
|  | ||||
| func (el *HtmlElement) Compare(other core.Value) int { | ||||
|   | ||||
| @@ -12,5 +12,6 @@ func NewLib() map[string]core.Function { | ||||
| 		"WAIT_NAVIGATION": WaitNavigation, | ||||
| 		"CLICK":           Click, | ||||
| 		"NAVIGATE":        Navigate, | ||||
| 		"INPUT":           Input, | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user