JavaScript Csv file generator, part 3 of 3

#javascript #csv

Written by Anders Marzi Tornblad

This is part 3 of the JavaScript Csv file generator series. If you haven't read the first part, here it is: JavaScript Csv file generator, part 1 of 3

The Csv file generator is almost done. All we need to do is to enclose and escape certain special characters. Values containing the separator need to be enclosed in double quotes. Values containing double quotes need to be escaped and, just to be sure, enclosed in double quotes.

Two more requirements and two more unit tests coming up...

Requirements

// Tests

engine.add("Csv.getFileContents should quote fields containing the separator",
function(testContext, the) {
    // Arrange
    var properties = ["name", "age"];
    var csv = new Csv(properties);
    csv.add({"name" : "Doe, John", "age" : "Unknown"});
    csv.add({"name" : "Bunny", "age" : "2"});

    // Act
    var file = csv.getFileContents();

    // Assert
    the(file).shouldBeSameAs("\"Doe, John\",Unknown\r\nBunny,2");
});

engine.add("Csv.getFileContents should quote and escape fields containing double quotes",
function(testContext, the) {
    // Arrange
    var properties = ["model", "size"];
    var csv = new Csv(properties);
    csv.add({"model" : "Punysonic", "size" : "28\""});
    csv.add({"model" : "Philip", "size" : "42\""});

    // Act
    var file = csv.getFileContents();

    // Assert
    the(file).shouldBeSameAs('Punysonic,"28"""\r\nPhilip,"42"""');
});
// Implementation

// Helper function to create one line of text
function createTextLine(values, separator) {
    var result = [];
    var doubleQuotes = new RegExp("\"", "g");

    values.forEach(function(value) {
        var text = value.toString();

        if (text.indexOf(separator) == -1 && text.indexOf("\"") == -1) {
            result.push(text);
        } else {
            result.push("\"" + text.replace(doubleQuotes, "\"\"") + "\"");
        }
    });

    return result.join(separator);
}

// New getFileContents implementation
Csv.prototype.getFileContents = function(separator, includePropertyNames) {
    separator = separator || ",";

    var textLines = [];
    if (includePropertyNames) {
        textLines.push(createTextLine(this.propertyOrder, separator));
    }

    this.items.forEach((function(item) {
        var values = [];
        this.propertyOrder.forEach(function(propertyName) {
            values.push(item[propertyName]);
        });

        textLines.push(createTextLine(values, separator));
    }).bind(this));

    return textLines.join("\r\n");
};

And it's done!

The latest version of the code is always available in the GitHub repository.

Articles in this series: