@contrail/cli 3.3.3 → 3.5.0-alpha

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.
Files changed (50) hide show
  1. package/README.md +150 -1
  2. package/dist/api/types.d.ts +35 -0
  3. package/dist/api/types.js +47 -1
  4. package/dist/auth/login.js +0 -8
  5. package/dist/basecommand.d.ts +3 -1
  6. package/dist/basecommand.js +1 -1
  7. package/dist/commands/app/extension/deploy.js +2 -4
  8. package/dist/commands/entities/create.d.ts +37 -0
  9. package/dist/commands/entities/create.js +555 -0
  10. package/dist/commands/entities/create.spec.d.ts +1 -0
  11. package/dist/commands/entities/create.spec.js +514 -0
  12. package/dist/commands/entities/delete.d.ts +16 -0
  13. package/dist/commands/entities/delete.js +118 -0
  14. package/dist/commands/entities/get.d.ts +20 -0
  15. package/dist/commands/entities/get.js +204 -0
  16. package/dist/commands/entities/update.d.ts +18 -0
  17. package/dist/commands/entities/update.js +116 -0
  18. package/dist/commands/types/uploadUsageInfo.js +2 -14
  19. package/dist/common.d.ts +1 -1
  20. package/dist/helpers/app/app-deployer.js +4 -8
  21. package/dist/helpers/app/extension-package-deployer.js +1 -1
  22. package/dist/helpers/config/config.js +3 -3
  23. package/dist/helpers/entities/assortment-items.d.ts +10 -0
  24. package/dist/helpers/entities/assortment-items.js +84 -0
  25. package/dist/helpers/entities/batchFetch.d.ts +8 -0
  26. package/dist/helpers/entities/batchFetch.js +41 -0
  27. package/dist/helpers/entities/index.d.ts +3 -0
  28. package/dist/helpers/entities/index.js +6 -0
  29. package/dist/helpers/entities/items.d.ts +10 -0
  30. package/dist/helpers/entities/items.js +102 -0
  31. package/dist/helpers/entities/project-items.d.ts +3 -0
  32. package/dist/helpers/entities/project-items.js +65 -0
  33. package/dist/helpers/file-helpers.d.ts +1 -0
  34. package/dist/helpers/file-helpers.js +19 -1
  35. package/dist/helpers/propertySpecifications/dateRanges.d.ts +38 -0
  36. package/dist/helpers/propertySpecifications/dateRanges.js +89 -0
  37. package/dist/helpers/propertySpecifications/dateRanges.spec.d.ts +1 -0
  38. package/dist/helpers/propertySpecifications/dateRanges.spec.js +95 -0
  39. package/dist/helpers/propertySpecifications/propertySpecifications.d.ts +27 -0
  40. package/dist/helpers/propertySpecifications/propertySpecifications.js +70 -0
  41. package/dist/helpers/propertySpecifications/propertySpecifications.spec.d.ts +1 -0
  42. package/dist/helpers/propertySpecifications/propertySpecifications.spec.js +266 -0
  43. package/dist/helpers/types/type-uploader.js +0 -7
  44. package/dist/interfaces.d.ts +0 -1
  45. package/dist/templates/typescript/README.md +1 -3
  46. package/dist/templates/typescript/assets/sample.json +1 -1
  47. package/dist/templates/typescript/eslintrc.json +4 -1
  48. package/dist/templates/typescript/tsconfig.json +21 -5
  49. package/oclif.manifest.json +361 -1
  50. package/package.json +6 -5
