Task 450: .NF File Format

Task 450: .NF File Format

File Format Specifications for the .NF File Format

The .NF file format is the script format used by Nextflow, a workflow management system for data-intensive computational pipelines. It is a text-based format using a domain-specific language (DSL) based on Groovy syntax. The specifications are documented in the Nextflow scripting language reference, which defines the syntax, semantics, and structure for defining workflows, processes, and other components. .NF files are plain text, UTF-8 encoded, and typically contain declarative code for pipeline configuration, data flow, and execution logic. There is no binary encoding or magic number; the format is identified by extension and content. Scripts are executable by the Nextflow engine, which interprets them to orchestrate tasks across computing environments.

List of all the properties of this file format intrinsic to its file system:

  • Variables: Declared with def, support types like numbers, dates, booleans, strings.
  • Lists: Defined with [], support indexing, size(), collect, each.
  • Maps: Defined with [key: value], support key access, addition with +.
  • Tuples: Created with tuple(), immutable, accessed by index, destructurable.
  • Operators: Equality (==, !=), comparison (<, >, etc.), logical (&&, ||, !), membership (in), arithmetic (+, -, *, /, **, %), concatenation (+ for strings/lists/maps).
  • Conditional Execution: if-else statements, ternary (condition ? true : false), Elvis (?:).
  • Strings: Single ('), double (" with interpolation $var), multi-line ("""), backslash continuation (\).
  • Regular Expressions: Matching with =~ (partial) or ==~ (exact), replacement with replaceFirst(), replaceAll(), matcher groups.
  • Closures: { params -> body }, implicit it parameter, access outer scope.
  • Script Definitions: workflow { } for entry point, def for functions, includes for modules.
  • Keywords: def, println, new, assert, if, else, tuple, workflow.
  • Structure Elements: Curly braces { } for blocks, # for comments, (args) for invocations, .method() for calls.

Two direct download links for files of format .NF:

Ghost blog embedded HTML JavaScript for drag and drop .NF file to dump properties to screen:

Drag and drop .NF file here

1.Python class for opening .NF file, decode/read/write, print properties to console:

import re

class NFHandler:
    def __init__(self, filename):
        self.filename = filename
        self.content = ''
        self.properties = {}

    def read(self):
        with open(self.filename, 'r', encoding='utf-8') as f:
            self.content = f.read()
        self.decode()

    def decode(self):
        lines = self.content.split('\n')
        self.properties = {
            'variables': [], 'lists': [], 'maps': [], 'tuples': [], 'operators': [], 'conditionals': [], 'strings': [], 'regex': [], 'closures': [], 'definitions': [], 'keywords': [], 'structures': []
        }
        keywords = ['def', 'println', 'new', 'assert', 'if', 'else', 'tuple', 'workflow']
        for line in lines:
            if line.strip().startswith('def '):
                self.properties['variables'].append(line.strip())
            if '[]' in line:
                self.properties['lists'].append(line.strip())
            if '[:' in line:
                self.properties['maps'].append(line.strip())
            if 'tuple(' in line:
                self.properties['tuples'].append(line.strip())
            if re.search(r'==|!=|<|>|&&|\|\|', line):
                self.properties['operators'].append(line.strip())
            if 'if' in line or 'else' in line or '?' in line:
                self.properties['conditionals'].append(line.strip())
            if '"' in line or "'" in line or '"""' in line:
                self.properties['strings'].append(line.strip())
            if '=~' in line or '==~' in line:
                self.properties['regex'].append(line.strip())
            if '{' in line and '->' in line:
                self.properties['closures'].append(line.strip())
            if 'workflow {' in line:
                self.properties['definitions'].append(line.strip())
            for kw in keywords:
                if kw in line:
                    self.properties['keywords'].append(line.strip())
                    break
            if '#' in line or '{' in line or '(' in line:
                self.properties['structures'].append(line.strip())

    def print_properties(self):
        for key, values in self.properties.items():
            if values:
                print(f"{key.capitalize()}:")
                for value in values:
                    print(f"  - {value}")

    def write(self, new_filename=None):
        filename = new_filename or self.filename
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(self.content)

# Example usage:
# handler = NFHandler('example.nf')
# handler.read()
# handler.print_properties()
# handler.write('output.nf')
  1. Java class for opening .NF file, decode/read/write, print properties to console:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class NFHandler {
    private String filename;
    private String content = "";
    private Map<String, List<String>> properties = new HashMap<>();

    public NFHandler(String filename) {
        this.filename = filename;
    }

    public void read() throws IOException {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }
        }
        content = sb.toString();
        decode();
    }

    private void decode() {
        String[] lines = content.split("\n");
        String[] keywords = {"def", "println", "new", "assert", "if", "else", "tuple", "workflow"};
        properties.put("variables", new ArrayList<>());
        properties.put("lists", new ArrayList<>());
        properties.put("maps", new ArrayList<>());
        properties.put("tuples", new ArrayList<>());
        properties.put("operators", new ArrayList<>());
        properties.put("conditionals", new ArrayList<>());
        properties.put("strings", new ArrayList<>());
        properties.put("regex", new ArrayList<>());
        properties.put("closures", new ArrayList<>());
        properties.put("definitions", new ArrayList<>());
        properties.put("keywords", new ArrayList<>());
        properties.put("structures", new ArrayList<>());

        Pattern operatorPattern = Pattern.compile("==|!=|<|>|&&|\\|\\|");

        for (String line : lines) {
            if (line.trim().startsWith("def ")) {
                properties.get("variables").add(line.trim());
            }
            if (line.contains("[]")) {
                properties.get("lists").add(line.trim());
            }
            if (line.contains("[:")) {
                properties.get("maps").add(line.trim());
            }
            if (line.contains("tuple(")) {
                properties.get("tuples").add(line.trim());
            }
            if (operatorPattern.matcher(line).find()) {
                properties.get("operators").add(line.trim());
            }
            if (line.contains("if") || line.contains("else") || line.contains("?")) {
                properties.get("conditionals").add(line.trim());
            }
            if (line.contains("\"") || line.contains("'") || line.contains("\"\"\"")) {
                properties.get("strings").add(line.trim());
            }
            if (line.contains("=~") || line.contains("==~")) {
                properties.get("regex").add(line.trim());
            }
            if (line.contains("{") && line.contains("->")) {
                properties.get("closures").add(line.trim());
            }
            if (line.contains("workflow {")) {
                properties.get("definitions").add(line.trim());
            }
            for (String kw : keywords) {
                if (line.contains(kw)) {
                    properties.get("keywords").add(line.trim());
                    break;
                }
            }
            if (line.contains("#") || line.contains("{") || line.contains("(")) {
                properties.get("structures").add(line.trim());
            }
        }
    }

    public void printProperties() {
        for (Map.Entry<String, List<String>> entry : properties.entrySet()) {
            if (!entry.getValue().isEmpty()) {
                System.out.println(entry.getKey().substring(0, 1).toUpperCase() + entry.getKey().substring(1) + ":");
                for (String value : entry.getValue()) {
                    System.out.println("  - " + value);
                }
            }
        }
    }

    public void write(String newFilename) throws IOException {
        String file = (newFilename == null) ? filename : newFilename;
        try (FileWriter fw = new FileWriter(file)) {
            fw.write(content);
        }
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     NFHandler handler = new NFHandler("example.nf");
    //     handler.read();
    //     handler.printProperties();
    //     handler.write("output.nf");
    // }
}
  1. JavaScript class for opening .NF file, decode/read/write, print properties to console:
