-
Notifications
You must be signed in to change notification settings - Fork 4
Create a new generator
Before start writing a generator, give a look at how slush-vertx works
First thing to do is create the right directory tree. If you generator name is super_awesome_generator
, add this directory tree to slush-vertx:
├── project_templates
│ └── super_awesome_generator
│ ├── language_a
│ │ └── template1.a
│ ├── language_b
│ │ └── template1.b
│ └── language_c
│ └── template1.c
└── src
└── generators
└── super_awesome_generator
└── main.js
If your generator creates only sources to put inside a defined sources directory, you can start from main.js
of Vert.x Starter generator.
Otherwise if you are going to create a generator that renders sources, tests, docs and so on start from main.js
of Vert.x Web Server generator
The main.js
of your generator has to export an object containing at least the name
of the generator and the Generation function inside generate
field.
You can also add a description through description
field.
Define metadata for every language, as described here. Try to take advantage as much as possible from variables templates and [[questions
array|Slush-Vert.x-Structure#project-info-and-languages-metadata]].
Before defining new dependency, question or variable template, give a look at common_metadata.js
to check if It already exists.
An example of a language metadata is the following:
{
name: "java",
build_tools: [ // Use build tools defined in common_metadata
common_metadata.build_tools.gradle,
common_metadata.build_tools.maven
],
templates: { // Remember: this objects DEPENDS on the rendering function behaviour
src: ["MainVerticle.java", path.join("users", "UsersRouter.java"), path.join("products", "ProductsRouter.java")],
test: ["BaseTest.java", "ProductsTest.java", "UsersTest.java"]
},
dependencies: _.concat( // Create a project with vertx-core, junit, vertx-unit
common_metadata.dependencies.java_dependencies,
common_metadata.dependencies.java_test_dependencies,
common_metadata.dependencies.vertx_test_dependencies
),
questions: [
common_metadata.questions.package
],
var_templates: {
package: common_metadata.var_templates.package, // Clean the package name
main: common_metadata.var_templates.main_class, // Render the main class full name
src_dir: common_metadata.var_templates.src_dir, // Render the src directory based on package name
test_dir: common_metadata.var_templates.test_dir // Render the test src directory based on package name
}
}
Give a look to Rendering function to understand how to create a rendering function with pre-built methods
If you need more complex metadata processing, create your own rendering function:
let super_awesome_rendering_function = function (project_info) {
let result = [];
// Load you super awesome templates!
// Render your super awesome templates and put results of the rendering inside result as:
// {"path": "/final/path/of/the/file.txt", "content": "Content of file"}
// Don't forget to render the build files!
let buildFilesTemplatesFunctions = Utils
.loadBuildFilesTemplates(project_info.build_tool.templates, project_info.build_tool.name);
return _.concat(
result,
_.zipWith( // Some lodash magic to render build files
project_info.build_tool.templates,
buildFilesTemplatesFunctions.map(template => template(project_info)),
(path, content) => new Object({path: path, content: content})
)
)
}
To create the generation function, use Utils.generateGenerationFunction(languagesMetadata, renderingFunction)
and pass to it the languages metadata and the rendering function. For example:
let languagesMetadata = [...];
let renderingFunction = Utils.generateRenderingFunction("super_awesome_generator");
let generationFunction = Utils.generateGenerationFunction(languagesMetadata, renderingFunction);
// Now export the generator!
module.exports = {
name: "Super Awesome Vert.x generator",
description: "This generator does a lot of awesome things, like generate the code",
generate: generationFunction,
render: renderingFunction
}
Sometimes you need to create a custom generation function, for example when you need to load an external Json. In this case you can write your own generation function:
let renderingFunction = Utils.generateRenderingFunction("super_awesome_generator");
let generationFunction = function (project_info, done) { // This function is async!
// You can, of course, use the slush-vertx power of metadata processing, with the function below
Utils.processLanguage(languagesMetadata, project_info).then(result => {
// Utils.processLanguage() returns a Promise, so you are free to chain it
return Promise.all([result, anotherSuperAwesomePromise])
}).then(results => {
// Build project_info object
let project_info = results[0].project_info; // This is project_info rendered by Utils.processLanguage
// Render files with your rendering function
let files = renderingFunction(project_info);
// Write files
Utils.writeFilesArraySync(files);
// Call slush callback
done();
}).catch(error => done(new gutil.PluginError('new', error.stack)));
}
Now you are ready to write templates. Follow the (http://handlebarsjs.com/) guide to start writing the templates and remember that you have all the power of Handlebars helpers library.
Don't forget to add the templates to language metadata with [[the correct directory|Slush-Vert.x-Structure#rendering-function]].
Also remember that you can create sub directories inside the templates directory and they will reflected in generated code directory structure