@microtronics/studio-cli 0.53.0 → 0.55.0

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.
@@ -1812,6 +1812,7 @@ export declare namespace DefaultFiles {
1812
1812
  bloPath: string;
1813
1813
  reportTemplate: string;
1814
1814
  definesTs: string;
1815
+ definesAppTs: string;
1815
1816
  };
1816
1817
  dlo: {
1817
1818
  path: string;
@@ -2252,6 +2253,8 @@ export declare namespace Globals {
2252
2253
  definesWithSource: {
2253
2254
  [key: string]: DefineEntry;
2254
2255
  };
2256
+ /** For library projects: defaults-only config without app.ini overrides */
2257
+ defaultsOnly?: ResolvedConfig;
2255
2258
  }
2256
2259
  /**
2257
2260
  * Read all ini files from the project directory and its dependencies.
@@ -2275,7 +2278,7 @@ export declare namespace Globals {
2275
2278
  * @param fs - filesystem abstraction
2276
2279
  * @param resolvedConfig - the resolved config from Globals.read()
2277
2280
  */
2278
- export function exportDefinesTs(cwd: URI, fs: LocalFS, resolvedConfig: ResolvedConfig): Promise<void>;
2281
+ export function exportDefinesTs(cwd: URI, fs: LocalFS, resolvedConfig: ResolvedConfig, outputPath?: string): Promise<void>;
2279
2282
  /**
2280
2283
  * Replace {{KEY}} template tokens in a string with their resolved values.
2281
2284
  *
package/out/dde/dde.js CHANGED
@@ -396,7 +396,7 @@ var DDE;
396
396
  const manifest = await manifest_1.Manifest.read(cwd, fs);
397
397
  const dependencies = await getDependencies(cwd, fs, manifest);
398
398
  const resolvedConfig = await globals_1.Globals.read(cwd, fs, logger);
399
- const autoInc = (0, dlo_1.generateAutoIncFromMap)(ddeJSON, resolvedConfig.flat, manifest);
399
+ const autoInc = (0, dlo_1.generateAutoIncFromMap)(ddeJSON, resolvedConfig, manifest);
400
400
  const appAutoDDE = new dlo_1.AutoDDEGenerator(manifest, ddeJSON, null);
401
401
  const appDDEInc = appAutoDDE.generate();
402
402
  // generate AutoDDe Files for the libraries:
@@ -97,7 +97,7 @@ function dloCoreSupportsFlags(manifest) {
97
97
  return semver.gte(releaseVersion, '1.1.0');
98
98
  }
99
99
  // eslint-disable-next-line sonarjs/cognitive-complexity
100
- function generateAutoIncFromMap(ddeMap, globalDefines, manifest) {
100
+ function generateAutoIncFromMap(ddeMap, resolvedConfig, manifest) {
101
101
  const _pwn = []; // sample code output for pawn
102
102
  const pwn = _pwn.push.bind(_pwn);
103
103
  function pwn_section(s) {
@@ -139,8 +139,24 @@ function generateAutoIncFromMap(ddeMap, globalDefines, manifest) {
139
139
  /**
140
140
  * generate global dlo defines if there are any
141
141
  */
142
+ const globalDefines = resolvedConfig.flat;
143
+ const { definesWithSource } = resolvedConfig;
142
144
  pwn_section('GLOBAL DEFINES');
143
145
  for (const [define, value] of Object.entries(globalDefines)) {
146
+ const comment = definesWithSource[define]?.comment;
147
+ if (comment) {
148
+ const lines = comment.split('\n');
149
+ if (lines.length === 1) {
150
+ pwn(`/** ${lines[0]} */`);
151
+ }
152
+ else {
153
+ pwn('/**');
154
+ for (const line of lines) {
155
+ pwn(` * ${line}`);
156
+ }
157
+ pwn(' */');
158
+ }
159
+ }
144
160
  const valueIsDefine = Object.hasOwn(globalDefines, value);
145
161
  addDefinition(define, `${value}`, valueIsDefine);
146
162
  }
@@ -73,7 +73,8 @@ var DefaultFiles;
73
73
  dfilesProperties: `${deployDirectoryName}dfiles/properties.json`,
74
74
  bloPath: `${deployDirectoryName}blo`,
75
75
  reportTemplate: `${deployDirectoryName}/${DefaultFiles.fileNames.reportTemplate}`,
76
- definesTs: `${deployDirectoryName}defines.ts`
76
+ definesTs: `${deployDirectoryName}defines.ts`,
77
+ definesAppTs: `${deployDirectoryName}defines.app.ts`
77
78
  },