const fs = require('fs'); // For Node.js environment

class NFHandler {
  constructor(filename) {
    this.filename = filename;
    this.content = '';
    this.properties = {};
  }

  read() {
    this.content = fs.readFileSync(this.filename, 'utf8');
    this.decode();
  }

  decode() {
    const lines = this.content.split('\n');
    this.properties = {
      variables: [], lists: [], maps: [], tuples: [], operators: [], conditionals: [], strings: [], regex: [], closures: [], definitions: [], keywords: [], structures: []
    };
    const keywords = ['def', 'println', 'new', 'assert', 'if', 'else', 'tuple', 'workflow'];
    const operatorRegex = /==|!=|<|>|&&|\|\|/;
    lines.forEach((line) => {
      if (line.trim().startsWith('def ')) this.properties.variables.push(line.trim());
      if (line.includes('[]')) this.properties.lists.push(line.trim());
      if (line.includes('[:')) this.properties.maps.push(line.trim());
      if (line.includes('tuple(')) this.properties.tuples.push(line.trim());
      if (operatorRegex.test(line)) this.properties.operators.push(line.trim());
      if (line.includes('if') || line.includes('else') || line.includes('?')) this.properties.conditionals.push(line.trim());
      if (line.includes('"') || line.includes("'") || line.includes('"""')) this.properties.strings.push(line.trim());
      if (line.includes('=~') || line.includes('==~')) this.properties.regex.push(line.trim());
      if (line.includes('{') && line.includes('->')) this.properties.closures.push(line.trim());
      if (line.includes('workflow {')) this.properties.definitions.push(line.trim());
      if (keywords.some(kw => line.includes(kw))) this.properties.keywords.push(line.trim());
      if (line.includes('#') || line.includes('{') || line.includes('(')) this.properties.structures.push(line.trim());
    });
  }

