@contrail/cli 3.6.0-alpha-2 → 3.6.0-alpha-3
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/README.md +2 -2
- package/dist/commands/entities/get.js +8 -1
- package/dist/commands/entities/update.js +1 -1
- package/dist/helpers/entities/batchFetch.d.ts +2 -2
- package/dist/helpers/entities/batchFetch.js +9 -1
- package/dist/helpers/propertySpecifications/propertySpecifications.d.ts +4 -6
- package/dist/helpers/propertySpecifications/propertySpecifications.js +3 -10
- package/dist/helpers/propertySpecifications/propertySpecifications.spec.js +4 -64
- package/oclif.manifest.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
|
|
|
17
17
|
$ contrail COMMAND
|
|
18
18
|
running command...
|
|
19
19
|
$ contrail (--version)
|
|
20
|
-
@contrail/cli/3.6.0-alpha-
|
|
20
|
+
@contrail/cli/3.6.0-alpha-3 darwin-arm64 node-v22.19.0
|
|
21
21
|
$ contrail --help [COMMAND]
|
|
22
22
|
USAGE
|
|
23
23
|
$ contrail COMMAND
|
|
@@ -683,7 +683,7 @@ DESCRIPTION
|
|
|
683
683
|
EXAMPLES
|
|
684
684
|
$ contrail entities update color 123 -- name=obsidian hex=000000
|
|
685
685
|
|
|
686
|
-
$ contrail entities update color 123 -- description= notes='""'
|
|
686
|
+
$ contrail entities update color 123 -- description= notes='""' # Unset description, set notes to empty string
|
|
687
687
|
```
|
|
688
688
|
|
|
689
689
|
## `contrail file upload FILELOCATION CONTENTTYPE`
|
|
@@ -8,6 +8,7 @@ const sdk_1 = require("@contrail/sdk");
|
|
|
8
8
|
const login_1 = require("../../auth/login");
|
|
9
9
|
const types_1 = require("../../api/types");
|
|
10
10
|
const propertySpecifications_1 = require("../../helpers/propertySpecifications/propertySpecifications");
|
|
11
|
+
const batchFetch_1 = require("../../helpers/entities/batchFetch");
|
|
11
12
|
let SHOULD_USE_PAGINATED_FIND = false;
|
|
12
13
|
let MAX_NUMBER_OF_ENTITIES_TO_FETCH = undefined;
|
|
13
14
|
class GetEntity extends basecommand_1.BaseCommand {
|
|
@@ -162,7 +163,13 @@ async function find(entityName, options = {}) {
|
|
|
162
163
|
if (propertySlugs && propertySlugs.length > 0) {
|
|
163
164
|
queryOptions.customParams = { propertySlugs: propertySlugs.join(',') };
|
|
164
165
|
}
|
|
165
|
-
|
|
166
|
+
const payload = id ? { id, ...queryOptions } : { criteria, ...queryOptions };
|
|
167
|
+
if ((0, batchFetch_1.canBatchFetchEntity)(entityName)) {
|
|
168
|
+
return (0, batchFetch_1.batchFetch)(entityName, payload);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
return client.get(payload);
|
|
172
|
+
}
|
|
166
173
|
}
|
|
167
174
|
async function* streamPaginatedFind(typePath, options = {}) {
|
|
168
175
|
const client = new sdk_1.Entities();
|
|
@@ -12,7 +12,7 @@ class UpdateEntity extends basecommand_1.BaseCommand {
|
|
|
12
12
|
static description = '(BETA) Update an entity';
|
|
13
13
|
static examples = [
|
|
14
14
|
'contrail entities update color 123 -- name=obsidian hex=000000',
|
|
15
|
-
'contrail entities update color 123 -- description= notes=\'""\'
|
|
15
|
+
'contrail entities update color 123 -- description= notes=\'""\' # Unset description, set notes to empty string',
|
|
16
16
|
];
|
|
17
17
|
static flags = {
|
|
18
18
|
...basecommand_1.BaseCommand.baseFlags,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { AssortmentItem,
|
|
1
|
+
import { AssortmentItem, ProjectItem } from '@contrail/entity-types';
|
|
2
2
|
import { EntitiesClientGetOptions } from '@contrail/sdk';
|
|
3
|
+
export declare function canBatchFetchEntity(entityName: string): entityName is keyof BatchFetchableEntityMap;
|
|
3
4
|
export interface BatchFetchableEntityMap {
|
|
4
|
-
item: Item;
|
|
5
5
|
'project-item': ProjectItem;
|
|
6
6
|
'assortment-item': AssortmentItem;
|
|
7
7
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.batchFetch = void 0;
|
|
3
|
+
exports.batchFetch = exports.canBatchFetchEntity = void 0;
|
|
4
4
|
const sdk_1 = require("@contrail/sdk");
|
|
5
5
|
const util_1 = require("@contrail/util");
|
|
6
|
+
// Maps entity names to their types for batch fetching.
|
|
7
|
+
// This allows for type-safe batch fetching of entities
|
|
8
|
+
// such that the Type returned always matches the entity name.
|
|
9
|
+
const BATCH_FETCHABLE_ENTITIES = ['assortment-item', 'project-item'];
|
|
10
|
+
function canBatchFetchEntity(entityName) {
|
|
11
|
+
return BATCH_FETCHABLE_ENTITIES.includes(entityName);
|
|
12
|
+
}
|
|
13
|
+
exports.canBatchFetchEntity = canBatchFetchEntity;
|
|
6
14
|
async function batchFetch(entityName, options) {
|
|
7
15
|
const response = await requestBatchFetch(entityName, options);
|
|
8
16
|
return parseBatchFetchResponse(response);
|
|
@@ -10,24 +10,22 @@
|
|
|
10
10
|
*
|
|
11
11
|
* It is typically used as the argv in a command.
|
|
12
12
|
*
|
|
13
|
-
* Special handling for empty values
|
|
13
|
+
* Special handling for empty values:
|
|
14
14
|
* - slug= (empty value) → property is set to undefined (unset)
|
|
15
15
|
* - slug='""' or slug="''" → property is set to empty string ""
|
|
16
|
-
* - slug=null → property is set to null
|
|
17
|
-
* - slug="null" → property is set to the string "null"
|
|
18
16
|
*
|
|
19
17
|
* Examples:
|
|
20
18
|
*
|
|
21
19
|
* contrail entities get color -- id=123
|
|
22
20
|
* contrail entities update color 123 -- name=obsidian hex=000000
|
|
23
|
-
* contrail entities update color 123 -- description= notes='""'
|
|
21
|
+
* contrail entities update color 123 -- description= notes='""'
|
|
24
22
|
* contrail entities get loader-processes -- createdOn=2025-09-15..2025-09-16
|
|
25
23
|
*/
|
|
26
24
|
export type PropertySpecification = {
|
|
27
25
|
slug: string;
|
|
28
|
-
value: string | undefined
|
|
26
|
+
value: string | undefined;
|
|
29
27
|
};
|
|
30
|
-
export type PropertySpecificationBySlug = Map<string, string | number | string[] | number[] | undefined
|
|
28
|
+
export type PropertySpecificationBySlug = Map<string, string | number | string[] | number[] | undefined>;
|
|
31
29
|
export type PropertySpecificationString = `${string}=${string}`;
|
|
32
30
|
export declare function parsePropertySpecification(spec: PropertySpecificationString): PropertySpecification;
|
|
33
31
|
export declare function parsePropertySpecificationsIntoMap(propertySpecifications: PropertySpecificationString[]): PropertySpecificationBySlug;
|
|
@@ -11,17 +11,15 @@
|
|
|
11
11
|
*
|
|
12
12
|
* It is typically used as the argv in a command.
|
|
13
13
|
*
|
|
14
|
-
* Special handling for empty values
|
|
14
|
+
* Special handling for empty values:
|
|
15
15
|
* - slug= (empty value) → property is set to undefined (unset)
|
|
16
16
|
* - slug='""' or slug="''" → property is set to empty string ""
|
|
17
|
-
* - slug=null → property is set to null
|
|
18
|
-
* - slug="null" → property is set to the string "null"
|
|
19
17
|
*
|
|
20
18
|
* Examples:
|
|
21
19
|
*
|
|
22
20
|
* contrail entities get color -- id=123
|
|
23
21
|
* contrail entities update color 123 -- name=obsidian hex=000000
|
|
24
|
-
* contrail entities update color 123 -- description= notes='""'
|
|
22
|
+
* contrail entities update color 123 -- description= notes='""'
|
|
25
23
|
* contrail entities get loader-processes -- createdOn=2025-09-15..2025-09-16
|
|
26
24
|
*/
|
|
27
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -40,11 +38,9 @@ function parsePropertySpecification(spec) {
|
|
|
40
38
|
if (!slug) {
|
|
41
39
|
throw new Error(`Invalid property specification: ${spec}`);
|
|
42
40
|
}
|
|
43
|
-
// Handle special cases for empty strings
|
|
41
|
+
// Handle special cases for empty strings:
|
|
44
42
|
// - x= means undefined (unset the property)
|
|
45
43
|
// - x='""' or x="''" means empty string ""
|
|
46
|
-
// - x=null means null value
|
|
47
|
-
// - x="null" means the string "null"
|
|
48
44
|
let finalValue;
|
|
49
45
|
if (value === '') {
|
|
50
46
|
finalValue = undefined;
|
|
@@ -52,9 +48,6 @@ function parsePropertySpecification(spec) {
|
|
|
52
48
|
else if (value === DOUBLE_QUOTED_EMPTY || value === SINGLE_QUOTED_EMPTY) {
|
|
53
49
|
finalValue = '';
|
|
54
50
|
}
|
|
55
|
-
else if (value === 'null') {
|
|
56
|
-
finalValue = null;
|
|
57
|
-
}
|
|
58
51
|
else {
|
|
59
52
|
finalValue = value;
|
|
60
53
|
}
|
|
@@ -78,28 +78,6 @@ describe('parsePropertySpecification', () => {
|
|
|
78
78
|
value: '',
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
|
-
it('should parse property specification with null value', () => {
|
|
82
|
-
const spec = 'description=null';
|
|
83
|
-
const result = (0, propertySpecifications_1.parsePropertySpecification)(spec);
|
|
84
|
-
expect(result).toEqual({
|
|
85
|
-
slug: 'description',
|
|
86
|
-
value: null,
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
it('should distinguish between null and the string "null"', () => {
|
|
90
|
-
const nullSpec = 'field=null';
|
|
91
|
-
const stringNullSpec = 'field="null"';
|
|
92
|
-
const nullResult = (0, propertySpecifications_1.parsePropertySpecification)(nullSpec);
|
|
93
|
-
const stringNullResult = (0, propertySpecifications_1.parsePropertySpecification)(stringNullSpec);
|
|
94
|
-
expect(nullResult).toEqual({
|
|
95
|
-
slug: 'field',
|
|
96
|
-
value: null,
|
|
97
|
-
});
|
|
98
|
-
expect(stringNullResult).toEqual({
|
|
99
|
-
slug: 'field',
|
|
100
|
-
value: '"null"',
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
81
|
it('should throw error for spec without equals sign', () => {
|
|
104
82
|
const spec = 'invalidspec';
|
|
105
83
|
expect(() => (0, propertySpecifications_1.parsePropertySpecification)(spec)).toThrow('Invalid property specification: invalidspec');
|
|
@@ -175,23 +153,9 @@ describe('parsePropertySpecificationsIntoMap', () => {
|
|
|
175
153
|
const result = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(specs);
|
|
176
154
|
expect(result.get('name')).toBe('john');
|
|
177
155
|
expect(result.get('description')).toBeUndefined();
|
|
178
|
-
expect(result.get('notes')).toBe('');
|
|
156
|
+
expect(result.get('notes')).toBe(''); // Empty quotes are converted to empty string
|
|
179
157
|
expect(result.size).toBe(3);
|
|
180
158
|
});
|
|
181
|
-
it('should handle property specifications with null values', () => {
|
|
182
|
-
const specs = [
|
|
183
|
-
'name=john',
|
|
184
|
-
'description=null',
|
|
185
|
-
'notes="null"',
|
|
186
|
-
'empty=',
|
|
187
|
-
];
|
|
188
|
-
const result = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(specs);
|
|
189
|
-
expect(result.get('name')).toBe('john');
|
|
190
|
-
expect(result.get('description')).toBeNull();
|
|
191
|
-
expect(result.get('notes')).toBe('"null"');
|
|
192
|
-
expect(result.get('empty')).toBeUndefined();
|
|
193
|
-
expect(result.size).toBe(4);
|
|
194
|
-
});
|
|
195
159
|
it('should throw error for invalid property specifications', () => {
|
|
196
160
|
const specs = [
|
|
197
161
|
'name=john',
|
|
@@ -278,21 +242,13 @@ describe('integration tests', () => {
|
|
|
278
242
|
const quotedSpecs = ['description=""'];
|
|
279
243
|
const quotedMap = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(quotedSpecs);
|
|
280
244
|
expect(quotedMap.get('description')).toBe(''); // Quoted empty = empty string
|
|
281
|
-
// Test case 3: Mixed usage
|
|
282
|
-
const mixedSpecs = [
|
|
283
|
-
'name=test',
|
|
284
|
-
'description=',
|
|
285
|
-
'notes=""',
|
|
286
|
-
'data=null',
|
|
287
|
-
'status="null"',
|
|
288
|
-
];
|
|
245
|
+
// Test case 3: Mixed usage
|
|
246
|
+
const mixedSpecs = ['name=test', 'description=', 'notes=""'];
|
|
289
247
|
const mixedMap = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(mixedSpecs);
|
|
290
248
|
expect(mixedMap.get('name')).toBe('test');
|
|
291
249
|
expect(mixedMap.get('description')).toBeUndefined(); // Unset
|
|
292
250
|
expect(mixedMap.get('notes')).toBe(''); // Empty string
|
|
293
|
-
expect(mixedMap.
|
|
294
|
-
expect(mixedMap.get('status')).toBe('"null"'); // String "null"
|
|
295
|
-
expect(mixedMap.size).toBe(5);
|
|
251
|
+
expect(mixedMap.size).toBe(3);
|
|
296
252
|
});
|
|
297
253
|
});
|
|
298
254
|
describe('edge cases and limitations', () => {
|
|
@@ -362,20 +318,4 @@ describe('edge cases and limitations', () => {
|
|
|
362
318
|
value: 'value',
|
|
363
319
|
});
|
|
364
320
|
});
|
|
365
|
-
it('should document all special value types', () => {
|
|
366
|
-
// This test documents all the special value types and their parsing behavior
|
|
367
|
-
const specs = [
|
|
368
|
-
{ input: 'a=value', expected: 'value', description: 'regular string' },
|
|
369
|
-
{ input: 'b=', expected: undefined, description: 'undefined (unset)' },
|
|
370
|
-
{ input: 'c=""', expected: '', description: 'empty string' },
|
|
371
|
-
{ input: 'd=null', expected: null, description: 'null value' },
|
|
372
|
-
{ input: 'e="null"', expected: '"null"', description: 'string "null"' },
|
|
373
|
-
{ input: 'f=123', expected: '123', description: 'numeric string' },
|
|
374
|
-
{ input: 'g=true', expected: 'true', description: 'boolean string' },
|
|
375
|
-
];
|
|
376
|
-
for (const { input, expected } of specs) {
|
|
377
|
-
const result = (0, propertySpecifications_1.parsePropertySpecification)(input);
|
|
378
|
-
expect(result.value).toBe(expected);
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
321
|
});
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.6.0-alpha-
|
|
2
|
+
"version": "3.6.0-alpha-3",
|
|
3
3
|
"commands": {
|
|
4
4
|
"app:create": {
|
|
5
5
|
"id": "app:create",
|
|
@@ -964,7 +964,7 @@
|
|
|
964
964
|
"aliases": [],
|
|
965
965
|
"examples": [
|
|
966
966
|
"contrail entities update color 123 -- name=obsidian hex=000000",
|
|
967
|
-
"contrail entities update color 123 -- description= notes='\"\"'
|
|
967
|
+
"contrail entities update color 123 -- description= notes='\"\"' # Unset description, set notes to empty string"
|
|
968
968
|
],
|
|
969
969
|
"flags": {
|
|
970
970
|
"logLevel": {
|