78
79
  dlo: {
79
80
  path: dloDirectoryName,
package/out/globals.js CHANGED
@@ -67,10 +67,10 @@ var Globals;
67
67
  const depPath = dependencies_1.Dependencies.dependencyToPath(cwd, dependencyId);
68
68
  const name = dependencies_1.Dependencies.dependencyIdToName(dependencyId);
69
69
  const libIniPath = vscode_uri_1.Utils.joinPath(depPath, DLO_PATH, `${name}.ini`);
70
- await mergeIniFile(fs, libIniPath, allDefines, sections, definesWithSource);
70
+ await mergeIniFile(fs, libIniPath, allDefines, sections, definesWithSource, name);
71
71
  // defaults.ini files
72
72
  const libDefaultsPath = vscode_uri_1.Utils.joinPath(depPath, defaultFiles_1.DefaultFiles.filePaths.defaultsIni);
73
- await mergeIniFile(fs, libDefaultsPath, allDefines, sections, definesWithSource);
73
+ await mergeIniFile(fs, libDefaultsPath, allDefines, sections, definesWithSource, name);
74
74
  }
75
75
  // Load the library project's specific ini file (deprecated location)
76
76
  if (manifest_1.Manifest.isLibrary(manifest)) {
@@ -78,7 +78,7 @@ var Globals;
78
78
  if (logger && (await fs.stat(libIni))) {
79
79
  logger.warn(`dlo/${manifest.name}.ini is deprecated. Please migrate your defines to defaults.ini in the project root.`);
80
80
  }
81
- await mergeIniFile(fs, libIni, allDefines, sections, definesWithSource);
81
+ await mergeIniFile(fs, libIni, allDefines, sections, definesWithSource, manifest.name);
82
82
  }
83
83
  // Load the project's main.ini and overwrite existing defines (deprecated location)
84
84
  const mainIniRelPath = manifest.dlo?.iniFile || defaultFiles_1.DefaultFiles.filePaths.dlo.mainINI;
@@ -86,16 +86,19 @@ var Globals;
86
86
  if (logger && (await fs.stat(mainIni))) {
87
87
  logger.warn(`${mainIniRelPath} is deprecated. Please migrate your defines to app.ini in the project root.`);
88
88
  }
89
- await mergeIniFile(fs, mainIni, allDefines, sections, definesWithSource);
89
+ const mainIniLabel = iniFileLabel(mainIniRelPath);
90
+ await mergeIniFile(fs, mainIni, allDefines, sections, definesWithSource, mainIniLabel);
90
91
  // Project root: defaults.ini (library) or app.ini (app/addon/analytics)
91
92
  if (manifest_1.Manifest.isLibrary(manifest)) {
92
93
  const defaultsIni = vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.defaultsIni);
93
- await mergeIniFile(fs, defaultsIni, allDefines, sections, definesWithSource);
94
+ await mergeIniFile(fs, defaultsIni, allDefines, sections, definesWithSource, 'defaults');
94
95
  }
95
- // app.ini is always loaded
96
+ // Snapshot defaults-only state before app.ini merge (for library dual-defines)
97
+ const defaultsOnly = snapshotDefaultsOnly(manifest, allDefines, sections, definesWithSource);
98
+ // app.ini is always loaded (provides local dev overrides for libraries, main config for apps)
96
99
  const appIni = vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.appIni);
