diff --git a/README.md b/README.md index 5b3615f..b9ece5f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ npm i ``` > ./bin/cli.js -b examples list templates # listTemplates [ + "context.js", "context.njk" ] ``` @@ -128,12 +129,18 @@ prd: "tags": { "type": "application" }, - "templateContext": { - "name": "templator" + "templateData": { + "context": { + "name": "templator" + }, + "meta": { + "__mapping": "mappings/nested/example.njk", + "__template": "templates/context.njk" + } } }, { - "template": "context.njk", + "template": "context.js", "contextSelector": "components.database", "destination": { "type": "echo", @@ -145,8 +152,14 @@ prd: "tags": { "type": "database" }, - "templateContext": { - "name": "Database" + "templateData": { + "context": { + "name": "Database" + }, + "meta": { + "__mapping": "mappings/nested/example.njk", + "__template": "templates/context.js" + } } } ] @@ -165,50 +178,52 @@ prd: } ``` -## Render in json format +## Render in yaml format + +``` +> ./bin/cli.js -b examples generate -o yaml nested/example.njk dev # renderTemplate +locations: + - template: context.njk + contextSelector: components.application + destination: + type: echo + params: + repo: myorg/development + filepath: application.json + tags: + type: application + templateData: + context: + name: templator + meta: + __mapping: mappings/nested/example.njk + __template: templates/context.njk + renderedTemplate: | + # Template file templates/context.njk + # Mapping file mappings/nested/example.njk + + {"name":"templator"} + - template: context.js + contextSelector: components.database + destination: + type: echo + params: + repo: myorg/development + filepath: database.json + tags: + type: database + templateData: + context: + name: Database + meta: + __mapping: mappings/nested/example.njk + __template: templates/context.js + renderedTemplate: | + # Template file templates/context.js + # Mapping file mappings/nested/example.njk + + {"name":"Database"} -``` -> ./bin/cli.js -b examples generate -o json nested/example.njk dev # renderTemplate -{ - "locations": [ - { - "template": "context.njk", - "contextSelector": "components.application", - "destination": { - "type": "echo", - "params": { - "repo": "myorg/development", - "filepath": "application.json" - } - }, - "tags": { - "type": "application" - }, - "templateContext": { - "name": "templator" - }, - "renderedTemplate": "# Template file templates/context.njk\n# Mapping file mappings/nested/example.njk\n\n{\"name\":\"templator\"}\n" - }, - { - "template": "context.njk", - "contextSelector": "components.database", - "destination": { - "type": "echo", - "params": { - "repo": "myorg/development", - "filepath": "database.json" - } - }, - "tags": { - "type": "database" - }, - "templateContext": { - "name": "Database" - }, - "renderedTemplate": "# Template file templates/context.njk\n# Mapping file mappings/nested/example.njk\n\n{\"name\":\"Database\"}\n" - } - ] -} ``` ## Render in human readable format @@ -226,7 +241,7 @@ prd: --- {"destination":{"type":"echo","params":{"repo":"myorg/development","filepath":"database.json"}},"tags":{"type":"database"}} --- -# Template file templates/context.njk +# Template file templates/context.js # Mapping file mappings/nested/example.njk {"name":"Database"} @@ -240,7 +255,7 @@ prd: --- {"destination":{"type":"echo","params":{"repo":"myorg/development","filepath":"database.json"}},"tags":{"type":"database"}} --- -# Template file templates/context.njk +# Template file templates/context.js # Mapping file mappings/nested/example.njk {"name":"Database"} @@ -251,7 +266,7 @@ prd: ``` > ./bin/cli.js -b examples generate nested/example.njk dev -h --limit-to '{"type": "database"}' --hide-headers # renderFileContent -# Template file templates/context.njk +# Template file templates/context.js # Mapping file mappings/nested/example.njk {"name":"Database"} @@ -278,13 +293,19 @@ prd: "tags": { "type": "application" }, - "templateContext": { - "name": "templator" + "templateData": { + "context": { + "name": "templator" + }, + "meta": { + "__mapping": "mappings/nested/example.njk", + "__template": "templates/context.njk" + } }, "renderedTemplate": "# Template file templates/context.njk\n# Mapping file mappings/nested/example.njk\n\n{\"name\":\"templator\"}\n" }, { - "template": "context.njk", + "template": "context.js", "contextSelector": "components.database", "destination": { "type": "echo", @@ -296,10 +317,16 @@ prd: "tags": { "type": "database" }, - "templateContext": { - "name": "Database" + "templateData": { + "context": { + "name": "Database" + }, + "meta": { + "__mapping": "mappings/nested/example.njk", + "__template": "templates/context.js" + } }, - "renderedTemplate": "# Template file templates/context.njk\n# Mapping file mappings/nested/example.njk\n\n{\"name\":\"Database\"}\n" + "renderedTemplate": "# Template file templates/context.js\n# Mapping file mappings/nested/example.njk\n\n{\"name\":\"Database\"}\n" } ] } diff --git a/cmds/generate.js b/cmds/generate.js index 83191dd..1fb8693 100644 --- a/cmds/generate.js +++ b/cmds/generate.js @@ -76,7 +76,8 @@ exports.handler = async (args) => { args.mapping, args.contextSelector ); - await templator.expandTemplatesContext(mapping, context); + + await templator.expandTemplatesContext(mapping, context, args.mapping); output({ mapping, context }, args.output || 'json'); return; diff --git a/examples/mappings/nested/example.njk b/examples/mappings/nested/example.njk index 94a0065..6257809 100644 --- a/examples/mappings/nested/example.njk +++ b/examples/mappings/nested/example.njk @@ -1,11 +1,12 @@ {# You can access the context with 'this' #} {# the output should be a valid json #} {% set comma = joiner() %} +{% set templates = ['njk', 'js'] %} { "locations": [ {%- for component, data in context.components %} {{comma()}}{ - "template": "context.njk", + "template": "context.{{templates[loop.index-1]}}", "contextSelector": "components.{{ component }}", "destination": { "type": "echo", diff --git a/examples/templates/context.js b/examples/templates/context.js new file mode 100644 index 0000000..66d5881 --- /dev/null +++ b/examples/templates/context.js @@ -0,0 +1,7 @@ +exports.render = function (context, meta) { + return `# Template file ${meta.__template} +# Mapping file ${meta.__mapping} + +${JSON.stringify(context)} +`; +}; diff --git a/lib/mappings.js b/lib/mappings.js index 432f557..50f6ce3 100644 --- a/lib/mappings.js +++ b/lib/mappings.js @@ -23,10 +23,6 @@ class Mappings extends Templates { } } - list() { - return utils.listFiles(this.absTemplatesPath); - } - async render(template, context) { const result = await super.render(template, context); diff --git a/lib/templates.js b/lib/templates.js index 5df255b..c00ffca 100644 --- a/lib/templates.js +++ b/lib/templates.js @@ -13,11 +13,9 @@ class Templates { this.base = base; log('options %o', options); + this.templatesDir = options.templatesDir || 'templates'; - this.absTemplatesPath = path.resolve( - base, - options.templatesDir || 'templates' - ); + this.absTemplatesPath = path.resolve(base, this.templatesDir); nunjucks.installJinjaCompat(); this.njk = nunjucks.configure(this.absTemplatesPath, { @@ -27,15 +25,19 @@ class Templates { }); } - getAbsTemplatePath(template) { + absPath(template) { return path.resolve(this.absTemplatesPath, template); } + relPath(template) { + return path.join(this.templatesDir, template); + } + list() { return utils.listFiles(this.absTemplatesPath); } - async _renderJs(templatePath, context, mappingFilepath) { + async _renderJs(templatePath, context, meta) { const jsTemplate = require(templatePath); if (jsTemplate.render == undefined) { @@ -44,34 +46,22 @@ class Templates { ); } - return jsTemplate.render({ - context, - meta: { - __template: path.relative(this.base, templatePath), - __mapping: mappingFilepath, - }, - }); + return jsTemplate.render(context, meta); } - async render(template, context, mappingFilepath = undefined) { - const templatePath = this.getAbsTemplatePath(template); + async render(template, context, meta) { + const templatePath = this.absPath(template); const deepClonedContext = _.cloneDeep(context); log('Template path %o, context %o', templatePath, deepClonedContext); - if (mappingFilepath !== undefined) { - mappingFilepath = path.relative(this.base, mappingFilepath); - } if (templatePath.endsWith('.js')) { - return this._renderJs(templatePath, deepClonedContext, mappingFilepath); + return this._renderJs(templatePath, deepClonedContext, meta); } return this.njk .addGlobal('context', deepClonedContext) - .addGlobal('meta', { - __mapping: mappingFilepath, - __template: path.relative(this.base, templatePath), - }) - .render(templatePath, deepClonedContext); + .addGlobal('meta', meta) + .render(templatePath, context); } } diff --git a/lib/templates/mapping.js b/lib/templates/mapping.js index 65117e3..319518b 100644 --- a/lib/templates/mapping.js +++ b/lib/templates/mapping.js @@ -1,11 +1,11 @@ // You can access the context with 'data.context' // the output should be an object -exports.render = (data) => { +exports.render = (context) => { return { locations: [ { - template: `${data.context.TEMPLATE}`, + template: `${context.TEMPLATE}`, contextSelector: 'PATH.TO.CONTEXT', destination: { type: 'echo', diff --git a/lib/templator.js b/lib/templator.js index 97fc240..195b708 100644 --- a/lib/templator.js +++ b/lib/templator.js @@ -1,12 +1,13 @@ -const ContextParser = require('@gitops-toolbox/config-loader'); const Templates = require('./templates'); const Mappings = require('./mappings'); +const path = require('path'); const utils = require('./utils'); const [log, error] = require('./utils').getLogger(__filename); const _ = require('lodash'); class Templator { constructor(base, options = {}) { + this.base = base; options.configDir = options.configDir || 'context'; this.contextParser = utils.getContextParser(base, { @@ -33,22 +34,30 @@ class Templator { contextSelector ); log('Base mapping %o', mapping); - await this.expandTemplatesContext(mapping, context); + await this.expandTemplatesContext(mapping, context, mappingFilepath); await this._expandTemplates(mapping, mappingFilepath); log('Expanded mapping %o', mapping); return mapping; } - async expandTemplatesContext(renderedMapping, mappingContext) { + async expandTemplatesContext( + renderedMapping, + mappingContext, + mappingFilepath + ) { for (const location of renderedMapping.locations) { log('Expand location %o', location); - location.templateContext = - location.templateContext || - (await this.contextParser._selectFromConfig( + location.templateData = location.templateData || { + context: await this.contextParser._selectFromConfig( mappingContext, location.contextSelector - )); + ), + meta: { + __mapping: this.mappings.relPath(mappingFilepath), + __template: this.templates.relPath(location.template), + }, + }; } } @@ -60,8 +69,8 @@ class Templator { location.renderedTemplate = await this.templates.render( location.template, - location.templateContext, - this.mappings.getAbsTemplatePath(mappingFilepath) + location.templateData.context, + location.templateData.meta ); } } diff --git a/tests/fixtures/base/mappings/components.js b/tests/fixtures/base/mappings/components.js index db18277..221a487 100644 --- a/tests/fixtures/base/mappings/components.js +++ b/tests/fixtures/base/mappings/components.js @@ -1,10 +1,6 @@ -/** - * - * @param {*} data - */ -exports.render = function (data) { +exports.render = function (context, meta) { const locations = []; - for (const component of Object.keys(data.context.components)) { + for (const component of Object.keys(context.components)) { locations.push({ template: `components/${component}.njk`, contextSelector: `components.${component}`, diff --git a/tests/fixtures/base/mappings/mutates_context.js b/tests/fixtures/base/mappings/mutates_context.js index a81b02a..fd0dd98 100644 --- a/tests/fixtures/base/mappings/mutates_context.js +++ b/tests/fixtures/base/mappings/mutates_context.js @@ -1,5 +1,5 @@ -exports.render = function (data) { - data.context.newProperty = true; +exports.render = function (context) { + context.newProperty = true; const locations = [ { template: 'does not matter', diff --git a/tests/fixtures/base/mappings/no_contextSelector.js b/tests/fixtures/base/mappings/no_contextSelector.js index db154d8..d3284f4 100644 --- a/tests/fixtures/base/mappings/no_contextSelector.js +++ b/tests/fixtures/base/mappings/no_contextSelector.js @@ -2,9 +2,9 @@ * * @param {*} context */ -exports.render = function (data) { +exports.render = function (context) { const locations = []; - for (const component of Object.keys(data.context.components)) { + for (const component of Object.keys(context.components)) { locations.push({ template: `components/${component}.njk`, destination: {}, diff --git a/tests/fixtures/base/mappings/no_template.js b/tests/fixtures/base/mappings/no_template.js index 80f39c3..5501e50 100644 --- a/tests/fixtures/base/mappings/no_template.js +++ b/tests/fixtures/base/mappings/no_template.js @@ -2,9 +2,9 @@ * * @param {*} context */ -exports.render = function (data) { +exports.render = function (context) { const locations = []; - for (const component of Object.keys(data.context.components)) { + for (const component of Object.keys(context.components)) { locations.push({ contextSelector: `components.${component}`, destination: {}, diff --git a/tests/fixtures/base/mappings/render.js b/tests/fixtures/base/mappings/render.js index ecc869e..ef32443 100644 --- a/tests/fixtures/base/mappings/render.js +++ b/tests/fixtures/base/mappings/render.js @@ -1,8 +1,8 @@ -exports.render = (data) => { +exports.render = (context, meta) => { return { locations: [ { - template: `templates/${data.context['1']}`, + template: `templates/${context['1']}`, contextSelector: '1', }, ], diff --git a/tests/templator.test.js b/tests/templator.test.js index a54b9d4..43f727f 100644 --- a/tests/templator.test.js +++ b/tests/templator.test.js @@ -22,8 +22,14 @@ tap.test('Given a destination template and a context', (t) => { destination: {}, renderedTemplate: 'size: 5\n', tags: {}, - templateContext: { - size: 5, + templateData: { + context: { + size: 5, + }, + meta: { + __mapping: 'mappings/components.js', + __template: 'templates/components/database.njk', + }, }, }, ], @@ -84,8 +90,14 @@ tap.test('Given a destination template and a context', (t) => { destination: {}, renderedTemplate: 'replication: 5\n', tags: {}, - templateContext: { - replicas: 5, + templateData: { + context: { + replicas: 5, + }, + meta: { + __mapping: 'mappings/components.js', + __template: 'templates/components/application.njk', + }, }, }, { @@ -94,8 +106,14 @@ tap.test('Given a destination template and a context', (t) => { destination: {}, renderedTemplate: 'size: 20\n', tags: {}, - templateContext: { - size: 20, + templateData: { + context: { + size: 20, + }, + meta: { + __mapping: 'mappings/components.js', + __template: 'templates/components/database.njk', + }, }, }, ],