/// <summary> /// Checks the given JSON object key-value pair is a valid EntryPoint output. /// Extracts out any variables that need to be populated and adds them to the /// EntryPoint context. /// </summary> private void CheckAndMarkOutputValue(KeyValuePair <string, JToken> pair) { if (!VariableBinding.IsBindingToken(pair.Value)) { throw _host.Except("Only variables allowed as outputs"); } // Output variable. var varBinding = VariableBinding.Create(_host, pair.Value.Value <string>()); if (!(varBinding is SimpleVariableBinding)) { throw _host.Except($"Output '{pair.Key}' can only be bound to a variable"); } var valueType = _outputHelper.GetFieldType(pair.Key); if (valueType == null) { throw _host.Except($"Unexpected output name: '{pair.Key}"); } if (!EntryPointVariable.IsValidType(valueType)) { throw _host.Except($"Output '{pair.Key}' has invalid type"); } _context.AddOutputVariable(varBinding.VariableName, valueType); _outputMap[pair.Key] = varBinding.VariableName; }
/// <summary> /// Checks the given JSON object key-value pair is a valid EntryPoint input and /// extracts out any variables that need to be populated. These variables will be /// added to the EntryPoint context. Input parameters that are not set to variables /// will be immediately set using the input builder instance. /// </summary> private void CheckAndSetInputValue(KeyValuePair <string, JToken> pair) { var inputName = _inputBuilder.GetFieldNameOrNull(pair.Key); if (VariableBinding.IsBindingToken(pair.Value)) { Type valueType = _inputBuilder.GetFieldTypeOrNull(pair.Key); if (valueType == null) { throw _host.Except($"Unexpected input name: '{pair.Key}'"); } if (!EntryPointVariable.IsValidType(valueType)) { throw _host.Except($"Unexpected input variable type: {valueType}"); } var varBinding = VariableBinding.Create(_host, pair.Value.Value <string>()); _context.AddInputVariable(varBinding, valueType); if (!_inputBindingMap.ContainsKey(inputName)) { _inputBindingMap[inputName] = new List <ParameterBinding>(); } var paramBinding = new SimpleParameterBinding(inputName); _inputBindingMap[inputName].Add(paramBinding); _inputMap[paramBinding] = varBinding; } else if (pair.Value is JArray && ((JArray)pair.Value).Any(tok => VariableBinding.IsBindingToken(tok))) { // REVIEW: EntryPoint arrays and dictionaries containing // variables must ONLY contain variables right now. if (!((JArray)pair.Value).All(tok => VariableBinding.IsBindingToken(tok))) { throw _host.Except($"Input {pair.Key} may ONLY contain variables."); } Type valueType = _inputBuilder.GetFieldTypeOrNull(pair.Key); if (valueType == null || !valueType.HasElementType) { throw _host.Except($"Unexpected input name: '{pair.Key}'"); } valueType = valueType.GetElementType(); int i = 0; foreach (var varName in (JArray)pair.Value) { var varBinding = VariableBinding.Create(_host, varName.Value <string>()); _context.AddInputVariable(varBinding, valueType); if (!_inputBindingMap.ContainsKey(inputName)) { _inputBindingMap[inputName] = new List <ParameterBinding>(); } var paramBinding = new ArrayIndexParameterBinding(inputName, i++); _inputBindingMap[inputName].Add(paramBinding); _inputMap[paramBinding] = varBinding; } } // REVIEW: Implement support for Dictionary of variable values. We need to differentiate // between a Dictionary and a Component here, and likely need to support nested components // all of which might have variables. Our current machinery only works at the 'Node' level. else { // This is not a variable. if (!_inputBuilder.TrySetValueJson(pair.Key, pair.Value)) { throw _host.Except($"Unexpected input: '{pair.Key}'"); } } }