97
- await mergeIniFile(fs, appIni, allDefines, sections, definesWithSource);
98
- return { flat: allDefines, sections, definesWithSource };
100
+ await mergeIniFile(fs, appIni, allDefines, sections, definesWithSource, 'app');
101
+ return { flat: allDefines, sections, definesWithSource, defaultsOnly };
99
102
  }
100
103
  Globals.read = read;
101
104
  /**
@@ -106,7 +109,7 @@ var Globals;
106
109
  * @param fs - filesystem abstraction
107
110
  * @param resolvedConfig - the resolved config from Globals.read()
108
111
  */
109
- async function exportDefinesTs(cwd, fs, resolvedConfig) {
112
+ async function exportDefinesTs(cwd, fs, resolvedConfig, outputPath) {
110
113
  const entries = Object.entries(resolvedConfig.flat);
111
114
  // Build the StudioDefines interface members
112
115
  const interfaceLines = [];
@@ -149,7 +152,7 @@ var Globals;
149
152
  lines.push('');
150
153
  lines.push('export {};');
151
154
  lines.push('');
152
- const definesPath = vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.dist.definesTs);
155
+ const definesPath = vscode_uri_1.Utils.joinPath(cwd, outputPath ?? defaultFiles_1.DefaultFiles.filePaths.dist.definesTs);
153
156
  await fs.writeFile(definesPath, lines.join('\n'));
154
157
  }
155
158
  Globals.exportDefinesTs = exportDefinesTs;
@@ -174,6 +177,21 @@ var Globals;
174
177
  }
175
178
  Globals.replaceDefineTemplates = replaceDefineTemplates;
176
179
  })(Globals || (exports.Globals = Globals = {}));
180
+ /**
181
+ * For library projects, snapshot the current defines state (before app.ini merge)
182
+ * so the published library only contains defaults.ini values.
183
+ * Returns undefined for non-library projects.
184
+ */
185
+ function snapshotDefaultsOnly(manifest, allDefines, sections, definesWithSource) {
186
+ if (!manifest_1.Manifest.isLibrary(manifest)) {
187
+ return undefined;
188
+ }
189
+ return {
190
+ flat: { ...allDefines },
191
+ sections: structuredClone(sections),
192
+ definesWithSource: { ...definesWithSource }
193
+ };
194
+ }
177
195
  /**
178
196
  * Classify a trimmed ini-file line into one of the known kinds.
179
197
  * Moves boolean-operator branching out of the main loop to reduce cognitive complexity.
@@ -252,10 +270,35 @@ function formatJsDoc(comment) {
252
270
  function isNumericValue(value) {
253
271
  return value !== '' && !isNaN(Number(value));
254
272
  }
273
+ /**
274
+ * Derive a human-readable source label from an ini file path.
275
+ * Strips the directory prefix and `.ini` extension.
276
+ * E.g. `dlo/main.ini` → `main`, `app.ini` → `app`.
277
+ */
278
+ function iniFileLabel(relPath) {
279
+ const filename = relPath.split('/').pop() || relPath;
280
+ return filename.replace(/\.ini$/i, '');
281
+ }
282
+ /**
283
+ * Merge an incoming comment with an existing one.
284
+ *
285
+ * - Both present → join existing (already prefixed) and new (prefixed) with `\n`
286
+ * - Only existing → keep it
287
+ * - Only new → use it (prefixed)
288
+ * - Neither → undefined
289
+ */
290
+ function mergeComment(existingComment, newRawComment, sourceLabel) {
291
+ const prefixedNew = newRawComment ? `${sourceLabel}: ${newRawComment}` : undefined;
292
+ if (existingComment && prefixedNew) {
293
+ return `${existingComment}\n${prefixedNew}`;
294
+ }
295
+ return prefixedNew || existingComment;
296
+ }
255
297
  /**
256
298
  * Create a DefineEntry, attaching a comment from the comment map if available.
299
+ * The comment is prefixed with the source label for provenance tracking.
257
300
  */
