public override bool TryCreate(FunctionFolderInfo functionFolderInfo, out FunctionDescriptor functionDescriptor)
        {
            functionDescriptor = null;

            // name might point to a single file, or a module
            string extension = Path.GetExtension(functionFolderInfo.Source).ToLower();
            if (!(extension == ".js" || string.IsNullOrEmpty(extension)))
            {
                return false;
            }

            // parse the bindings
            JObject bindings = (JObject)functionFolderInfo.Configuration["bindings"];
            JArray inputs = (JArray)bindings["input"];
            Collection<Binding> inputBindings = Binding.GetBindings(inputs, FileAccess.Read);

            JArray outputs = (JArray)bindings["output"];
            Collection<Binding> outputBindings = Binding.GetBindings(outputs, FileAccess.Write);

            JObject trigger = (JObject)inputs.FirstOrDefault(p => ((string)p["type"]).ToLowerInvariant().EndsWith("trigger"));
            string triggerType = (string)trigger["type"];

            string triggerParameterName = (string)trigger["name"];
            if (string.IsNullOrEmpty(triggerParameterName))
            {
                // default the name to simply 'input'
                trigger["name"] = triggerParameterName = "input";
            }

            NodeFunctionInvoker invoker = new NodeFunctionInvoker(triggerParameterName, functionFolderInfo.Source, inputBindings, outputBindings);

            ParameterDescriptor triggerParameter = null;
            switch (triggerType)
            {
                case "queueTrigger":
                    triggerParameter = ParseQueueTrigger(trigger);
                    break;
                case "blobTrigger":
                    triggerParameter = ParseBlobTrigger(trigger);
                    break;
                case "serviceBusTrigger":
                    triggerParameter = ParseServiceBusTrigger(trigger);
                    break;
                case "timerTrigger":
                    triggerParameter = ParseTimerTrigger(trigger, typeof(TimerInfo));
                    break;
                case "webHookTrigger":
                    triggerParameter = ParseWebHookTrigger(trigger);
                    break;
            }

            Collection<ParameterDescriptor> parameters = new Collection<ParameterDescriptor>();
            parameters.Add(triggerParameter);

            // Add a TraceWriter for logging
            parameters.Add(new ParameterDescriptor("log", typeof(TraceWriter)));

            // Add an IBinder to support the binding programming model
            parameters.Add(new ParameterDescriptor("binder", typeof(IBinder)));

            functionDescriptor = new FunctionDescriptor(functionFolderInfo.Name, invoker, parameters);

            return true;
        }
 public abstract bool TryCreate(FunctionFolderInfo functionFolderInfo, out FunctionDescriptor functionDescriptor);
        internal static Collection<FunctionDescriptor> ReadFunctions(ScriptHostConfiguration config, IEnumerable<FunctionDescriptorProvider> descriptionProviders)
        {
            string scriptRootPath = config.RootPath;
            List<FunctionFolderInfo> functionFolderInfos = new List<FunctionFolderInfo>();
            foreach (var scriptDir in Directory.EnumerateDirectories(scriptRootPath))
            {
                FunctionFolderInfo functionInfo = new FunctionFolderInfo();

                // read the function config
                string functionConfigPath = Path.Combine(scriptDir, "function.json");
                if (!File.Exists(functionConfigPath))
                {
                    // not a function directory
                    continue;
                }
                string json = File.ReadAllText(functionConfigPath);
                functionInfo.Configuration = JObject.Parse(json);

                // unless the name is explicitly set in the config,
                // default it to the function folder name
                string name = (string)functionInfo.Configuration["name"];
                if (string.IsNullOrEmpty(name))
                {
                    functionInfo.Name = Path.GetFileNameWithoutExtension(scriptDir);
                }

                // determine the primary script
                string[] functionFiles = Directory.EnumerateFiles(scriptDir).Where(p => Path.GetFileName(p).ToLowerInvariant() != "function.json").ToArray();
                if (functionFiles.Length == 0)
                {
                    continue;
                }
                else if (functionFiles.Length == 1)
                {
                    // if there is only a single file, that file is primary
                    functionInfo.Source = functionFiles[0];
                }
                else
                {
                    // if there is a "run" file, that file is primary
                    string functionPrimary = null;
                    functionPrimary = functionFiles.FirstOrDefault(p => Path.GetFileNameWithoutExtension(p).ToLowerInvariant() == "run");
                    if (string.IsNullOrEmpty(functionPrimary))
                    {
                        // for Node, any index.js file is primary
                        functionPrimary = functionFiles.FirstOrDefault(p => Path.GetFileName(p).ToLowerInvariant() == "index.js");
                        if (string.IsNullOrEmpty(functionPrimary))
                        {
                            // finally, if there is an explicit primary file indicated
                            // in config, use it
                            JToken token = functionInfo.Configuration["source"];
                            if (token != null)
                            {
                                string sourceFileName = (string)token;
                                functionPrimary = Path.Combine(scriptDir, sourceFileName);
                            }
                        }
                    }

                    if (string.IsNullOrEmpty(functionPrimary))
                    {
                        // TODO: should this be an error?
                        continue;
                    }
                    functionInfo.Source = functionPrimary;
                }

                functionFolderInfos.Add(functionInfo);
            }

            var functions = ReadFunctions(functionFolderInfos, descriptionProviders);
            return functions;
        }
        private static MethodInfo GenerateMethod(JObject trigger)
        {
            FunctionFolderInfo functionFolderInfo = new FunctionFolderInfo();
            functionFolderInfo.Name = "Test";
            functionFolderInfo.Source = Path.Combine(Environment.CurrentDirectory, @"scripts\Common\test.js");

            JArray inputs = new JArray(trigger);
            functionFolderInfo.Configuration = new JObject();
            functionFolderInfo.Configuration["bindings"] = new JObject();
            functionFolderInfo.Configuration["bindings"]["input"] = inputs;

            List<FunctionFolderInfo> functionFolderInfos = new List<FunctionFolderInfo>();
            functionFolderInfos.Add(functionFolderInfo);

            FunctionDescriptorProvider[] descriptorProviders = new FunctionDescriptorProvider[]
            {
                new NodeFunctionDescriptorProvider(Environment.CurrentDirectory)
            };
            var functionDescriptors = ScriptHost.ReadFunctions(functionFolderInfos, descriptorProviders);
            Type t = FunctionGenerator.Generate("TestScriptHost", "Host.Functions", functionDescriptors);

            MethodInfo method = t.GetMethods(BindingFlags.Public | BindingFlags.Static).First();
            return method;
        }