{"_id":"5cbf26d364ca2c005dffeb6f","project":"55faf11ba62ba1170021a9a7","version":{"_id":"55faf11ba62ba1170021a9aa","project":"55faf11ba62ba1170021a9a7","__v":46,"createdAt":"2015-09-17T16:58:03.490Z","releaseDate":"2015-09-17T16:58:03.490Z","categories":["55faf11ca62ba1170021a9ab","55faf8f4d0e22017005b8272","55faf91aa62ba1170021a9b5","55faf929a8a7770d00c2c0bd","55faf932a8a7770d00c2c0bf","55faf94b17b9d00d00969f47","55faf958d0e22017005b8274","55faf95fa8a7770d00c2c0c0","55faf96917b9d00d00969f48","55faf970a8a7770d00c2c0c1","55faf98c825d5f19001fa3a6","55faf99aa62ba1170021a9b8","55faf99fa62ba1170021a9b9","55faf9aa17b9d00d00969f49","55faf9b6a8a7770d00c2c0c3","55faf9bda62ba1170021a9ba","5604570090ee490d00440551","5637e8b2fbe1c50d008cb078","5649bb624fa1460d00780add","5671974d1b6b730d008b4823","5671979d60c8e70d006c9760","568e8eef70ca1f0d0035808e","56d0a2081ecc471500f1795e","56d4a0adde40c70b00823ea3","56d96b03dd90610b00270849","56fbb83d8f21c817002af880","573c811bee2b3b2200422be1","576bc92afb62dd20001cda85","5771811e27a5c20e00030dcd","5785191af3a10c0e009b75b0","57bdf84d5d48411900cd8dc0","57ff5c5dc135231700aed806","5804caf792398f0f00e77521","58458b4fba4f1c0f009692bb","586d3c287c6b5b2300c05055","58ef66d88646742f009a0216","58f5d52d7891630f00fe4e77","59a555bccdbd85001bfb1442","5a2a81f688574d001e9934f5","5b080c8d7833b20003ddbb6f","5c222bed4bc358002f21459a","5c22412594a2a5005cc9e919","5c41ae1c33592700190a291e","5c8a525e2ba7b2003f9b153c","5cbf14d58c79c700ef2b502e","5db6f03a6e187c006f667fa4"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"category":{"_id":"5cbf14d58c79c700ef2b502e","project":"55faf11ba62ba1170021a9a7","version":"55faf11ba62ba1170021a9aa","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2019-04-23T13:36:21.375Z","from_sync":false,"order":33,"slug":"edit-an-app-1","title":"EDIT AN APP"},"user":"5767bc73bb15f40e00a28777","__v":0,"parentDoc":null,"metadata":{"title":"","description":"","image":[]},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2019-04-23T14:53:07.503Z","link_external":false,"link_url":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":8,"body":"[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"This page provides sample dynamics expressions in version **1.0** of the Common Workflow Language. If you are describing a tool using the sbg:draft-2 version of CWL, please see [this page](doc:javascript-cookbook) for sample expressions.\"\n}\n[/block]\nThis page provides examples of expressions that are entered in the tool editor when wrapping a tool for use on the CGC. Expressions can be used to dynamically set different tool properties such as arguments, secondary files, metadata, output file names, etc. Dynamic expressions commonly use the `self` and `inputs` predefined objects, which are determined at runtime and denote properties of the tool's inputs or outputs in a given execution and the ongoing tool execution (the job). The expressions are entered anywhere in the Tool Editor where the **</>** symbol is present. For general information about expressions, please refer to [dynamic expressions in tool descriptions](doc:dynamic-expressions-in-tool-descriptions-1).\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"* [Capture the name and content of an input file](#section-capture-the-name-and-content-of-an-input-file)\\n* [Name output files based on the Sample ID metadata field of input files](#section-name-output-files-based-on-the-sample-id-metadata-field-of-input-files)\\n* [Name output files based on input file names](#section-name-output-files-based-on-input-file-names)\\n* [Setting metadata fields of output files based on inputs for paired end 1 and 2](#section-setting-metadata-fields-of-output-files-based-on-inputs-for-paired-end-1-and-2)\\n* [Order input reads based on paired-end metadata](#section-order-input-reads-based-on-paired-end-metadata)\\n* [Configure a tool to unpack a TAR archive provided as its input](#section-configure-a-tool-to-unpack-a-tar-archive-provided-as-its-input)\"\n}\n[/block]\n### Capture the name and content of an input file\nThe following expression picks out the name of the data file input for each execution of the tool. The dynamic expression will be based on the `inputs` object. We will use the following Javascript expression to fetch the input file name:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"$(inputs.<input_ID_for_data_file>.basename)\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nIn this expression, you should replace `<input_ID_for_data_file>` with the ID for the input port that the data file goes into. This expression will then take the path of the input to the specified port, split the path on '/', and then select the last slice of the split list. This should be the file name, at the end of the path.\n\nTo refer to the content of the file, use the following expression:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"$(inputs.<input_ID_for_data_file>.contents)\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nAs before, `<input_ID_for_data_file>` refers to the ID of the input port that the data file gets inputted to. This expression will pick out the file object that is inputted there, and set it to the content of the file named in the expression above.\n\n### Name output files based on the Sample ID metadata field of input files\nThe expression below is used to name an output file of a tool based on the value in the **Sample ID** metadata field obtained from the input files. As some tools allow you to specify the output file name as a command line argument, this expression can be used to define the argument value in the [Arguments section](doc:create-a-tool#section-arguments).\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"${\\n  var input_files = [].concat(inputs.<input_port_ID>)\\n  var filename = input_files[0].basename;\\n   \\n  if (input_files[0].metadata && input_files[0].metadata.sample_id)\\n  {\\n    var filebase = input_files[0].metadata.sample_id\\n  }\\n  else\\n  {\\n    var filebase = \\\"sample_unknown\\\"\\n  }\\n \\n  return filebase.concat(\\\"<file_extension>\\\")\\n}\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nThe expression works as follows:\n\nThe following two lines of code get the file name(s) from the input file or array of files.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var input_files = [].concat(inputs.<input_port_ID>)\\nvar filename = input_files[0].basename;\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nMake sure to replace `<input_port_ID>` value with the the corresponding port ID of your app.\n\nThe next part of the expression checks whether the input file has a value set in the **Sample ID** metadata field. If there is a value, it is used as the base name of the output file. Otherwise, the base name will be `sample_unknown`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if (input_files[0].metadata && input_files[0].metadata.sample_id)\\n  {\\n    var filebase = input_files[0].metadata.sample_id\\n  }\\n  else\\n  {\\n    var filebase = \\\"sample_unknown\\\"\\n  }\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nFinally, the extension is appended to the base name of the file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"return filebase.concat(\\\"<file_extension>\\\")\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nMake sure to replace `<file_extension>` with the extension of the tool's output file, including the dot (for example `.bam`).\n\n### Name output files based on input file names\nThe following expression will retrieve the name of the input file for the job and return it as the name of the output file. This expression can also be used with tools that allow output file name to be defined through a command line argument. It is entered as the argument value in the [Arguments section](doc:create-a-tool#section-arguments) of the tool editor's **Visual Editor** tab.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"${\\n  var reads = [].concat(inputs.<input_port_ID>)\\n  var file_path = reads[0].path  // result in format /path/to/input_file.bam\\n  var filename = reads[0].basename // result in format input_file.bam\\n  var filebase = reads[0].nameroot // result in format input_file\\n  var out_name = filebase.concat(\\\"<file_extension>\\\")  //e.g. input_file.vcf\\n  return out_name \\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression works as follows:\n\nThe following four lines of code get the file path, name and basename from the file or array of files that have been provided as the input.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var reads = [].concat(inputs.<input_port_ID>)\\nvar file_path = reads[0].path  // result in format /path/to/input_file.bam\\nvar filename = reads[0].basename // result in format input_file.bam\\nvar filebase = reads[0].nameroot // result in format input_file\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe last part of the expression appends the extension to the base name and returns the full name of the output file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var out_name = filebase.concat(\\\"<file_extension>\\\")  //e.g. input_file.vcf\\nreturn out_name\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nYou need to replace `<file_extension>` in the code to match the extension you need for your output file. The extension should also include the dot (for example `.vcf`).\n\n### Setting metadata fields of output files based on inputs for paired end 1 and 2\nThis expression is used to copy the values in the **Paired-end** metadata field from input files for a given job to their corresponding paired-end output files.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"${\\n  var out = self;\\n \\n  var filename = self.basename;\\n  var filebase = filename.split('.').slice(0, -3).join('.')\\n   \\n  var reads = [].concat(inputs.<input_port_ID>);\\n \\n  for (i=0; i<reads.length; i++)\\n  {\\n    var input_filename = reads[i].basename;\\n    var input_filebase = input_filename.split('.').slice(0, -3).join('.');\\n       \\n    if (filebase==input_filebase && inputs.<input_port_ID>[i].metadata && inputs.<input_port_ID>[i].metadata.paired_end)\\n    {\\n      out.metadata={\\\"paired_end\\\": \\\"\\\"}\\n      out.metadata[\\\"paired_end\\\"] = inputs.<input_port_ID>[i].metadata.paired_end;\\n      return out\\n    }\\n    return out\\n  }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression is entered in the **OutputEval** field on the output port's setup screen.\n\nThe code is analyzed below:\n\nThe **OutputEval** field is used to transform the output and modify it's attributes. The following line defines a variable containing the original value of the output:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var out = self\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe following two lines extract the base name of the output file on the output port:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var filename = self.basename\\nvar filebase = filename.split('.').slice(0, -3).join('.')\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression assumes that the file extension includes three dot-separated portions, such as `<base_name>.pe_1.fastq.gz`. The `slice(0, -3)` method in the second line above is used to extract the part of the file name before `.pe_1.fastq.gz`, but can be adjusted to match the file naming convention for your tool's input paired-end files. For example, if the naming convention is `<base_name>.fastq`, the method needs to be `slice(0, -1)`.\n\nThe next line creates an array containing the input file(s):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var reads = [].concat(inputs.<input_port_ID>)\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nMake sure to replace `<input_port_ID>` with the actual ID of the input port for paired-end files.\n\nFinally, there is a for loop that iterates through the array of input file paths and gets the base name of each of the files.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"for (var i=0; i<reads.length; i++)\\n{\\n  var input_filename = reads[i].basename;\\n  var input_filebase = input_filename.split('.').slice(0, -3).join('.');\\n     \\n  if (filebase==input_filebase && inputs.<input_port_ID>[i].metadata && inputs.<input_port_ID>[i].metadata.paired_end)\\n  {\\n    out.metadata={\\\"paired_end\\\": \\\"\\\"}\\n    out.metadata[\\\"paired_end\\\"] = inputs.<input_port_ID>[i].metadata.paired_end;\\n    return out\\n  }\\n  return out\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nOnce it finds the input file whose name matches the name of the output file, it checks whether the input file has metadata and has a value in the **Paired-end** metadata field. If there is a value, the value becomes the **Paired-end** metadata value for the output file.\n\n### Order input reads based on paired-end metadata\nSome tools, such as **BWA MEM Bundle** require paired-end input reads to be ordered in the correct sequence (paired-end 1 first, followed by paired-end 2). This expression will automatically order the input reads based on the values entered in the **paired_end** metadata field:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"${\\n \\n var input_reads = inputs.input_reads\\n \\n var read_metadata = input_reads[0].metadata\\n if(!read_metadata) read_metadata = []\\n  \\n var order = 0\\n  \\n if(read_metadata == []){ order = 0 }\\n else if('paired_end' in read_metadata){\\n var pe1 = read_metadata.paired_end\\n if(pe1 != 1) order = 1\\n }\\n if (input_reads.length == 1){\\n   return input_reads[0].path\\n }\\n else if (input_reads.length == 2){\\n   if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\\n   else return input_reads[1].path + ' ' + input_reads[0].path\\n }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression works as follows:\n\nThe first code block declares a variable containing the input reads:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var input_reads = inputs.input_reads\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe following part reads metadata from the first supplied input read. If there is no metadata, assigns an empty array to the `read_metadata` variable:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var read_metadata = input_reads[0].metadata\\nif(!read_metadata) read_metadata = []\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe `order` flag is used to mark the order of input reads. The starting assumption is that the reads are ordered correctly, which is denoted by assigning the value 0 to `order`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"var order = 0\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe following code block starts by checking whether the first input read has any assigned metadata values. If it finds no values, no sorting can be done based on metadata and it assumes that the reads are in correct order (`order = 0`). Otherwise, it checks whether paired-end 1 corresponds to the first given read:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if(read_metadata == []){ order = 0 }\\n else if('paired_end' in read_metadata){\\n var pe1 = read_metadata.paired_end\\n if(pe1 != 1) order = 1 // change order\\n }\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nFinally, the expression checks how many reads there are and returns them in the correct order. If only one input read is present, this read is returned as there is no need for ordering. If there are two input reads, they are returned in the correct order based on the value of the `order` flag.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if (input_reads.length == 1){\\n   return input_reads[0].path\\n }\\n else if (input_reads.length == 2){\\n   if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\\n   else return input_reads[1].path + ' ' + input_reads[0].path\\n }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### Configure a tool to unpack a TAR archive provided as its input\nIn some cases, input files taken by a tool come in the form of a TAR archive. TAR archives can be produced by e.g. aligner indexers, which are a set of indexing tools that index reference files and output an archive containing the reference and the index file(s). A tool that needs to use the files from a TAR archive can be configured to unpack it.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"**Prerequisite**: In order to simplify the process of unpacking the archive using the expression below, the tool's input port that takes the archive file will have have to be [staged](doc:input-file-options#section-stage-input). This will make the TAR archive available directly in the tool's working directory.\"\n}\n[/block]\n1. Leave **Base Command** empty\n2. Define the entire command line via arguments\n3. Click **Add** in the **File Requirements** section and select **Expression**\n4. Click **</>** next to the first field.\n5. Add the following code:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"$(inputs.<input_port_id>)\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nPlease make sure to replace `<input_port_ID>`  in the above code with the ID value of your tool's input port that takes the archive file.\n6. Click **Save**. The input will now be available in the working directory.\n7. In the **Arguments** section click **Add an argument**.\n8. In the **Value** field on the right click **</>**.\n9. Paste the following code:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  var index_files_bundle = inputs.<input_port_ID>.basename\\n  return 'tar -xf ' + index_files_bundle + ' ; '\\n}\\n\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe first line of the expression retrieves the name of the archive file using the [inputs object](doc:dynamic-expressions-in-tool-descriptions-1#section-inputs-object). The second line appends the retrieved file name to the command that will unpack the archive file.\n\nPlease make sure to replace `<input_port_ID>`  in the above code with the ID value of your tool's input port that takes the archive file.\n\n10. Click **Save**.\n11. Click the **Save** icon in the top-right corner of the tool editor.\nYour tool is now configured to unpack a TAR archive it receives as its input.","excerpt":"","slug":"javascript-cookbook-1","type":"basic","title":"Javascript Cookbook"}

Javascript Cookbook


[block:callout] { "type": "info", "body": "This page provides sample dynamics expressions in version **1.0** of the Common Workflow Language. If you are describing a tool using the sbg:draft-2 version of CWL, please see [this page](doc:javascript-cookbook) for sample expressions." } [/block] This page provides examples of expressions that are entered in the tool editor when wrapping a tool for use on the CGC. Expressions can be used to dynamically set different tool properties such as arguments, secondary files, metadata, output file names, etc. Dynamic expressions commonly use the `self` and `inputs` predefined objects, which are determined at runtime and denote properties of the tool's inputs or outputs in a given execution and the ongoing tool execution (the job). The expressions are entered anywhere in the Tool Editor where the **</>** symbol is present. For general information about expressions, please refer to [dynamic expressions in tool descriptions](doc:dynamic-expressions-in-tool-descriptions-1). [block:callout] { "type": "info", "body": "* [Capture the name and content of an input file](#section-capture-the-name-and-content-of-an-input-file)\n* [Name output files based on the Sample ID metadata field of input files](#section-name-output-files-based-on-the-sample-id-metadata-field-of-input-files)\n* [Name output files based on input file names](#section-name-output-files-based-on-input-file-names)\n* [Setting metadata fields of output files based on inputs for paired end 1 and 2](#section-setting-metadata-fields-of-output-files-based-on-inputs-for-paired-end-1-and-2)\n* [Order input reads based on paired-end metadata](#section-order-input-reads-based-on-paired-end-metadata)\n* [Configure a tool to unpack a TAR archive provided as its input](#section-configure-a-tool-to-unpack-a-tar-archive-provided-as-its-input)" } [/block] ### Capture the name and content of an input file The following expression picks out the name of the data file input for each execution of the tool. The dynamic expression will be based on the `inputs` object. We will use the following Javascript expression to fetch the input file name: [block:code] { "codes": [ { "code": "$(inputs.<input_ID_for_data_file>.basename)", "language": "javascript" } ] } [/block] In this expression, you should replace `<input_ID_for_data_file>` with the ID for the input port that the data file goes into. This expression will then take the path of the input to the specified port, split the path on '/', and then select the last slice of the split list. This should be the file name, at the end of the path. To refer to the content of the file, use the following expression: [block:code] { "codes": [ { "code": "$(inputs.<input_ID_for_data_file>.contents)", "language": "javascript" } ] } [/block] As before, `<input_ID_for_data_file>` refers to the ID of the input port that the data file gets inputted to. This expression will pick out the file object that is inputted there, and set it to the content of the file named in the expression above. ### Name output files based on the Sample ID metadata field of input files The expression below is used to name an output file of a tool based on the value in the **Sample ID** metadata field obtained from the input files. As some tools allow you to specify the output file name as a command line argument, this expression can be used to define the argument value in the [Arguments section](doc:create-a-tool#section-arguments). [block:code] { "codes": [ { "code": "${\n var input_files = [].concat(inputs.<input_port_ID>)\n var filename = input_files[0].basename;\n \n if (input_files[0].metadata && input_files[0].metadata.sample_id)\n {\n var filebase = input_files[0].metadata.sample_id\n }\n else\n {\n var filebase = \"sample_unknown\"\n }\n \n return filebase.concat(\"<file_extension>\")\n}", "language": "text" } ] } [/block] The expression works as follows: The following two lines of code get the file name(s) from the input file or array of files. [block:code] { "codes": [ { "code": "var input_files = [].concat(inputs.<input_port_ID>)\nvar filename = input_files[0].basename;", "language": "text" } ] } [/block] Make sure to replace `<input_port_ID>` value with the the corresponding port ID of your app. The next part of the expression checks whether the input file has a value set in the **Sample ID** metadata field. If there is a value, it is used as the base name of the output file. Otherwise, the base name will be `sample_unknown`. [block:code] { "codes": [ { "code": "if (input_files[0].metadata && input_files[0].metadata.sample_id)\n {\n var filebase = input_files[0].metadata.sample_id\n }\n else\n {\n var filebase = \"sample_unknown\"\n }", "language": "javascript" } ] } [/block] Finally, the extension is appended to the base name of the file: [block:code] { "codes": [ { "code": "return filebase.concat(\"<file_extension>\")", "language": "javascript" } ] } [/block] Make sure to replace `<file_extension>` with the extension of the tool's output file, including the dot (for example `.bam`). ### Name output files based on input file names The following expression will retrieve the name of the input file for the job and return it as the name of the output file. This expression can also be used with tools that allow output file name to be defined through a command line argument. It is entered as the argument value in the [Arguments section](doc:create-a-tool#section-arguments) of the tool editor's **Visual Editor** tab. [block:code] { "codes": [ { "code": "${\n var reads = [].concat(inputs.<input_port_ID>)\n var file_path = reads[0].path // result in format /path/to/input_file.bam\n var filename = reads[0].basename // result in format input_file.bam\n var filebase = reads[0].nameroot // result in format input_file\n var out_name = filebase.concat(\"<file_extension>\") //e.g. input_file.vcf\n return out_name \n}", "language": "javascript" } ] } [/block] The expression works as follows: The following four lines of code get the file path, name and basename from the file or array of files that have been provided as the input. [block:code] { "codes": [ { "code": "var reads = [].concat(inputs.<input_port_ID>)\nvar file_path = reads[0].path // result in format /path/to/input_file.bam\nvar filename = reads[0].basename // result in format input_file.bam\nvar filebase = reads[0].nameroot // result in format input_file", "language": "javascript" } ] } [/block] The last part of the expression appends the extension to the base name and returns the full name of the output file: [block:code] { "codes": [ { "code": "var out_name = filebase.concat(\"<file_extension>\") //e.g. input_file.vcf\nreturn out_name", "language": "javascript" } ] } [/block] You need to replace `<file_extension>` in the code to match the extension you need for your output file. The extension should also include the dot (for example `.vcf`). ### Setting metadata fields of output files based on inputs for paired end 1 and 2 This expression is used to copy the values in the **Paired-end** metadata field from input files for a given job to their corresponding paired-end output files. [block:code] { "codes": [ { "code": "${\n var out = self;\n \n var filename = self.basename;\n var filebase = filename.split('.').slice(0, -3).join('.')\n \n var reads = [].concat(inputs.<input_port_ID>);\n \n for (i=0; i<reads.length; i++)\n {\n var input_filename = reads[i].basename;\n var input_filebase = input_filename.split('.').slice(0, -3).join('.');\n \n if (filebase==input_filebase && inputs.<input_port_ID>[i].metadata && inputs.<input_port_ID>[i].metadata.paired_end)\n {\n out.metadata={\"paired_end\": \"\"}\n out.metadata[\"paired_end\"] = inputs.<input_port_ID>[i].metadata.paired_end;\n return out\n }\n return out\n }\n}", "language": "javascript" } ] } [/block] The expression is entered in the **OutputEval** field on the output port's setup screen. The code is analyzed below: The **OutputEval** field is used to transform the output and modify it's attributes. The following line defines a variable containing the original value of the output: [block:code] { "codes": [ { "code": "var out = self", "language": "javascript" } ] } [/block] The following two lines extract the base name of the output file on the output port: [block:code] { "codes": [ { "code": "var filename = self.basename\nvar filebase = filename.split('.').slice(0, -3).join('.')", "language": "javascript" } ] } [/block] The expression assumes that the file extension includes three dot-separated portions, such as `<base_name>.pe_1.fastq.gz`. The `slice(0, -3)` method in the second line above is used to extract the part of the file name before `.pe_1.fastq.gz`, but can be adjusted to match the file naming convention for your tool's input paired-end files. For example, if the naming convention is `<base_name>.fastq`, the method needs to be `slice(0, -1)`. The next line creates an array containing the input file(s): [block:code] { "codes": [ { "code": "var reads = [].concat(inputs.<input_port_ID>)", "language": "javascript" } ] } [/block] Make sure to replace `<input_port_ID>` with the actual ID of the input port for paired-end files. Finally, there is a for loop that iterates through the array of input file paths and gets the base name of each of the files. [block:code] { "codes": [ { "code": "for (var i=0; i<reads.length; i++)\n{\n var input_filename = reads[i].basename;\n var input_filebase = input_filename.split('.').slice(0, -3).join('.');\n \n if (filebase==input_filebase && inputs.<input_port_ID>[i].metadata && inputs.<input_port_ID>[i].metadata.paired_end)\n {\n out.metadata={\"paired_end\": \"\"}\n out.metadata[\"paired_end\"] = inputs.<input_port_ID>[i].metadata.paired_end;\n return out\n }\n return out\n}", "language": "javascript" } ] } [/block] Once it finds the input file whose name matches the name of the output file, it checks whether the input file has metadata and has a value in the **Paired-end** metadata field. If there is a value, the value becomes the **Paired-end** metadata value for the output file. ### Order input reads based on paired-end metadata Some tools, such as **BWA MEM Bundle** require paired-end input reads to be ordered in the correct sequence (paired-end 1 first, followed by paired-end 2). This expression will automatically order the input reads based on the values entered in the **paired_end** metadata field: [block:code] { "codes": [ { "code": "${\n \n var input_reads = inputs.input_reads\n \n var read_metadata = input_reads[0].metadata\n if(!read_metadata) read_metadata = []\n \n var order = 0\n \n if(read_metadata == []){ order = 0 }\n else if('paired_end' in read_metadata){\n var pe1 = read_metadata.paired_end\n if(pe1 != 1) order = 1\n }\n if (input_reads.length == 1){\n return input_reads[0].path\n }\n else if (input_reads.length == 2){\n if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\n else return input_reads[1].path + ' ' + input_reads[0].path\n }\n}", "language": "javascript" } ] } [/block] The expression works as follows: The first code block declares a variable containing the input reads: [block:code] { "codes": [ { "code": "var input_reads = inputs.input_reads", "language": "javascript" } ] } [/block] The following part reads metadata from the first supplied input read. If there is no metadata, assigns an empty array to the `read_metadata` variable: [block:code] { "codes": [ { "code": "var read_metadata = input_reads[0].metadata\nif(!read_metadata) read_metadata = []", "language": "javascript" } ] } [/block] The `order` flag is used to mark the order of input reads. The starting assumption is that the reads are ordered correctly, which is denoted by assigning the value 0 to `order`. [block:code] { "codes": [ { "code": "var order = 0", "language": "javascript" } ] } [/block] The following code block starts by checking whether the first input read has any assigned metadata values. If it finds no values, no sorting can be done based on metadata and it assumes that the reads are in correct order (`order = 0`). Otherwise, it checks whether paired-end 1 corresponds to the first given read: [block:code] { "codes": [ { "code": "if(read_metadata == []){ order = 0 }\n else if('paired_end' in read_metadata){\n var pe1 = read_metadata.paired_end\n if(pe1 != 1) order = 1 // change order\n }", "language": "javascript" } ] } [/block] Finally, the expression checks how many reads there are and returns them in the correct order. If only one input read is present, this read is returned as there is no need for ordering. If there are two input reads, they are returned in the correct order based on the value of the `order` flag. [block:code] { "codes": [ { "code": "if (input_reads.length == 1){\n return input_reads[0].path\n }\n else if (input_reads.length == 2){\n if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\n else return input_reads[1].path + ' ' + input_reads[0].path\n }\n}", "language": "javascript" } ] } [/block] ### Configure a tool to unpack a TAR archive provided as its input In some cases, input files taken by a tool come in the form of a TAR archive. TAR archives can be produced by e.g. aligner indexers, which are a set of indexing tools that index reference files and output an archive containing the reference and the index file(s). A tool that needs to use the files from a TAR archive can be configured to unpack it. [block:callout] { "type": "info", "body": "**Prerequisite**: In order to simplify the process of unpacking the archive using the expression below, the tool's input port that takes the archive file will have have to be [staged](doc:input-file-options#section-stage-input). This will make the TAR archive available directly in the tool's working directory." } [/block] 1. Leave **Base Command** empty 2. Define the entire command line via arguments 3. Click **Add** in the **File Requirements** section and select **Expression** 4. Click **</>** next to the first field. 5. Add the following code: [block:code] { "codes": [ { "code": "$(inputs.<input_port_id>)", "language": "javascript" } ] } [/block] Please make sure to replace `<input_port_ID>` in the above code with the ID value of your tool's input port that takes the archive file. 6. Click **Save**. The input will now be available in the working directory. 7. In the **Arguments** section click **Add an argument**. 8. In the **Value** field on the right click **</>**. 9. Paste the following code: [block:code] { "codes": [ { "code": "{\n var index_files_bundle = inputs.<input_port_ID>.basename\n return 'tar -xf ' + index_files_bundle + ' ; '\n}\n", "language": "javascript" } ] } [/block] The first line of the expression retrieves the name of the archive file using the [inputs object](doc:dynamic-expressions-in-tool-descriptions-1#section-inputs-object). The second line appends the retrieved file name to the command that will unpack the archive file. Please make sure to replace `<input_port_ID>` in the above code with the ID value of your tool's input port that takes the archive file. 10. Click **Save**. 11. Click the **Save** icon in the top-right corner of the tool editor. Your tool is now configured to unpack a TAR archive it receives as its input.