@microtronics/studio-cli 0.55.0 → 0.56.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.
@@ -1897,35 +1897,39 @@ export declare namespace Dependencies {
1897
1897
  * @param cwd
1898
1898
  * @param fs
1899
1899
  * @param libraryName
1900
+ * @param logger
1900
1901
  */
1901
- export function removeExisting(cwd: URI, fs: LocalFS, libraryName: string): Promise<void>;
1902
+ export function removeExisting(cwd: URI, fs: LocalFS, logger: Log.Logger, libraryName: string): Promise<void>;
1902
1903
  /**
1903
1904
  * Extract the given library.tar.gz array buffer
1904
1905
  * @param cwd
1905
1906
  * @param fs
1907
+ * @param logger
1906
1908
  * @param libraryName
1907
1909
  * @param archiveBuffer
1908
1910
  */
1909
- export function extractLibraryContent(cwd: URI, fs: LocalFS, libraryName: string, archiveBuffer: ArrayBuffer): Promise<void>;
1911
+ export function extractLibraryContent(cwd: URI, fs: LocalFS, logger: Log.Logger, libraryName: string, archiveBuffer: ArrayBuffer): Promise<void>;
1910
1912
  /**
1911
1913
  * Install the given library with the version that the semver range accepts
1912
1914
  * @param cwd
1913
1915
  * @param fs
1916
+ * @param logger
1914
1917
  * @param env
1915
1918
  * @param token
1916
1919
  * @param publisherIdName
1917
1920
  * @param version
1918
1921
  * @param development - install as development dependency
1919
1922
  */
1920
- export function installDependency(cwd: URI, fs: LocalFS, env: Globals.ENV, token: string | null, publisherIdName: string, version: string | null, development?: boolean): Promise<undefined>;
1923
+ export function installDependency(cwd: URI, fs: LocalFS, logger: Log.Logger, env: Globals.ENV, token: string | null, publisherIdName: string, version: string | null, development?: boolean): Promise<undefined>;
1921
1924
  /**
1922
1925
  * Install all dependencies that are referenced within the studio manifest
1923
1926
  * @param cwd
1924
1927
  * @param fs
1928
+ * @param logger
1925
1929
  * @param env
1926
1930
  * @param token
1927
1931
  */
1928
- export function installDependencies(cwd: URI, fs: LocalFS, env: Globals.ENV, token: string | null): Promise<void>;
1932
+ export function installDependencies(cwd: URI, fs: LocalFS, logger: Log.Logger, env: Globals.ENV, token: string | null): Promise<void>;
1929
1933
  /**
1930
1934
  * Uninstall the given library
1931
1935
  * Validates if the library is any sub-dependency of any other library
@@ -1934,7 +1938,15 @@ export declare namespace Dependencies {
1934
1938
  * @param publisherId
1935
1939
  * @param libraryName
1936
1940
  */
1937
- export function uninstallDependency(cwd: URI, fs: LocalFS, publisherId: string, libraryName: string): Promise<void>;
1941
+ export function uninstallDependency(cwd: URI, fs: LocalFS, logger: Log.Logger, publisherId: string, libraryName: string): Promise<void>;
1942
+ /**
1943
+ * Install npm dependencies in pov and blo working paths if they exist and contain a package.json.
1944
+ * This ensures that a single `studio install` command sets up the entire project.
1945
+ * @param cwd
1946
+ * @param fs
1947
+ * @param logger
1948
+ */
1949
+ export function installNpmInApmParts(cwd: URI, fs: LocalFS, logger: Log.Logger): Promise<void>;
1938
1950
  export interface APMPartLibrary {
1939
1951
  name: string;
1940
1952
  path: URI;
@@ -1946,6 +1958,25 @@ export declare namespace Dependencies {
1946
1958
  * @param apmPart currently only dlo and dfiles are supported
1947
1959
  */
1948
1960
  export function getApmPartDependencies(cwd: URI, fs: LocalFS, apmPart: APM.Part.dlo | APM.Part.dfiles): Promise<APMPartLibrary[]>;
1961
+ /**
1962
+ * Link a library's blo/pov exports into the consuming project's part package.json files.
1963
+ * After a library is extracted, check if it exports blo or pov parts and add `file:` references.
1964
+ * @param cwd
1965
+ * @param fs
1966
+ * @param logger
1967
+ * @param libraryName - short name, e.g. "pets-demo-lib"
1968
+ * @param development
1969
+ */
1970
+ export function linkLibraryApmParts(cwd: URI, fs: LocalFS, logger: Log.Logger, libraryName: string, development?: boolean): Promise<void>;
1971
+ /**
1972
+ * Unlink a library's blo/pov exports from the consuming project's part package.json files.
1973
+ * Removes `file:` references that were added by linkLibraryApmParts.
1974
+ * @param cwd
1975
+ * @param fs
1976
+ * @param logger
1977
+ * @param libraryName - short name, e.g. "pets-demo-lib"
1978
+ */
1979
+ export function unlinkLibraryApmParts(cwd: URI, fs: LocalFS, logger: Log.Logger, libraryName: string): Promise<void>;
1949
1980
  }
1950
1981
 
1951
1982
  /**
@@ -2372,15 +2403,18 @@ export declare enum HttpMethod {
2372
2403
 
2373
2404
  /**
2374
2405
  * Installs the specified dependencies or all dependencies if none are provided.
2406
+ * Additionally runs `npm install` in pov and blo working paths if they exist and contain a package.json,
2407
+ * ensuring a single install command sets up the entire project.
2375
2408
  *
2376
2409
  * @param {URI} cwd - The current working directory where the installation process takes place.
2377
2410
  * @param {LocalFS} fs - The file system interface used for managing files during the installation process.
2411
+ * @param {Log.Logger} logger - Logger instance for logging details during the install process.
2378
2412
  * @param {Globals.ENV} env - The global environment configuration used during the installation.
2379
2413
  * @param {string|null} apiToken - The API token for authentication, if required, or null if not applicable.
2380
2414
  * @param {string[]} dependencies - An array of dependency strings in the format "libraryId@version". If empty, all dependencies will be installed.
2381
2415
  * @return {Promise<void>} A promise that resolves when the installation process completes successfully or logs an error if it fails.
2382
2416
  */
2383
- export declare function install(cwd: URI, fs: LocalFS, env: Globals.ENV, apiToken: string | null, dependencies: string[]): Promise<void>;
2417
+ export declare function install(cwd: URI, fs: LocalFS, logger: Log.Logger, env: Globals.ENV, apiToken: string | null, dependencies: string[]): Promise<void>;
2384
2418
 
2385
2419
  export declare namespace Library {
2386
2420
  /**
package/out/api.js CHANGED
@@ -41,24 +41,29 @@ const log_1 = require("./log");
41
41
  Object.defineProperty(exports, "Log", { enumerable: true, get: function () { return log_1.Log; } });
42
42
  /**
43
43
  * Installs the specified dependencies or all dependencies if none are provided.
44
+ * Additionally runs `npm install` in pov and blo working paths if they exist and contain a package.json,
45
+ * ensuring a single install command sets up the entire project.
44
46
  *
45
47
  * @param {URI} cwd - The current working directory where the installation process takes place.
46
48
  * @param {LocalFS} fs - The file system interface used for managing files during the installation process.
49
+ * @param {Log.Logger} logger - Logger instance for logging details during the install process.
47
50
  * @param {Globals.ENV} env - The global environment configuration used during the installation.
48
51
  * @param {string|null} apiToken - The API token for authentication, if required, or null if not applicable.
49
52
  * @param {string[]} dependencies - An array of dependency strings in the format "libraryId@version". If empty, all dependencies will be installed.
50
53
  * @return {Promise<void>} A promise that resolves when the installation process completes successfully or logs an error if it fails.
51
54
  */
52
- async function install(cwd, fs, env, apiToken, dependencies) {
55
+ async function install(cwd, fs, logger, env, apiToken, dependencies) {
53
56
  if (dependencies.length > 0) {
54
57
  for (const dependency of dependencies) {
55
58
  const [libraryId, version] = dependency.split('@');
56
- await dependencies_1.Dependencies.installDependency(cwd, fs, env, apiToken, libraryId, version || null);
59
+ await dependencies_1.Dependencies.installDependency(cwd, fs, logger, env, apiToken, libraryId, version || null);
57
60
  }
58
61
  }
59
62
  else {
60
- return await dependencies_1.Dependencies.installDependencies(cwd, fs, env, apiToken);
63
+ await dependencies_1.Dependencies.installDependencies(cwd, fs, logger, env, apiToken);
61
64
  }
65
+ // Run npm install in pov/blo working paths if they have a package.json
66
+ await dependencies_1.Dependencies.installNpmInApmParts(cwd, fs, logger);
62
67
  }
63
68
  /**
64
69
  * Builds the specified parts of the project located in the given directory.
@@ -30,9 +30,11 @@ const semver = __importStar(require("semver"));
30
30
  const registryAPI_1 = require("./registryAPI");
31
31
  const defaultFiles_1 = require("./defaultFiles");
32
32
  const apm_1 = require("./package/apm");
33
+ const child_process = __importStar(require("node:child_process"));
33
34
  const tinytar = require('tinytar-fix');
34
35
  const pako = require('pako');
35
36
  exports.LIB_DEPS_PATH = '.studio/libdeps';
37
+ const PACKAGE_JSON = 'package.json';
36
38
  var Dependencies;
37
39
  (function (Dependencies) {
38
40
  /**
@@ -163,11 +165,12 @@ var Dependencies;
163
165
  * @param cwd
164
166
  * @param fs
165
167
  * @param libraryName
168
+ * @param logger
166
169
  */
167
- async function removeExisting(cwd, fs, libraryName) {
170
+ async function removeExisting(cwd, fs, logger, libraryName) {
168
171
  const libraryPath = vscode_uri_1.Utils.joinPath(cwd, exports.LIB_DEPS_PATH, libraryName);
169
172
  await fs.rm(libraryPath).catch(err => {
170
- console.error('removeExisting', err);
173
+ logger.error('removeExisting', err);
171
174
  });
172
175
  }
173
176
  Dependencies.removeExisting = removeExisting;
@@ -175,19 +178,20 @@ var Dependencies;
175
178
  * Extract the given library.tar.gz array buffer
176
179
  * @param cwd
177
180
  * @param fs
181
+ * @param logger
178
182
  * @param libraryName
179
183
  * @param archiveBuffer
180
184
  */
181
- async function extractLibraryContent(cwd, fs, libraryName, archiveBuffer) {
185
+ async function extractLibraryContent(cwd, fs, logger, libraryName, archiveBuffer) {
182
186
  const files = tinytar.untar(pako.ungzip(archiveBuffer));
183
- await removeExisting(cwd, fs, libraryName);
187
+ await removeExisting(cwd, fs, logger, libraryName);
184
188
  for (const file of files.values()) {
185
189
  try {
186
190
  const filePath = vscode_uri_1.Utils.joinPath(cwd, exports.LIB_DEPS_PATH, libraryName, file.name);
187
191
  await fs.writeFile(filePath, file.data);
188
192
  }
189
193
  catch (e) {
190
- console.error('Extracting lib', e);
194
+ logger.error('Extracting lib', e);
191
195
  }
192
196
  }
193
197
  }
@@ -196,19 +200,20 @@ var Dependencies;
196
200
  * Install the given library with the version that the semver range accepts
197
201
  * @param cwd
198
202
  * @param fs
203
+ * @param logger
199
204
  * @param env
200
205
  * @param token
201
206
  * @param publisherIdName
202
207
  * @param version
203
208
  * @param development - install as development dependency
204
209
  */
205
- async function installDependency(cwd, fs, env, token, publisherIdName, version, development = false) {
210
+ async function installDependency(cwd, fs, logger, env, token, publisherIdName, version, development = false) {
206
211
  const [publisherId, libraryName] = publisherIdName.split('/');
207
212
  if (version && (await isDependencyInstalled(cwd, fs, publisherId, libraryName, version))) {
208
213
  return;
209
214
  }
210
215
  // just remove any existing version of this library.
211
- await removeExisting(cwd, fs, libraryName);
216
+ await removeExisting(cwd, fs, logger, libraryName);
212
217
  const libraryProfile = await registryAPI_1.Registry.getLibraryProfile(token, publisherId, libraryName, env);
213
218
  const versionToDownload = version
214
219
  ? libraryProfile.versions?.find(versionInfo => {
@@ -229,7 +234,7 @@ var Dependencies;
229
234
  await validateDependencyTree(cwd, fs, newDependencies, development);
230
235
  // install sub dependencies first
231
236
  for (const [libraryName, libraryVersion] of Object.entries(librarySubDependencies)) {
232
- await installDependency(cwd, fs, env, token, libraryName, libraryVersion, development);
237
+ await installDependency(cwd, fs, logger, env, token, libraryName, libraryVersion, development);
233
238
  }
234
239
  const libraryArchive = versionToDownload.files.find(file => {
235
240
  return file.name === 'library.tar.gz';
@@ -238,7 +243,8 @@ var Dependencies;
238
243
  throw new Error(`Library ${publisherIdName} has no content!`);
239
244
  }
240
245
  const libraryBuffer = await registryAPI_1.Registry.fetchCustomContent(token, libraryArchive.downloadUrl);
241
- await extractLibraryContent(cwd, fs, libraryName, libraryBuffer);
246
+ await extractLibraryContent(cwd, fs, logger, libraryName, libraryBuffer);
247
+ await linkLibraryApmParts(cwd, fs, logger, libraryName, development);
242
248
  // update manifest
243
249
  const manifest = await manifest_1.Manifest.read(cwd, fs);
244
250
  const dependencies = manifest.libraryDependencies || {};
@@ -255,10 +261,11 @@ var Dependencies;
255
261
  * Install all dependencies that are referenced within the studio manifest
256
262
  * @param cwd
257
263
  * @param fs
264
+ * @param logger
258
265
  * @param env
259
266
  * @param token
260
267
  */
261
- async function installDependencies(cwd, fs, env, token) {
268
+ async function installDependencies(cwd, fs, logger, env, token) {
262
269
  const manifest = await manifest_1.Manifest.read(cwd, fs);
263
270
  const dependencies = manifest.libraryDependencies || {};
264
271
  const devDependencies = manifest.libraryDevDependencies || {};
@@ -266,9 +273,16 @@ var Dependencies;
266
273
  for (const [libraryName, libraryVersion] of Object.entries(allDependencies)) {
267
274
  const isDevelopment = Object.hasOwn(devDependencies, libraryName);
268
275
  // update the tree version with the actual installed version
269
- await installDependency(cwd, fs, env, token, libraryName, libraryVersion, isDevelopment);
276
+ await installDependency(cwd, fs, logger, env, token, libraryName, libraryVersion, isDevelopment);
270
277
  }
271
- console.log(`Installed ${Object.entries(allDependencies).length} dependencies`);
278
+ // Ensure blo/pov file: references are linked for all dependencies
279
+ // (installDependency skips linking when the dependency is already installed)
280
+ for (const [libraryId] of Object.entries(allDependencies)) {
281
+ const libName = dependencyIdToName(libraryId);
282
+ const isDevelopment = Object.hasOwn(devDependencies, libraryId);
283
+ await linkLibraryApmParts(cwd, fs, logger, libName, isDevelopment);
284
+ }
285
+ logger.done(`Installed ${Object.entries(allDependencies).length} dependencies`);
272
286
  }
273
287
  Dependencies.installDependencies = installDependencies;
274
288
  /**
@@ -279,7 +293,7 @@ var Dependencies;
279
293
  * @param publisherId
280
294
  * @param libraryName
281
295
  */
282
- async function uninstallDependency(cwd, fs, publisherId, libraryName) {
296
+ async function uninstallDependency(cwd, fs, logger, publisherId, libraryName) {
283
297
  const manifest = await manifest_1.Manifest.read(cwd, fs);
284
298
  const dependencies = manifest.libraryDependencies || {};
285
299
  const devDependencies = manifest.libraryDevDependencies || {};
@@ -288,7 +302,8 @@ var Dependencies;
288
302
  delete allDependencies[libraryId];
289
303
  const validatedDependencies = await validateIfLibraryCanBeRemoved(cwd, fs, allDependencies);
290
304
  if (!Object.hasOwn(validatedDependencies, libraryId)) {
291
- await removeExisting(cwd, fs, libraryName);
305
+ await unlinkLibraryApmParts(cwd, fs, logger, libraryName);
306
+ await removeExisting(cwd, fs, logger, libraryName);
292
307
  delete devDependencies[libraryId];
293
308
  delete dependencies[libraryId];
294
309
  await manifest_1.Manifest.write(cwd, fs, manifest);
@@ -298,6 +313,33 @@ var Dependencies;
298
313
  }
299
314
  }
300
315
  Dependencies.uninstallDependency = uninstallDependency;
316
+ /**
317
+ * Install npm dependencies in pov and blo working paths if they exist and contain a package.json.
318
+ * This ensures that a single `studio install` command sets up the entire project.
319
+ * @param cwd
320
+ * @param fs
321
+ * @param logger
322
+ */
323
+ async function installNpmInApmParts(cwd, fs, logger) {
324
+ const manifest = await manifest_1.Manifest.read(cwd, fs);
325
+ const parts = [];
326
+ if (manifest.pov?.details?.workingPath) {
327
+ parts.push({ name: 'pov', workingPath: manifest.pov.details.workingPath });
328
+ }
329
+ if (manifest.blo?.workingPath) {
330
+ parts.push({ name: 'blo', workingPath: manifest.blo.workingPath });
331
+ }
332
+ for (const { name, workingPath } of parts) {
333
+ const partDir = vscode_uri_1.Utils.joinPath(cwd, workingPath);
334
+ const packageJsonPath = vscode_uri_1.Utils.joinPath(partDir, PACKAGE_JSON);
335
+ const hasPackageJson = await fs.stat(packageJsonPath);
336
+ if (hasPackageJson) {
337
+ logger.info(`Installing npm dependencies for ${name} (${workingPath})...`);
338
+ await execNpmInstall(partDir, logger);
339
+ }
340
+ }
341
+ }
342
+ Dependencies.installNpmInApmParts = installNpmInApmParts;
301
343
  /**
302
344
  * Get all libraries that have dlo source
303
345
  * @param cwd
@@ -336,7 +378,100 @@ var Dependencies;
336
378
  return apmDependencies;
337
379
  }
338
380
  Dependencies.getApmPartDependencies = getApmPartDependencies;
381
+ /**
382
+ * Link a library's blo/pov exports into the consuming project's part package.json files.
383
+ * After a library is extracted, check if it exports blo or pov parts and add `file:` references.
384
+ * @param cwd
385
+ * @param fs
386
+ * @param logger
387
+ * @param libraryName - short name, e.g. "pets-demo-lib"
388
+ * @param development
389
+ */
390
+ async function linkLibraryApmParts(cwd, fs, logger, libraryName, development) {
391
+ const manifest = await manifest_1.Manifest.read(cwd, fs);
392
+ const partConfigs = [
393
+ { partName: 'blo', partDistPath: 'blo', workingPath: manifest.blo?.workingPath },
394
+ { partName: 'pov', partDistPath: 'pov/details', workingPath: manifest.pov?.details?.workingPath }
395
+ ];
396
+ for (const { partName, partDistPath, workingPath } of partConfigs) {
397
+ if (!workingPath) {
398
+ continue;
399
+ }
400
+ const libPartPackageJson = vscode_uri_1.Utils.joinPath(cwd, exports.LIB_DEPS_PATH, libraryName, 'dist', ...partDistPath.split('/'), PACKAGE_JSON);
401
+ const libPartExists = await fs.stat(libPartPackageJson);
402
+ if (!libPartExists) {
403
+ continue;
404
+ }
405
+ try {
406
+ const pkg = await readPartPackageJson(cwd, fs, workingPath);
407
+ const depsKey = development ? 'devDependencies' : 'dependencies';
408
+ pkg[depsKey] = pkg[depsKey] || {};
409
+ const depth = workingPath.split('/').length;
410
+ const relativePrefix = Array(depth).fill('..').join('/');
411
+ pkg[depsKey][libraryName] = `file:${relativePrefix}/${exports.LIB_DEPS_PATH}/${libraryName}/dist/${partDistPath}`;
412
+ await writePartPackageJson(cwd, fs, workingPath, pkg);
413
+ logger.info(`Linked ${libraryName} to ${partName} (${workingPath})`);
414
+ }
415
+ catch (e) {
416
+ logger.warn(`Could not link ${libraryName} to ${partName}: ${e}`);
417
+ }
418
+ }
419
+ }
420
+ Dependencies.linkLibraryApmParts = linkLibraryApmParts;
421
+ /**
422
+ * Unlink a library's blo/pov exports from the consuming project's part package.json files.
423
+ * Removes `file:` references that were added by linkLibraryApmParts.
424
+ * @param cwd
425
+ * @param fs
426
+ * @param logger
427
+ * @param libraryName - short name, e.g. "pets-demo-lib"
428
+ */
429
+ async function unlinkLibraryApmParts(cwd, fs, logger, libraryName) {
430
+ const manifest = await manifest_1.Manifest.read(cwd, fs);
431
+ const partConfigs = [
432
+ { partName: 'blo', workingPath: manifest.blo?.workingPath },
433
+ { partName: 'pov', workingPath: manifest.pov?.details?.workingPath }
434
+ ];
435
+ for (const { partName, workingPath } of partConfigs) {
436
+ if (!workingPath) {
437
+ continue;
438
+ }
439
+ try {
440
+ const pkg = await readPartPackageJson(cwd, fs, workingPath);
441
+ let changed = false;
442
+ // Remove from dependencies if it's a file: reference
443
+ if (pkg.dependencies?.[libraryName]?.startsWith('file:')) {
444
+ delete pkg.dependencies[libraryName];
445
+ changed = true;
446
+ }
447
+ // Remove from devDependencies if it's a file: reference
448
+ if (pkg.devDependencies?.[libraryName]?.startsWith('file:')) {
449
+ delete pkg.devDependencies[libraryName];
450
+ changed = true;
451
+ }
452
+ if (changed) {
453
+ await writePartPackageJson(cwd, fs, workingPath, pkg);
454
+ logger.info(`Unlinked ${libraryName} from ${partName}`);
455
+ }
456
+ }
457
+ catch (e) {
458
+ logger.warn(`Could not unlink ${libraryName} from ${partName}: ${e}`);
459
+ }
460
+ }
461
+ }
462
+ Dependencies.unlinkLibraryApmParts = unlinkLibraryApmParts;
339
463
  })(Dependencies || (exports.Dependencies = Dependencies = {}));
464
+ async function readPartPackageJson(cwd, fs, workingPath) {
465
+ const packageJsonPath = vscode_uri_1.Utils.joinPath(cwd, workingPath, PACKAGE_JSON);
466
+ const data = await fs.readFile(packageJsonPath);
467
+ const text = new TextDecoder().decode(data);
468
+ return JSON.parse(text);
469
+ }
470
+ async function writePartPackageJson(cwd, fs, workingPath, pkg) {
471
+ const packageJsonPath = vscode_uri_1.Utils.joinPath(cwd, workingPath, PACKAGE_JSON);
472
+ const content = JSON.stringify(pkg, null, '\t') + '\n';
473
+ await fs.writeFile(packageJsonPath, content);
474
+ }
340
475
  async function fetchStudioJson(token, studioJsonURL) {
341
476
  return await registryAPI_1.Registry.fetchCustomContent(token, studioJsonURL, true);
342
477
  }
@@ -419,4 +554,25 @@ function buildDependencyEntry(publisherId, libraryId, libraryVersion) {
419
554
  libraryId: `${publisherId}/${libraryId}`
420
555
  };
421
556
  }
557
+ /**
558
+ * Execute `npm install` in the given directory
559
+ * @param cwd - working directory where npm install should be executed
560
+ * @param logger
561
+ */
562
+ function execNpmInstall(cwd, logger) {
563
+ return new Promise((resolve, reject) => {
564
+ child_process.exec('npm ci', { cwd: cwd.fsPath, env: process.env }, (error, stdout, stderr) => {
565
+ if (stdout) {
566
+ logger.log(stdout);
567
+ }
568
+ if (stderr) {
569
+ logger.error(stderr);
570
+ }
571
+ if (error) {
572
+ reject(error);
573
+ }
574
+ resolve();
575
+ });
576
+ });
577
+ }
422
578
  //# sourceMappingURL=dependencies.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microtronics/studio-cli",
3
- "version": "0.55.0",
3
+ "version": "0.56.0",
4
4
  "description": "Microtronics Studio CLI Tool",
5
5
  "main": "./out/api.js",
6
6
  "typings": "./dist/studio-cli.d.ts",