  printProperties() {
    for (const key in this.properties) {
      if (this.properties[key].length > 0) {
        console.log(`${key.charAt(0).toUpperCase() + key.slice(1)}:`);
        this.properties[key].forEach(value => console.log(`  - ${value}`));
      }
    }
  }

  write(newFilename = this.filename) {
    fs.writeFileSync(newFilename, this.content, 'utf8');
  }
}

// Example usage:
// const handler = new NFHandler('example.nf');
// handler.read();
// handler.printProperties();
// handler.write('output.nf');
  1. C class (C++ implementation) for opening .NF file, decode/read/write, print properties to console:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <regex>

class NFHandler {
private:
    std::string filename;
    std::string content;
    std::map<std::string, std::vector<std::string>> properties;

public:
    NFHandler(const std::string& fn) : filename(fn) {}

    void read() {
        std::ifstream file(filename);
        if (file.is_open()) {
            std::string line;
            while (std::getline(file, line)) {
                content += line + "\n";
            }
            file.close();
            decode();
        } else {
            std::cerr << "Unable to open file" << std::endl;
        }
    }

    void decode() {
        std::vector<std::string> lines;
        std::string temp = content;
        size_t pos = 0;
        while ((pos = temp.find("\n")) != std::string::npos) {
            lines.push_back(temp.substr(0, pos));
            temp.erase(0, pos + 1);
        }

        std::vector<std::string> keywords = {"def", "println", "new", "assert", "if", "else", "tuple", "workflow"};
        std::regex operatorRegex(R"(==|!=|<|>|&&|\|\|)");

        properties["variables"] = {};
        properties["lists"] = {};
        properties["maps"] = {};
        properties["tuples"] = {};
        properties["operators"] = {};
        properties["conditionals"] = {};
        properties["strings"] = {};
        properties["regex"] = {};
        properties["closures"] = {};
        properties["definitions"] = {};
        properties["keywords"] = {};
        properties["structures"] = {};

        for (const auto& line : lines) {
            std::string trimmed = line;
            // Trim whitespace (simple implementation)
            trimmed.erase(0, trimmed.find_first_not_of(" \t"));
            trimmed.erase(trimmed.find_last_not_of(" \t") + 1);

            if (trimmed.rfind("def ", 0) == 0) properties["variables"].push_back(trimmed);
            if (line.find("[]") != std::string::npos) properties["lists"].push_back(trimmed);
            if (line.find("[:") != std::string::npos) properties["maps"].push_back(trimmed);
            if (line.find("tuple(") != std::string::npos) properties["tuples"].push_back(trimmed);
            if (std::regex_search(line, operatorRegex)) properties["operators"].push_back(trimmed);
            if (line.find("if") != std::string::npos || line.find("else") != std::string::npos || line.find("?") != std::string::npos) properties["conditionals"].push_back(trimmed);
            if (line.find("\"") != std::string::npos || line.find("'") != std::string::npos || line.find("\"\"\"") != std::string::npos) properties["strings"].push_back(trimmed);
            if (line.find("=~") != std::string::npos || line.find("==~") != std::string::npos) properties["regex"].push_back(trimmed);
            if (line.find("{") != std::string::npos && line.find("->") != std::string::npos) properties["closures"].push_back(trimmed);
            if (line.find("workflow {") != std::string::npos) properties["definitions"].push_back(trimmed);
            bool hasKw = false;
            for (const auto& kw : keywords) {
                if (line.find(kw) != std::string::npos) {
                    properties["keywords"].push_back(trimmed);
                    hasKw = true;
                    break;
                }
            }
            if (line.find("#") != std::string::npos || line.find("{") != std::string::npos || line.find("(") != std::string::npos) properties["structures"].push_back(trimmed);
        }
    }

    void printProperties() {
        for (const auto& pair : properties) {
            if (!pair.second.empty()) {
                std::string key = pair.first;
                key[0] = std::toupper(key[0]);
                std::cout << key << ":" << std::endl;
                for (const auto& value : pair.second) {
                    std::cout << "  - " << value << std::endl;
                }
            }
        }
    }

    void write(const std::string& newFilename = "") {
        std::string file = newFilename.empty() ? filename : newFilename;
        std::ofstream outFile(file);
        if (outFile.is_open()) {
            outFile << content;
            outFile.close();
        } else {
            std::cerr << "Unable to write file" << std::endl;
        }
    }
};

// Example usage:
// int main() {
//     NFHandler handler("example.nf");
//     handler.read();
//     handler.printProperties();
//     handler.write("output.nf");
//     return 0;
// }