UNPKG

82.8 kBapplication/x-httpd-phpView Raw
1<?php
2
3/* PARSER SCRIPT FOR TAGUI FRAMEWORK ~ TEBEL.ORG */
4
5// check flow filename for .tagui or .js or .txt or no extension
6$script = $argv[1]; if ($script=="") die("ERROR - specify flow filename as first parameter\n");
7if (strpos(pathinfo($script, PATHINFO_BASENAME), '.') !== false) // check if file has extension
8if ((pathinfo($script, PATHINFO_EXTENSION)!="gui") and (pathinfo($script, PATHINFO_EXTENSION)!="txt") and (pathinfo($script, PATHINFO_EXTENSION)!="js") and (pathinfo($script, PATHINFO_EXTENSION)!="tagui"))
9die("ERROR - use .tagui .js .txt or no extension for flow filename\n");
10
11// make sure required files are available and can be opened
12if (!file_exists($script)) die("ERROR - cannot find " . $script . "\n");
13$input_file = fopen($script,'r') or die("ERROR - cannot open " . $script . "\n");
14$output_file = fopen($script . '.js','w') or die("ERROR - cannot open " . $script . '.js' . "\n");
15$config_file = fopen('tagui_config.txt','r') or die("ERROR - cannot open tagui_config.txt" . "\n");
16$header_file = fopen('tagui_header.js','r') or die("ERROR - cannot open tagui_header.js" . "\n");
17$footer_file = fopen('tagui_footer.js','r') or die("ERROR - cannot open tagui_footer.js" . "\n");
18
19$repo_count = 0; if (file_exists(getenv('custom_csv_file'))) { // load datatable or legacy datatable / repository
20$repo_file = fopen(getenv('custom_csv_file'),'r') or die("ERROR - cannot open " . getenv('custom_csv_file') . "\n");
21while (!feof($repo_file)) {$repo_data[$repo_count] = fgetcsv($repo_file);
22if (count($repo_data[$repo_count]) == 0) die("ERROR - empty row found in " . getenv('custom_csv_file') . "\n");
23$repo_count++;} fclose($repo_file); $repo_count-=1; //-1 for header, for EOF need to check flexibly using below line
24if (count($repo_data[$repo_count]) == 1) $repo_count-=1;} //-1 for EOF (Windows files don't end with newline character)
25
26$local_repo_location = str_replace("\\","/",dirname($script)) . '/tagui_local.csv';
27if (file_exists($local_repo_location)) { // load local repository file if it exists for objects and keywords
28$local_repo_file = fopen($local_repo_location,'r') or die("ERROR - cannot open " . 'tagui_local.csv' . "\n");
29if ($repo_count != 0) $repo_count++; fgetcsv($local_repo_file); // +1 if array has data, discard header record
30while (!feof($local_repo_file)) {$repo_data[$repo_count] = fgetcsv($local_repo_file);
31if (count($repo_data[$repo_count]) == 0) die("ERROR - empty row found in " . 'tagui_local.csv' . "\n");
32if (count($repo_data[$repo_count]) != 1) // pad the empty columns when local repository is used with datatable
33{$repo_data[$repo_count] = array_pad($repo_data[$repo_count], count($repo_data[0]), $repo_data[$repo_count][1]);}
34$repo_count++;} fclose($local_repo_file); $repo_count-=1; if (count($repo_data[$repo_count]) == 1) $repo_count-=1;}
35
36if (file_exists('tagui_global.csv')) { // load global repository file if it exists for objects and keywords
37$global_repo_file = fopen('tagui_global.csv','r') or die("ERROR - cannot open " . 'tagui_global.csv' . "\n");
38if ($repo_count != 0) $repo_count++; fgetcsv($global_repo_file); // +1 if array has data, discard header record
39while (!feof($global_repo_file)) {$repo_data[$repo_count] = fgetcsv($global_repo_file);
40if (count($repo_data[$repo_count]) == 0) die("ERROR - empty row found in " . 'tagui_global.csv' . "\n");
41if (count($repo_data[$repo_count]) != 1) // pad the empty columns when global repository is used with datatable
42{$repo_data[$repo_count] = array_pad($repo_data[$repo_count], count($repo_data[0]), $repo_data[$repo_count][1]);}
43$repo_count++;} fclose($global_repo_file); $repo_count-=1; if (count($repo_data[$repo_count]) == 1) $repo_count-=1;}
44
45$tagui_web_browser = "this"; // set the web browser to be used base on tagui_web_browser environment variable
46if ((getenv('tagui_web_browser')=='headless') or (getenv('tagui_web_browser')=='chrome')) $tagui_web_browser = 'chrome';
47
48$inside_code_block = 0; // track if step or code is inside user-defined code block
49$inside_while_loop = 0; // track if step is in while loop and avoid async wait
50$for_loop_tracker = ""; // track for loop to implement IIFE pattern
51$code_block_tracker = ""; // track code blocks defined in flow
52$integration_block_body = ""; // track body of integration block
53$line_number = 0; // track flow line number for error message
54$real_line_number = 0; // line number excluding comments and blank lines
55$test_automation = 0; // to determine casperjs script structure
56$url_provided = false; // to detect if url is provided in user-script
57
58// track begin-finish blocks for integrations eg - py, r, run, vision, js, dom
59$inside_py_block = 0; $inside_r_block = 0; $inside_run_block = 0;
60$inside_vision_block = 0; $inside_js_block = 0; $inside_dom_block = 0;
61
62// series of loops to create casperjs script from header, user flow, footer files
63
64// create header of casperjs script using tagui config and header template
65fwrite($output_file,"/* OUTPUT CASPERJS SCRIPT FOR TAGUI FRAMEWORK ~ TEBEL.ORG */\n\n");
66fwrite($output_file,"var casper = require('casper').create();\n"); // opening lines
67while(!feof($config_file)) {fwrite($output_file,fgets($config_file));} fclose($config_file);
68while(!feof($header_file)) {fwrite($output_file,fgets($header_file));} fclose($header_file);
69
70// append global functions file created by user if the file exists
71if (file_exists('tagui_global.js')) {
72$global_functions_file = fopen('tagui_global.js','r') or die("ERROR - cannot open tagui_global.js" . "\n");
73while(!feof($global_functions_file)) {fwrite($output_file,fgets($global_functions_file));}
74fwrite($output_file,"\n"); fclose($global_functions_file);}
75
76// append local functions file created by user if the file exists
77$local_functions_location = str_replace("\\","/",dirname($script)) . '/tagui_local.js';
78if (file_exists($local_functions_location)) {
79$local_functions_file = fopen($local_functions_location,'r') or die("ERROR - cannot open tagui_local.js" . "\n");
80while(!feof($local_functions_file)) {fwrite($output_file,fgets($local_functions_file));}
81fwrite($output_file,"\n"); fclose($local_functions_file);}
82
83// append comment on flow path variable in casperjs script
84fwrite($output_file,"// flow path for save_text and snap_image\n");
85
86// save flow path in casperjs script to be used by save_text and snap_image
87// casperjs/phantomjs do not seem to support \ for windows paths, replace with / to work
88// below marker for appending url_intent when flow file does not start with comments or url
89$marker_for_opening_url = "var flow_path = '" . str_replace("\\","/",dirname($script)) . "';\n\n";
90fwrite($output_file,$marker_for_opening_url);
91
92// section to handle calling of other TagUI automation scripts for reusability
93$temp_output_file = fopen($script . '.raw','w') or die("ERROR - cannot open " . $script . '.raw' . "\n");
94while(!feof($input_file)) {fwrite($temp_output_file,expand_intent(fgets($input_file)));} fclose($input_file);
95fclose($temp_output_file); // generate temp output file of expanded intents (if any) before reopening as input
96$input_file = fopen($script . '.raw','r') or die("ERROR - cannot open " . $script . '.raw' . "\n");
97
98if (strpos(strtolower(file_get_contents('tagui_config.txt')),"var tagui_language = 'english';")==false)
99{ // section which includes translation engine for handling flows in other languages
100$temp_argv1 = $argv[1]; $temp_argv2 = $argv[2]; $temp_argv3 = $argv[3];
101$argv[1] = 'tagui_parse.php'; $argv[2] = 'from';
102$temp_tagui_config = strtolower(file_get_contents('tagui_config.txt'));
103$temp_tagui_config_start = strpos($temp_tagui_config,'var tagui_language');
104$temp_tagui_config_end = strpos($temp_tagui_config,"\n",$temp_tagui_config_start);
105$temp_tagui_config = substr($temp_tagui_config,$temp_tagui_config_start,$temp_tagui_config_end-$temp_tagui_config_start);
106$temp_tagui_config = str_replace('var tagui_language','',$temp_tagui_config);
107$temp_tagui_config = str_replace('"','',$temp_tagui_config); $temp_tagui_config = str_replace("'",'',$temp_tagui_config);
108$temp_tagui_config = str_replace('=','',$temp_tagui_config); $temp_tagui_config = str_replace(';','',$temp_tagui_config);
109$argv[3] = trim($temp_tagui_config); require 'translate.php'; // set parameters to load translation engine
110$argv[1] = $temp_argv1; $argv[2] = $temp_argv2; $argv[3] = $temp_argv3; $translated_raw_flow = "";
111while(!feof($input_file)) {$translated_raw_flow .= translate_intent(fgets($input_file));} fclose($input_file);
112file_put_contents($script . '.raw', $translated_raw_flow); // save translated output before reopening as input
113$input_file = fopen($script . '.raw','r') or die("ERROR - cannot open " . $script . '.raw' . "\n");}
114
115// section to do required pre-processing on expanded .raw flow file
116$padded_raw_flow = ""; $previous_line_is_condition = false; $reference_indentation = "";
117while(!feof($input_file)) {$padded_raw_flow_line = fgets($input_file);
118$indentation_tracker = str_replace(ltrim($padded_raw_flow_line),'',$padded_raw_flow_line);
119$indentation_tracker = substr($indentation_tracker,strlen($reference_indentation));
120// above line handles py and vision blocks that begin indented (eg in if or loops)
121$padded_raw_flow_line = ltrim($padded_raw_flow_line);
122
123// track whether line is inside integrations begin-finish code blocks
124if (strtolower(trim($padded_raw_flow_line)) == "js begin") $inside_js_block = 1;
125else if (strtolower(trim($padded_raw_flow_line)) == "js finish") $inside_js_block = 0;
126else if (strtolower(trim($padded_raw_flow_line)) == "py begin")
127{$inside_py_block = 1; $reference_indentation = $indentation_tracker;}
128else if (strtolower(trim($padded_raw_flow_line)) == "py finish")
129{$inside_py_block = 0; $reference_indentation = "";} // reset reference indentation
130else if (strtolower(trim($padded_raw_flow_line)) == "r begin") $inside_r_block = 1;
131else if (strtolower(trim($padded_raw_flow_line)) == "r finish") $inside_r_block = 0;
132else if (strtolower(trim($padded_raw_flow_line)) == "dom begin") $inside_dom_block = 1;
133else if (strtolower(trim($padded_raw_flow_line)) == "dom finish") $inside_dom_block = 0;
134else if (strtolower(trim($padded_raw_flow_line)) == "run begin") $inside_run_block = 1;
135else if (strtolower(trim($padded_raw_flow_line)) == "run finish") $inside_run_block = 0;
136else if (strtolower(trim($padded_raw_flow_line)) == "vision begin")
137{$inside_vision_block = 1; $reference_indentation = $indentation_tracker;}
138else if (strtolower(trim($padded_raw_flow_line)) == "vision finish")
139{$inside_vision_block = 0; $reference_indentation = "";} // reset reference indentation
140
141// auto-padding not relevant in integrations code blocks
142if (($inside_js_block + $inside_py_block + $inside_r_block +
143$inside_dom_block + $inside_run_block + $inside_vision_block) > 0)
144{$padded_raw_flow .= $indentation_tracker . $padded_raw_flow_line; continue;}
145
146// rewrite JS function definitions to work in scope within CasperJS blocks
147if ((substr($padded_raw_flow_line,0,9)=="function ") or (substr($padded_raw_flow_line,0,12)=="js function "))
148if (strpos($padded_raw_flow_line,"(")!==false) {$js_function_name_startpos = strpos($padded_raw_flow_line,"function ")+9;
149$js_function_name_endpos = strpos($padded_raw_flow_line,"(",$js_function_name_startpos);
150$padded_raw_flow_line = trim(substr($padded_raw_flow_line,$js_function_name_startpos,$js_function_name_endpos -
151$js_function_name_startpos)) . ' = function ' . trim(substr($padded_raw_flow_line,$js_function_name_endpos))."\n";}
152else die("ERROR - missing brackets () for ".$padded_raw_flow_line);
153// pad { and } blocks for conditions, to keep JavaScript syntax correct
154if ((substr($padded_raw_flow_line,0,3)=="if ") or (substr($padded_raw_flow_line,0,8)=="else if ")
155or (substr($padded_raw_flow_line,0,4)=="for ") or (substr($padded_raw_flow_line,0,6)=="while ") or
156(substr($padded_raw_flow_line,0,6)=="popup ") or (substr($padded_raw_flow_line,0,6)=="frame ") or
157(trim($padded_raw_flow_line)=="else")) $current_line_is_condition = true; else $current_line_is_condition = false;
158if (($previous_line_is_condition == true) and ($current_line_is_condition == true))
159die("ERROR - for nested conditions, loops, popup, frame, set { and } explicitly\n".
160"ERROR - add { before this line and add } accordingly - ".$padded_raw_flow_line);
161if (($previous_line_is_condition == true) and (substr($padded_raw_flow_line,0,1)!="{"))
162$padded_raw_flow .= "{\n".trim($padded_raw_flow_line)."\n}\n"; else $padded_raw_flow .= $padded_raw_flow_line;
163$previous_line_is_condition = $current_line_is_condition; // prepare for next line
164} fclose($input_file); file_put_contents($script . '.raw', $padded_raw_flow);
165// generate temp output file with padded { and } (if any) before reopening as input
166$input_file = fopen($script . '.raw','r') or die("ERROR - cannot open " . $script . '.raw' . "\n");
167// re-initialize trackers for begin-finish blocks of integrations
168$inside_py_block = 0; $inside_r_block = 0; $inside_run_block = 0;
169$inside_vision_block = 0; $inside_js_block = 0; $inside_dom_block = 0;
170
171// main loop to parse intents in flow file for conversion into javascript code
172while(!feof($input_file)) {fwrite($output_file,parse_intent(fgets($input_file)));} fclose($input_file);
173
174// create footer of casperjs script using footer template and do post-processing
175while(!feof($footer_file)) {fwrite($output_file,fgets($footer_file));} fclose($footer_file); fclose($output_file);
176chmod ($script . '.js',0600); // append url opening block below instead of throwing error
177if (!$url_provided) { // echo "ERROR - first line of " . $script . " not URL or comments\n";
178$GLOBALS['real_line_number'] = 1; $generated_js_file_contents = file_get_contents($script . '.js');
179$generated_js_file_contents = str_replace($marker_for_opening_url, $marker_for_opening_url .
180url_intent('about:blank'), $generated_js_file_contents); file_put_contents($script . '.js',$generated_js_file_contents);}
181if ($inside_code_block != 0) echo "ERROR - number of step { does not tally with with }\n";
182
183// post-processing to clean up artifacts from translating human language to JavaScript
184$script_content = file_get_contents($script . '.js');
185$script_content = str_replace("});\n\ncasper.then(function() {else\n","\nelse\n\n",$script_content);
186$script_content = str_replace("});\n\ncasper.then(function() {else if ","\nelse if ",$script_content);
187$script_content = str_replace("}); // end of JS code\n\ncasper.then(function() { // start of JS code\n",
188"",$script_content); // above collapse separate js step CasperJS blocks into one continuous block
189$script_content = preg_replace('/^casper\.then\(function\(\) {{(.*) \/\/ beg_tx while loop marker/m',
190'$1',$script_content); // above regular expression replace lines having beg_tx while loop markers
191$script_content = preg_replace('/^casper\.then\(function\(\) {(.*) \/\/ end_fi while loop marker(.*)}\);/m',
192'$1$2',$script_content); // above regular expression replace lines having end_fi while loop markers
193$script_content = preg_replace('/^casper\.then\(function\(\) {(.*)\n(.*) \/\/ end_fi while loop marker(.*)}\);/m',
194"$1\n$2$3",$script_content); // above regular expression replace lines having end_fi while loop markers
195file_put_contents($script . '.js',$script_content);
196
197// special handling if chrome or headless chrome is used as browser for automation
198// replacement of this.method already happens in step intents, this is mostly to handle user inserted casperjs code
199if ($tagui_web_browser == 'chrome') {$script_content = file_get_contents($script . '.js'); // read generated script
200$script_content = str_replace("var chrome_id = 0;","var chrome_id = 1;",$script_content); // websocket message id
201$script_content = str_replace("casper.exists","chrome.exists",$script_content); // change locator check to chrome
202$script_content = str_replace("this.exists","chrome.exists",$script_content); // change this.exists call as well
203$script_content = str_replace("casper.click","chrome.click",$script_content); // change click method to chrome
204$script_content = str_replace("this.click","chrome.click",$script_content); // change this.click call as well
205$script_content = str_replace("casper.mouse","chrome.mouse",$script_content); // change mouse object to chrome
206$script_content = str_replace("this.mouse","chrome.mouse",$script_content); // change this.mouse call as well
207$script_content = str_replace("casper.sendKeys","chrome.sendKeys",$script_content); // change sendKeys method to chrome
208$script_content = str_replace("this.sendKeys","chrome.sendKeys",$script_content); // change this.sendKeys call as well
209// for selectOptionByValue check for '(' in order to only overwrite calls and not the custom defined function
210$script_content = str_replace("casper.selectOptionByValue(","chrome.selectOptionByValue(",$script_content); // select
211$script_content = str_replace("this.selectOptionByValue(","chrome.selectOptionByValue(",$script_content); // select
212// for countElements check for '(' in order to only overwrite calls and not the custom function casper.countElements()
213$script_content = str_replace("casper.countElements(","chrome.countElements(",$script_content); // count elements
214$script_content = str_replace("this.countElements(","chrome.countElements(",$script_content); // count elements
215// for elementVisible check for '(' in order to only overwrite calls and not the custom function casper.elementVisible()
216$script_content = str_replace("casper.elementVisible(","chrome.elementVisible(",$script_content); // check element visible
217$script_content = str_replace("this.elementVisible(","chrome.elementVisible(",$script_content); // check element visible
218$script_content = str_replace("casper.fetchText","chrome.fetchText",$script_content); // change fetchText method to chrome
219$script_content = str_replace("this.fetchText","chrome.fetchText",$script_content); // change this.fetchText call as well
220$script_content = str_replace("casper.capture","chrome.capture",$script_content); // change capture method to chrome
221$script_content = str_replace("this.capture","chrome.capture",$script_content); // change this.capture call as well
222$script_content = str_replace("casper.captureSelector","chrome.captureSelector",$script_content); // capture selector
223$script_content = str_replace("this.captureSelector","chrome.captureSelector",$script_content); // capture selector
224$script_content = str_replace("chrome.page.uploadFile","chrome.upload",$script_content); // change upload method to chrome
225$script_content = str_replace("casper.page.uploadFile","chrome.upload",$script_content); // change upload method to chrome
226$script_content = str_replace("this.page.uploadFile","chrome.upload",$script_content); // change this.upload call as well
227$script_content = str_replace("casper.download","chrome.download",$script_content); // change download method to chrome
228$script_content = str_replace("this.download","chrome.download",$script_content); // change this.download call as well
229$script_content = str_replace("casper.evaluate","chrome.evaluate",$script_content); // change evaluate method to chrome
230$script_content = str_replace("this.evaluate","chrome.evaluate",$script_content); // change this.evaluate call as well
231$script_content = str_replace("casper.withFrame","chrome.withFrame",$script_content); // change withFrame method to chrome
232$script_content = str_replace("this.withFrame","chrome.withFrame",$script_content); // change this.withFrame call as well
233$script_content = str_replace("casper.waitForPopup","chrome.waitForPopup",$script_content); // change waitForPopup method
234$script_content = str_replace("this.waitForPopup","chrome.waitForPopup",$script_content); // change this.waitForPopup call
235$script_content = str_replace("casper.withPopup","chrome.withPopup",$script_content); // change withPopup method to chrome
236$script_content = str_replace("this.withPopup","chrome.withPopup",$script_content); // change this.withPopup call as well
237$script_content = str_replace("casper.getHTML","chrome.getHTML",$script_content); // change getHTML method to chrome
238$script_content = str_replace("this.getHTML","chrome.getHTML",$script_content); // change this.getHTML call as well
239$script_content = str_replace("casper.getTitle","chrome.getTitle",$script_content); // change getTitle method to chrome
240$script_content = str_replace("this.getTitle","chrome.getTitle",$script_content); // change this.getTitle call as well
241$script_content = str_replace("casper.getCurrentUrl","chrome.getCurrentUrl",$script_content); // get current url
242$script_content = str_replace("this.getCurrentUrl","chrome.getCurrentUrl",$script_content); // get current url
243$script_content = str_replace("casper.debugHTML","chrome.debugHTML",$script_content); // change debugHTML method to chrome
244$script_content = str_replace("this.debugHTML","chrome.debugHTML",$script_content); // change this.debugHTML call as well
245$script_content = str_replace("casper.reload","chrome.reload",$script_content); // change reload method to chrome
246$script_content = str_replace("this.reload","chrome.reload",$script_content); // change this.reload call as well
247$script_content = str_replace("casper.back","chrome.back",$script_content); // change back method to chrome
248$script_content = str_replace("this.back","chrome.back",$script_content); // change this.back call as well
249$script_content = str_replace("casper.forward","chrome.forward",$script_content); // change forward method to chrome
250$script_content = str_replace("this.forward","chrome.forward",$script_content); // change this.forward call as well
251file_put_contents($script . '.js',$script_content); // below initialise chrome integration files
252if (!touch('tagui_chrome.in')) die("ERROR - cannot initialise tagui_chrome.in\n");
253if (!touch('tagui_chrome.out')) die("ERROR - cannot initialise tagui_chrome.out\n");}
254
255// check quiet parameter to run flow quietly by only showing explicit output
256if (getenv('tagui_quiet_mode') == 'true') {$script_content = file_get_contents($script . '.js'); // read generated script
257$script_content = str_replace("var quiet_mode = false;","var quiet_mode = true;",$script_content); // set quiet_mode
258$script_content = str_replace("casper.echo('\\nSTART - automation started - ","dummy_echo('",$script_content);
259file_put_contents($script . '.js',$script_content);}
260
261// convert casperjs script into test script structure if test option is used
262if (getenv('tagui_test_mode') == 'true') {$script_content = file_get_contents($script . '.js'); // read generated script
263$script_content = str_replace("casper.echo('\\nSTART - automation started - ","casper.echo('",$script_content); // date
264$script_content = str_replace("techo('FINISH - automation","dummy_echo('FINISH - test",$script_content); // silent
265$script_content = str_replace("this.echo(","test.comment(",$script_content); // change echo to test comment
266$script_content = str_replace("test.comment('ERROR","test.fail('ERROR",$script_content); // error comment to fail
267// change echo to test comment in techo to show output correctly as test comments
268$script_content = str_replace("casper.echo(echo_string);","casper.test.comment(echo_string);",$script_content);
269$script_content = str_replace("casper.echo(translated_string);","casper.test.comment(translated_string);",$script_content);
270$script_content = str_replace("\\n'","'",str_replace("'\\n","'",$script_content)); // compact test output
271// casperjs testing does not allow creation of casper object as it is already created by test engine
272$script_content = str_replace("var casper = require(","// var casper = require(",$script_content);
273// following help to define the script structure required by casperjs for test automation purpose
274$script_content = str_replace("casper.start(","casper.test.begin('" . str_replace("\\","\\\\",$script) . "', " .
275$test_automation.", function(test) {\ncasper.start(",$script_content); // define required casperjs test structure
276$script_content = str_replace("casper.run();","casper.run(function() {test.done();});});",$script_content);
277file_put_contents($script . '.js',$script_content);} // save script after restructuring for testing
278
279// otherwise prep for normal execution by commenting out test assertions as they will kill the script
280else if ($test_automation > 0) {$script_content = file_get_contents($script . '.js'); // read generated script
281$script_content = str_replace("test.","// test.",$script_content); file_put_contents($script . '.js',$script_content);}
282
283function expand_intent($script_line) { // function to handle calling of other TagUI automation scripts for reusability
284if ((strpos(strtolower(trim($script_line)),'tagui ') === 0) or (strtolower(trim($script_line)) == 'tagui')) {
285$params = trim(substr(trim($script_line)." ",1+strpos(trim($script_line)." "," "))); if ($params == "")
286die("ERROR - filename missing for step " . trim($script_line) . "\n");
287else if (!file_exists(abs_file($params)))
288die("ERROR - file not found for step " . trim($script_line) . "\n");
289else {$expanded_intent = ""; $temp_input_file = fopen(abs_file($params),'r'); if ($temp_input_file == false)
290die("ERROR - cannot open file for step " . trim($script_line) . "\n");
291while(!feof($temp_input_file)) {$expanded_intent .= expand_intent(fgets($temp_input_file));} fclose($temp_input_file);
292return $expanded_intent;}} else return rtrim($script_line) . "\n";}
293
294function current_line() {return "[LINE " . $GLOBALS['line_number'] . "]";}
295
296function parse_intent($script_line) {$GLOBALS['line_number']++; $GLOBALS['real_line_number']++;
297$indentation_tracker = str_replace(ltrim($script_line),'',$script_line); // tracking for py and vision
298$script_line = trim($script_line); if ($script_line=="") {$GLOBALS['real_line_number']--; return "";}
299$script_line = parse_backticks($script_line); // below check again after replacing repository definitions
300$script_line = trim($script_line); if ($script_line=="") {$GLOBALS['real_line_number']--; return "";}
301// below use buffer to handle integration code blocks if inside integration code block
302$intent_type = get_intent($script_line); if ($intent_type == "integration_block")
303{$GLOBALS['integration_block_body'] .= $indentation_tracker . $script_line ."[END_OF_LINE]"; return "";}
304else {$script_line = parse_closure($script_line); return process_intent($intent_type, $script_line);}}
305
306function parse_backticks($script_line) {
307// check existence of objects or keywords by searching for `object or keyword name`, then expand from repository
308// check for even number of ` to reduce false-positive because backtick syntax is supposed to be matching pairs
309if ((substr_count($script_line,'`') > 1) and (!(substr_count($script_line,'`') & 1))) {
310 if ($GLOBALS['repo_count'] == 0) {
311 $script_line = parse_variables($script_line);
312 } else {
313 if (getenv('tagui_data_set')!==false) {
314 $data_set = intval(getenv('tagui_data_set'));
315 } else {
316 $data_set = 1;
317 }
318 $escaped_line_ends = ["\n" => "\\n", "\r" => "\\r"];
319 // loop through repository data to search and replace definitions, do it twice to handle objects within keywords
320 for ($repo_check = 0; $repo_check <= $GLOBALS['repo_count']; $repo_check++) {
321 $repo_keyword = "`".$GLOBALS['repo_data'][$repo_check][0]."`";
322 $repo_data_value = strtr($GLOBALS['repo_data'][$repo_check][$data_set], $escaped_line_ends);
323 $script_line = str_replace($repo_keyword, $repo_data_value, $script_line);
324 }
325 for ($repo_check = 0; $repo_check <= $GLOBALS['repo_count']; $repo_check++) {
326 $repo_keyword = "`".$GLOBALS['repo_data'][$repo_check][0]."`";
327 $repo_data_value = strtr($GLOBALS['repo_data'][$repo_check][$data_set], $escaped_line_ends);
328 $script_line = str_replace($repo_keyword, $repo_data_value, $script_line);
329 }
330 if (strpos($script_line,'`')!==false) {
331 $script_line = parse_variables($script_line);
332 }
333 }
334} return $script_line;}
335
336function parse_variables($script_line) { // `variable` --> '+variable+'
337$quote_token = "'+"; // token to alternate replacements for '+variable+'
338for ($char_counter = 0; $char_counter < strlen($script_line); $char_counter++) {
339 if (substr($script_line,$char_counter,1) == "`") {
340 $script_line = substr_replace($script_line,$quote_token,$char_counter,1);
341 if ($quote_token == "'+") $quote_token = "+'"; else $quote_token = "'+";
342 }
343} return $script_line;}
344
345function parse_closure($script_line) {switch($script_line) {
346// \\n is needed for py, r, vision as multi-line string needs to have \n escaped to work in javascript
347// replacement code for [END_OF_LINE] custom token to denote line break is done at py, r, vision intents
348case "py finish":
349{$script_line = substr($GLOBALS['integration_block_body'],0,-13); $GLOBALS['inside_py_block'] = 0; break;}
350case "r finish":
351{$script_line = substr($GLOBALS['integration_block_body'],0,-13); $GLOBALS['inside_r_block'] = 0;
352$script_line = str_replace(";; ","; ",str_replace("[END_OF_LINE]","; ",$GLOBALS['integration_block_body'])); break;}
353case "vision finish":
354{$script_line = substr($GLOBALS['integration_block_body'],0,-13); $GLOBALS['inside_vision_block'] = 0; break;}
355case "js finish":
356{$script_line = str_replace("[END_OF_LINE]", "\n", $GLOBALS['integration_block_body']); $GLOBALS['inside_js_block'] = 0; break;}
357case "dom finish":
358{$script_line = str_replace("[END_OF_LINE]", "\n", $GLOBALS['integration_block_body']); $GLOBALS['inside_dom_block'] = 0; break;}}
359return $script_line;}
360
361function process_intent($intent_type, $script_line) {
362// check intent of step for interpretation into casperjs code
363switch ($intent_type) {
364case "url": return url_intent($script_line); break;
365case "tap": return tap_intent($script_line); break;
366case "rtap": return rtap_intent($script_line); break;
367case "dtap": return dtap_intent($script_line); break;
368case "hover": return hover_intent($script_line); break;
369case "type": return type_intent($script_line); break;
370case "select": return select_intent($script_line); break;
371case "read": return read_intent($script_line); break;
372case "show": return show_intent($script_line); break;
373case "upload": return upload_intent($script_line); break;
374case "down": return down_intent($script_line); break;
375case "receive": return receive_intent($script_line); break;
376case "echo": return echo_intent($script_line); break;
377case "save": return save_intent($script_line); break;
378case "dump": return dump_intent($script_line); break;
379case "write": return write_intent($script_line); break;
380case "load": return load_intent($script_line); break;
381case "snap": return snap_intent($script_line); break;
382case "table": return table_intent($script_line); break;
383case "wait": return wait_intent($script_line); break;
384case "live": return live_intent($script_line); break;
385case "ask": return ask_intent($script_line); break;
386case "check": return check_intent($script_line); break;
387case "test": return test_intent($script_line); break;
388case "frame": return frame_intent($script_line); break;
389case "popup": return popup_intent($script_line); break;
390case "api": return api_intent($script_line); break;
391case "run": return run_intent($script_line); break;
392case "dom": return dom_intent($script_line); break;
393case "js": return js_intent($script_line); break;
394case "r": return r_intent($script_line); break;
395case "py": return py_intent($script_line); break;
396case "vision": return vision_intent($script_line); break;
397case "timeout": return timeout_intent($script_line); break;
398case "code": return code_intent($script_line); break;
399default: echo "ERROR - " . current_line() . " cannot understand step " . $script_line . "\n";}}
400
401function get_intent($raw_intent) {$lc_raw_intent = strtolower($raw_intent);
402//check for a finish command and return, so we don't accidentally count it as a block intent
403if ($lc_raw_intent == "py finish") return "py"; if ($lc_raw_intent == "r finish") return "r";
404if ($lc_raw_intent == "vision finish") return "vision"; if ($lc_raw_intent == "js finish") return "js";
405if ($lc_raw_intent == "dom finish") return "dom";
406
407if ($GLOBALS['inside_py_block'] != 0 || $GLOBALS['inside_r_block'] != 0 ||
408$GLOBALS['inside_vision_block'] != 0 || $GLOBALS['inside_js_block'] != 0 ||
409$GLOBALS['inside_dom_block'] != 0) return "integration_block";
410if ($GLOBALS['inside_run_block'] != 0) return "run";
411
412if ((substr($lc_raw_intent,0,7)=="http://") or (substr($lc_raw_intent,0,8)=="https://") or (substr($lc_raw_intent,0,11)=="about:blank")) return "url"; // recognizing about:blank as valid URL as it is part of HTML5 standard
413
414// first set of conditions check for valid keywords with their parameters
415if ((substr($lc_raw_intent,0,4)=="tap ") or (substr($lc_raw_intent,0,6)=="click ")) return "tap";
416if ((substr($lc_raw_intent,0,5)=="rtap ") or (substr($lc_raw_intent,0,7)=="rclick ")) return "rtap";
417if ((substr($lc_raw_intent,0,5)=="dtap ") or (substr($lc_raw_intent,0,7)=="dclick ")) return "dtap";
418if ((substr($lc_raw_intent,0,6)=="hover ")or(substr($lc_raw_intent,0,5)=="move ")) return "hover";
419if ((substr($lc_raw_intent,0,5)=="type ") or (substr($lc_raw_intent,0,6)=="enter ")) return "type";
420if ((substr($lc_raw_intent,0,7)=="select ") or (substr($lc_raw_intent,0,7)=="choose ")) return "select";
421if ((substr($lc_raw_intent,0,5)=="read ") or (substr($lc_raw_intent,0,6)=="fetch ")) return "read";
422if ((substr($lc_raw_intent,0,5)=="show ") or (substr($lc_raw_intent,0,6)=="print ")) return "show";
423if ((substr($lc_raw_intent,0,3)=="up ") or (substr($lc_raw_intent,0,7)=="upload ")) return "upload";
424if ((substr($lc_raw_intent,0,5)=="down ") or (substr($lc_raw_intent,0,9)=="download ")) return "down";
425if (substr($lc_raw_intent,0,8)=="receive ") return "receive";
426if (substr($lc_raw_intent,0,5)=="echo ") return "echo";
427if (substr($lc_raw_intent,0,5)=="save ") return "save";
428if (substr($lc_raw_intent,0,5)=="dump ") return "dump";
429if (substr($lc_raw_intent,0,6)=="write ") return "write";
430if (substr($lc_raw_intent,0,5)=="load ") return "load";
431if (substr($lc_raw_intent,0,5)=="snap ") return "snap";
432if (substr($lc_raw_intent,0,6)=="table ") return "table";
433if (substr($lc_raw_intent,0,5)=="wait ") return "wait";
434if (substr($lc_raw_intent,0,5)=="live ") return "live";
435if (substr($lc_raw_intent,0,4)=="ask ") return "ask";
436if (substr($lc_raw_intent,0,6)=="check ") {$GLOBALS['test_automation']++; return "check";}
437if (substr($lc_raw_intent,0,5)=="test ") return "test";
438if (substr($lc_raw_intent,0,6)=="frame ") return "frame";
439if (substr($lc_raw_intent,0,6)=="popup ") return "popup";
440if (substr($lc_raw_intent,0,4)=="api ") return "api";
441if (substr($lc_raw_intent,0,4)=="run ") return "run";
442if (substr($lc_raw_intent,0,4)=="dom ") return "dom";
443if (substr($lc_raw_intent,0,3)=="js ") return "js";
444if (substr($lc_raw_intent,0,2)=="r ") return "r";
445if (substr($lc_raw_intent,0,3)=="py ") return "py";
446if (substr($lc_raw_intent,0,7)=="vision ") return "vision";
447if (substr($lc_raw_intent,0,8)=="timeout ") return "timeout";
448
449// second set of conditions check for valid keywords with missing parameters
450if (($lc_raw_intent=="tap") or ($lc_raw_intent=="click")) return "tap";
451if (($lc_raw_intent=="rtap") or ($lc_raw_intent=="rclick")) return "rtap";
452if (($lc_raw_intent=="dtap") or ($lc_raw_intent=="dclick")) return "dtap";
453if (($lc_raw_intent=="hover") or ($lc_raw_intent=="move")) return "hover";
454if (($lc_raw_intent=="type") or ($lc_raw_intent=="enter")) return "type";
455if (($lc_raw_intent=="select") or ($lc_raw_intent=="choose")) return "select";
456if (($lc_raw_intent=="read") or ($lc_raw_intent=="fetch")) return "read";
457if (($lc_raw_intent=="show") or ($lc_raw_intent=="print")) return "show";
458if (($lc_raw_intent=="up") or ($lc_raw_intent=="upload")) return "upload";
459if (($lc_raw_intent=="down") or ($lc_raw_intent=="download")) return "down";
460if ($lc_raw_intent=="receive") return "receive";
461if ($lc_raw_intent=="echo") return "echo";
462if ($lc_raw_intent=="save") return "save";
463if ($lc_raw_intent=="dump") return "dump";
464if ($lc_raw_intent=="write") return "write";
465if ($lc_raw_intent=="load") return "load";
466if ($lc_raw_intent=="snap") return "snap";
467if ($lc_raw_intent=="table") return "table";
468if ($lc_raw_intent=="wait") return "wait";
469if ($lc_raw_intent=="live") return "live";
470if ($lc_raw_intent=="ask") return "ask";
471if ($lc_raw_intent=="check") {$GLOBALS['test_automation']++; return "check";}
472if ($lc_raw_intent=="test") return "test";
473if ($lc_raw_intent=="frame") return "frame";
474if ($lc_raw_intent=="popup") return "popup";
475if ($lc_raw_intent=="api") return "api";
476if ($lc_raw_intent=="run") return "run";
477if ($lc_raw_intent=="dom") return "dom";
478if ($lc_raw_intent=="js") return "js";
479if ($lc_raw_intent=="r") return "r";
480if ($lc_raw_intent=="py") return "py";
481if ($lc_raw_intent=="vision") return "vision";
482if ($lc_raw_intent=="timeout") return "timeout";
483
484// final check for recognized code before returning error
485if (is_code($raw_intent)) return "code"; else return "error";}
486
487function is_code($raw_intent) {
488// due to asynchronous waiting for element, if/for/while can work for parsing single step
489// other scenarios can be assumed to behave as unparsed javascript in casperjs context
490// to let if/for/while handle multiple steps/code use the { and } steps to define block
491if ((substr($raw_intent,0,4)=="var ") or (substr($raw_intent,0,3)=="do ")) return true;
492if ((substr($raw_intent,0,1)=="{") or (substr($raw_intent,0,1)=="}")) return true;
493if ((substr($raw_intent,-1)=="{") or (substr($raw_intent,-1)=="}")) return true;
494if ((substr($raw_intent,0,3)=="if ") or (substr($raw_intent,0,4)=="else")) return true;
495if ((substr($raw_intent,0,4)=="for ") or (substr($raw_intent,0,6)=="while ")) return true;
496if ((substr($raw_intent,0,7)=="switch ") or (substr($raw_intent,0,5)=="case ")) return true;
497if ((substr($raw_intent,0,6)=="break;") or ($raw_intent=="break")) return true;
498if ((substr($raw_intent,0,9)=="continue;") or ($raw_intent=="continue")) return true;
499if ((substr($raw_intent,0,7)=="casper.") or (substr($raw_intent,0,5)=="this.")) return true;
500if (substr($raw_intent,0,7)=="chrome.") return true; // chrome object for chrome integration
501if (substr($raw_intent,0,5)=="test.") {$GLOBALS['test_automation']++; return true;}
502if (substr($raw_intent,0,2)=="//") {$GLOBALS['real_line_number']--; return true;}
503if (substr($raw_intent,-1)==";") return true; if (substr($raw_intent,0,9)=="function ") return true;
504// assume = is assignment statement, kinda acceptable as this is checked at the very end
505if (strpos($raw_intent,"=")!==false) return true; return false;}
506
507function abs_file($filename) { // helper function to return absolute filename
508if ($filename == "") return ""; $flow_script = $GLOBALS['script']; // get flow filename
509if (substr($filename,0,1)=="/") return $filename; // return mac/linux absolute filename directly
510if (substr($filename,1,1)==":") return str_replace("\\","/",$filename); // return windows absolute filename directly
511if (strpos($filename,"'+")!==false and strpos($filename,"+'")!==false)
512return "'+abs_file('" . $filename . "')+'"; // throw to runtime abs_file function if dynamic filename is given
513$flow_path = str_replace("\\","/",dirname($flow_script)); // otherwise use flow script path to build absolute filename
514// above str_replace is because casperjs/phantomjs do not seem to support \ for windows paths, replace with / to work
515if (strpos($flow_path,"/")!==false) return str_replace("\\","/",$flow_path . '/' . $filename);
516else return $flow_path . '\\' . $filename;}
517
518function beg_tx($locator) { // helper function to return beginning string for handling locators
519if ($GLOBALS['inside_while_loop'] == 0)
520return "\ncasper.waitFor(function check() {return check_tx('".$locator."');},\nfunction then() {";
521else return " // beg_tx while loop marker\n";}
522
523function end_tx($locator) { // helper function to return ending string for handling locators
524if ($GLOBALS['inside_while_loop'] == 0)
525return "},\nfunction timeout() {this.echo('ERROR - cannot find ".$locator."').exit();});}"."});".end_fi()."\n\n";
526else if ($GLOBALS['inside_code_block']==0)
527{$GLOBALS['inside_while_loop'] = 0; // reset inside_while_loop if not inside block
528$GLOBALS['for_loop_tracker'] = ""; // reset for_loop_tracker if not inside block
529return "\n";} else return "\n";}
530
531function end_fi() { // used to be a helper function primarily to end frame_intent by closing parsed step block
532if ($GLOBALS['inside_code_block'] == 0) $GLOBALS['inside_while_loop'] = 0; // reset inside_while_loop if not inside block
533if ($GLOBALS['inside_code_block'] == 0) $GLOBALS['for_loop_tracker'] = ""; // reset for_loop_tracker if not inside block
534if ($GLOBALS['inside_while_loop'] == 1) return " // end_fi while loop marker"; return "";}
535
536function add_concat($source_string) { // parse string and add missing + concatenator
537if ((strpos($source_string,"'")!==false) and (strpos($source_string,"\"")!==false))
538{echo "ERROR - " . current_line() . " inconsistent quotes in " . $source_string . "\n";}
539else if (strpos($source_string,"'")!==false) $quote_type = "'"; // derive quote type used
540else if (strpos($source_string,"\"")!==false) $quote_type = "\""; else $quote_type = "none";
541$within_quote = false; $source_string = trim($source_string); // trim for future proof
542for ($srcpos=0; $srcpos<strlen($source_string); $srcpos++) {
543if ($source_string[$srcpos] == $quote_type) $within_quote = !$within_quote;
544if (($within_quote == false) and ($source_string[$srcpos]==" ")) $source_string[$srcpos] = "+";}
545$source_string = str_replace("+++++","+",$source_string); $source_string = str_replace("++++","+",$source_string);
546$source_string = str_replace("+++","+",$source_string); $source_string = str_replace("++","+",$source_string);
547return $source_string;} // replacing multiple variations of + to handle user typos of double spaces etc
548
549function is_sikuli($input_params) { // helper function to check if input is meant for sikuli visual automation
550if (strlen($input_params)>4 and strtolower(substr($input_params,-4))=='.png') return true; // support png and bmp
551else if (strlen($input_params)>4 and strtolower(substr($input_params,-4))=='.bmp') return true; else return false;}
552
553function call_sikuli($input_intent,$input_params,$other_actions = '') { // helper function to use sikuli visual automation
554if (!touch('tagui.sikuli/tagui_sikuli.in')) die("ERROR - cannot initialise tagui_sikuli.in\n");
555if (!touch('tagui.sikuli/tagui_sikuli.out')) die("ERROR - cannot initialise tagui_sikuli.out\n");
556if ($other_actions != '') $other_actions = "\n" . $other_actions;
557return "{techo('".str_replace(' to snap_image()','',$input_intent)."'); var fs = require('fs');\n" .
558"if (!sikuli_step('".$input_intent."')) if (!fs.exists('".$input_params."'))\n" .
559"this.echo('ERROR - cannot find image file ".$input_params."').exit(); else\n" .
560"this.echo('ERROR - cannot find " . $input_params." on screen').exit(); this.wait(0);" . $other_actions. "}" .
561end_fi()."});\n\n";}
562
563function call_r($input_intent) { // helper function to use R integration for data analytics and machine learning
564if (!touch('tagui_r/tagui_r.in')) die("ERROR - cannot initialise tagui_r.in\n");
565if (!touch('tagui_r/tagui_r.out')) die("ERROR - cannot initialise tagui_r.out\n");
566return "{techo('".$input_intent."');\n" . "r_result = ''; if (!r_step('".$input_intent."'))\n" .
567"this.echo('ERROR - cannot execute R command(s)').exit(); this.wait(0);\n" .
568"r_result = fetch_r_text(); clear_r_text();\n" .
569"try {r_json = JSON.parse(r_result);} catch(e) {r_json = JSON.parse('null');}}" .
570end_fi()."});\n\n";}
571
572function call_py($input_intent) { // helper function to use Python integration for data analytics and machine learning
573if (!touch('tagui_py/tagui_py.in')) die("ERROR - cannot initialise tagui_py.in\n");
574if (!touch('tagui_py/tagui_py.out')) die("ERROR - cannot initialise tagui_py.out\n");
575return "{techo('".$input_intent."');\n" . "py_result = ''; if (!py_step('".$input_intent."'))\n" .
576"this.echo('ERROR - cannot execute Python command(s)').exit(); this.wait(0);\n" .
577"py_result = fetch_py_text(); clear_py_text();\n" .
578"try {py_json = JSON.parse(py_result);} catch(e) {py_json = JSON.parse('null');}}" .
579end_fi()."});\n\n";}
580
581// set of functions to interpret steps into corresponding casperjs code
582function url_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser']; $casper_url = $raw_intent; $chrome_call = '';
583if ($twb == 'chrome') {$chrome_call = "var download_path = flow_path; // to set path correctly for Windows\n" .
584"if (download_path.indexOf(':')>0) download_path = download_path.replace(/\//g,'\\\\').replace(/\\\\/g,'\\\\');\n" .
585"chrome_step('Page.setDownloadBehavior',{behavior: 'allow', downloadPath: download_path});\n";
586$casper_url = 'about:blank'; $chrome_call .= "chrome_step('Page.navigate',{url: '".$raw_intent."'}); sleep(1000);\n";}
587if (strpos($raw_intent,"'+")!==false and strpos($raw_intent,"+'")!==false) // check if dynamic url is used
588// wrap step within casper context if variable (casper context) is used in url, in order to access variable
589{$dynamic_header = "casper.then(function() {"; $dynamic_footer = "}); // end of dynamic url block";}
590else {$dynamic_header = ""; $dynamic_footer = ""; // else casper.start/thenOpen can be outside casper context
591if (filter_var($raw_intent, FILTER_VALIDATE_URL) == false) // do url validation only for raw text url string
592if ($raw_intent != 'about:blank') echo "ERROR - " . current_line() . " invalid URL " . $raw_intent . "\n";}
593if ($GLOBALS['real_line_number'] == 1) { // use casper.start for first URL call and casper.thenOpen for subsequent calls
594$GLOBALS['url_provided']=true; return $dynamic_header."casper.start('".$casper_url."', function() {\n".$chrome_call.
595"techo('".$raw_intent."' + ' - ' + ".$twb.".getTitle() + '\\n');});".$dynamic_footer."\n\n";}
596else return $dynamic_header."casper.thenOpen('".$casper_url."', function() {\n".$chrome_call."techo('".
597$raw_intent."' + ' - ' + ".$twb.".getTitle());});".$dynamic_footer."\n\n";}
598
599function tap_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
600$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
601if (is_sikuli($params)) {$abs_params = abs_file($params); $abs_intent = str_replace($params,$abs_params,$raw_intent);
602return "casper.then(function() {".call_sikuli($abs_intent,$abs_params);} // use sikuli visual automation as needed
603if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n"; else
604return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).$twb.".click(tx('" . $params . "'));".end_tx($params);}
605
606function rtap_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
607$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
608if (is_sikuli($params)) {$abs_params = abs_file($params); $abs_intent = str_replace($params,$abs_params,$raw_intent);
609return "casper.then(function() {".call_sikuli($abs_intent,$abs_params);} // use sikuli visual automation as needed
610if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n"; else
611return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).$twb.".mouse.rightclick(tx('" . $params . "'));".end_tx($params);}
612
613function dtap_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
614$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
615if (is_sikuli($params)) {$abs_params = abs_file($params); $abs_intent = str_replace($params,$abs_params,$raw_intent);
616return "casper.then(function() {".call_sikuli($abs_intent,$abs_params);} // use sikuli visual automation as needed
617if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n"; else
618return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).$twb.".mouse.doubleclick(tx('" . $params . "'));".end_tx($params);}
619
620function hover_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
621$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
622if (is_sikuli($params)) {$abs_params = abs_file($params); $abs_intent = str_replace($params,$abs_params,$raw_intent);
623return "casper.then(function() {".call_sikuli($abs_intent,$abs_params);} // use sikuli visual automation as needed
624if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n"; else
625return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).$twb.".mouse.move(tx('" . $params . "'));".end_tx($params);}
626
627function type_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
628$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
629$param1 = trim(substr($params,0,strpos($params," as "))); $param2 = trim(substr($params,4+strpos($params," as ")));
630if (is_sikuli($param1) and $param2 != "") {
631$abs_param1 = abs_file($param1); $abs_intent = str_replace($param1,$abs_param1,$raw_intent);
632return "casper.then(function() {".call_sikuli($abs_intent,$abs_param1);} // use sikuli visual automation as needed
633if (($param1 == "") or ($param2 == ""))
634echo "ERROR - " . current_line() . " target/text missing for " . $raw_intent . "\n"; else {
635// special handling for [clear] keyword to clear text field by doing an extra step to clear the field
636if (substr($param2,0,7)=="[clear]") {if (strlen($param2)>7) $param2 = substr($param2,7); else $param2 = "";
637$clear_field = $twb.".sendKeys(tx('".$param1."'),'',{reset: true});\n";} else $clear_field = "";
638if (strpos($param2,"[enter]")===false) return "casper.then(function() {"."{techo('".$raw_intent."');".
639beg_tx($param1).$clear_field.$twb.".sendKeys(tx('".$param1."'),'".$param2."');".end_tx($param1);
640else // special handling for [enter] keyword to send enter key events
641{$param2 = str_replace("[enter]","',{keepFocus: true});\n" .
642$twb.".sendKeys(tx('".$param1."'),casper.page.event.key.Enter,{keepFocus: true});\n" .
643$twb.".sendKeys(tx('".$param1."'),'",$param2); return "casper.then(function() {"."{techo('".$raw_intent."');".
644beg_tx($param1).$clear_field.$twb.".sendKeys(tx('".$param1."'),'".$param2."',{keepFocus: true});".end_tx($param1);}}}
645
646function select_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
647$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
648$param1 = trim(substr($params,0,strpos($params," as "))); $param2 = trim(substr($params,4+strpos($params," as ")));
649if (is_sikuli($param1) and is_sikuli($param2)) {
650$abs_param1 = abs_file($param1); $abs_intent = str_replace($param1,$abs_param1,$raw_intent);
651$abs_param2 = abs_file($param2); $abs_intent = str_replace($param2,$abs_param2,$abs_intent);
652return "casper.then(function() {".call_sikuli($abs_intent,$abs_param1);} // use sikuli visual automation as needed
653if (($param1 == "") or ($param2 == ""))
654echo "ERROR - " . current_line() . " target/option missing for " . $raw_intent . "\n"; else
655return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($param1)."var select_locator = tx('".$param1."');\n"
656."if (is_xpath_selector(select_locator.toString().replace('xpath selector: ','')))\n".
657"select_locator = select_locator.toString().substring(16);\n".
658$twb.".selectOptionByValue(select_locator,'".$param2."');".end_tx($param1);}
659
660function read_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
661$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
662$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
663if (is_sikuli($param1) and (strpos($params," to ")!==false)) { // use sikuli visual automation as needed
664$abs_param1 = abs_file($param1); $abs_intent = str_replace($param1,$abs_param1,$raw_intent);
665return "casper.then(function() {".
666call_sikuli($abs_intent,$abs_param1,$param2." = fetch_sikuli_text(); clear_sikuli_text();");}
667if ((strtolower($param1) == "page") and ($param2 != ""))
668return "casper.then(function() {"."{techo('".$raw_intent."');\n".$param2." = ".$twb.".getHTML();}".end_fi()."});"."\n\n";
669if (($param1 == "") or ($param2 == ""))
670echo "ERROR - " . current_line() . " target/variable missing for " . $raw_intent . "\n"; else
671return "casper.then(function() {".
672"{techo('".$raw_intent."');".beg_tx($param1).$param2." = ".$twb.".fetchText(tx('".$param1."')).trim();".end_tx($param1);}
673
674function show_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
675$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
676if (is_sikuli($params)) { // use sikuli visual automation as needed
677$abs_params = abs_file($params); $abs_intent = str_replace($params,$abs_params,$raw_intent);
678return "casper.then(function() {".
679call_sikuli($abs_intent,$abs_params,"this.echo(fetch_sikuli_text()); clear_sikuli_text();");}
680if (strtolower($params) == "page") return "casper.then(function() {".
681"this.echo('".$raw_intent."' + ' - \\n' + ".$twb.".getHTML());".end_fi()."});"."\n\n";
682if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n"; else
683return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).
684"this.echo(".$twb.".fetchText(tx('" . $params . "')).trim());".end_tx($params);}
685
686function upload_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
687$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
688$param1 = trim(substr($params,0,strpos($params," as "))); $param2 = trim(substr($params,4+strpos($params," as ")));
689if (($param1 == "") or ($param2 == ""))
690echo "ERROR - " . current_line() . " filename missing for " . $raw_intent . "\n"; else
691return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($param1).
692$twb.".page.uploadFile(tx('".$param1."'),'".abs_file($param2)."');".end_tx($param1);}
693
694function down_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
695$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
696$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
697if (($param1 == "") or ($param2 == ""))
698echo "ERROR - " . current_line() . " url/filename missing for " . $raw_intent . "\n"; else
699return "casper.then(function() {"."{techo('".$raw_intent."');\n".$twb.".download('".$param1."','".abs_file($param2)."');}".end_fi()."});"."\n\n";}
700
701function receive_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
702$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
703$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
704if (($param1 == "") or ($param2 == ""))
705echo "ERROR - " . current_line() . " keyword/filename missing for " . $raw_intent . "\n"; else
706return "casper.then(function() {"."{techo('".$raw_intent."');\n".
707"casper.on('resource.received', function(resource) {if (resource.stage !== 'end') return;\n".
708"if (resource.url.indexOf('".$param1."') > -1) ".$twb.".download(resource.url, '".abs_file($param2)."');});}".end_fi()."});"."\n\n";}
709
710function echo_intent($raw_intent) {
711$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
712if ($params == "") echo "ERROR - " . current_line() . " text missing for " . $raw_intent . "\n"; else
713return "casper.then(function() {"."this.echo(".add_concat($params).");".end_fi()."});"."\n\n";}
714
715function save_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
716$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
717$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
718if (is_sikuli($param1) and (strpos($params," to ")!==false)) { // use sikuli visual automation as needed
719$abs_param1 = abs_file($param1); $abs_intent = str_replace($param1,$abs_param1,$raw_intent);
720return "casper.then(function() {".
721call_sikuli($abs_intent,$abs_param1,"save_text('".abs_file($param2)."',fetch_sikuli_text()); clear_sikuli_text();");}
722else if (is_sikuli($params) and (strpos($params," to ")==false)) {
723$abs_params = abs_file($params); $abs_intent = str_replace($params,$abs_params,$raw_intent);
724return "casper.then(function() {".
725call_sikuli($abs_intent,$abs_param1,"save_text('',fetch_sikuli_text()); clear_sikuli_text();");}
726if ((strtolower($params) == "page") or (strtolower($param1) == "page")) {if (strpos($params," to ")!==false)
727return "casper.then(function() {".
728"{techo('".$raw_intent."');\nsave_text('".abs_file($param2)."',".$twb.".getHTML());}".end_fi()."});"."\n\n";
729else return "casper.then(function() {"."{techo('".$raw_intent."');\nsave_text('',".$twb.".getHTML());}".end_fi()."});"."\n\n";}
730if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n";
731else if (strpos($params," to ")!==false)
732return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($param1).
733 "save_text('".abs_file($param2)."',".$twb.".fetchText(tx('".$param1."')).trim());".end_tx($param1); else
734return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).
735 "save_text('',".$twb.".fetchText(tx('" . $params . "')).trim());".end_tx($params);}
736
737function dump_intent($raw_intent) {
738$safe_intent = str_replace("'","\'",$raw_intent); // avoid breaking echo below when single quote is used
739$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
740$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
741if ($params == "") echo "ERROR - " . current_line() . " variable missing for " . $raw_intent . "\n";
742else if (strpos($params," to ")!==false)
743return "casper.then(function() {".
744"{techo('".$safe_intent."');\nsave_text('".abs_file($param2)."',".add_concat($param1).");}".end_fi()."});"."\n\n";
745else return "casper.then(function() {".
746"{techo('".$safe_intent."');\nsave_text(''," . add_concat($params) . ");}".end_fi()."});"."\n\n";}
747
748function write_intent($raw_intent) {
749$safe_intent = str_replace("'","\'",$raw_intent); // avoid breaking echo below when single quote is used
750$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
751$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
752if ($params == "") echo "ERROR - " . current_line() . " variable missing for " . $raw_intent . "\n";
753else if (strpos($params," to ")!==false)
754return "casper.then(function() {".
755"{techo('".$safe_intent."');\nappend_text('".abs_file($param2)."',".add_concat($param1).");}".end_fi()."});"."\n\n";
756else return "casper.then(function() {".
757"{techo('".$safe_intent."');\nappend_text(''," . add_concat($params) . ");}".end_fi()."});"."\n\n";}
758
759function load_intent($raw_intent) {
760$safe_intent = str_replace("'","\'",$raw_intent); // avoid breaking echo below when single quote is used
761$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
762$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
763if ($params == "") echo "ERROR - " . current_line() . " filename missing for " . $raw_intent . "\n";
764else if (strpos($params," to ")!==false)
765return "casper.then(function() {"."{techo('".$safe_intent."');\nvar fs = require('fs'); ".$param2." = '';\n".
766 "if (fs.exists('".abs_file($param1)."'))\n".$param2." = fs.read('".abs_file($param1)."').trim();\n".
767 "else this.echo('ERROR - cannot find file ".$param1."').exit();}".end_fi()."});"."\n\n";
768else echo "ERROR - " . current_line() . " variable missing for " . $raw_intent . "\n";}
769
770function snap_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
771$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
772$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
773if (is_sikuli($param1) and (strpos($params," to ")!==false)) {
774$abs_param1 = abs_file($param1); $abs_intent = str_replace($param1,$abs_param1,$raw_intent);
775$abs_param2 = abs_file($param2); $abs_intent = str_replace($param2,$abs_param2,$abs_intent);
776return "casper.then(function() {".call_sikuli($abs_intent,$abs_param1);} // use sikuli visual automation as needed
777else if (is_sikuli($params) and (strpos($params," to ")==false)) {
778$abs_params = abs_file($params); $abs_intent = str_replace($params,$abs_params,$raw_intent);
779return "casper.then(function() {".call_sikuli($abs_intent.' to snap_image()',$abs_params);} // handle no output filename
780if ((strtolower($params) == "page") or (strtolower($param1) == "page")) {if (strpos($params," to ")!==false)
781return "casper.then(function() {".
782"{techo('".$raw_intent."');\n".$twb.".capture('".abs_file($param2)."');}".end_fi()."});"."\n\n";
783else return "casper.then(function() {".
784"{techo('".$raw_intent."');\n".$twb.".capture(snap_image());}".end_fi()."});"."\n\n";}
785if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n";
786else if (strpos($params," to ")!==false)
787return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($param1).
788 $twb.".captureSelector('".abs_file($param2)."',tx('".$param1."'));".end_tx($param1); else
789return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).
790 $twb.".captureSelector(snap_image(),tx('".$params."'));".end_tx($params);}
791
792function table_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser'];
793$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
794$param1 = trim(substr($params,0,strpos($params," to "))); $param2 = trim(substr($params,4+strpos($params," to ")));
795if ($params == "") echo "ERROR - " . current_line() . " target missing for " . $raw_intent . "\n";
796else if (strpos($params," to ")!==false)
797return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($param1).
798 "save_table('".abs_file($param2)."',tx('".$param1."'));".end_tx($param1); else
799return "casper.then(function() {"."{techo('".$raw_intent."');".beg_tx($params).
800 "save_table('',tx('".$params."'));".end_tx($params);}
801
802function wait_intent($raw_intent) {
803$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," "))); if ($params == "") $params = "5";
804if (strpos($params,"'+")!==false and strpos($params,"+'")!==false) // handling for dynamic time
805return "casper.then(function() {".
806"techo('".$raw_intent."');});\ncasper.then(function() {casper.wait((parseFloat('".$params."')*1000), function() {"."});});"."\n\n";
807else return "casper.then(function() {".
808"techo('".$raw_intent."');});\ncasper.then(function() {casper.wait(" . (floatval($params)*1000) . ", function() {"."});});"."\n\n";}
809
810function live_intent($raw_intent) { // live mode to interactively test tagui steps and js code (casperjs context)
811return "casper.then(function() {".
812"{var live_input = '';\nvar sys = require('system'); sys.stdout.write('LIVE MODE - type done to quit\\n \\b');\n".
813"while (true) {live_input = sys.stdin.readLine(); // evaluate input in casperjs context until done is entered\n".
814"if (live_input.indexOf('done') == 0) break; eval(tagui_parse(live_input));}}".end_fi()."});"."\n\n";}
815
816function ask_intent($raw_intent) { // ask user for input during automation and save to ask_result variable
817$raw_intent = str_replace("\'","'",$raw_intent); $raw_intent = str_replace("'","\'",$raw_intent);
818$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
819if ($params == "") echo "ERROR - " . current_line() . " prompt missing for " . $raw_intent . "\n";
820else if (getenv('tagui_web_browser')=='chrome') { // show a popup window if running on visible chrome mode
821return "casper.then(function() {".
822"{ask_result = ''; ask_result = chrome.evaluate(function() {\nreturn prompt('".$params."');}); ".
823"if (ask_result == null) ask_result = '';}".end_fi()."});"."\n\n";}
824else return "casper.then(function() {".
825"{ask_result = ''; var sys = require('system');\nthis.echo('".$params." '); ".
826"ask_result = sys.stdin.readLine();}".end_fi()."});"."\n\n";}
827
828function check_intent($raw_intent) {
829$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
830$params = str_replace("||"," JAVASCRIPT_OR ",$params); // to handle conflict with "|" delimiter
831$param1 = trim(substr($params,0,strpos($params,"|"))); $param2 = trim(substr($params,1+strpos($params,"|")));
832$param3 = trim(substr($param2,1+strpos($param2,"|"))); $param2 = trim(substr($param2,0,strpos($param2,"|")));
833$param1 = str_replace(" JAVASCRIPT_OR ","||",$param1); // to restore back "||" that were replaced
834$param2 = str_replace(" JAVASCRIPT_OR ","||",$param2); $param3 = str_replace(" JAVASCRIPT_OR ","||",$param3);
835if (substr_count($params,"|")!=2)
836echo "ERROR - " . current_line() . " if/true/false missing for " . $raw_intent . "\n";
837else if (getenv('tagui_test_mode') == 'true') return "casper.then(function() {"."{".parse_condition("if ".$param1).
838"\ntest.assert(true,".add_concat($param2).");\nelse test.assert(false,".add_concat($param3).");}".end_fi()."});"."\n\n";
839else return "casper.then(function() {"."{".parse_condition("if ".$param1)."\nthis.echo(".add_concat($param2).");\nelse this.echo(".add_concat($param3).");}".end_fi()."});"."\n\n";}
840
841function test_intent($raw_intent) {
842echo "ERROR - " . current_line() . " use CasperJS tester module to professionally " . $raw_intent . "\n";
843echo "ERROR - " . current_line() . " info at http://docs.casperjs.org/en/latest/modules/tester.html" . "\n";
844echo "ERROR - " . current_line() . " support CSS selector or tx('selector') for XPath algo by TagUI" . "\n";}
845
846function frame_intent($raw_intent) {
847$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
848$param1 = trim(substr($params,0,strpos($params,"|"))); $param2 = trim(substr($params,1+strpos($params,"|")));
849if ($params == "") echo "ERROR - " . current_line() . " name missing for " . $raw_intent . "\n";
850else if (strpos($params,"|")!==false)
851{$GLOBALS['code_block_tracker'] .= "|" . 'dframe';
852return "casper.then(function() {"."techo('".$raw_intent."');});\n".
853"casper.withFrame('".$param1."', function() {casper.withFrame('".$param2."', function() {\n";} else
854{$GLOBALS['code_block_tracker'] .= "|" . 'frame';
855return "casper.then(function() {"."techo('".$raw_intent."');});\n"."casper.withFrame('".$params."', function() {\n";}}
856
857function popup_intent($raw_intent) {
858$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
859if ($params == "") echo "ERROR - " . current_line() . " keyword missing for " . $raw_intent . "\n";
860else {$GLOBALS['code_block_tracker'] .= "|" . 'popup';
861return "casper.then(function() {"."techo('".$raw_intent."');"."});\n".
862"casper.waitForPopup(/".preg_quote($params)."/, function then() {},\n".
863"function timeout() {this.echo('ERROR - cannot find popup ".$params."').exit();});\n".
864"casper.withPopup(/".preg_quote($params)."/, function() {\n";}}
865
866function api_intent($raw_intent) {
867$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
868if ($params == "") echo "ERROR - " . current_line() . " API URL missing for " . $raw_intent . "\n"; else
869return "casper.then(function() {"."{techo('".$raw_intent."');\napi_result = ''; api_result = call_api('".$params."');\n".
870"try {api_json = JSON.parse(api_result);} catch(e) {api_json = JSON.parse('null');}}".end_fi()."});"."\n\n";}
871
872function run_intent($raw_intent) {
873$raw_intent = str_replace('\\','\\\\',$raw_intent); // to call paths correctly for Windows
874if (strtolower($raw_intent) == "run begin") {$GLOBALS['inside_run_block'] = 1; return "";}
875else if (strtolower($raw_intent) == "run finish") {$GLOBALS['inside_run_block'] = 0; return "";}
876if ($GLOBALS['inside_run_block'] == 1) $raw_intent = "run " . $raw_intent;
877$safe_intent = str_replace("'","\'",$raw_intent); // avoid breaking echo when single quote is used
878$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
879if ($params == "") echo "ERROR - " . current_line() . " command to run missing for " . $raw_intent . "\n"; else
880return "casper.then(function() {"."techo('".$safe_intent."');});\ncasper.then(function() {".
881"casper.waitForExec('".$params."', null, function(response) {run_result = '';\n" .
882"run_result = (response.data.stdout.trim() || response.data.stderr.trim()); " .
883"run_result = run_result.replace(/\\r\\n/g,'\\n');\nrun_json = response.data;}, function() {" .
884"this.echo('ERROR - command to run exceeded '+(casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},".
885"casper.options.waitTimeout);});\n\n";}
886
887function dom_intent($raw_intent) {$twb = $GLOBALS['tagui_web_browser']; if (strtolower($raw_intent) == "dom begin")
888{$GLOBALS['inside_dom_block'] = 1; $GLOBALS['integration_block_body'] = "dom "; return "";}
889$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
890if ($params == "") echo "ERROR - " . current_line() . " statement missing for " . $raw_intent . "\n";
891else return "casper.then(function() {"."dom_result = ''; dom_result = ".$twb.".evaluate(function(dom_json) {".$params."}, dom_json);".end_fi()."});"."\n\n";}
892
893function js_intent($raw_intent) {if (strtolower($raw_intent) == "js begin")
894{$GLOBALS['inside_js_block'] = 1; $GLOBALS['integration_block_body'] = "js "; return "";}
895$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
896if ($params == "") echo "ERROR - " . current_line() . " statement missing for " . $raw_intent . "\n";
897else return "casper.then(function() { // start of JS code\n".$params."\n}); // end of JS code"."\n\n";}
898
899function r_intent($raw_intent) {if (strtolower($raw_intent) == "r begin")
900{$GLOBALS['inside_r_block'] = 1; $GLOBALS['integration_block_body'] = "r "; return "";}
901$raw_intent = str_replace('\\','\\\\',$raw_intent); // to send \ correctly over to integration
902$raw_intent = str_replace('[END_OF_LINE]','\\n',$raw_intent); // replace after above to prevent from escape
903$safe_intent = str_replace("'","\'",$raw_intent); // avoid breaking echo when single quote is used
904$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
905if ($params == "") echo "ERROR - " . current_line() . " R command(s) missing for " . $raw_intent . "\n"; else
906return "casper.then(function() {".call_r($safe_intent);}
907
908function py_intent($raw_intent) {if (strtolower($raw_intent) == "py begin")
909{$GLOBALS['inside_py_block'] = 1; $GLOBALS['integration_block_body'] = "py "; return "";}
910$raw_intent = str_replace('\\','\\\\',$raw_intent); // to send \ correctly over to integration
911$raw_intent = str_replace('[END_OF_LINE]','\\n',$raw_intent); // replace after above to prevent from escape
912$safe_intent = str_replace("'","\'",$raw_intent); // avoid breaking echo when single quote is used
913$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
914if ($params == "") echo "ERROR - " . current_line() . " Python command(s) missing for " . $raw_intent . "\n"; else
915return "casper.then(function() {".call_py($safe_intent);}
916
917function vision_intent($raw_intent) {if (strtolower($raw_intent) == "vision begin")
918{$GLOBALS['inside_vision_block'] = 1; $GLOBALS['integration_block_body'] = "vision "; return "";}
919$raw_intent = str_replace('\\','\\\\',$raw_intent); // to send \ correctly over to integration
920$raw_intent = str_replace('[END_OF_LINE]','\\n',$raw_intent); // replace after above to prevent from escape
921$safe_intent = str_replace("'","\'",$raw_intent); // avoid breaking echo when single quote is used
922$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
923if ($params == "") echo "ERROR - " . current_line() . " Sikuli command(s) missing for " . $raw_intent . "\n"; else
924return "casper.then(function() {".call_sikuli($safe_intent,'for vision step');} // use sikuli visual automation explicitly
925
926function timeout_intent($raw_intent) {
927$params = trim(substr($raw_intent." ",1+strpos($raw_intent." "," ")));
928if ($params == "") echo "ERROR - " . current_line() . " time in seconds missing for " . $raw_intent . "\n";
929else return "casper.then(function() {"."casper.options.waitTimeout = " . (floatval($params)*1000) . ";" . end_fi()."});"."\n\n";}
930
931function code_intent($raw_intent) {
932$params = parse_condition($raw_intent);
933if (substr($raw_intent,0,2)=="//") return $params."\n"; // return comments directly without casper.then wrappers
934if ((substr($raw_intent,0,1)=="{") or (substr($raw_intent,0,1)=="}")) return $params."\n"; // no wrappers for {}
935if ((substr($params,0,3)=="if ") or (substr($params,0,8)=="else if ")
936or (substr($params,0,4)=="for ") or (substr($params,0,6)=="while ") or
937(trim($raw_intent)=="else")) return "casper.then(function() {".$params."\n";
938else if ($GLOBALS['inside_while_loop'] == 1) return $params."\n";
939else return "casper.then(function() { // start of JS code\n".$params."\n}); // end of JS code"."\n\n";}
940
941function parse_condition($logic) { // natural language handling for conditions
942$raw_logic = $logic; // store an original copy for use when showing error message
943if (substr($logic,0,2)=="//") return $logic; // skip processing for comment
944
945// section 1 - replace braces block {} with casperjs block to group steps or code
946// take only lines starting with { or } as code blocks for processing, otherwise will break many valid javascript code
947if (substr($logic,0,1) == "{") $GLOBALS['inside_code_block']++; // assume nothing on rest of the line except comment
948if (substr($logic,0,1) == "}") $GLOBALS['inside_code_block']--; // assume nothing on rest of the line except comment
949$code_block_header = ""; $code_block_footer = "";
950$last_delimiter_pos = strrpos($GLOBALS['code_block_tracker'],"|");
951$code_block_intent = substr($GLOBALS['code_block_tracker'],$last_delimiter_pos+1);
952
953if (($GLOBALS['inside_code_block'] > substr_count($GLOBALS['code_block_tracker'],"|")) and (substr($logic,0,1) == "{"))
954{$GLOBALS['code_block_tracker'] .= "|" . 'normal_bracket'; return $logic."\n";} // handle normal JavaScript brackets
955else if ((substr($logic,0,1) == "}") and ($code_block_intent == "normal_bracket"))
956{$GLOBALS['code_block_tracker']=substr($GLOBALS['code_block_tracker'],0,$last_delimiter_pos); return $logic."\n";}
957
958if (($code_block_intent == "if") or ($code_block_intent == "else if") or ($code_block_intent == "else")
959or ($code_block_intent == "popup") or ($code_block_intent == "frame")) {if (substr($logic,0,1) == "}")
960$GLOBALS['code_block_tracker']=substr($GLOBALS['code_block_tracker'],0,$last_delimiter_pos);}
961
962else if (($code_block_intent == "for") and (substr($logic,0,1) == "{")) {
963$last_delimiter_pos = strrpos($GLOBALS['for_loop_tracker'],"|");
964$for_loop_variable_name = substr($GLOBALS['for_loop_tracker'],$last_delimiter_pos+1);
965$code_block_header = "{casper.then(function() {for_loop_signal = '[CONTINUE_SIGNAL][".$for_loop_variable_name."]';});\n".
966"(function (" . $for_loop_variable_name . ") { // start of IIFE pattern\n";}
967
968else if (($code_block_intent == "for") and (substr($logic,0,1) == "}")) {
969$last_delimiter_pos = strrpos($GLOBALS['for_loop_tracker'],"|");
970$for_loop_variable_name = substr($GLOBALS['for_loop_tracker'],$last_delimiter_pos+1);
971$code_block_footer = "})(" . $for_loop_variable_name . "); // end of IIFE pattern, with dummy marker for break step\n".
972"casper.then(function() {for_loop_signal = '[BREAK_SIGNAL][".$for_loop_variable_name."]';});}";
973$last_delimiter_pos = strrpos($GLOBALS['code_block_tracker'],"|");
974$GLOBALS['code_block_tracker']=substr($GLOBALS['code_block_tracker'],0,$last_delimiter_pos);
975$last_delimiter_pos = strrpos($GLOBALS['for_loop_tracker'],"|");
976$GLOBALS['for_loop_tracker']=substr($GLOBALS['for_loop_tracker'],0,$last_delimiter_pos);}
977
978else if ($code_block_intent == "dframe") {if (substr($logic,0,1) == "}") {$code_block_footer = "});";
979$GLOBALS['code_block_tracker']=substr($GLOBALS['code_block_tracker'],0,$last_delimiter_pos);}}
980
981else if ($code_block_intent == "while") {if (substr($logic,0,1) == "}") {$GLOBALS['inside_while_loop'] = 0;
982$GLOBALS['code_block_tracker']=substr($GLOBALS['code_block_tracker'],0,$last_delimiter_pos);}}
983
984if (substr($logic,0,1) == "{") $logic = $code_block_header."{ // start of code block\n".substr($logic,1)."\n";
985else if (substr($logic,0,1) == "}") $logic = "} // end of code block\n".substr($logic,1)."\n".$code_block_footer."});\n";
986$logic = str_replace("\n\n","\n",$logic); // clean up empty lines from { and } processing
987
988// section 2 - natural language handling for conditions and loops
989if ((substr($logic,0,3)=="if ") or (substr($logic,0,8)=="else if ")
990or (substr($logic,0,4)=="for ") or (substr($logic,0,6)=="while ")) {
991
992$logic = str_replace(" more than or equals to "," >= ",$logic);
993$logic = str_replace(" greater than or equals to "," >= ",$logic);
994$logic = str_replace(" higher than or equals to "," >= ",$logic);
995$logic = str_replace(" less than or equals to "," <= ",$logic);
996$logic = str_replace(" lesser than or equals to "," <= ",$logic);
997$logic = str_replace(" lower than or equals to "," <= ",$logic);
998$logic = str_replace(" more than or equal to "," >= ",$logic);
999$logic = str_replace(" greater than or equal to "," >= ",$logic);
1000$logic = str_replace(" higher than or equal to "," >= ",$logic);
1001$logic = str_replace(" less than or equal to "," <= ",$logic);
1002$logic = str_replace(" lesser than or equal to "," <= ",$logic);
1003$logic = str_replace(" lower than or equal to "," <= ",$logic);
1004
1005$logic = str_replace(" more than "," > ",$logic); $logic = str_replace(" greater than "," > ",$logic);
1006$logic = str_replace(" higher than "," > ",$logic); $logic = str_replace(" less than "," < ",$logic);
1007$logic = str_replace(" lesser than "," < ",$logic); $logic = str_replace(" lower than "," < ",$logic);
1008$logic = str_replace(" not equals to "," != ",$logic); $logic = str_replace(" equals to "," == ",$logic);
1009$logic = str_replace(" not equal to "," != ",$logic); $logic = str_replace(" equal to "," == ",$logic);
1010
1011// special handling to manage not contains, not contain, contains, contain conditions
1012$contain_list = array(" not contains ", " not contain ", " contains ", " contain ");
1013foreach ($contain_list as $contain_type) { // outer loop, iterate through 4 types of contain conditions
1014for ($condition_counter=1;$condition_counter<=5;$condition_counter++) { // inner loop, avoid while due to infinite loops
1015if (strpos($logic,$contain_type)==!false) {$pos_keyword = strpos($logic,$contain_type);
1016$pos_single_quote = strpos($logic,"'",$pos_keyword+strlen($contain_type)); // check type of quote used
1017if ($pos_single_quote == false) $pos_single_quote = 1024; // set to large number, for comparison later
1018$pos_double_quote = strpos($logic,"\"",$pos_keyword+strlen($contain_type)); // check type of quote used
1019if ($pos_double_quote == false) $pos_double_quote = 1024; // set to large number, for comparison later
1020if ($pos_double_quote < $pos_single_quote) {$pos_quote_start = $pos_double_quote; $quote_type = "\"";}
1021else if ($pos_single_quote < $pos_double_quote) {$pos_quote_start = $pos_single_quote; $quote_type = "'";}
1022else {echo "ERROR - " . current_line() . " no quoted text - " . $raw_logic . "\n"; $quote_type = "missing";}
1023if ($quote_type != "missing") {$pos_quote_end = strpos($logic,$quote_type,$pos_quote_start+1);
1024$pos_variable_start = strrpos($logic," ",$pos_keyword-strlen($logic)-2); $contain_operator = "<0";
1025if (($contain_type == " contains ") or ($contain_type == " contain ")) $contain_operator = ">-1";
1026$logic = substr($logic,0,$pos_variable_start+1)."(".
1027trim(substr($logic,$pos_variable_start,$pos_keyword-$pos_variable_start)).".indexOf(".
1028$quote_type.substr($logic,$pos_quote_start+1,$pos_quote_end-$pos_quote_start-1).
1029$quote_type.")".$contain_operator.")".substr($logic,$pos_quote_end+1);}}
1030else break;}}
1031
1032// $logic = str_replace(" not "," ! ",$logic); // leaving not out until meaningful to implement
1033$logic = str_replace(" and ",") && (",$logic); $logic = str_replace(" or ",") || (",$logic);
1034
1035// special handling to manage for loop in natural language
1036if ((substr($logic,0,4)=="for ") and (strpos($logic,";")==false)) { // no ; means in natural language
1037if (strpos($raw_logic,"count(")!==false)
1038echo "ERROR - " . current_line() . " assign count() to variable before using - " . $raw_logic . "\n";
1039$logic = str_replace("(","",$logic); $logic = str_replace(")","",$logic); // remove brackets if present
1040$logic = str_replace(" "," ",$logic); $logic = str_replace(" "," ",$logic); // remove typo extra spaces
1041$token = explode(" ",$logic); // split into tokens for loop in natural language, eg - for cupcake from 1 to 4
1042if (strpos($raw_logic,"{")!==false) // show error to put { to next line for parsing as { step
1043echo "ERROR - " . current_line() . " put { to next line - " . $raw_logic . "\n";
1044else if (count($token) != 6) echo "ERROR - " . current_line() . " invalid for loop - " . $raw_logic . "\n";
1045else $logic = $token[0]." (".$token[1]."=".$token[3]."; ".$token[1]."<=".$token[5]."; ".$token[1]."++)";}
1046else if ((substr($logic,0,4)=="for ") and (strpos($raw_logic,"{")!==false))
1047echo "ERROR - " . current_line() . " put { to next line - " . $raw_logic . "\n";
1048
1049// add to tracker the for loop variable name, to implement IIFE pattern if step/code blocks are used
1050if (substr($logic,0,4)=="for ") { // get the variable name used in the for loop and append into tracker
1051$GLOBALS['code_block_tracker'] .= "|" . 'for'; // append for loop marker to track upcoming code block
1052$GLOBALS['for_loop_tracker'] .= "|" . trim(substr($logic,strpos($logic,"(")+1,strpos($logic,"=")-strpos($logic,"(")-1));}
1053
1054// add opening and closing brackets twice to handle no brackets, and, or cases
1055if (substr($logic,0,3)=="if ") {
1056$GLOBALS['code_block_tracker'] .= "|" . 'if'; $logic = "if ((" . trim(substr($logic,3)) . "))";
1057if (strpos($raw_logic,"{")!==false) echo "ERROR - " . current_line() . " put { to next line - " . $raw_logic . "\n";}
1058if (substr($logic,0,8)=="else if ") {
1059$GLOBALS['code_block_tracker'] .= "|" . 'else if'; $logic = "else if ((" . trim(substr($logic,8)) . "))";
1060if (strpos($raw_logic,"{")!==false) echo "ERROR - " . current_line() . " put { to next line - " . $raw_logic . "\n";}
1061if (substr($logic,0,6)=="while ") {
1062$GLOBALS['code_block_tracker'] .= "|" . 'while'; $logic = "while ((" . trim(substr($logic,6)) . "))";
1063if (strpos($raw_logic,"{")!==false) echo "ERROR - " . current_line() . " put { to next line - " . $raw_logic . "\n";}}
1064
1065// special part for else because not in section 2 condition block
1066if (trim($logic)=="else") {$GLOBALS['code_block_tracker'] .= "|" . 'else'; $logic = "else";
1067if (strpos($raw_logic,"{")!==false) echo "ERROR - " . current_line() . " put { to next line - " . $raw_logic . "\n";}
1068
1069// section 3 - track if next statement is going to be or still inside while loop,
1070// then avoid async wait (casper.then/waitFor/timeout will hang casperjs/phantomjs??)
1071if (substr($logic,0,6)=="while ") $GLOBALS['inside_while_loop'] = 1;
1072
1073// section 4 - to handle break and continue steps in for loops
1074if (($logic=="break") or ($logic=="break;"))
1075{$teleport_marker = str_replace("|","",substr($GLOBALS['for_loop_tracker'],strrpos($GLOBALS['for_loop_tracker'],"|")));
1076$logic = "casper.bypass(teleport_distance('[BREAK_SIGNAL][".$teleport_marker."]')); return;";}
1077if (($logic=="continue") or ($logic=="continue;"))
1078{$teleport_marker = str_replace("|","",substr($GLOBALS['for_loop_tracker'],strrpos($GLOBALS['for_loop_tracker'],"|")));
1079$logic = "casper.bypass(teleport_distance('[CONTINUE_SIGNAL][".$teleport_marker."]')); return;";}
1080
1081// return code after all the parsing and special handling
1082return $logic;}
1083
1084?>