@@ -0,0 +1,555 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doesPropertyLevelMatchRole = exports.selectRandomObject = exports.buildObjectReferenceCache = exports.getReferencedObjectPaths = exports.pickRandomValueForProperty = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_1 = tslib_1.__importDefault(require("fs"));
6
+ const unique_names_generator_1 = require("unique-names-generator");
7
+ const p_limit_1 = tslib_1.__importDefault(require("p-limit"));
8
+ const types_1 = require("@contrail/types");
9
+ const types_2 = require("../../api/types");
10
+ const core_1 = require("@oclif/core");
11
+ const types_3 = require("../../api/types");
12
+ const login_1 = require("../../auth/login");
13
+ const basecommand_1 = require("../../basecommand");
14
+ const sdk_1 = require("@contrail/sdk");
15
+ const entities_1 = require("../../helpers/entities");
16
+ const propertySpecifications_1 = require("../../helpers/propertySpecifications/propertySpecifications");
17
+ const file_helpers_1 = require("../../helpers/file-helpers");
18
+ let IS_DRY_RUN = false;
19
+ let SHOULD_USE_READABLE_IDS = false;
20
+ let SHOULD_SKIP_HYDRATE_RELATIONSHIPS = false;
21
+ let SHOULD_ONLY_USE_SPECIFIED_PROPERTIES = false;
22
+ let NUM_ENTITIES_TO_CREATE = 1; // Default to creating one entity if not specified
23
+ const getNumEntitiesToCreate = () => NUM_ENTITIES_TO_CREATE; // method to get the latest number in case this changes later
24
+ const baseValidationMap = {
25
+ assortmentId: async (_slug, assortmentId) => (0, entities_1.throwIfInvalidAssortmentId)(assortmentId),
26
+ itemId: async (_slug, itemId) => (0, entities_1.throwIfInvalidItemId)(itemId),
27
+ projectId: async (_slug, projectId) => (0, entities_1.throwIfInvalidProjectId)(projectId),
28
+ };
29
+ const throwIfInvalidPropertyLevelFn = async (_slug, maybeRoles) => maybeRoles.forEach((maybeRole) => (0, entities_1.throwIfInvalidItemLevel)(maybeRole));
30
+ const throwIfInvalidUserOrgRoleFn = async (_slug, maybeRole) => {
31
+ if (maybeRole !== 'MEMBER' && maybeRole !== 'ADMIN') {
32
+ throw new Error(`${maybeRole} is not a valid User Org Role`); // TODO: get these roles from a shared library
33
+ }
34
+ };
35
+ const SLUG_VALIDATION_BY_ROOT_MAP = {
36
+ item: { ...baseValidationMap, roles: throwIfInvalidPropertyLevelFn },
37
+ 'project-item': { ...baseValidationMap, roles: throwIfInvalidPropertyLevelFn },
38
+ 'assortment-item': baseValidationMap,
39
+ 'user-org': baseValidationMap,
40
+ 'custom-entity': { ...baseValidationMap, role: throwIfInvalidUserOrgRoleFn },
41
+ };
42
+ const SLUGS_THAT_MUST_BE_SPECIFIED_BY_TYPE_PATH = {
43
+ item: ['roles'],
44
+ 'project-item': ['projectId'],
45
+ 'assortment-item': ['assortmentId'],
46
+ 'user-org': ['role'],
47
+ };
48
+ const FIND_VALID_VALUE_MAP = {
49
+ assortment: [
50
+ {
51
+ slug: 'name',
52
+ findValidValuesFn: async (assortments) => new Set(Array.from({ length: assortments.length }, () => generateRandomReadableString())),
53
+ applyValueToEntityFn: (entity, validValues) => {
54
+ if (entity.name)
55
+ return; // skip if already specified
56
+ entity.name = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
57
+ validValues.delete(entity.name);
58
+ },
59
+ },
60
+ ],
61
+ 'assortment-item': [
62
+ {
63
+ slug: 'itemId',
64
+ findValidValuesFn: async (assortmentItems, count) => new Set((await (0, entities_1.findItemsNotInAssortment)(assortmentItems[0].assortmentId, count)).map(({ id }) => id)),
65
+ applyValueToEntityFn: (entity, validValues) => {
66
+ if (entity.itemId)
67
+ return; // skip if already specified
68
+ entity.itemId = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
69
+ validValues.delete(entity.itemId);
70
+ },
71
+ },
72
+ ],
73
+ 'project-item': [
74
+ {
75
+ slug: 'itemId',
76
+ findValidValuesFn: async (projectItems) => new Set((await (0, entities_1.findItemsNotInProject)(projectItems[0].projectId)).map(({ id }) => id)),
77
+ applyValueToEntityFn: (entity, validValues) => {
78
+ if (entity.itemId)
79
+ return; // skip if already specified
80
+ entity.itemId = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
81
+ validValues.delete(entity.itemId);
82
+ },
83
+ },
84
+ ],
85
+ item: [
86
+ {
87
+ slug: 'familyId',
88
+ findValidValuesFn: async (_items) => new Set(await (0, entities_1.getItemFamilies)(getNumEntitiesToCreate()).then((families) => families === undefined ? undefined : families.map(({ id }) => id))),
89
+ applyValueToEntityFn: (entity, validValues) => {
90
+ if (entity.familyId)
91
+ return; // skip if already specified
92
+ if (entity.roles?.includes('option')) {
93
+ entity.familyId = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
94
+ // can reuse familyId for options
95
+ }
96
+ },
97
+ },
98
+ {
99
+ slug: 'name',
100
+ findValidValuesFn: async (items) => new Set(Array.from({ length: items.length }, () => generateRandomReadableString())),
101
+ applyValueToEntityFn: (entity, validValues) => {
102
+ if (entity.name)
103
+ return; // skip if already specified
104
+ entity.name = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
105
+ validValues.delete(entity.name);
106
+ },
107
+ },
108
+ {
109
+ slug: 'optionName',
110
+ findValidValuesFn: async (items) => new Set(Array.from({ length: items.length }, () => generateRandomReadableString())),
111
+ applyValueToEntityFn: (entity, validValues) => {
112
+ if (entity.optionName)
113
+ return; // skip if already specified
114
+ if (!entity.roles?.includes('option'))
115
+ return; // only apply to options
116
+ entity.optionName = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
117
+ validValues.delete(entity.optionName);
118
+ },
119
+ },
120
+ {
121
+ slug: 'optionGroup',
122
+ findValidValuesFn: async (_items) => new Set(),
123
+ applyValueToEntityFn: (entity, _validValues) => {
124
+ if (entity.optionGroup)
125
+ return; // skip if already specified
126
+ if (!entity.roles?.includes('option'))
127
+ return; // only apply to options
128
+ entity.optionGroup = 'color';
129
+ },
130
+ },
131
+ ],
132
+ workspace: [
133
+ {
134
+ slug: 'name',
135
+ findValidValuesFn: async (items) => new Set(Array.from({ length: items.length }, () => generateRandomReadableString())),
136
+ applyValueToEntityFn: (entity, validValues) => {
137
+ if (entity.name)
138
+ return; // skip if already specified
139
+ entity.name = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
140
+ validValues.delete(entity.name);
141
+ },
142
+ },
143
+ ],
144
+ };
145
+ class CreateEntity extends basecommand_1.BaseCommand {
146
+ static description = '(BETA) Create entities';
147
+ static examples = [
148
+ 'contrail entities create color -n=10 # creates 10 random colors',
149
+ 'contrail entities create color # creates one item',
150
+ 'contrail entities create custom-entities:franchise',
151
+ 'contrail entities create project-item -n=1 -- projectId=abc # creates 10 project items within project ABC',
152
+ 'contrail entities create color -r # creates a random color with a human readable ID',
153
+ 'contrail entities create color -d # simulates the creation of a random color without actually creating it',
154
+ 'contrail entities create custom-entity:franchise -s # creates a random color and the response does not contain hydrating relationships',
155
+ 'contrail entities create color -p -- name=Electric Blue green=1 red=2 blue=3 # creates a color with specified properties',
156
+ 'contrail entities create color -o /tmp/colors.json # creates a random color and saves the output to /tmp/colors.json',
157
+ ];
158
+ static flags = {
159
+ ...basecommand_1.BaseCommand.baseFlags,
160
+ count: core_1.Flags.integer({
161
+ char: 'n',
162
+ description: 'Number of random entities to create',
163
+ required: false,
164
+ }),
165
+ dryRun: core_1.Flags.boolean({
166
+ char: 'd',
167
+ description: 'If true, does not create the entity but simulates the creation',
168
+ required: false,
169
+ default: false,
170
+ }),
171
+ inputFile: core_1.Flags.string({
172
+ char: 'i',
173
+ description: 'A file with a JSON array of objects where each object is one entity to create. Cannot be used with --count. Unless --precise is specified, any missing values will be populated with random values.',
174
+ required: false,
175
+ multiple: false,
176
+ }),
177
+ outputFile: core_1.Flags.string({
178
+ char: 'o',
179
+ description: 'File to save the output (optional)',
180
+ required: false,
181
+ multiple: false,
182
+ }),
183
+ preciseProperties: core_1.Flags.boolean({
184
+ char: 'p',
185
+ description: 'If true, does not generate random values for properties. All values must be specified.',
186
+ required: false,
187
+ default: false,
188
+ }),
189
+ readableIds: core_1.Flags.boolean({
190
+ char: 'r',
191
+ description: 'If true, uses readable IDs for the created entities',
192
+ required: false,
193
+ default: false,
194
+ }),
195
+ skipHydrateRelationships: core_1.Flags.boolean({
196
+ char: 's',
197
+ description: 'If true, does not hydrate relationships for the created entities',
198
+ required: false,
199
+ default: false,
200
+ }),
201
+ };
202
+ static args = {
203
+ path: core_1.Args.string({
204
+ description: 'Path of the entity type to create',
205
+ required: true,
206
+ multiple: false,
207
+ }),
208
+ };
209
+ static strict = false;
210
+ async run() {
211
+ this.log('🚨 This command is in BETA and may change or be removed at any time.');
212
+ await (0, login_1.authUser)();
213
+ const { flags, argv, args } = await this.parse(CreateEntity);
214
+ const { count, dryRun: isDryRun, inputFile: inputFilename, outputFile: outputFilename, preciseProperties: shouldOnlyUseSpecifiedProperties, readableIds: shouldUseReadableIds, skipHydrateRelationships, } = flags;
215
+ const { path: entityTypePath } = args;
216
+ // Global flags is a little hacky, but it was easier
217
+ // and it doesn't see *that* bad because they are only valid
218
+ // for the lifecycle of the command.
219
+ IS_DRY_RUN = isDryRun;
220
+ SHOULD_USE_READABLE_IDS = shouldUseReadableIds;
221
+ SHOULD_SKIP_HYDRATE_RELATIONSHIPS = skipHydrateRelationships;
222
+ SHOULD_ONLY_USE_SPECIFIED_PROPERTIES = shouldOnlyUseSpecifiedProperties;
223
+ const propertySpecificationArgs = argv
224
+ .slice(1, argv.length)
225
+ .filter(propertySpecifications_1.isValidPropertySpecification);
226
+ const propertySpecBySlug = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(propertySpecificationArgs);
227
+ // Validate args
228
+ if (!entityTypePath) {
229
+ this.error('You must specify an entity type path.');
230
+ }
231
+ if (inputFilename && count) {
232
+ throw new Error('You cannot use --input and --count together. Please specify one or the other.');
233
+ }
234
+ if (count !== undefined && count <= 0) {
235
+ this.error('Count must be a positive integer.');
236
+ }
237
+ const partialEntities = inputFilename
238
+ ? (0, file_helpers_1.parseFileAsJsonArray)(inputFilename)
239
+ : Array.from({ length: count || 1 }).fill({});
240
+ NUM_ENTITIES_TO_CREATE = partialEntities.length;
241
+ // Ensure we have the required properties for the entity type
242
+ if (SLUGS_THAT_MUST_BE_SPECIFIED_BY_TYPE_PATH[entityTypePath]) {
243
+ const requiredSlugs = SLUGS_THAT_MUST_BE_SPECIFIED_BY_TYPE_PATH[entityTypePath];
244
+ for (const slug of requiredSlugs) {
245
+ if (!propertySpecBySlug.has(slug)) {
246
+ this.error(`Property '${slug}' must be specified for entity type '${entityTypePath}'.`);
247
+ }
248
+ }
249
+ }
250
+ try {
251
+ const entitiesToCreate = await buildEntitiesToCreate(entityTypePath, partialEntities, propertySpecBySlug);
252
+ const { root: entityName } = (0, types_2.parseTypePath)(entityTypePath);
253
+ const createdEntities = await createEntities(entityName, entitiesToCreate);
254
+ if (outputFilename) {
255
+ fs_1.default.writeFileSync(outputFilename, JSON.stringify(createdEntities, null, 2));
256
+ this.log(`Output saved to ${outputFilename}`);
257
+ }
258
+ else {
259
+ console.log(`Created ${entityTypePath}(s), Entity: ${JSON.stringify(createdEntities, null, 2)}`);
260
+ }
261
+ }
262
+ catch (error) {
263
+ this.error(`Failed to create entities: ${error.message}, ${error.stack}`);
264
+ }
265
+ }
266
+ }
267
+ exports.default = CreateEntity;
268
+ async function createEntities(entityName, entities) {
269
+ const limit = (0, p_limit_1.default)(20);
270
+ const createdEntities = IS_DRY_RUN
271
+ ? entities
272
+ : await Promise.allSettled(entities.map(async (e) => limit(() => createEntity(entityName, e))));
273
+ if (IS_DRY_RUN) {
274
+ console.log(`Dry run mode: not creating entities, but simulating creation for ${entityName}`);
275
+ }
276
+ return createdEntities;
277
+ }
278
+ async function buildEntitiesToCreate(entityTypePath, entities, propertySpecificationBySlug) {
279
+ let type = await (0, types_3.getTypeByPath)(entityTypePath);
280
+ if (!type) {
281
+ console.warn(`Type not found for path: ${entityTypePath}`);
282
+ type = {
283
+ typePath: '',
284
+ typeProperties: [],
285
+ }; // Fallback to an empty type; This allows us to create entities that are not type-managed
286
+ }
287
+ const [typesCache, objectReferencesCache] = await Promise.all([
288
+ (0, types_2.buildLocalTypesCache)([...(0, types_2.getReferencedTypePaths)(type), entityTypePath]),
289
+ buildLocalObjectReferencesCache(getReferencedObjectPaths(type)),
290
+ ]);
291
+ const populatedEntities = entities.map((entity) => ({
292
+ ...createEntityWithPopulatedValues(type, typesCache, objectReferencesCache, propertySpecificationBySlug),
293
+ ...entity,
294
+ }));
295
+ const limit = (0, p_limit_1.default)(30);
296
+ await Promise.all(populatedEntities.map(async () => limit(() => throwIfEntityIsInvalid)));
297
+ // Add system values if needed
298
+ const { root } = (0, types_2.parseTypePath)(type.typePath);
299
+ const valueFinderApplierForEntity = FIND_VALID_VALUE_MAP[root] || [];
300
+ for (const { slug, findValidValuesFn, applyValueToEntityFn } of valueFinderApplierForEntity) {
301
+ // If the property is already specified, skip it unless it is a role for an option or family
302
+ if (propertySpecificationBySlug?.has(slug)) {
303
+ console.log(`Skipping property ${slug} because it is already specified.`);
304
+ continue;
305
+ }
306
+ const values = await findValidValuesFn(populatedEntities, entities.length);
307
+ if (values) {
308
+ populatedEntities.forEach((e) => applyValueToEntityFn(e, values));
309
+ }
310
+ else {
311
+ console.warn(`No valid values found for property ${slug}. Skipping.`);
312
+ }
313
+ }
314
+ return populatedEntities;
315
+ }
316
+ function createEntityWithPopulatedValues(type, typeReferencesCache, objectReferencesCache, propertySpecificationBySlug) {
317
+ const roles = propertySpecificationBySlug?.get('roles');
318
+ const entity = SHOULD_ONLY_USE_SPECIFIED_PROPERTIES
319
+ ? {}
320
+ : pickRandomPropertyValues(type, objectReferencesCache, typeReferencesCache, roles);
321
+ // Handle property specifications
322
+ for (const [propertySlug, specifiedValue] of propertySpecificationBySlug.entries()) {
323
+ const correspondingProperty = type.typeProperties.find((prop) => getPropertySlug(prop) === propertySlug);
324
+ if (!specifiedValue) {
325
+ throw new Error(`Value for property ${propertySlug} is required`);
326
+ }
327
+ entity[propertySlug] = castValueToPropertyType(specifiedValue, correspondingProperty?.propertyType || types_1.PropertyType.String);
328
+ }
329
+ // Give Readbable IDs if specified
330
+ if (SHOULD_USE_READABLE_IDS) {
331
+ entity.specifiedId = generateRandomReadableString();
332
+ }
333
+ // Support specifiedId
334
+ if (propertySpecificationBySlug?.has('specifiedId')) {
335
+ const specifiedId = propertySpecificationBySlug.get('specifiedId');
336
+ entity.specifiedId = specifiedId;
337
+ }
338
+ // There are some required values for certain entity types
339
+ const requiredValuesForType = requiredValues(type.typePath, typeReferencesCache);
340
+ if (requiredValuesForType) {
341
+ requiredValuesForType.forEach(({ slug, value }) => {
342
+ entity[slug] = value;
343
+ });
344
+ }
345
+ return entity;
346
+ }
347
+ function pickRandomPropertyValues(type, objectReferencesCache, typeReferencesCache, roles) {
348
+ const entity = {};
349
+ // Get values for properties
350
+ for (const property of type.typeProperties) {
351
+ // Validate property level
352
+ if (roles?.length && roles.every((r) => !doesPropertyLevelMatchRole(property.propertyLevel, r)))
353
+ continue;
354
+ // Generate random value
355
+ if (property.propertyType === types_1.PropertyType.ObjectReference) {
356
+ const cache = objectReferencesCache.get(property.referencedTypePath);
357
+ if (!cache || cache.size === 0) {
358
+ throw new Error(`No object references found for referencedTypePath: ${property.referencedTypePath}`);
359
+ }
360
+ entity[getPropertySlug(property)] = selectRandomObject(cache).id;
361
+ }
362
+ else {
363
+ entity[getPropertySlug(property)] = pickRandomValueForProperty(property, objectReferencesCache, typeReferencesCache);
364
+ }
365
+ }
366
+ return entity;
367
+ }
368
+ async function throwIfEntityIsInvalid(typeRoot, entity) {
369
+ const propertySlugs = Object.keys(entity);
370
+ const validationMap = SLUG_VALIDATION_BY_ROOT_MAP[typeRoot] || {};
371
+ const promises = propertySlugs
372
+ .filter((slug) => validationMap[slug])
373
+ .map((slug) => validationMap[slug](slug, entity[slug]));
374
+ await Promise.all(promises);
375
+ }
376
+ function pickRandomValueForProperty(property, objectReferencesCache, typeReferencesCache) {
377
+ const getRandomObjectReference = (referencedTypePath) => {
378
+ if (!objectReferencesCache.has(referencedTypePath)) {
379
+ throw new Error(`No object references found for referencedTypePath: ${referencedTypePath}`);
380
+ }
381
+ const cache = objectReferencesCache.get(referencedTypePath);
382
+ if (cache.size === 0) {
383
+ return null;
384
+ }
385
+ const randomIndex = Math.floor(Math.random() * cache.size);
386
+ const randomObjectReference = Array.from(cache.values())[randomIndex];
387
+ return randomObjectReference;
388
+ };
389
+ switch (property.propertyType) {
390
+ case types_1.PropertyType.String:
391
+ return generateRandomReadableString();
392
+ case types_1.PropertyType.Text:
393
+ return generateRandomReadableString();
394
+ case types_1.PropertyType.Boolean:
395
+ return generateRandomBooleanValue();
396
+ case types_1.PropertyType.Number:
397
+ return generateRandomNumber();
398
+ case types_1.PropertyType.Currency:
399
+ return generateRandomNumber();
400
+ case types_1.PropertyType.SingleSelect:
401
+ if (!property.options)
402
+ throw new Error(`Option set is required for SingleSelect property ${property.slug}, ${JSON.stringify(property, null, 2)}`);
403
+ return pickRandomOptions(property.options, 1)[0].value;
404
+ case types_1.PropertyType.MultiSelect:
405
+ if (!property.options)
406
+ throw new Error('Option set is required for MultiSelect property');
407
+ const randomSelection = pickRandomOptions(property.options, Math.max(2, property.options.length)); // Avoid picking more than the number of options
408
+ return randomSelection.map((option) => option.value);
409
+ case types_1.PropertyType.Sequence:
410
+ return generateRandomNumber();
411
+ case types_1.PropertyType.Date:
412
+ return generateRandomDateString();
413
+ case types_1.PropertyType.Percent:
414
+ return generateRandomNumber(0, 100);
415
+ case types_1.PropertyType.ObjectReference:
416
+ const { referencedTypePath: typeForObjectReference } = property;
417
+ const randomObjectReference = getRandomObjectReference(typeForObjectReference);
418
+ if (!randomObjectReference) {
419
+ throw new Error(`No object references found for referencedTypePath: ${typeForObjectReference}`);
420
+ }
421
+ return randomObjectReference.id; // Assuming the object reference has an 'id' field
422
+ case types_1.PropertyType.TypeReference:
423
+ const { referencedTypePath } = property;
424
+ const type = typeReferencesCache.get(referencedTypePath);
425
+ if (!type) {
426
+ throw new Error(`Referenced type not found for path: ${referencedTypePath}`);
427
+ }
428
+ return type.id;
429
+ case types_1.PropertyType.Formula:
430
+ return undefined; // Placeholder for formula properties because they are evaluated on save anyway
431
+ default:
432
+ throw new Error(`Cannot handle property type: ${property.propertyType}.\n\n See property: ${JSON.stringify(property, null, 2)}`);
433
+ // TODO: Handle UserList
434
+ // TODO: Handle ObjectReferenceList
435
+ }
436
+ }
437
+ exports.pickRandomValueForProperty = pickRandomValueForProperty;
438
+ function pickRandomOptions(options, count) {
439
+ const shuffled = options.sort(() => 0.5 - Math.random());
440
+ return shuffled.slice(0, count);
441
+ }
442
+ function generateRandomBooleanValue() {
443
+ return Math.random() < 0.5;
444
+ }
445
+ function generateRandomNumber(min, max) {
446
+ if (min === undefined) {
447
+ min = 0;
448
+ }
449
+ if (max === undefined) {
450
+ max = 100;
451
+ }
452
+ return Math.floor(Math.random() * (max - min + 1)) + min;
453
+ }
454
+ function generateRandomReadableString() {
455
+ return (0, unique_names_generator_1.uniqueNamesGenerator)({ dictionaries: [unique_names_generator_1.adjectives, unique_names_generator_1.animals, unique_names_generator_1.colors, unique_names_generator_1.starWars], length: 3 });
456
+ }
457
+ function generateRandomDateString() {
458
+ return new Date().toISOString();
459
+ }
460
+ function castValueToPropertyType(value, propertyType) {
461
+ switch (propertyType) {
462
+ case types_1.PropertyType.Boolean:
463
+ return value.toString().toLowerCase() === 'true';
464
+ case types_1.PropertyType.Number:
465
+ const numValue = parseFloat(value.toString());
466
+ if (isNaN(numValue)) {
467
+ throw new Error(`Invalid number value: ${value}`);
468
+ }
469
+ return numValue;
470
+ case types_1.PropertyType.Date:
471
+ return new Date(value.toString()).toISOString();
472
+ default:
473
+ return value; // For string and other types, return as is
474
+ }
475
+ }
476
+ async function createEntity(entityName, entity) {
477
+ const client = new sdk_1.Entities();
478
+ const skipHydrateRelationships = SHOULD_SKIP_HYDRATE_RELATIONSHIPS;
479
+ if (entityName === 'assortment-item')
480
+ return (0, entities_1.createAssortmentItem)(entity, { skipHydrateRelationships }); // special case
481
+ const response = await client.create({ entityName, object: entity, skipHydrateRelationships });
482
+ return response;
483
+ }
484
+ function getReferencedObjectPaths(type) {
485
+ const properties = type.typeProperties || [];
486
+ return properties
487
+ .filter((prop) => prop.propertyType === types_1.PropertyType.ObjectReference)
488
+ .map(({ referencedTypePath }) => referencedTypePath);
489
+ }
490
+ exports.getReferencedObjectPaths = getReferencedObjectPaths;
491
+ async function buildLocalObjectReferencesCache(paths) {
492
+ const cache = new Map();
493
+ const getExampleCustomEntitiesByTypePath = (path) => {
494
+ const client = new sdk_1.Entities();
495
+ const entities = client.get({
496
+ entityName: 'custom-entity',
497
+ criteria: {
498
+ typePath: path,
499
+ },
500
+ });
501
+ return entities;
502
+ };
503
+ const getExampleEntites = async (path) => {
504
+ if (path.startsWith('custom-entity')) {
505
+ return getExampleCustomEntitiesByTypePath(path);
506
+ }
507
+ const { root } = (0, types_2.parseTypePath)(path);
508
+ const client = new sdk_1.Entities();
509
+ const entities = await client.get({
510
+ entityName: root,
511
+ });
512
+ return entities;
513
+ };
514
+ const entitiesByPath = await Promise.all((paths || []).map(async (path) => {
515
+ const entities = await getExampleEntites(path);
516
+ return { path, entities };
517
+ }));
518
+ entitiesByPath.forEach(({ path, entities }) => {
519
+ const cacheForPath = buildObjectReferenceCache(entities);
520
+ cache.set(path, cacheForPath);
521
+ });
522
+ return cache;
523
+ }
524
+ function buildObjectReferenceCache(entities) {
525
+ const cache = new Map();
526
+ entities.forEach((entity) => {
527
+ const { id } = entity;
528
+ if (id && !cache.has(id)) {
529
+ cache.set(id, entity);
530
+ }
531
+ });
532
+ return cache;
533
+ }
534
+ exports.buildObjectReferenceCache = buildObjectReferenceCache;
535
+ function selectRandomObject(cache) {
536
+ return Array.from(cache.values())[Math.floor(Math.random() * cache.size)];
537
+ }
538
+ exports.selectRandomObject = selectRandomObject;
539
+ function requiredValues(path, typeCache) {
540
+ if (path.startsWith('custom-entity')) {
541
+ return [{ slug: 'typeId', value: typeCache.get(path)?.id || '' }];
542
+ }
543
+ }
544
+ function getPropertySlug(property) {
545
+ return property.propertyType === types_1.PropertyType.ObjectReference
546
+ ? `${property.slug}Id`
547
+ : property.slug;
548
+ }
549
+ function doesPropertyLevelMatchRole(propertyLevel, role) {
550
+ const isMatchingLevel = propertyLevel === role;
551
+ return (isMatchingLevel ||
552
+ propertyLevel === types_1.PropertyLevel.ALL ||
553
+ propertyLevel === types_1.PropertyLevel.OVERRIDABLE);
554
+ }
555
+ exports.doesPropertyLevelMatchRole = doesPropertyLevelMatchRole;
@@ -0,0 +1 @@
1
+ export {};