@aifabrix/builder 2.39.1 → 2.39.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/app/readme.js CHANGED
@@ -12,6 +12,7 @@ const fs = require('fs').promises;
12
12
  const fsSync = require('fs');
13
13
  const path = require('path');
14
14
  const handlebars = require('handlebars');
15
+ const yaml = require('js-yaml');
15
16
  const { generateExternalReadmeContent } = require('../utils/external-readme');
16
17
 
17
18
  /**
@@ -158,28 +159,69 @@ function generateReadmeMd(appName, config) {
158
159
  }
159
160
 
160
161
  /**
161
- * Generates README.md file if it doesn't exist
162
+ * Generates README.md file (optionally only if missing)
162
163
  * @async
163
164
  * @function generateReadmeMdFile
164
165
  * @param {string} appPath - Path to application directory
165
166
  * @param {string} appName - Application name
166
- * @param {Object} config - Application configuration
167
+ * @param {Object} config - Application configuration (e.g. from variables.yaml)
168
+ * @param {Object} [options] - Options
169
+ * @param {boolean} [options.force] - If true, overwrite existing README.md (dynamic generation)
167
170
  * @returns {Promise<void>} Resolves when README.md is generated or skipped
168
171
  * @throws {Error} If file generation fails
169
172
  */
170
- async function generateReadmeMdFile(appPath, appName, config) {
171
- // Ensure directory exists
173
+ async function generateReadmeMdFile(appPath, appName, config, options = {}) {
172
174
  await fs.mkdir(appPath, { recursive: true });
173
175
  const readmePath = path.join(appPath, 'README.md');
174
- if (!(await fileExists(readmePath))) {
175
- const readmeContent = generateReadmeMd(appName, config);
176
- await fs.writeFile(readmePath, readmeContent, 'utf8');
176
+ if (!options.force && (await fileExists(readmePath))) {
177
+ return;
178
+ }
179
+ const readmeContent = generateReadmeMd(appName, config);
180
+ await fs.writeFile(readmePath, readmeContent, 'utf8');
181
+ }
182
+
183
+ /**
184
+ * Loads variables.yaml from app path and generates README.md (overwrites if present).
185
+ * Used when copying template apps or running up-miso / up-platform / up-dataplane.
186
+ * @async
187
+ * @function ensureReadmeForAppPath
188
+ * @param {string} appPath - Path to application directory (must contain variables.yaml)
189
+ * @param {string} appName - Application name
190
+ * @returns {Promise<void>} Resolves when README.md is written or skipped (no variables.yaml)
191
+ */
192
+ async function ensureReadmeForAppPath(appPath, appName) {
193
+ const variablesPath = path.join(appPath, 'variables.yaml');
194
+ if (!(await fileExists(variablesPath))) {
195
+ return;
196
+ }
197
+ const content = await fs.readFile(variablesPath, 'utf8');
198
+ const config = yaml.load(content) || {};
199
+ await generateReadmeMdFile(appPath, appName, config, { force: true });
200
+ }
201
+
202
+ /**
203
+ * Generates README.md for an app at builder path(s): primary and cwd/builder if different.
204
+ * Use after ensureAppFromTemplate in up-miso / up-dataplane so README reflects current config.
205
+ * @async
206
+ * @function ensureReadmeForApp
207
+ * @param {string} appName - Application name (e.g. keycloak, miso-controller, dataplane)
208
+ * @returns {Promise<void>}
209
+ */
210
+ async function ensureReadmeForApp(appName) {
211
+ const pathsUtil = require('../utils/paths');
212
+ const primaryPath = pathsUtil.getBuilderPath(appName);
213
+ await ensureReadmeForAppPath(primaryPath, appName);
214
+ const cwdBuilderPath = path.join(process.cwd(), 'builder', appName);
215
+ if (path.resolve(cwdBuilderPath) !== path.resolve(primaryPath)) {
216
+ await ensureReadmeForAppPath(cwdBuilderPath, appName);
177
217
  }
178
218
  }
179
219
 
180
220
  module.exports = {
181
221
  generateReadmeMdFile,
182
222
  generateReadmeMd,
183
- formatAppDisplayName
223
+ formatAppDisplayName,
224
+ ensureReadmeForAppPath,
225
+ ensureReadmeForApp
184
226
  };
185
227
 
@@ -15,9 +15,11 @@ const chalk = require('chalk');
15
15
  const logger = require('../utils/logger');
16
16
  const pathsUtil = require('../utils/paths');
17
17
  const { copyTemplateFiles } = require('../validation/template');
18
+ const { ensureReadmeForAppPath, ensureReadmeForApp } = require('../app/readme');
18
19
 
19
20
  /**
20
21
  * Copy template to a target path if variables.yaml is missing there.
22
+ * After copy, generates README.md from templates/applications/README.md.hbs.
21
23
  * @param {string} appName - Application name
22
24
  * @param {string} targetAppPath - Target directory (e.g. builder/keycloak)
23
25
  * @returns {Promise<boolean>} True if template was copied, false if already present
@@ -28,6 +30,7 @@ async function ensureTemplateAtPath(appName, targetAppPath) {
28
30
  return false;
29
31
  }
30
32
  await copyTemplateFiles(appName, targetAppPath);
33
+ await ensureReadmeForAppPath(targetAppPath, appName);
31
34
  return true;
32
35
  }
33
36
 
@@ -160,6 +163,7 @@ async function ensureAppFromTemplate(appName) {
160
163
  }
161
164
  }
162
165
 
166
+ await ensureReadmeForApp(appName);
163
167
  return primaryCopied;
164
168
  }
165
169
 
@@ -35,13 +35,19 @@ async function generateExternalSystemTemplate(appPath, systemKey, config) {
35
35
  const templateContent = await fs.readFile(templatePath, 'utf8');
36
36
  const template = handlebars.compile(templateContent);
37
37
 
38
+ const roles = (config.roles || null) && config.roles.map((role) => ({
39
+ ...role,
40
+ groups: role.groups || role.Groups || undefined
41
+ }));
42
+
38
43
  const context = {
39
44
  systemKey: systemKey,
40
45
  systemDisplayName: config.systemDisplayName || systemKey.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
41
46
  systemDescription: config.systemDescription || `External system integration for ${systemKey}`,
42
47
  systemType: config.systemType || 'openapi',
43
48
  authType: config.authType || 'apikey',
44
- roles: config.roles || null,
49
+ baseUrl: config.baseUrl || null,
50
+ roles: roles || null,
45
51
  permissions: config.permissions || null
46
52
  };
47
53
 
@@ -74,6 +80,8 @@ async function generateExternalDataSourceTemplate(appPath, datasourceKey, config
74
80
  const templateContent = await fs.readFile(templatePath, 'utf8');
75
81
  const template = handlebars.compile(templateContent);
76
82
 
83
+ const dimensions = config.dimensions || {};
84
+ const attributes = config.attributes || {};
77
85
  const context = {
78
86
  datasourceKey: datasourceKey,
79
87
  datasourceDisplayName: config.datasourceDisplayName || datasourceKey.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
@@ -82,8 +90,11 @@ async function generateExternalDataSourceTemplate(appPath, datasourceKey, config
82
90
  entityType: config.entityType || datasourceKey.split('-').pop(),
83
91
  resourceType: config.resourceType || 'document',
84
92
  systemType: config.systemType || 'openapi',
85
- dimensions: config.dimensions || {},
86
- attributes: config.attributes || {}
93
+ // Pass non-empty objects so template uses custom block; empty/null so template uses schema-valid defaults
94
+ dimensions: Object.keys(dimensions).length > 0 ? dimensions : null,
95
+ attributes: Object.keys(attributes).length > 0 ? attributes : null,
96
+ // Literal expression strings for default attribute block (schema: pipe-based DSL {{raw.path}})
97
+ raw: { id: '{{raw.id}}', name: '{{raw.name}}' }
87
98
  };
88
99
 
89
100
  const rendered = template(context);