2018-05-21 11:58:35 +02:00
/ * *
* @ author n1474335 [ n1474335 @ gmail . com ]
* @ copyright Crown Copyright 2018
* @ license Apache - 2.0
* /
2019-07-09 13:23:59 +02:00
import Operation from "../Operation.mjs" ;
import Recipe from "../Recipe.mjs" ;
import Dish from "../Dish.mjs" ;
2018-05-21 11:58:35 +02:00
/ * *
* Fork operation
* /
class Fork extends Operation {
/ * *
* Fork constructor
* /
constructor ( ) {
super ( ) ;
this . name = "Fork" ;
this . flowControl = true ;
this . module = "Default" ;
this . description = "Split the input data up based on the specified delimiter and run all subsequent operations on each branch separately.<br><br>For example, to decode multiple Base64 strings, enter them all on separate lines then add the 'Fork' and 'From Base64' operations to the recipe. Each string will be decoded separately." ;
this . inputType = "string" ;
this . outputType = "string" ;
this . args = [
{
"name" : "Split delimiter" ,
"type" : "binaryShortString" ,
"value" : "\\n"
} ,
{
"name" : "Merge delimiter" ,
"type" : "binaryShortString" ,
"value" : "\\n"
} ,
{
"name" : "Ignore errors" ,
"type" : "boolean" ,
"value" : false
}
] ;
}
/ * *
* @ param { Object } state - The current state of the recipe .
* @ param { number } state . progress - The current position in the recipe .
* @ param { Dish } state . dish - The Dish being operated on .
* @ param { Operation [ ] } state . opList - The list of operations in the recipe .
* @ returns { Object } The updated state of the recipe .
* /
async run ( state ) {
const opList = state . opList ,
inputType = opList [ state . progress ] . inputType ,
outputType = opList [ state . progress ] . outputType ,
input = await state . dish . get ( inputType ) ,
ings = opList [ state . progress ] . ingValues ,
2018-05-21 13:39:10 +02:00
[ splitDelim , mergeDelim , ignoreErrors ] = ings ,
2018-05-21 11:58:35 +02:00
subOpList = [ ] ;
let inputs = [ ] ,
i ;
if ( input )
inputs = input . split ( splitDelim ) ;
2022-06-17 10:17:28 +02:00
// Set to 1 as if we are here, then there is one, the current one.
let numOp = 1 ;
2018-05-21 11:58:35 +02:00
// Create subOpList for each tranche to operate on
2022-06-17 10:17:28 +02:00
// all remaining operations unless we encounter a Merge
2018-05-21 11:58:35 +02:00
for ( i = state . progress + 1 ; i < opList . length ; i ++ ) {
if ( opList [ i ] . name === "Merge" && ! opList [ i ] . disabled ) {
2022-06-17 10:17:28 +02:00
numOp -- ;
if ( numOp === 0 || opList [ i ] . ingValues [ 0 ] )
break ;
else
// Not this Fork's Merge.
subOpList . push ( opList [ i ] ) ;
2018-05-21 11:58:35 +02:00
} else {
2022-06-17 10:17:28 +02:00
if ( opList [ i ] . name === "Fork" || opList [ i ] . name === "Subsection" )
numOp ++ ;
2018-05-21 11:58:35 +02:00
subOpList . push ( opList [ i ] ) ;
}
}
const recipe = new Recipe ( ) ;
2019-10-18 14:57:21 +02:00
const outputs = [ ] ;
let progress = 0 ;
2018-05-21 11:58:35 +02:00
state . forkOffset += state . progress + 1 ;
recipe . addOperations ( subOpList ) ;
// Take a deep(ish) copy of the ingredient values
const ingValues = subOpList . map ( op => JSON . parse ( JSON . stringify ( op . ingValues ) ) ) ;
// Run recipe over each tranche
for ( i = 0 ; i < inputs . length ; i ++ ) {
// Baseline ing values for each tranche so that registers are reset
2019-03-07 17:26:42 +01:00
recipe . opList . forEach ( ( op , i ) => {
2018-05-21 11:58:35 +02:00
op . ingValues = JSON . parse ( JSON . stringify ( ingValues [ i ] ) ) ;
} ) ;
const dish = new Dish ( ) ;
dish . set ( inputs [ i ] , inputType ) ;
try {
progress = await recipe . execute ( dish , 0 , state ) ;
} catch ( err ) {
if ( ! ignoreErrors ) {
throw err ;
}
progress = err . progress + 1 ;
}
2019-10-18 14:57:21 +02:00
outputs . push ( await dish . get ( outputType ) ) ;
2018-05-21 11:58:35 +02:00
}
2019-10-18 14:57:21 +02:00
state . dish . set ( outputs . join ( mergeDelim ) , outputType ) ;
2018-05-21 11:58:35 +02:00
state . progress += progress ;
return state ;
}
}
export default Fork ;