JavaScript Csv file generator, part 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

  • Values containing the current separator must be enclosed in double quotes.
  • Values containing double quotes must be escaped (by doubling the double quote characters), and also enclosed in double quotes.
// 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! EDIT: The finished code can be found on github at /lbrtw/csv.

Posted by Anders Tornblad on Category JavaScript Labels
Tweet this