258
- function createDefineEntry(stringValue, fileUri, lines, key, sectionName, commentMap) {
301
+ function createDefineEntry(stringValue, fileUri, lines, key, sectionName, commentMap, sourceLabel) {
259
302
  const flatKey = sectionName ? `${sectionName}_${key}` : key;
260
303
  const entry = {
261
304
  value: stringValue,
@@ -263,23 +306,26 @@ function createDefineEntry(stringValue, fileUri, lines, key, sectionName, commen
263
306
  sourceLine: findLineNumber(lines, key, sectionName)
264
307
  };
265
308
  if (commentMap[flatKey]) {
266
- entry.comment = commentMap[flatKey];
309
+ entry.comment = `${sourceLabel}: ${commentMap[flatKey]}`;
267
310
  }
268
311
  return entry;
269
312
  }
270
313
  /**
271
314
  * Merge all keys from a parsed ini section into the accumulators.
272
315
  */
273
- function mergeSectionEntries(sectionName, sectionData, allDefines, sections, definesWithSource, fileUri, lines, commentMap) {
316
+ function mergeSectionEntries(sectionName, sectionData, allDefines, sections, definesWithSource, fileUri, lines, commentMap, sourceLabel) {
274
317
  if (!sections[sectionName]) {
275
318
  sections[sectionName] = {};
276
319
  }
277
320
  for (const [key, sectionValue] of Object.entries(sectionData)) {
278
321
  const flatKey = `${sectionName}_${key}`;
322
+ const rawComment = commentMap[flatKey];
279
323
  const stringValue = `${sectionValue}`;
280
324
  allDefines[flatKey] = stringValue;
281
325
  sections[sectionName][key] = stringValue;
282
- definesWithSource[flatKey] = createDefineEntry(stringValue, fileUri, lines, key, sectionName, commentMap);
326
+ const newEntry = createDefineEntry(stringValue, fileUri, lines, key, sectionName, commentMap, sourceLabel);
327
+ newEntry.comment = mergeComment(definesWithSource[flatKey]?.comment, rawComment, sourceLabel);
328
+ definesWithSource[flatKey] = newEntry;
283
329
  }
284
330
  }
285
331
  /**
@@ -292,7 +338,7 @@ function mergeSectionEntries(sectionName, sectionData, allDefines, sections, def
292
338
  * @param sections - accumulated sectioned config (mutated)
293
339
  * @param definesWithSource - accumulated source tracking (mutated)
294
340
  */
295
- async function mergeIniFile(fs, filePath, allDefines, sections, definesWithSource) {
341
+ async function mergeIniFile(fs, filePath, allDefines, sections, definesWithSource, sourceLabel) {
296
342
  // early return if the file doesn't exist
297
343
  if (!(await fs.stat(filePath))) {
298
344
  return;
@@ -305,12 +351,15 @@ async function mergeIniFile(fs, filePath, allDefines, sections, definesWithSourc
305
351
  const commentMap = extractComments(rawText);
306
352
  for (const [sectionOrKey, value] of Object.entries(parsed)) {
307
353
  if (typeof value === 'object' && value !== null) {
308
- mergeSectionEntries(sectionOrKey, value, allDefines, sections, definesWithSource, fileUri, lines, commentMap);
354
+ mergeSectionEntries(sectionOrKey, value, allDefines, sections, definesWithSource, fileUri, lines, commentMap, sourceLabel);
309
355
  }
310
356
  else {
357
+ const rawComment = commentMap[sectionOrKey];
311
358
  const stringValue = `${value}`;
312
359
  allDefines[sectionOrKey] = stringValue;
313
- definesWithSource[sectionOrKey] = createDefineEntry(stringValue, fileUri, lines, sectionOrKey, null, commentMap);
360
+ const newEntry = createDefineEntry(stringValue, fileUri, lines, sectionOrKey, null, commentMap, sourceLabel);
361
+ newEntry.comment = mergeComment(definesWithSource[sectionOrKey]?.comment, rawComment, sourceLabel);
362
+ definesWithSource[sectionOrKey] = newEntry;
314
363
  }
315
364
  }
316
365
  }
@@ -46,7 +46,7 @@ const defaultIgnore = [
46
46
  '**/.vscode-test/**',
47
47
  '**/.vscode-test-web/**'
48
48
  ];
49
- defaultIgnore.push(...['**/.studio/**', '**/node_modules/**', STUDIO_IGNORE_FILE]);
49
+ defaultIgnore.push(...['**/.studio/**', '**/node_modules/**', STUDIO_IGNORE_FILE, 'dist/defines.app.ts']);
50
50
  const MINIMATCH_OPTIONS = { dot: true };
51
51
  var Library;
52
52
  (function (Library) {
@@ -46,8 +46,7 @@ var Package;
46
46
  // Generate dist/defines.ts before POV/BLO builds
47
47
  try {
48
48
  const resolvedConfig = await globals_1.Globals.read(cwd, fs, logger);
49
- await globals_1.Globals.exportDefinesTs(cwd, fs, resolvedConfig);
50
- logger.log('Generated', defaultFiles_1.DefaultFiles.filePaths.dist.definesTs);
49
+ await exportDefinesForProject(cwd, fs, logger, resolvedConfig);
51
50
  }
52
51
  catch (e) {
53
52
  logger.warn('Could not generate defines.ts:', e);
@@ -367,6 +366,26 @@ async function preBuild(cwd, fs, logger, env, apiToken, selectedParts) {
367
366
  await dde_1.DDE.fetchPreviousHistoryJson(cwd, fs, logger, env, apiToken);
368
367
  }
369
368
  }
369
+ /**
370
+ * Export defines.ts file(s) based on project type.
371
+ * Library projects get two files: dist/defines.ts (defaults only) and dist/defines.app.ts (full merged).
372
+ * App/addon/analytics projects get a single dist/defines.ts with all merged values.
373
+ */
374
+ async function exportDefinesForProject(cwd, fs, logger, resolvedConfig) {
375
+ if (resolvedConfig.defaultsOnly) {
376
+ // Library: dist/defines.ts = defaults only (for publishing)
377
+ await globals_1.Globals.exportDefinesTs(cwd, fs, resolvedConfig.defaultsOnly);
378
+ logger.log('Generated', defaultFiles_1.DefaultFiles.filePaths.dist.definesTs, '(defaults only)');
379
+ // Library: dist/defines.app.ts = full merged (for local dev)
380
+ await globals_1.Globals.exportDefinesTs(cwd, fs, resolvedConfig, defaultFiles_1.DefaultFiles.filePaths.dist.definesAppTs);
381
+ logger.log('Generated', defaultFiles_1.DefaultFiles.filePaths.dist.definesAppTs, '(with app.ini overrides)');
382
+ }
383
+ else {
384
+ // App/addon/analytics: single merged file
385
+ await globals_1.Globals.exportDefinesTs(cwd, fs, resolvedConfig);
386
+ logger.log('Generated', defaultFiles_1.DefaultFiles.filePaths.dist.definesTs);
387
+ }
388
+ }
370
389
  /**
371
390
  * Generates all needed files out of the dde declaration
372
391
  * @param cwd
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microtronics/studio-cli",
3
- "version": "0.53.0",
3
+ "version": "0.55.0",
4
4
  "description": "Microtronics Studio CLI Tool",
5
5
  "main": "./out/api.js",
6
6
  "typings": "./dist/studio-cli.d.ts",