public static call ElementSelected(this call kall, obj env) { var lastCall = env.trace.Last(); if (lastCall.name == "sel" || lastCall.name == "id") { return(kall); throw ObjException.MissingElementAndCalled(kall); } return(kall); }
public static obj TopLevel() { var topLevel = new obj(); BrowsingContext ctx = new BrowsingContext(Configuration.Default.WithDefaultLoader()); IDocument dom = null; IElement el = null; topLevel.funcs["true"] = async(kall) => { Ensure.ArityMatches(kall, 0).NoBlock(); topLevel.result = true; return(true); }; topLevel.funcs["false"] = async(kall) => { Ensure.ArityMatches(kall, 0).NoBlock(); topLevel.result = false; return(true); }; topLevel.funcs["out"] = async(kall) => { Ensure.ArityMatches(kall, 1); topLevel.Output[kall.args[0]] = topLevel.result; topLevel.result = null; return(false); }; topLevel.funcs["all"] = async(kall) => { Ensure.HasBlock(kall); foreach (call k in kall.block.calls) { await topLevel.eval(k); if (topLevel.resultSet && topLevel.result is false) { topLevel.result = false; return(false); } } // If we didn't find any results set to false, it then set result to true topLevel.result = true; return(false); }; topLevel.funcs["any"] = async(kall) => { Ensure.HasBlock(kall); foreach (call k in kall.block.calls) { await topLevel.eval(k); if (topLevel.resultSet && topLevel.result is true) { return(false); } } // If we didn't find any truthy values, then topLevel.result = false; return(false); }; topLevel.funcs["none"] = async(kall) => { Ensure.ArityMatches(kall, 0).HasBlock(); foreach (call k in kall.block.calls) { await topLevel.eval(k); if (topLevel.resultSet && topLevel.result is true) { topLevel.result = false; return(false); } } // If we didn't find any truthy values, then this was true topLevel.result = true; return(false); }; topLevel.funcs["has-text"] = async(kall) => { Ensure.ArityMatches(kall, 1).NoBlock().ElementSelected(topLevel); topLevel.result = el.TextContent.Contains(kall.args[0]); return(true); }; topLevel.funcs["sel"] = async(kall) => { Ensure.ArityMatches(kall, 1).NoBlock().DomBuilt(dom); el = dom.QuerySelector(kall.args[0]); return(false); }; topLevel.funcs["id"] = async(kall) => { Ensure.ArityMatches(kall, 1).DomBuilt(dom).NoBlock(); el = dom.GetElementById(kall.args[0]); return(false); }; topLevel.funcs["site"] = async(kall) => { Ensure.ArityMatches(kall, 1); dom = await ctx.OpenAsync(kall.args[0]); var outName = kall.block?.calls?.FirstOrDefault(x => x.name == "out")?.args?[0] ?? kall.args[0]; if (dom == null) { var failMsg = ObjException.UrlFailed(kall).Message; topLevel.Output[$"{outName}-error"] = failMsg; topLevel.Output[outName] = false; return(false); } if (kall.block != null) { try { await kall.block.eval(topLevel); } catch (ObjException) { // This sort of exception needs to pass through, since it indicates code is constructed incorrectly. throw; } catch (Exception ex) { topLevel.Output[$"{outName}-error"] = ex.Message; // In this case, we don't know if the site is up or down, // just that something went wrong topLevel.Output[outName] = null; return(false); } } return(false); }; return(topLevel); }