The following example shows how you can parse a text file and create new directories and files using Node.js.

var fs = require('fs'),
    path = require('path');
 
fs.readFile("examples.txt", "ascii", function (err, data) {
    var lineArr,
        tmp = "",
        fname,
        idx = 0,
        /* Hash of file names so we can create unique file/folder names like Ext.Button.1 */
        fileHash = {},
        /* Regular expressions to determine if the current line is an @example or a README.md file. */
        atExampleRE = /^@example in (.*):$/i,
        isReadmeRE = /^.*\/guides\/(.*)\/README.md$/i,
        /* Prefixes and suffixes to control how/where examples get written out. Ie: "./examples/{foldername.1}/app.js" */
        outputPrefix = "./examples/",
        outputSuffix = "/app.js";
 
    if (err) {
        console.error(err);
        process.exit(1);
    }
 
    lineArr = data.trim().split("\n");
    /* Push a dummy @example tag to the end of the array so the last example gets written out. */ 
    lineArr.push("@example in ---EOF fix---:");
 
    /* Loop over every line. */
    lineArr.forEach(function (line) {
        /* Check to see if the current line is an @example. */
        var atExampleLine = line.match(atExampleRE),
            isReadmeLine,
            fixedFileName,
            tmpPath;
 
        if (atExampleLine !== null) {
            /* If the current @example name and is a guide, tweak the file name to the guide's folder name. */
            isReadmeLine = atExampleLine[1].match(isReadmeRE);
            if (isReadmeLine !== null) {
                atExampleLine[1] = isReadmeLine[1];
            }
 
            /* Update the file name count in the hash. */
            if (!fileHash.hasOwnProperty(fname)) {
                fileHash[fname] = 1;
            } else {
                fileHash[fname] += 1;
            }
 
            /* If we aren't the first @example tag, output the results. */
            if (tmp.trim().length !== 0) {
                fixedFileName = fname + "." + fileHash[fname];
                tmpPath = outputPrefix + fixedFileName;
                // You could also use a try/catch block instead of path.existsSync(). */
                if (!path.existsSync(tmpPath)) {
                    fs.mkdirSync(tmpPath);
                }
                fs.writeFile(tmpPath + outputSuffix, tmp);
            }
 
            /* Update the fname, idx, and reset the tmp output. */
            fname = atExampleLine[1];
            idx += 1;
            tmp = "";
        } else {
            /* This isn't an @example line, so append the example code. */
            tmp += line + "\n";
        }
    });
});

Now, if you have a file named examples.txt and then run the previous Node.js script, you’ll see that each of the @example blocks in the following snippet gets copied in to its own unique folder name:

@example in Ext.grid.feature.RowBody:
Ext.define('Animal', {
    extend: 'Ext.data.Model',
    fields: ['name', 'latin', 'desc']
});
 
@example in Ext.grid.plugin.DragDrop:
Ext.create('Ext.data.Store', {
    storeId:'simpsonsStore',
    fields:['name'],
    data: [["Lisa"], ["Bart"], ["Homer"], ["Marge"]],
    proxy: {
        type: 'memory',
        reader: 'array'
    }
});
 
@example in Ext.chart.Legend:
var store = Ext.create('Ext.data.JsonStore', {
    fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
    data: [
        { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
        { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
        { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
        { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
        { 'name': 'metric five',  'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
    ]
});
 
@example in Ext.fx.Animator:
Ext.create('Ext.fx.Animator', {
    target: Ext.getBody().createChild({
        style: {
            width: '100px',
            height: '100px',
            'background-color': 'red'
        }
    }),
    duration: 10000 // 10 seconds
});
 
@example in Ext.fx.Anim:
var myComponent = Ext.create('Ext.Component', {
    renderTo: document.body,
    width: 200,
    height: 200,
    style: 'border: 1px solid red;'
});

And the output should be something like the following (where each generated file contains the contents of the @example block):

  • ./examples/Ext.grid.feature.RowBody.1/app.js
  • ./examples/Ext.grid.plugin.DragDrop.1/app.js
  • ./examples/Ext.chart.Legend.1/app.js
  • ./examples/Ext.fx.Animator.1/app.js
  • ./examples/Ext.fx.Anim.1/app.js
Tagged with:
 
  • http://senchaexamples.com/ Peter deHaan

    Ideally the file names and paths wouldn’t be hard coded in to the Node.js application, but this was just a quick script I wrote which was fairly specific to my usage.

    -peter