Ignacio A. Rivas
Ignacio A. Rivas

Reputation: 636

Appropriate way to concat JSON files with Grunt

I'm looking for the best way to combine json files maintaining certain structure using Grunt.

The files are disposed in folders in a structure like this:

App
├── locales
│   ├── en
│   │   └── translation.json
│   ├── es
│   │   └── translation.json
│   └── fr
│       └── translation.json
└── widgets
    ├── Posts
    │   └── locales
    │       ├── en
    │       │   └── translation.json
    │       ├── es
    │       │   └── translation.json
    │       └── fr
    │           └── translation.json
    ├── Comments
    │   └── locales
    │       ├── en
    │       │   └── translation.json
    │       ├── es
    │       │   └── translation.json
    │       └── fr
    │           └── translation.json
    └── Links
        ├── locales
        │   ├── en
        │   │   └── translation.json
        │   ├── es
        │   │   └── translation.json
        │   └── fr
        │       └── translation.json

And the desired output with the files merged would be:

App
│
├── lang
│   ├── en
│   │   └── translation.json
│   ├── es
│   │   └── translation.json
│   └── fr
│       └── translation.json
├── locales
└── widgets

So far I came up with one solution using grunt-contrib-concat, but I think there should be a better way to do it.

concat: {
  translateEN: {
    src: [
      'www/js/app/locales/en/*.json',
      'www/js/app/widgets/posts/locales/en/*.json',
      'www/js/app/widgets/comments/locales/en/*.json',
      'www/js/app/widgets/links/locales/en/*.json'
    ],
    dest: 'www/js/app/lang/en/translation.json',
    options: {
      banner: '{',
      footer: "}",
      separator: ','
    }
  },
  translateES: {
    src: [
      'www/js/app/locales/es/*.json',
      'www/js/app/widgets/posts/locales/es/*.json',
      'www/js/app/widgets/comments/locales/es/*.json',
      'www/js/app/widgets/links/locales/es/*.json'
    ],
    dest: 'www/js/app/lang/es/translation.json',
    options: {
      banner: '{',
      footer: "}",
      separator: ','
    }
  },
  translateFR: {
    src: [
      'www/js/app/locales/fr/*.json',
      'www/js/app/widgets/posts/locales/fr/*.json',
      'www/js/app/widgets/comments/locales/fr/*.json',
      'www/js/app/widgets/links/locales/fr/*.json'
    ],
    dest: 'www/js/app/lang/fr/translation.json',
    options: {
      banner: '{',
      footer: "}",
      separator: ','
    }
  }
}

Upvotes: 4

Views: 2205

Answers (1)

Ignacio A. Rivas
Ignacio A. Rivas

Reputation: 636

I ended up writting my own grunt task for this:

  grunt.task.registerMultiTask('buildLocales', 'Build Locale files.', function() {
    var that = this,
        len = this.filesSrc.length,
        outputDir,
        outputFile,
        originalFile,
        destFile,
        merged;

    var jsonConcat = function(object1, object2) {
      var key, a1, a2;
      for (key in object2) {
        if (object2.hasOwnProperty(key)) {
          a2 = object2[key];
          a1 = object1[key];
          if (a1) {
            a1.push.apply(a1, a2);
          } else {
            object1[key] = a2;
          }
        }
      }

      return object1;
    };

    var iterateTroughFiles = function(abspath, rootdir, subdir, filename){
      if (abspath.indexOf('/.svn') === -1){
        outputDir = that.data.dest + '/' + subdir;
        outputFile = outputDir + '/' + filename;

        // If output dir doesnt exists, then create it
        if (!grunt.file.exists(outputDir)) {
          grunt.file.mkdir(outputDir);
        }

        originalFile = grunt.file.readJSON(abspath);

        // if dest file doenst exist, then just copy it.
        if (!grunt.file.exists(outputFile)) {
          grunt.file.write(outputFile, JSON.stringify(originalFile));
        } else {
          // read source file, read dest file. merge them. write it in dest file
          destFile = grunt.file.readJSON(outputFile);

          merged = jsonConcat(destFile, originalFile);

          grunt.file.write(outputFile, JSON.stringify(merged));
        }
      }
    };

    for (var x = 0; x < len; x++) {
      grunt.file.recurse(this.filesSrc[x], iterateTroughFiles);
    }
  });

And the implementation is something like this:

buildLocales: {
  locales:{
    src: [
      'www/js/app/**/locales'
    ],
    dest: PATH_BUILD_LANGUAGES
  }
},

Upvotes: 2

Related Questions