Skip to content

Instantly share code, notes, and snippets.

@mattjcowan
Last active December 14, 2015 21:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattjcowan/17ded31d87bd282feafe to your computer and use it in GitHub Desktop.
Save mattjcowan/17ded31d87bd282feafe to your computer and use it in GitHub Desktop.
A gulpfile with a 'codegen' task (from command line: gulp codegen) that you can use to code-generate files (in my case Android java files) against a ServiceStack /types/metadata.json endpoint ...
{%- extends "package.java.template.nunjucks" -%}
{%- set templateName = "models/DTO.nunjucks" -%}
{%- set subPackage = ".models" -%}
{%- import 'macros.java.nunjucks' as macros -%}
{% block content %}
import java.math.*;
import java.util.*;
import net.servicestack.client.*;
import com.google.gson.annotations.*;
import com.google.gson.reflect.*;
public class DTO
{
{% for operation in metadata.operations %}
{# do something with the operation #}
{%- endfor %}
{% for type in metadata.types %}
{# do something with the type #}
{%- endfor %}
}
// Gulp docs at: https://github.com/gulpjs/gulp
// Primary libs used are:
// - https://github.com/devoptix/gulp-nunjucks-api
// - https://mozilla.github.io/nunjucks/
// Sample directory structure for this gulpfile
// src/ <-- this is where my app is
// scripts/ <-- this is where I put node.js scripts to do codegeneration and other things
// scripts/.gulpfile.js
// package.json
// /node_modules/
// /codegen/input/ <-- this is where i put all my codegen files (each file = 1 codegen .java file (could be for any language you want))
// /templates/ <-- this is where i put all my codegen templates (i.e.: layouts, macros, includes, used by files in input dir)
// /output/ <-- you could output your codegenerated files here, OR what I do is output them directory to my src directory as part of my app
// (maintains the same directory structure as inside /input)
var gulp = require('gulp')
,glob = require('glob')
,path = require('path')
,lodash = require('lodash')
,data = require('gulp-data')
,nunjucksRender = require('gulp-nunjucks-api')
,request = require('request')
,rename = require('gulp-rename')
,source = require('vinyl-source-stream')
,jeditor = require('gulp-json-editor')
,streamify = require('gulp-streamify')
;
/****** MODIFY THIS CODEGEN_DATA, ADD ANYTHING YOU WOULD LIKE TO PASS TO THE TEMPLATES *******/
var codegen_data = {
// required!!!!
date: new Date(),
baseDir: './codegen',
destDir: '../src/app/src/main/java/org/mycompany/droidapp',
baseJavaPackage: 'org.mycompany.droidapp',
metadataUrl: 'https://mycompany.org/api/types/metadata.json',
// add any data you'd like to pass to the templates below
hello: 'world',
exclude_request_types: [
],
exclude_response_types: [
],
exclude_dto_types: [
]
};
// create some custom filters, functions, extensions here, to use inside your templates, or load them in using
// a require statement to an external file, however you want ...
// var custom_filters = require('./libs/custom_filters.js');
var custom_filters = {
'camelCase': function(str) { return lodash.camelCase(str); }
};
var custom_extensions = {};
var custom_functions = {};
var metadata_json_transform = function(json /* this is actually an object (not a string) */) {
// this is the /types/metadata.json of your api (or whatever file you decide to point to), transform it however you want
// or build a completely different json file ...
// whatever you put here will be available in your templates using "metadata.<your object>" as a global
return json;
}
/****** do advanced editing as needed below ******/
var nunjucksDate = require('nunjucks-date')
nunjucksDate.setDefaultFormat('MM/DD/YYYY, h:mm:ss a');
custom_filters['date'] = nunjucksDate;
var CODEGEN_INPUT_SRC = codegen_data.baseDir + '/input';
var CODEGEN_DEST_PATH = codegen_data.destDir;
var CODEGEN_TEMPLATES = codegen_data.baseDir + '/templates';
var SS_METADATA_FILE = codegen_data.metadataUrl.substr(codegen_data.metadataUrl.lastIndexOf('/') + 1);
var SS_METADATA_FILE_PATH = CODEGEN_INPUT_SRC + '/' + SS_METADATA_FILE;
gulp.task('codegen_metadata', function () {
return request({ url: codegen_data.metadataUrl })
.pipe(source(SS_METADATA_FILE))
.pipe(streamify(jeditor(metadata_json_transform, {'indent_char': '\t', 'indent_size': 1})))
.pipe(gulp.dest(CODEGEN_INPUT_SRC));
});
gulp.task('codegen', ['codegen_metadata'], function () {
return gulp.src(CODEGEN_INPUT_SRC + '/**/*.nunjucks')
.pipe(data(function() {
return lodash.merge({}, codegen_data, { metadata: require(SS_METADATA_FILE_PATH) } );
}))
.pipe(nunjucksRender({
src: CODEGEN_TEMPLATES
,extension: '.java'
,renderString: true
,extensions: custom_extensions
,filters: custom_filters
,functions: custom_functions
}))
.pipe(gulp.dest(CODEGEN_DEST_PATH));
});
{%- macro header(date, template, apiUrl, metadataUrl) -%}
/*
Code generated on: {{ creation_date | date }}
Template: {{ template }}
Api at: {{ apiUrl }}
Metadata at: {{ metadataUrl }}
*/
{%- endmacro -%}
{%- import 'macros.java.nunjucks' as macros -%}
{#-
This is a comment block.
This file is a layout/master page kind of file inherited by child templates in the /input directory ...
1) Notice the macro below: 'macros.header' which comes from the macros.java.nunjucks file imported above ...
2) The variables data, metadataUrl, baseJavaPackage come from the codegen_data object in the gulpfile.js
3) The variable metadata.config.baseUrl is from the metadata.json file from ServiceStack
4) Other variables like 'subPackage', 'templateName' are assigned in the child templates using
{% set subPackage = '.models' %} syntax
-#}
{{ macros.header(date, templateName, metadata.config.baseUrl, metadataUrl) }}
package {{ baseJavaPackage }}{{ subPackage }};
{% block content -%}
{%- endblock -%}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment