@microtronics/studio-cli 0.32.3 → 0.34.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.
- package/CHANGELOG.md +18 -1
- package/dist/studio-cli.d.ts +19 -7
- package/out/argumentParser.js +64 -0
- package/out/dde/dde.js +4 -3
- package/out/dde/fileGenerators/api.js +69 -17
- package/out/dde/yamlDdePreCompiler.js +20 -5
- package/out/globals.js +1 -1
- package/out/main.js +21 -9
- package/out/manifest.js +34 -9
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.34.0 (2025-09-12)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **cli:** add App Center routing support in API generator ([6586c8b](https://bitbucket.org/microtronics-core/vscode-studio/commits/6586c8bee9a9bdf0a803b5c0e33d04fa22092d8e))
|
|
8
|
+
* **cli:** add support for analytics project type in manifest ([ff0f354](https://bitbucket.org/microtronics-core/vscode-studio/commits/ff0f354f3d95028a889ca87495b24ad36800b1b1))
|
|
9
|
+
* **cli:** enhance path generation for analytics projects ([bb0936a](https://bitbucket.org/microtronics-core/vscode-studio/commits/bb0936afdb385cc67569305c1363617df19b258a))
|
|
1
10
|
|
|
11
|
+
## 0.33.0 (2025-09-01)
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **cli:** add description to CLI tool usage ([97e8562](https://bitbucket.org/microtronics-core/vscode-studio/commits/97e85625a7c6d11070e2713f3ec3d2c24691854a))
|
|
16
|
+
* **cli:** add support for parsing unknown long options ([fa6523c](https://bitbucket.org/microtronics-core/vscode-studio/commits/fa6523caef791d508b31ed5d563452b616e99ae0))
|
|
17
|
+
* **cli:** support custom ini file in manifest ([5ae2741](https://bitbucket.org/microtronics-core/vscode-studio/commits/5ae2741ad379258fee95311fd28acc8b3dd1bdb6))
|
|
18
|
+
* **cli:** support manifest overwrites with deep merge ([10b69e2](https://bitbucket.org/microtronics-core/vscode-studio/commits/10b69e29c9426bec08022610b66e85b86cee79c9))
|
|
2
19
|
|
|
3
20
|
## 0.32.3 (2025-06-11)
|
|
4
21
|
|
|
@@ -185,7 +202,7 @@
|
|
|
185
202
|
|
|
186
203
|
## 0.19.1 (2025-02-20)
|
|
187
204
|
|
|
188
|
-
|
|
205
|
+
|
|
189
206
|
|
|
190
207
|
## 0.19.0 (2025-02-19)
|
|
191
208
|
|
package/dist/studio-cli.d.ts
CHANGED
|
@@ -1166,7 +1166,7 @@ export declare namespace DDE {
|
|
|
1166
1166
|
* @param ddeHistory
|
|
1167
1167
|
* @constructor
|
|
1168
1168
|
*/
|
|
1169
|
-
const PreCompiler: (libraries: DDE_Core.LibraryFile[], ddeHistory: HistoryJson | null) => YamlPreCompiler.PreCompiler;
|
|
1169
|
+
const PreCompiler: (manifest: Manifest.Manifest, libraries: DDE_Core.LibraryFile[], ddeHistory: HistoryJson | null) => YamlPreCompiler.PreCompiler;
|
|
1170
1170
|
/**
|
|
1171
1171
|
* File Generators
|
|
1172
1172
|
*/
|
|
@@ -2171,7 +2171,8 @@ export declare namespace Manifest {
|
|
|
2171
2171
|
export enum ProjectTypes {
|
|
2172
2172
|
app = "app",
|
|
2173
2173
|
library = "library",
|
|
2174
|
-
addon = "addon"
|
|
2174
|
+
addon = "addon",
|
|
2175
|
+
analytics = "analytics"
|
|
2175
2176
|
}
|
|
2176
2177
|
export interface Manifest {
|
|
2177
2178
|
version: string;
|
|
@@ -2196,6 +2197,7 @@ export declare namespace Manifest {
|
|
|
2196
2197
|
dlo?: {
|
|
2197
2198
|
mainFile: string;
|
|
2198
2199
|
compileOptions: string[];
|
|
2200
|
+
iniFile?: string;
|
|
2199
2201
|
};
|
|
2200
2202
|
registry?: {
|
|
2201
2203
|
id?: string;
|
|
@@ -2234,6 +2236,8 @@ export declare namespace Manifest {
|
|
|
2234
2236
|
embedded = "$embedded",
|
|
2235
2237
|
pure = "$pure"
|
|
2236
2238
|
}
|
|
2239
|
+
export function setOverwrites(manifest: Partial<Manifest.Manifest> | null): void;
|
|
2240
|
+
export function clearOverwrites(): void;
|
|
2237
2241
|
/**
|
|
2238
2242
|
* Read the studio.json manifest and parse it
|
|
2239
2243
|
* @param cwd
|
|
@@ -2267,6 +2271,11 @@ export declare namespace Manifest {
|
|
|
2267
2271
|
* @param manifest
|
|
2268
2272
|
*/
|
|
2269
2273
|
export function isApp(manifest: Manifest.Manifest): boolean;
|
|
2274
|
+
/**
|
|
2275
|
+
* Check if the current project is an analytics project
|
|
2276
|
+
* @param manifest
|
|
2277
|
+
*/
|
|
2278
|
+
export function isAnalytics(manifest: Manifest.Manifest): boolean;
|
|
2270
2279
|
/**
|
|
2271
2280
|
* Validates if the properties within
|
|
2272
2281
|
* @param cwd
|
|
@@ -4711,13 +4720,14 @@ declare interface XMLField {
|
|
|
4711
4720
|
|
|
4712
4721
|
declare namespace YamlPreCompiler {
|
|
4713
4722
|
class PreCompiler {
|
|
4723
|
+
private manifest;
|
|
4714
4724
|
private libraryFiles;
|
|
4715
4725
|
private ddeHistory;
|
|
4716
4726
|
private readonly fieldNamesPerContainer;
|
|
4717
4727
|
private readonly usedContainerNames;
|
|
4718
4728
|
private fileDiagnostics;
|
|
4719
4729
|
private readonly libraryDDE;
|
|
4720
|
-
constructor(libraryFiles: DDE_Core.LibraryFile[], ddeHistory: DDE.HistoryJson | null);
|
|
4730
|
+
constructor(manifest: Manifest.Manifest, libraryFiles: DDE_Core.LibraryFile[], ddeHistory: DDE.HistoryJson | null);
|
|
4721
4731
|
/**
|
|
4722
4732
|
* Parse the given library files and return the diagnostics
|
|
4723
4733
|
*/
|
|
@@ -4729,10 +4739,12 @@ declare namespace YamlPreCompiler {
|
|
|
4729
4739
|
diagnostics: Diagnostics.File[];
|
|
4730
4740
|
};
|
|
4731
4741
|
/**
|
|
4732
|
-
*
|
|
4733
|
-
*
|
|
4734
|
-
* @param
|
|
4735
|
-
* @param
|
|
4742
|
+
* Parses a YAML file and validates its content to produce a structured JSON object along with diagnostic information.
|
|
4743
|
+
*
|
|
4744
|
+
* @param filePath The URI of the YAML file being parsed.
|
|
4745
|
+
* @param yaml The raw YAML content to parse.
|
|
4746
|
+
* @param libraryName An optional parameter specifying the library name for additional validation.
|
|
4747
|
+
* @return An object containing the parsed DDE JSON and an array of diagnostic messages related to the file.
|
|
4736
4748
|
*/
|
|
4737
4749
|
parseYamlFile(filePath: URI, yaml: string, libraryName?: string): {
|
|
4738
4750
|
parsedDDE: DDEJson;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseUnknownLongOptions = parseUnknownLongOptions;
|
|
4
|
+
/**
|
|
5
|
+
* Set a nested value in an object by a dot-separated path.
|
|
6
|
+
* Example: setByDotPath(obj, 'dlo.mainFile', 'x') => obj = { dlo: { mainFile: 'x' } }
|
|
7
|
+
*/
|
|
8
|
+
function setByDotPath(target, path, value) {
|
|
9
|
+
const parts = path.split('.').filter(Boolean);
|
|
10
|
+
let cur = target;
|
|
11
|
+
for (let i = 0; i < parts.length; i++) {
|
|
12
|
+
const key = parts[i];
|
|
13
|
+
const isLeaf = i === parts.length - 1;
|
|
14
|
+
if (isLeaf) {
|
|
15
|
+
cur[key] = value;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
if (typeof cur[key] !== 'object' || cur[key] === null || Array.isArray(cur[key])) {
|
|
19
|
+
cur[key] = {};
|
|
20
|
+
}
|
|
21
|
+
cur = cur[key];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse unknown long options (starting with `--`) into a key/value object.
|
|
27
|
+
* - Supports `--key=value` and `--key value`
|
|
28
|
+
*/
|
|
29
|
+
function parseUnknownLongOptions(command) {
|
|
30
|
+
const argv = command.args;
|
|
31
|
+
const result = {};
|
|
32
|
+
for (let i = 0; i < argv.length; i++) {
|
|
33
|
+
const token = argv[i];
|
|
34
|
+
// Only process long options that start with `--`
|
|
35
|
+
if (!token || !token.startsWith('--')) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// Split inline assignment: --key=value
|
|
39
|
+
const [flag, inlineVal] = token.split('=', 2);
|
|
40
|
+
// Unknown option: collect it
|
|
41
|
+
const key = flag.slice(2); // remove leading '--'
|
|
42
|
+
let value = true;
|
|
43
|
+
if (inlineVal !== undefined) {
|
|
44
|
+
value = inlineVal;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// If next token exists and doesn't look like another flag, use it as the value
|
|
48
|
+
const next = argv[i + 1];
|
|
49
|
+
if (next && !next.startsWith('-')) {
|
|
50
|
+
value = next;
|
|
51
|
+
i++; // consume the value
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Dot-notation => nested object
|
|
55
|
+
if (key.includes('.')) {
|
|
56
|
+
setByDotPath(result, key, value);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
result[key] = value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=argumentParser.js.map
|
package/out/dde/dde.js
CHANGED
|
@@ -93,9 +93,10 @@ var DDE;
|
|
|
93
93
|
* @param fileName
|
|
94
94
|
*/
|
|
95
95
|
async function compileDDE(cwd, fs, logger, fileName = defaultFiles_1.DefaultFiles.fileNames.mainDDE) {
|
|
96
|
+
const manifest = await manifest_1.Manifest.read(cwd, fs);
|
|
96
97
|
const validated = await validate(cwd, fs, logger, fileName);
|
|
97
98
|
const historyJson = await getHistoryJson(cwd, fs, logger);
|
|
98
|
-
const preCompiler = new yamlDdePreCompiler_1.YamlPreCompiler.PreCompiler(validated.libraryFiles, historyJson);
|
|
99
|
+
const preCompiler = new yamlDdePreCompiler_1.YamlPreCompiler.PreCompiler(manifest, validated.libraryFiles, historyJson);
|
|
99
100
|
const libraryDiagnostics = preCompiler.parseLibraries();
|
|
100
101
|
const librariesHaveError = libraryDiagnostics.find(diagnostics => diagnostics.level === 'error');
|
|
101
102
|
if (librariesHaveError) {
|
|
@@ -137,8 +138,8 @@ var DDE;
|
|
|
137
138
|
* @param ddeHistory
|
|
138
139
|
* @constructor
|
|
139
140
|
*/
|
|
140
|
-
DDE.PreCompiler = (libraries, ddeHistory) => {
|
|
141
|
-
return new yamlDdePreCompiler_1.YamlPreCompiler.PreCompiler(libraries, ddeHistory);
|
|
141
|
+
DDE.PreCompiler = (manifest, libraries, ddeHistory) => {
|
|
142
|
+
return new yamlDdePreCompiler_1.YamlPreCompiler.PreCompiler(manifest, libraries, ddeHistory);
|
|
142
143
|
};
|
|
143
144
|
/**
|
|
144
145
|
* File Generators
|
|
@@ -33,6 +33,7 @@ var fieldTypeDefinitions = coreDefinitions_1.DDE_Core.fieldTypeDefinitions;
|
|
|
33
33
|
const manifest_1 = require("../../manifest");
|
|
34
34
|
const contextIdRef = { $ref: '#/components/parameters/contextId' };
|
|
35
35
|
const addonIdRef = { $ref: '#/components/parameters/addonId' };
|
|
36
|
+
const appIdRef = { $ref: '#/components/parameters/appId' };
|
|
36
37
|
const histdataResponseRef = { $ref: '#/components/schemas/histdataResponse' };
|
|
37
38
|
const histdataRequestRef = { $ref: '#/components/schemas/histdataRequest' };
|
|
38
39
|
const rapidM2MStampRef = { $ref: '#/components/schemas/rapidM2MStamp' };
|
|
@@ -52,6 +53,15 @@ const defaultComponents = {
|
|
|
52
53
|
type: 'string'
|
|
53
54
|
},
|
|
54
55
|
required: true
|
|
56
|
+
},
|
|
57
|
+
appId: {
|
|
58
|
+
name: 'appUid',
|
|
59
|
+
in: 'path',
|
|
60
|
+
description: 'The app uid',
|
|
61
|
+
schema: {
|
|
62
|
+
type: 'string'
|
|
63
|
+
},
|
|
64
|
+
required: true
|
|
55
65
|
}
|
|
56
66
|
},
|
|
57
67
|
schemas: {
|
|
@@ -182,6 +192,7 @@ function generateAPIFromMap(ddeMap, manifest, context = null) {
|
|
|
182
192
|
Object.assign(apiDescription.components, structuredClone(defaultAppComponents));
|
|
183
193
|
}
|
|
184
194
|
const isAddon = manifest_1.Manifest.isAddon(manifest);
|
|
195
|
+
const isAnalytics = manifest_1.Manifest.isAnalytics(manifest);
|
|
185
196
|
if (isAddon) {
|
|
186
197
|
// add addonUid parameter if this is an addon project
|
|
187
198
|
apiDescription.components.parameters['addonId'] = {
|
|
@@ -203,13 +214,17 @@ function generateAPIFromMap(ddeMap, manifest, context = null) {
|
|
|
203
214
|
}
|
|
204
215
|
generateTagDescriptionFromContainer(apiDescription, containerDefinition);
|
|
205
216
|
generateSchemasFromContainer(apiDescription, containerDefinition, context);
|
|
206
|
-
generatePathInformationFromContainer(apiDescription, containerDefinition, isAddon);
|
|
217
|
+
generatePathInformationFromContainer(apiDescription, containerDefinition, isAddon, isAnalytics);
|
|
207
218
|
// legacy routes
|
|
208
|
-
if (!isAddon) {
|
|
219
|
+
if (!isAddon && !isAnalytics) {
|
|
209
220
|
generateLegacySchemasFromContainer(apiDescription, containerDefinition, context);
|
|
210
221
|
generateLegacyPathInformationFromContainer(apiDescription, containerDefinition);
|
|
211
222
|
}
|
|
212
223
|
}
|
|
224
|
+
apiDescription.tags.push({
|
|
225
|
+
name: 'app-center',
|
|
226
|
+
description: 'App Center related routes'
|
|
227
|
+
});
|
|
213
228
|
return (0, yaml_1.stringify)(apiDescription);
|
|
214
229
|
}
|
|
215
230
|
function generateTagDescriptionFromContainer(apiDescription, containerDefinition) {
|
|
@@ -451,23 +466,46 @@ function generateLegacyPathInformationFromContainer(apiDescription, containerDef
|
|
|
451
466
|
}
|
|
452
467
|
apiDescription.paths[apiPath] = apiPathMethods;
|
|
453
468
|
}
|
|
454
|
-
function generatePathInformationFromContainer(apiDescription, containerDefinition, isAddonProject = false) {
|
|
469
|
+
function generatePathInformationFromContainer(apiDescription, containerDefinition, isAddonProject = false, isAnalyticsProject = false) {
|
|
455
470
|
const isTimeseriesContainer = containerDefinition.containerType === ContainerType.hx;
|
|
456
471
|
const containerType = isTimeseriesContainer ? 'timeseries' : 'containers';
|
|
457
472
|
const pathParameters = [contextIdRef];
|
|
458
|
-
let
|
|
473
|
+
let apiPathOptions = [];
|
|
474
|
+
const containerRouteTagName = tagNameFromContainerTitle(containerDefinition.title);
|
|
475
|
+
// analytic projects do not have any site
|
|
476
|
+
if (!isAnalyticsProject) {
|
|
477
|
+
apiPathOptions.push({
|
|
478
|
+
path: `/api/1/sites/{siteUid}/${containerType}/${containerDefinition.title}`,
|
|
479
|
+
params: [contextIdRef],
|
|
480
|
+
tags: [containerRouteTagName]
|
|
481
|
+
});
|
|
482
|
+
}
|
|
459
483
|
if (isAddonProject) {
|
|
460
|
-
|
|
461
|
-
|
|
484
|
+
apiPathOptions = [
|
|
485
|
+
{
|
|
486
|
+
path: `/api/1/sites/{siteUid}/addons/{addonUid}/${containerType}/${containerDefinition.title}`,
|
|
487
|
+
params: [addonIdRef],
|
|
488
|
+
tags: [containerRouteTagName]
|
|
489
|
+
}
|
|
490
|
+
];
|
|
491
|
+
}
|
|
492
|
+
const appCenterPathOptions = {
|
|
493
|
+
path: `/api/1/app-center/apps/{appUid}/${containerType}/${containerDefinition.title}`,
|
|
494
|
+
params: [appIdRef],
|
|
495
|
+
tags: ['app-center']
|
|
496
|
+
};
|
|
497
|
+
if (isAnalyticsProject) {
|
|
498
|
+
appCenterPathOptions.tags.push(containerRouteTagName);
|
|
462
499
|
}
|
|
500
|
+
apiPathOptions.push(appCenterPathOptions);
|
|
463
501
|
const apiPathMethods = {
|
|
464
502
|
get: undefined,
|
|
465
503
|
put: undefined
|
|
466
504
|
};
|
|
467
505
|
const getMethod = {
|
|
468
|
-
tags: [
|
|
506
|
+
tags: [],
|
|
469
507
|
summary: `Retrieve the data of the "${tagNameFromContainerTitle(containerDefinition.title)}" container`,
|
|
470
|
-
parameters: [
|
|
508
|
+
parameters: [],
|
|
471
509
|
responses: {
|
|
472
510
|
'200': {
|
|
473
511
|
...successfulOperationResponse,
|
|
@@ -498,9 +536,9 @@ function generatePathInformationFromContainer(apiDescription, containerDefinitio
|
|
|
498
536
|
apiPathMethods.get = getMethod;
|
|
499
537
|
if ([TransferDirection.down, TransferDirection.backendOnly].includes(containerDefinition.transferDirection)) {
|
|
500
538
|
apiPathMethods.put = {
|
|
501
|
-
tags: [
|
|
539
|
+
tags: [],
|
|
502
540
|
summary: `Modify the data of the "${tagNameFromContainerTitle(containerDefinition.title)}" container`,
|
|
503
|
-
parameters: [
|
|
541
|
+
parameters: [],
|
|
504
542
|
requestBody: {
|
|
505
543
|
content: {
|
|
506
544
|
'application/json': {
|
|
@@ -521,11 +559,18 @@ function generatePathInformationFromContainer(apiDescription, containerDefinitio
|
|
|
521
559
|
}
|
|
522
560
|
};
|
|
523
561
|
}
|
|
524
|
-
|
|
562
|
+
apiPathOptions.forEach(path => {
|
|
563
|
+
const methods = structuredClone(apiPathMethods);
|
|
564
|
+
Object.values(methods).forEach(value => {
|
|
565
|
+
value?.parameters?.unshift(...path.params);
|
|
566
|
+
value?.tags?.unshift(...path.tags);
|
|
567
|
+
});
|
|
568
|
+
apiDescription.paths[path.path] = methods;
|
|
569
|
+
});
|
|
525
570
|
}
|
|
526
571
|
if (containerDefinition.containerType === ContainerType.hx) {
|
|
527
572
|
apiPathMethods.get = {
|
|
528
|
-
tags: [
|
|
573
|
+
tags: [],
|
|
529
574
|
summary: `Get the historical data of "${containerDefinition.title}"`,
|
|
530
575
|
parameters: [
|
|
531
576
|
...pathParameters,
|
|
@@ -555,16 +600,23 @@ function generatePathInformationFromContainer(apiDescription, containerDefinitio
|
|
|
555
600
|
...defaultResponseCodes
|
|
556
601
|
}
|
|
557
602
|
};
|
|
558
|
-
|
|
559
|
-
const
|
|
603
|
+
// only site and addons support timeseries
|
|
604
|
+
const pathOptions = apiPathOptions[0];
|
|
605
|
+
const methods = structuredClone(apiPathMethods);
|
|
606
|
+
Object.values(methods).forEach(value => {
|
|
607
|
+
value?.parameters?.unshift(...pathOptions.params);
|
|
608
|
+
value?.tags?.unshift(...pathOptions.tags);
|
|
609
|
+
});
|
|
610
|
+
apiDescription.paths[pathOptions.path] = methods;
|
|
611
|
+
const youngestPath = `${pathOptions.path}/youngest`;
|
|
560
612
|
const youngestMethod = {
|
|
561
|
-
get:
|
|
613
|
+
get: methods.get
|
|
562
614
|
};
|
|
563
615
|
youngestMethod.get.summary = `Get the youngest record of "${containerDefinition.title}" container`;
|
|
564
616
|
apiDescription.paths[youngestPath] = youngestMethod;
|
|
565
|
-
const oldestPath = `${
|
|
617
|
+
const oldestPath = `${pathOptions.path}/oldest`;
|
|
566
618
|
const oldestMethod = {
|
|
567
|
-
get:
|
|
619
|
+
get: methods.get
|
|
568
620
|
};
|
|
569
621
|
oldestMethod.get.summary = `Get the oldest record of "${containerDefinition.title}" container`;
|
|
570
622
|
apiDescription.paths[oldestPath] = oldestMethod;
|
|
@@ -18,16 +18,19 @@ var CONFIG_CONTAINER = coreDefinitions_1.DDE_Core.CONFIG_CONTAINER;
|
|
|
18
18
|
var TransferDirection = coreDefinitions_1.DDE_Core.TransferDirection;
|
|
19
19
|
var fieldTypeDefinitions = coreDefinitions_1.DDE_Core.fieldTypeDefinitions;
|
|
20
20
|
var yamlRangeToLineInformation = helper_1.Helper.yamlRangeToLineInformation;
|
|
21
|
+
const api_1 = require("../api");
|
|
21
22
|
var YamlPreCompiler;
|
|
22
23
|
(function (YamlPreCompiler) {
|
|
23
24
|
class PreCompiler {
|
|
25
|
+
manifest;
|
|
24
26
|
libraryFiles;
|
|
25
27
|
ddeHistory;
|
|
26
28
|
fieldNamesPerContainer = {};
|
|
27
29
|
usedContainerNames = {};
|
|
28
30
|
fileDiagnostics = [];
|
|
29
31
|
libraryDDE = [];
|
|
30
|
-
constructor(libraryFiles, ddeHistory) {
|
|
32
|
+
constructor(manifest, libraryFiles, ddeHistory) {
|
|
33
|
+
this.manifest = manifest;
|
|
31
34
|
this.libraryFiles = libraryFiles;
|
|
32
35
|
this.ddeHistory = ddeHistory;
|
|
33
36
|
}
|
|
@@ -63,10 +66,12 @@ var YamlPreCompiler;
|
|
|
63
66
|
return { ddeJSON: mergedDDE, diagnostics };
|
|
64
67
|
}
|
|
65
68
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* @param
|
|
69
|
-
* @param
|
|
69
|
+
* Parses a YAML file and validates its content to produce a structured JSON object along with diagnostic information.
|
|
70
|
+
*
|
|
71
|
+
* @param filePath The URI of the YAML file being parsed.
|
|
72
|
+
* @param yaml The raw YAML content to parse.
|
|
73
|
+
* @param libraryName An optional parameter specifying the library name for additional validation.
|
|
74
|
+
* @return An object containing the parsed DDE JSON and an array of diagnostic messages related to the file.
|
|
70
75
|
*/
|
|
71
76
|
parseYamlFile(filePath, yaml, libraryName) {
|
|
72
77
|
this.fileDiagnostics.length = 0;
|
|
@@ -444,6 +449,16 @@ var YamlPreCompiler;
|
|
|
444
449
|
...yamlRangeToLineInformation(lineCounter, container.key.range)
|
|
445
450
|
});
|
|
446
451
|
}
|
|
452
|
+
if (api_1.Manifest.isAnalytics(this.manifest) &&
|
|
453
|
+
![DDEContainerName.relations, DDEContainerName.storage].includes(containerName)) {
|
|
454
|
+
const invalidName = containerName.includes('_') ? containerName.split('_')[1] : containerName;
|
|
455
|
+
this.fileDiagnostics.push({
|
|
456
|
+
file: sourceUri,
|
|
457
|
+
level: 'error',
|
|
458
|
+
message: `"${invalidName}" not allowed within an analytics app. Only "relations" and "storage" are allowed.`,
|
|
459
|
+
...yamlRangeToLineInformation(lineCounter, container.key.range)
|
|
460
|
+
});
|
|
461
|
+
}
|
|
447
462
|
}
|
|
448
463
|
validateContainerFields(yamlDoc, sourceUri, container, lineCounter) {
|
|
449
464
|
const containerFields = container.value; //(container.value as YAMLMap).get('fields', true);
|
package/out/globals.js
CHANGED
|
@@ -71,7 +71,7 @@ var Globals;
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
// load the projects main.ini and overwrite existing defines
|
|
74
|
-
const mainIni = vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.dlo.mainINI);
|
|
74
|
+
const mainIni = vscode_uri_1.Utils.joinPath(cwd, manifest.dlo?.iniFile || defaultFiles_1.DefaultFiles.filePaths.dlo.mainINI);
|
|
75
75
|
if (await fs.stat(mainIni)) {
|
|
76
76
|
const iniContent = await readIniFile(fs, mainIni);
|
|
77
77
|
Object.assign(allDefines, iniContent);
|
package/out/main.js
CHANGED
|
@@ -12,6 +12,7 @@ const globals_1 = require("./globals");
|
|
|
12
12
|
const update_notifier_1 = __importDefault(require("update-notifier"));
|
|
13
13
|
const api_1 = require("./api");
|
|
14
14
|
const log_1 = require("./log");
|
|
15
|
+
const argumentParser_1 = require("./argumentParser");
|
|
15
16
|
const program = new commander_1.Command();
|
|
16
17
|
const notifier = (0, update_notifier_1.default)({ pkg: package_json_1.default });
|
|
17
18
|
const logger = new log_1.Log.Logger();
|
|
@@ -30,14 +31,21 @@ const devPath = () => {
|
|
|
30
31
|
};
|
|
31
32
|
const cwd = vscode_uri_1.Utils.joinPath(vscode_uri_1.URI.file(process.cwd()), devPath());
|
|
32
33
|
program.version(package_json_1.default.version).usage('<command>');
|
|
34
|
+
program.description('This tool is used to manage the project dependencies, build, package and publish the project.\n' +
|
|
35
|
+
'The manifest options can be overwritten with the --option=value syntax.\n' +
|
|
36
|
+
'Example: "studio build --dlo.mainFile="./dlo/test.dlo" will overwrite the dlo.mainFile option of the manifest.\n' +
|
|
37
|
+
'\nUse "studio --help" for more information.');
|
|
33
38
|
/**
|
|
34
39
|
* Executes a task and ensures that the update available notification is sent after the task completes,
|
|
35
40
|
* regardless of whether it succeeds or fails.
|
|
36
41
|
*
|
|
42
|
+
* @param command
|
|
37
43
|
* @param {Promise<void>} task - A promise representing the task to be executed.
|
|
38
44
|
* @return {void} This function does not return a value.
|
|
39
45
|
*/
|
|
40
|
-
function main(task) {
|
|
46
|
+
function main(command, task) {
|
|
47
|
+
const manifestOptions = (0, argumentParser_1.parseUnknownLongOptions)(command);
|
|
48
|
+
api_1.Manifest.setOverwrites(manifestOptions);
|
|
41
49
|
// todo add task catch handler like: https://github.com/microsoft/vscode-vsce/blob/5518f2f242983d23f1983f6dd0350474f2011543/src/main.ts#L51
|
|
42
50
|
task.finally(() => {
|
|
43
51
|
notifier.notify();
|
|
@@ -94,9 +102,10 @@ program
|
|
|
94
102
|
.allowExcessArguments(true)
|
|
95
103
|
.addOption(optionStudioEnv)
|
|
96
104
|
.addOption(optionStudioToken)
|
|
97
|
-
.
|
|
105
|
+
.allowUnknownOption(true)
|
|
106
|
+
.action((dependencies, opts, command) => {
|
|
98
107
|
const { env, token } = getDefaultOptions(opts);
|
|
99
|
-
main((0, api_1.install)(cwd, cliFS_1.cliFS, env, token, dependencies));
|
|
108
|
+
main(command, (0, api_1.install)(cwd, cliFS_1.cliFS, env, token, dependencies));
|
|
100
109
|
});
|
|
101
110
|
program
|
|
102
111
|
.command('build')
|
|
@@ -104,9 +113,10 @@ program
|
|
|
104
113
|
.allowExcessArguments(true)
|
|
105
114
|
.addOption(optionStudioEnv)
|
|
106
115
|
.addOption(optionStudioToken)
|
|
107
|
-
.
|
|
116
|
+
.allowUnknownOption(true)
|
|
117
|
+
.action((opts, command) => {
|
|
108
118
|
const { env, token } = getDefaultOptions(opts);
|
|
109
|
-
main((0, api_1.build)(cwd, cliFS_1.cliFS, logger, env, token, opts.part));
|
|
119
|
+
main(command, (0, api_1.build)(cwd, cliFS_1.cliFS, logger, env, token, opts.part));
|
|
110
120
|
});
|
|
111
121
|
program
|
|
112
122
|
.command('publish')
|
|
@@ -114,10 +124,11 @@ program
|
|
|
114
124
|
.addOption(optionAllowedBackends)
|
|
115
125
|
.addOption(optionStudioEnv)
|
|
116
126
|
.addOption(optionStudioToken)
|
|
127
|
+
.allowUnknownOption(true)
|
|
117
128
|
.option('-i, --packagePath <path>', 'Publish the provided library or app package. Use "*" for autodetection.')
|
|
118
|
-
.action(async (opts) => {
|
|
129
|
+
.action(async (opts, command) => {
|
|
119
130
|
const { env, token } = getDefaultOptions(opts);
|
|
120
|
-
main((0, api_1.publish)(cwd, cliFS_1.cliFS, logger, env, token, opts.allowedBackends, opts.phase, opts.packagePath));
|
|
131
|
+
main(command, (0, api_1.publish)(cwd, cliFS_1.cliFS, logger, env, token, opts.allowedBackends, opts.phase, opts.packagePath));
|
|
121
132
|
});
|
|
122
133
|
program
|
|
123
134
|
.command('package')
|
|
@@ -126,9 +137,10 @@ program
|
|
|
126
137
|
.addOption(optionReleasePhase)
|
|
127
138
|
.addOption(optionStudioEnv)
|
|
128
139
|
.addOption(optionStudioToken)
|
|
129
|
-
.
|
|
140
|
+
.allowUnknownOption(true)
|
|
141
|
+
.action(async (opts, command) => {
|
|
130
142
|
const { env, token } = getDefaultOptions(opts);
|
|
131
|
-
main((0, api_1.pack)(cwd, cliFS_1.cliFS, logger, env, token, opts.phase));
|
|
143
|
+
main(command, (0, api_1.pack)(cwd, cliFS_1.cliFS, logger, env, token, opts.phase));
|
|
132
144
|
});
|
|
133
145
|
module.exports = function (argv) {
|
|
134
146
|
program.parse(argv);
|
package/out/manifest.js
CHANGED
|
@@ -12,20 +12,26 @@ const registryAPI_1 = require("./registryAPI");
|
|
|
12
12
|
const preload_1 = __importDefault(require("semver/preload"));
|
|
13
13
|
const apm_1 = require("./package/apm");
|
|
14
14
|
var isNumeric = helper_1.Helper.isNumeric;
|
|
15
|
+
const deepmerge_ts_1 = require("deepmerge-ts");
|
|
15
16
|
const PRODUCT_ID_SUPPORTED = '52v007';
|
|
16
17
|
const SEMVER_SUPPORTED = '53v001';
|
|
17
18
|
const ADDON_SUPPORTED = '54v001';
|
|
19
|
+
const ANALYTICS_SUPPORTED = '56v001';
|
|
18
20
|
// Cache to reduce the disk read requests
|
|
19
21
|
const manifestCache = {
|
|
20
22
|
_manifest: null,
|
|
21
23
|
_stat: null,
|
|
24
|
+
_overwrites: null,
|
|
22
25
|
get manifest() {
|
|
23
26
|
// clone the cached object to prevent any reference changes
|
|
24
|
-
return structuredClone(this._manifest);
|
|
27
|
+
return (0, deepmerge_ts_1.deepmerge)(structuredClone(this._manifest), manifestCache._overwrites || {});
|
|
25
28
|
},
|
|
26
29
|
set manifest(manifest) {
|
|
27
30
|
this._manifest = manifest;
|
|
28
31
|
},
|
|
32
|
+
set overwrites(manifest) {
|
|
33
|
+
this._overwrites = manifest;
|
|
34
|
+
},
|
|
29
35
|
get stat() {
|
|
30
36
|
return this._stat;
|
|
31
37
|
},
|
|
@@ -61,6 +67,7 @@ var Manifest;
|
|
|
61
67
|
ProjectTypes["app"] = "app";
|
|
62
68
|
ProjectTypes["library"] = "library";
|
|
63
69
|
ProjectTypes["addon"] = "addon";
|
|
70
|
+
ProjectTypes["analytics"] = "analytics";
|
|
64
71
|
})(ProjectTypes = Manifest.ProjectTypes || (Manifest.ProjectTypes = {}));
|
|
65
72
|
let BloAccessLevel;
|
|
66
73
|
(function (BloAccessLevel) {
|
|
@@ -72,6 +79,14 @@ var Manifest;
|
|
|
72
79
|
PovLocation["embedded"] = "$embedded";
|
|
73
80
|
PovLocation["pure"] = "$pure";
|
|
74
81
|
})(PovLocation = Manifest.PovLocation || (Manifest.PovLocation = {}));
|
|
82
|
+
function setOverwrites(manifest) {
|
|
83
|
+
manifestCache.overwrites = manifest;
|
|
84
|
+
}
|
|
85
|
+
Manifest.setOverwrites = setOverwrites;
|
|
86
|
+
function clearOverwrites() {
|
|
87
|
+
manifestCache.overwrites = null;
|
|
88
|
+
}
|
|
89
|
+
Manifest.clearOverwrites = clearOverwrites;
|
|
75
90
|
/**
|
|
76
91
|
* Read the studio.json manifest and parse it
|
|
77
92
|
* @param cwd
|
|
@@ -143,6 +158,14 @@ var Manifest;
|
|
|
143
158
|
return manifest.type === ProjectTypes.app;
|
|
144
159
|
}
|
|
145
160
|
Manifest.isApp = isApp;
|
|
161
|
+
/**
|
|
162
|
+
* Check if the current project is an analytics project
|
|
163
|
+
* @param manifest
|
|
164
|
+
*/
|
|
165
|
+
function isAnalytics(manifest) {
|
|
166
|
+
return manifest.type === ProjectTypes.analytics;
|
|
167
|
+
}
|
|
168
|
+
Manifest.isAnalytics = isAnalytics;
|
|
146
169
|
/**
|
|
147
170
|
* Validates if the properties within
|
|
148
171
|
* @param cwd
|
|
@@ -314,7 +337,7 @@ var Manifest;
|
|
|
314
337
|
throw new Error('Setting "engines.backend" is invalid');
|
|
315
338
|
}
|
|
316
339
|
validateHwFwOrProductId(manifest);
|
|
317
|
-
|
|
340
|
+
validateAddonOrAnalyticsSupported(manifest);
|
|
318
341
|
}
|
|
319
342
|
Manifest.validateEngineSettings = validateEngineSettings;
|
|
320
343
|
/**
|
|
@@ -329,9 +352,10 @@ var Manifest;
|
|
|
329
352
|
manifest = await Manifest.read(cwd, fs);
|
|
330
353
|
}
|
|
331
354
|
const isAddon = Manifest.isAddon(manifest);
|
|
355
|
+
const isAnalytics = Manifest.isAnalytics(manifest);
|
|
332
356
|
switch (apmPart) {
|
|
333
357
|
case apm_1.APM.Part.dlo:
|
|
334
|
-
return !!manifest?.dlo?.mainFile && !isAddon;
|
|
358
|
+
return !!manifest?.dlo?.mainFile && !isAddon && !isAnalytics;
|
|
335
359
|
case apm_1.APM.Part.blo:
|
|
336
360
|
return !!(manifest.blo?.buildCommand && manifest.blo?.workingPath);
|
|
337
361
|
case apm_1.APM.Part.pov:
|
|
@@ -390,19 +414,20 @@ function validateHwFwOrProductId(manifest) {
|
|
|
390
414
|
throw new Error(`"engines.productId" requires "engines.backend" to be "${PRODUCT_ID_SUPPORTED}"`);
|
|
391
415
|
}
|
|
392
416
|
}
|
|
393
|
-
function
|
|
394
|
-
if (!Manifest.isAddon(manifest)) {
|
|
417
|
+
function validateAddonOrAnalyticsSupported(manifest) {
|
|
418
|
+
if (!Manifest.isAddon(manifest) && !Manifest.isAnalytics(manifest)) {
|
|
395
419
|
return;
|
|
396
420
|
}
|
|
397
421
|
const { backend } = manifest.engines;
|
|
398
|
-
|
|
399
|
-
|
|
422
|
+
const requiredBackend = Manifest.isAddon(manifest) ? ADDON_SUPPORTED : ANALYTICS_SUPPORTED;
|
|
423
|
+
if (!backend || backend < requiredBackend) {
|
|
424
|
+
throw new Error(`Project type "${manifest.type}" requires "engines.backend" to be ">=${requiredBackend}"`);
|
|
400
425
|
}
|
|
401
426
|
if (manifest.dlo) {
|
|
402
|
-
throw new Error(
|
|
427
|
+
throw new Error(`For project type "${manifest.type}", "dlo" is not supported!"`);
|
|
403
428
|
}
|
|
404
429
|
if (manifest.dpid) {
|
|
405
|
-
throw new Error(
|
|
430
|
+
throw new Error(`For project type "${manifest.type}", "dpid" is not supported!"`);
|
|
406
431
|
}
|
|
407
432
|
}
|
|
408
433
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microtronics/studio-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Microtronics Studio CLI Tool",
|
|
5
5
|
"main": "./out/api.js",
|
|
6
6
|
"typings": "./dist/studio-cli.d.ts",
|
|
@@ -25,12 +25,14 @@
|
|
|
25
25
|
"author": "Microtronics",
|
|
26
26
|
"license": "ISC",
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@gera2ld/tarjs": "^0.3.1",
|
|
28
29
|
"ajv": "^8.17.1",
|
|
29
30
|
"ajv-formats": "^3.0.1",
|
|
30
31
|
"ajv-keywords": "^5.1.0",
|
|
31
32
|
"chalk": "^5.4.1",
|
|
32
33
|
"commander": "^12.1.0",
|
|
33
34
|
"cross-fetch": "^4.0.0",
|
|
35
|
+
"deepmerge-ts": "^7.1.5",
|
|
34
36
|
"dotenv": "^16.4.7",
|
|
35
37
|
"file-type-checker": "^1.1.2",
|
|
36
38
|
"glob": "^11.0.1",
|
|
@@ -41,7 +43,6 @@
|
|
|
41
43
|
"openapi-fetch": "^0.13.0",
|
|
42
44
|
"pako": "^2.1.0",
|
|
43
45
|
"semver": "^7.7.2",
|
|
44
|
-
"@gera2ld/tarjs": "^0.3.1",
|
|
45
46
|
"tinytar-fix": "^0.1.1",
|
|
46
47
|
"update-notifier": "^7.3.1",
|
|
47
48
|
"vscode-uri": "^3.0.8",
|