@contentstack/cli-cm-export-query 1.0.0-beta.9 → 1.0.1

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.
@@ -7,4 +7,5 @@ export default class ExportQueryCommand extends Command {
7
7
  static usage: string;
8
8
  static flags: FlagInput;
9
9
  run(): Promise<void>;
10
+ initializeMessageHandler(): void;
10
11
  }
@@ -8,6 +8,7 @@ class ExportQueryCommand extends cli_command_1.Command {
8
8
  async run() {
9
9
  try {
10
10
  const { flags } = await this.parse(ExportQueryCommand);
11
+ this.initializeMessageHandler();
11
12
  // Setup export configuration
12
13
  const exportQueryConfig = await (0, utils_1.setupQueryExportConfig)(flags);
13
14
  exportQueryConfig.host = this.cmaHost;
@@ -41,6 +42,9 @@ class ExportQueryCommand extends cli_command_1.Command {
41
42
  (0, cli_utilities_1.handleAndLogError)(error);
42
43
  }
43
44
  }
45
+ initializeMessageHandler() {
46
+ cli_utilities_1.messageHandler.init(this.context);
47
+ }
44
48
  }
45
49
  exports.default = ExportQueryCommand;
46
50
  ExportQueryCommand.description = 'Export content from a stack using query-based filtering';
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const config = {
4
- contentVersion: 2,
4
+ contentVersion: 1,
5
5
  host: 'https://api.contentstack.io/v3',
6
6
  // Query-based export module configuration
7
7
  modules: {
@@ -1,7 +1,7 @@
1
1
  import { DefaultConfig } from '../types';
2
2
 
3
3
  const config: DefaultConfig = {
4
- contentVersion: 2,
4
+ contentVersion: 1,
5
5
  host: 'https://api.contentstack.io/v3',
6
6
 
7
7
  // Query-based export module configuration
@@ -2,8 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ModuleExporter = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("path"));
5
6
  const cli_utilities_1 = require("@contentstack/cli-utilities");
6
7
  const cli_cm_export_1 = tslib_1.__importDefault(require("@contentstack/cli-cm-export"));
8
+ const read_content_type_schemas_1 = require("../utils/read-content-type-schemas");
7
9
  class ModuleExporter {
8
10
  constructor(exportQueryConfig) {
9
11
  this.exportedModules = [];
@@ -22,6 +24,13 @@ class ModuleExporter {
22
24
  // Create export command instance
23
25
  await cli_cm_export_1.default.run(cmd);
24
26
  cli_utilities_1.log.debug(`Export command completed for module: ${moduleName}`, moduleLogContext);
27
+ if (moduleName === 'content-types') {
28
+ const baseDir = options.directory || this.exportQueryConfig.exportDir;
29
+ const branch = options.branch || this.exportQueryConfig.branchName || '';
30
+ const ctDir = path.join((0, cli_utilities_1.sanitizePath)(baseDir), (0, cli_utilities_1.sanitizePath)(branch), 'content_types');
31
+ (0, read_content_type_schemas_1.rebuildContentTypesSchemaJson)(ctDir);
32
+ cli_utilities_1.log.debug('Rebuilt content_types/schema.json from all per-UID JSON files', moduleLogContext);
33
+ }
25
34
  // Read the exported data
26
35
  // const data = await this.readExportedData(moduleName, options);
27
36
  if (!this.exportedModules.includes(moduleName)) {
@@ -48,10 +57,13 @@ class ModuleExporter {
48
57
  cmd.push('-d', directory);
49
58
  // Module
50
59
  cmd.push('--module', moduleName);
51
- // Alias (management token)
60
+ // Alias or management token (mutually exclusive for the export CLI)
52
61
  if (options.alias) {
53
62
  cmd.push('-a', options.alias);
54
63
  }
64
+ else if (this.exportQueryConfig.managementToken) {
65
+ cmd.push('-a', this.exportQueryConfig.managementToken);
66
+ }
55
67
  // Branch
56
68
  if (options.branch || this.exportQueryConfig.branchName) {
57
69
  cmd.push('--branch', options.branch || this.exportQueryConfig.branchName);
@@ -9,8 +9,19 @@ export declare class QueryExporter {
9
9
  execute(): Promise<void>;
10
10
  private exportGeneralModules;
11
11
  private exportQueriedModule;
12
- private exportReferencedContentTypes;
13
- private exportDependentModules;
12
+ /**
13
+ * Iteratively expand the set of exported content types, global fields, extensions,
14
+ * taxonomies, and marketplace apps until no new items are discovered (fixpoint).
15
+ *
16
+ * Each iteration scans the combined set of CT and GF documents that currently exist on
17
+ * disk. Any newly discovered referenced content types or global fields are exported and
18
+ * the loop restarts so that their schemas can be scanned in turn. Leaf dependencies
19
+ * (extensions, taxonomies, marketplace apps) are collected and exported in the same pass
20
+ * without triggering an extra iteration, since they do not themselves produce new schemas.
21
+ *
22
+ * Personalize is exported exactly once, after the closure stabilises.
23
+ */
24
+ private expandSchemaClosure;
14
25
  private exportContentModules;
15
26
  private exportEntries;
16
27
  private exportReferencedAssets;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.QueryExporter = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const cli_utilities_1 = require("@contentstack/cli-utilities");
6
+ const fs = tslib_1.__importStar(require("fs"));
6
7
  const path = tslib_1.__importStar(require("path"));
7
8
  const query_parser_1 = require("../utils/query-parser");
8
9
  const module_exporter_1 = require("./module-exporter");
@@ -10,6 +11,7 @@ const utils_1 = require("../utils");
10
11
  const utils_2 = require("../utils");
11
12
  const utils_3 = require("../utils");
12
13
  const utils_4 = require("../utils");
14
+ const read_content_type_schemas_1 = require("../utils/read-content-type-schemas");
13
15
  class QueryExporter {
14
16
  constructor(managementAPIClient, exportQueryConfig) {
15
17
  this.exportQueryConfig = exportQueryConfig;
@@ -31,19 +33,10 @@ class QueryExporter {
31
33
  await this.exportGeneralModules();
32
34
  // Step 4: Export queried modules
33
35
  await this.exportQueriedModule(parsedQuery);
34
- // Step 1: Read initial content types and mark them as exported
35
- const contentTypesFilePath = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'content_types', 'schema.json');
36
- const contentTypes = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath)) || [];
37
- if (contentTypes.length === 0) {
38
- cli_utilities_1.log.info('No content types found, skipping export', this.exportQueryConfig.context);
39
- process.exit(0);
40
- }
41
- // Step 5: export other content types which are referenced in previous step
42
- cli_utilities_1.log.debug('Starting referenced content types export', this.exportQueryConfig.context);
43
- await this.exportReferencedContentTypes();
44
- // Step 6: export dependent modules global fields, extensions, taxonomies
45
- cli_utilities_1.log.debug('Starting dependent modules export', this.exportQueryConfig.context);
46
- await this.exportDependentModules();
36
+ // Step 5+6: resolve the full transitive closure of referenced content types,
37
+ // global fields, extensions, taxonomies, and marketplace apps.
38
+ cli_utilities_1.log.debug('Starting schema closure expansion', this.exportQueryConfig.context);
39
+ await this.expandSchemaClosure();
47
40
  // Step 7: export content modules entries, assets
48
41
  cli_utilities_1.log.debug('Starting content modules export', this.exportQueryConfig.context);
49
42
  await this.exportContentModules();
@@ -71,131 +64,112 @@ class QueryExporter {
71
64
  }
72
65
  cli_utilities_1.log.debug('Queried module export completed', this.exportQueryConfig.context);
73
66
  }
74
- async exportReferencedContentTypes() {
75
- cli_utilities_1.log.info('Starting export of referenced content types...', this.exportQueryConfig.context);
67
+ /**
68
+ * Iteratively expand the set of exported content types, global fields, extensions,
69
+ * taxonomies, and marketplace apps until no new items are discovered (fixpoint).
70
+ *
71
+ * Each iteration scans the combined set of CT and GF documents that currently exist on
72
+ * disk. Any newly discovered referenced content types or global fields are exported and
73
+ * the loop restarts so that their schemas can be scanned in turn. Leaf dependencies
74
+ * (extensions, taxonomies, marketplace apps) are collected and exported in the same pass
75
+ * without triggering an extra iteration, since they do not themselves produce new schemas.
76
+ *
77
+ * Personalize is exported exactly once, after the closure stabilises.
78
+ */
79
+ async expandSchemaClosure() {
80
+ cli_utilities_1.log.info('Starting export of referenced content types and dependent modules...', this.exportQueryConfig.context);
76
81
  try {
82
+ const ctPath = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'content_types');
83
+ const gfPath = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'global_fields');
77
84
  const referencedHandler = new utils_1.ReferencedContentTypesHandler(this.exportQueryConfig);
78
- const exportedContentTypeUIDs = new Set();
79
- // Step 1: Read initial content types and mark them as exported
80
- const contentTypesFilePath = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'content_types', 'schema.json');
81
- const contentTypes = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath)) || [];
82
- if (contentTypes.length === 0) {
83
- cli_utilities_1.log.info('No content types found, skipping referenced content types export', this.exportQueryConfig.context);
84
- return;
85
- }
86
- // Step 2: Start with initial batch (all currently exported content types)
87
- let currentBatch = [...contentTypes];
88
- cli_utilities_1.log.info(`Starting with ${currentBatch.length} initial content types`, this.exportQueryConfig.context);
89
- // track reference depth
85
+ const dependenciesHandler = new utils_3.ContentTypeDependenciesHandler(this.stackAPIClient, this.exportQueryConfig);
86
+ const exportedCTUIDs = new Set();
87
+ const exportedGFUIDs = new Set();
88
+ const exportedExtUIDs = new Set();
89
+ const exportedTaxUIDs = new Set();
90
+ const exportedMarketplaceUIDs = new Set();
90
91
  let iterationCount = 0;
91
- // Step 3: Process batches until no new references are found
92
- while (currentBatch.length > 0 && iterationCount < this.exportQueryConfig.maxCTReferenceDepth) {
92
+ while (iterationCount < this.exportQueryConfig.maxCTReferenceDepth) {
93
93
  iterationCount++;
94
- cli_utilities_1.log.debug(`Processing referenced content types iteration ${iterationCount}`, this.exportQueryConfig.context);
95
- currentBatch.forEach((ct) => exportedContentTypeUIDs.add(ct.uid));
96
- // Extract referenced content types from current batch
97
- const referencedUIDs = await referencedHandler.extractReferencedContentTypes(currentBatch);
98
- // Filter out already exported content types
99
- const newReferencedUIDs = referencedUIDs.filter((uid) => !exportedContentTypeUIDs.has(uid));
100
- if (newReferencedUIDs.length > 0) {
101
- cli_utilities_1.log.info(`Found ${newReferencedUIDs.length} new referenced content types to fetch`, this.exportQueryConfig.context);
102
- // // Add to exported set to avoid duplicates in future iterations
103
- // newReferencedUIDs.forEach((uid) => exportedContentTypeUIDs.add(uid));
104
- // Step 4: Fetch new content types using moduleExporter
105
- const query = {
106
- modules: {
107
- 'content-types': {
108
- uid: {
109
- $in: newReferencedUIDs,
110
- },
111
- },
112
- },
113
- };
114
- await this.moduleExporter.exportModule('content-types', { query });
115
- const newContentTypes = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath));
116
- currentBatch = [...newContentTypes];
117
- // Push new content types to main array
118
- contentTypes.push(...newContentTypes);
119
- cli_utilities_1.log.info(`Fetched ${currentBatch.length} new content types for next iteration`, this.exportQueryConfig.context);
94
+ cli_utilities_1.log.debug(`Schema closure iteration ${iterationCount}`, this.exportQueryConfig.context);
95
+ const allCTs = (0, read_content_type_schemas_1.readContentTypesFromExportDir)(ctPath);
96
+ const allGFs = (0, read_content_type_schemas_1.readGlobalFieldSchemasFromDir)(gfPath);
97
+ // Record everything currently on disk so we never re-export it.
98
+ allCTs.forEach((ct) => exportedCTUIDs.add(ct.uid));
99
+ allGFs.forEach((gf) => exportedGFUIDs.add(gf.uid));
100
+ const allSchemas = [...allCTs, ...allGFs];
101
+ if (allSchemas.length === 0) {
102
+ cli_utilities_1.log.info('No schemas found on disk, stopping closure', this.exportQueryConfig.context);
103
+ break;
104
+ }
105
+ let foundNewCTs = false;
106
+ let foundNewGFs = false;
107
+ // Step A: find and export referenced content types from the combined schema set.
108
+ if (!this.exportQueryConfig.skipReferences) {
109
+ const referencedUIDs = await referencedHandler.extractReferencedContentTypes(allSchemas);
110
+ const newCTUIDs = referencedUIDs.filter((uid) => !exportedCTUIDs.has(uid));
111
+ if (newCTUIDs.length > 0) {
112
+ cli_utilities_1.log.info(`Found ${newCTUIDs.length} new referenced content type(s) to fetch`, this.exportQueryConfig.context);
113
+ await this.moduleExporter.exportModule('content-types', {
114
+ query: { modules: { 'content-types': { uid: { $in: newCTUIDs } } } },
115
+ });
116
+ // Track immediately so the dedup filter works even if the disk reader
117
+ // hasn't picked up the newly written files yet.
118
+ newCTUIDs.forEach((uid) => exportedCTUIDs.add(uid));
119
+ foundNewCTs = true;
120
+ }
120
121
  }
121
- else {
122
- cli_utilities_1.log.info('No new referenced content types found, stopping recursion', this.exportQueryConfig.context);
122
+ // Step B: find and export dependent modules from the combined schema set.
123
+ if (!this.exportQueryConfig.skipDependencies) {
124
+ const deps = await dependenciesHandler.extractDependencies(allSchemas);
125
+ const newGFUIDs = [...deps.globalFields].filter((uid) => !exportedGFUIDs.has(uid));
126
+ if (newGFUIDs.length > 0) {
127
+ cli_utilities_1.log.info(`Found ${newGFUIDs.length} new global field(s)`, this.exportQueryConfig.context);
128
+ await this.moduleExporter.exportModule('global-fields', {
129
+ query: { modules: { 'global-fields': { uid: { $in: newGFUIDs } } } },
130
+ });
131
+ // Track immediately for the same reason as CTs above.
132
+ newGFUIDs.forEach((uid) => exportedGFUIDs.add(uid));
133
+ foundNewGFs = true;
134
+ }
135
+ // Extensions, taxonomies, and marketplace apps are leaf nodes: they do not
136
+ // produce new schemas, so exporting them never requires an extra iteration.
137
+ const newExtUIDs = [...deps.extensions].filter((uid) => !exportedExtUIDs.has(uid));
138
+ if (newExtUIDs.length > 0) {
139
+ cli_utilities_1.log.info(`Found ${newExtUIDs.length} new extension(s)`, this.exportQueryConfig.context);
140
+ await this.moduleExporter.exportModule('extensions', {
141
+ query: { modules: { extensions: { uid: { $in: newExtUIDs } } } },
142
+ });
143
+ newExtUIDs.forEach((uid) => exportedExtUIDs.add(uid));
144
+ }
145
+ const newMarketplaceUIDs = [...deps.marketplaceApps].filter((uid) => !exportedMarketplaceUIDs.has(uid));
146
+ if (newMarketplaceUIDs.length > 0) {
147
+ cli_utilities_1.log.info(`Found ${newMarketplaceUIDs.length} new marketplace app(s)`, this.exportQueryConfig.context);
148
+ await this.moduleExporter.exportModule('marketplace-apps', {
149
+ query: { modules: { 'marketplace-apps': { installation_uid: { $in: newMarketplaceUIDs } } } },
150
+ });
151
+ newMarketplaceUIDs.forEach((uid) => exportedMarketplaceUIDs.add(uid));
152
+ }
153
+ const newTaxUIDs = [...deps.taxonomies].filter((uid) => !exportedTaxUIDs.has(uid));
154
+ if (newTaxUIDs.length > 0) {
155
+ cli_utilities_1.log.info(`Found ${newTaxUIDs.length} new taxonom(ies)`, this.exportQueryConfig.context);
156
+ await this.moduleExporter.exportModule('taxonomies', {
157
+ query: { modules: { taxonomies: { uid: { $in: newTaxUIDs } } } },
158
+ });
159
+ newTaxUIDs.forEach((uid) => exportedTaxUIDs.add(uid));
160
+ }
161
+ }
162
+ if (!foundNewCTs && !foundNewGFs) {
163
+ cli_utilities_1.log.info('Schema closure complete, no new content types or global fields found', this.exportQueryConfig.context);
123
164
  break;
124
165
  }
125
166
  }
126
- utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath), contentTypes);
127
- cli_utilities_1.log.success('Referenced content types export completed successfully', this.exportQueryConfig.context);
128
- }
129
- catch (error) {
130
- (0, cli_utilities_1.handleAndLogError)(error, this.exportQueryConfig.context, 'Error exporting referenced content types');
131
- throw error;
132
- }
133
- }
134
- async exportDependentModules() {
135
- cli_utilities_1.log.info('Starting export of dependent modules...', this.exportQueryConfig.context);
136
- try {
137
- const dependenciesHandler = new utils_3.ContentTypeDependenciesHandler(this.stackAPIClient, this.exportQueryConfig);
138
- // Extract dependencies from all exported content types
139
- const dependencies = await dependenciesHandler.extractDependencies();
140
- cli_utilities_1.log.debug('Dependencies extracted successfully', this.exportQueryConfig.context);
141
- // Export Global Fields
142
- if (dependencies.globalFields.size > 0) {
143
- const globalFieldUIDs = Array.from(dependencies.globalFields);
144
- cli_utilities_1.log.info(`Exporting ${globalFieldUIDs.length} global fields...`, this.exportQueryConfig.context);
145
- const query = {
146
- modules: {
147
- 'global-fields': {
148
- uid: { $in: globalFieldUIDs },
149
- },
150
- },
151
- };
152
- await this.moduleExporter.exportModule('global-fields', { query });
153
- }
154
- // Export Extensions
155
- if (dependencies.extensions.size > 0) {
156
- const extensionUIDs = Array.from(dependencies.extensions);
157
- cli_utilities_1.log.info(`Exporting ${extensionUIDs.length} extensions...`, this.exportQueryConfig.context);
158
- const query = {
159
- modules: {
160
- extensions: {
161
- uid: { $in: extensionUIDs },
162
- },
163
- },
164
- };
165
- await this.moduleExporter.exportModule('extensions', { query });
166
- }
167
- // export marketplace apps
168
- if (dependencies.marketplaceApps.size > 0) {
169
- const marketplaceAppInstallationUIDs = Array.from(dependencies.marketplaceApps);
170
- cli_utilities_1.log.info(`Exporting ${marketplaceAppInstallationUIDs.length} marketplace apps...`, this.exportQueryConfig.context);
171
- const query = {
172
- modules: {
173
- 'marketplace-apps': {
174
- installation_uid: { $in: marketplaceAppInstallationUIDs },
175
- },
176
- },
177
- };
178
- await this.moduleExporter.exportModule('marketplace-apps', { query });
179
- }
180
- // Export Taxonomies
181
- if (dependencies.taxonomies.size > 0) {
182
- const taxonomyUIDs = Array.from(dependencies.taxonomies);
183
- cli_utilities_1.log.info(`Exporting ${taxonomyUIDs.length} taxonomies...`, this.exportQueryConfig.context);
184
- const query = {
185
- modules: {
186
- taxonomies: {
187
- uid: { $in: taxonomyUIDs },
188
- },
189
- },
190
- };
191
- await this.moduleExporter.exportModule('taxonomies', { query });
192
- }
193
- // export personalize
167
+ // Personalize is a single global module exported once after the closure stabilises.
194
168
  await this.moduleExporter.exportModule('personalize');
195
- cli_utilities_1.log.success('Dependent modules export completed successfully', this.exportQueryConfig.context);
169
+ cli_utilities_1.log.success('Referenced content types and dependent modules exported successfully', this.exportQueryConfig.context);
196
170
  }
197
171
  catch (error) {
198
- (0, cli_utilities_1.handleAndLogError)(error, this.exportQueryConfig.context, 'Error exporting dependent modules');
172
+ (0, cli_utilities_1.handleAndLogError)(error, this.exportQueryConfig.context, 'Error during schema closure expansion');
199
173
  throw error;
200
174
  }
201
175
  }
@@ -244,18 +218,9 @@ class QueryExporter {
244
218
  const assetUIDs = assetHandler.extractReferencedAssets();
245
219
  if (assetUIDs.length > 0) {
246
220
  cli_utilities_1.log.info(`Found ${assetUIDs.length} referenced assets to export`, this.exportQueryConfig.context);
221
+ fs.mkdirSync(assetsDir, { recursive: true });
247
222
  // Define batch size - can be configurable through exportQueryConfig
248
223
  const batchSize = this.exportQueryConfig.assetBatchSize || 100;
249
- if (assetUIDs.length <= batchSize) {
250
- const query = {
251
- modules: {
252
- assets: {
253
- uid: { $in: assetUIDs },
254
- },
255
- },
256
- };
257
- await this.moduleExporter.exportModule('assets', { query });
258
- }
259
224
  // if asset size is bigger than batch size, then we need to export in batches
260
225
  // Calculate number of batches
261
226
  const totalBatches = Math.ceil(assetUIDs.length / batchSize);
@@ -36,16 +36,22 @@ class ReferencedContentTypesHandler {
36
36
  getReferencedContentTypes(schema) {
37
37
  const referencedTypes = new Set();
38
38
  const traverseSchema = (schemaArray) => {
39
- var _a, _b, _c, _d;
39
+ var _a, _b, _c, _d, _e;
40
40
  for (const field of schemaArray) {
41
41
  if (field.data_type === 'group' || field.data_type === 'global_field') {
42
- // Recursively traverse group and global field schemas
43
- traverseSchema(field.schema);
42
+ // Recursively traverse group and global field schemas.
43
+ // field.schema may be absent when a global_field is represented only by
44
+ // its reference_to UID (stub form in a content type's inline schema).
45
+ if (Array.isArray(field.schema) && field.schema.length > 0) {
46
+ traverseSchema(field.schema);
47
+ }
44
48
  }
45
49
  else if (field.data_type === 'blocks') {
46
50
  // Traverse each block's schema
47
51
  for (const blockKey in field.blocks) {
48
- traverseSchema(field.blocks[blockKey].schema);
52
+ if ((_a = field.blocks[blockKey]) === null || _a === void 0 ? void 0 : _a.schema) {
53
+ traverseSchema(field.blocks[blockKey].schema);
54
+ }
49
55
  }
50
56
  }
51
57
  else if (field.data_type === 'reference' && field.reference_to) {
@@ -60,8 +66,8 @@ class ReferencedContentTypesHandler {
60
66
  else if (
61
67
  // Handle JSON RTE with embedded entries
62
68
  field.data_type === 'json' &&
63
- ((_a = field.field_metadata) === null || _a === void 0 ? void 0 : _a.rich_text_type) &&
64
- ((_b = field.field_metadata) === null || _b === void 0 ? void 0 : _b.embed_entry) &&
69
+ ((_b = field.field_metadata) === null || _b === void 0 ? void 0 : _b.rich_text_type) &&
70
+ ((_c = field.field_metadata) === null || _c === void 0 ? void 0 : _c.embed_entry) &&
65
71
  field.reference_to) {
66
72
  field.reference_to.forEach((ref) => {
67
73
  if (ref !== 'sys_assets') {
@@ -72,8 +78,8 @@ class ReferencedContentTypesHandler {
72
78
  else if (
73
79
  // Handle Text RTE with embedded entries
74
80
  field.data_type === 'text' &&
75
- ((_c = field.field_metadata) === null || _c === void 0 ? void 0 : _c.rich_text_type) &&
76
- ((_d = field.field_metadata) === null || _d === void 0 ? void 0 : _d.embed_entry) &&
81
+ ((_d = field.field_metadata) === null || _d === void 0 ? void 0 : _d.rich_text_type) &&
82
+ ((_e = field.field_metadata) === null || _e === void 0 ? void 0 : _e.embed_entry) &&
77
83
  field.reference_to) {
78
84
  field.reference_to.forEach((ref) => {
79
85
  if (ref !== 'sys_assets') {
@@ -3,7 +3,16 @@ export declare class ContentTypeDependenciesHandler {
3
3
  private exportQueryConfig;
4
4
  private stackAPIClient;
5
5
  constructor(stackAPIClient: any, exportQueryConfig: QueryExportConfig);
6
- extractDependencies(): Promise<{
6
+ /**
7
+ * Extract all dependencies (global fields, extensions, taxonomies, marketplace apps) from the
8
+ * provided schema documents. When `schemas` is omitted the method falls back to reading content
9
+ * type schemas from disk — kept for backward compatibility with callers that do not supply
10
+ * already-loaded documents.
11
+ *
12
+ * Pass the combined set of content-type AND global-field documents so that transitive
13
+ * dependencies inside global fields are discovered in the same pass.
14
+ */
15
+ extractDependencies(schemas?: any[]): Promise<{
7
16
  globalFields: Set<string>;
8
17
  extensions: Set<string>;
9
18
  taxonomies: Set<string>;
@@ -3,18 +3,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ContentTypeDependenciesHandler = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const path = tslib_1.__importStar(require("path"));
6
- const index_1 = require("./index");
7
6
  const cli_utilities_1 = require("@contentstack/cli-utilities");
7
+ const read_content_type_schemas_1 = require("./read-content-type-schemas");
8
8
  class ContentTypeDependenciesHandler {
9
9
  constructor(stackAPIClient, exportQueryConfig) {
10
10
  this.exportQueryConfig = exportQueryConfig;
11
11
  this.stackAPIClient = stackAPIClient;
12
12
  }
13
- async extractDependencies() {
14
- const contentTypesFilePath = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'content_types', 'schema.json');
15
- const allContentTypes = index_1.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath)) || [];
16
- if (allContentTypes.length === 0) {
17
- cli_utilities_1.log.info('No content types found, skipping dependency extraction', this.exportQueryConfig.context);
13
+ /**
14
+ * Extract all dependencies (global fields, extensions, taxonomies, marketplace apps) from the
15
+ * provided schema documents. When `schemas` is omitted the method falls back to reading content
16
+ * type schemas from disk — kept for backward compatibility with callers that do not supply
17
+ * already-loaded documents.
18
+ *
19
+ * Pass the combined set of content-type AND global-field documents so that transitive
20
+ * dependencies inside global fields are discovered in the same pass.
21
+ */
22
+ async extractDependencies(schemas) {
23
+ let allSchemas;
24
+ if (schemas !== undefined) {
25
+ allSchemas = schemas;
26
+ }
27
+ else {
28
+ const contentTypesFilePath = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'content_types');
29
+ allSchemas = (0, read_content_type_schemas_1.readContentTypesFromExportDir)(contentTypesFilePath);
30
+ }
31
+ if (allSchemas.length === 0) {
32
+ cli_utilities_1.log.info('No schemas found, skipping dependency extraction', this.exportQueryConfig.context);
18
33
  return {
19
34
  globalFields: new Set(),
20
35
  extensions: new Set(),
@@ -22,16 +37,16 @@ class ContentTypeDependenciesHandler {
22
37
  marketplaceApps: new Set(),
23
38
  };
24
39
  }
25
- cli_utilities_1.log.info(`Extracting dependencies from ${allContentTypes.length} content types`, this.exportQueryConfig.context);
40
+ cli_utilities_1.log.info(`Extracting dependencies from ${allSchemas.length} schema(s)`, this.exportQueryConfig.context);
26
41
  const dependencies = {
27
42
  globalFields: new Set(),
28
43
  extensions: new Set(),
29
44
  taxonomies: new Set(),
30
45
  marketplaceApps: new Set(),
31
46
  };
32
- for (const contentType of allContentTypes) {
33
- if (contentType.schema) {
34
- this.traverseSchemaForDependencies(contentType.schema, dependencies);
47
+ for (const doc of allSchemas) {
48
+ if (doc.schema) {
49
+ this.traverseSchemaForDependencies(doc.schema, dependencies);
35
50
  }
36
51
  }
37
52
  // Separate extensions from marketplace apps using the extracted extension UIDs
@@ -109,7 +124,7 @@ class ContentTypeDependenciesHandler {
109
124
  });
110
125
  }
111
126
  // Recursive traversal for nested structures
112
- if (field.data_type === 'group' && field.schema) {
127
+ if ((field.data_type === 'group' || field.data_type === 'global_field') && field.schema) {
113
128
  this.traverseSchemaForDependencies(field.schema, dependencies);
114
129
  }
115
130
  if (field.data_type === 'blocks' && field.blocks) {
@@ -35,6 +35,7 @@ class QueryParser {
35
35
  }
36
36
  catch (error) {
37
37
  (0, cli_utilities_1.handleAndLogError)(error, this.config.context, 'Invalid JSON query');
38
+ throw new cli_utilities_1.CLIError('Invalid JSON query');
38
39
  }
39
40
  }
40
41
  validate(query) {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * CLI v1 aggregate content types under `content_types/schema.json`.
3
+ */
4
+ export declare function readContentTypesFromExportDir(dir: string): any[];
5
+ /**
6
+ * Global fields: prefer `global_fields/globalfields.json` (cm-export v1), then per-file / per-subfolder layouts.
7
+ */
8
+ export declare function readGlobalFieldSchemasFromDir(dir: string): any[];
9
+ /**
10
+ * Rebuild `content_types/schema.json` from every per–content-type `*.json` in the folder
11
+ * (excluding `schema.json` itself). Each `cm:stacks:export --module content-types` run
12
+ * overwrites `schema.json` with that run’s batch only; query-export runs that module
13
+ * multiple times, so without this merge the aggregate omits earlier types and the
14
+ * entries module (which only reads `schema.json`) skips their entries.
15
+ */
16
+ export declare function rebuildContentTypesSchemaJson(ctDir: string): void;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rebuildContentTypesSchemaJson = exports.readGlobalFieldSchemasFromDir = exports.readContentTypesFromExportDir = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs = tslib_1.__importStar(require("fs"));
6
+ const path = tslib_1.__importStar(require("path"));
7
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
8
+ const file_helper_1 = require("./file-helper");
9
+ function normalizeToArray(raw) {
10
+ if (raw == null)
11
+ return [];
12
+ if (Array.isArray(raw))
13
+ return raw;
14
+ if (typeof raw === 'object')
15
+ return Object.values(raw);
16
+ return [];
17
+ }
18
+ /**
19
+ * CLI v1 aggregate content types under `content_types/schema.json`.
20
+ */
21
+ function readContentTypesFromExportDir(dir) {
22
+ const schemaPath = path.join((0, cli_utilities_1.sanitizePath)(dir), 'schema.json');
23
+ try {
24
+ const raw = file_helper_1.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(schemaPath));
25
+ return normalizeToArray(raw);
26
+ }
27
+ catch (_a) {
28
+ return [];
29
+ }
30
+ }
31
+ exports.readContentTypesFromExportDir = readContentTypesFromExportDir;
32
+ function readGlobalFieldSchemasFromSubdirs(base) {
33
+ if (!fs.existsSync(base))
34
+ return [];
35
+ const out = [];
36
+ for (const name of fs.readdirSync(base)) {
37
+ if (name === 'globalfields.json' || name === 'schema.json')
38
+ continue;
39
+ const full = path.join(base, name);
40
+ let st;
41
+ try {
42
+ st = fs.statSync(full);
43
+ }
44
+ catch (_a) {
45
+ continue;
46
+ }
47
+ if (!st.isDirectory()) {
48
+ if (name.endsWith('.json')) {
49
+ try {
50
+ const doc = file_helper_1.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(full));
51
+ if (doc && typeof doc === 'object')
52
+ out.push(doc);
53
+ }
54
+ catch (_b) {
55
+ /* skip invalid */
56
+ }
57
+ }
58
+ continue;
59
+ }
60
+ const uid = name;
61
+ const candidates = [path.join(full, `${uid}.json`), path.join(full, 'index.json')];
62
+ let loaded = false;
63
+ for (const p of candidates) {
64
+ if (fs.existsSync(p)) {
65
+ try {
66
+ const doc = file_helper_1.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(p));
67
+ if (doc && typeof doc === 'object') {
68
+ out.push(doc);
69
+ loaded = true;
70
+ break;
71
+ }
72
+ }
73
+ catch (_c) {
74
+ /* try next */
75
+ }
76
+ }
77
+ }
78
+ if (loaded)
79
+ continue;
80
+ try {
81
+ for (const f of fs.readdirSync(full)) {
82
+ if (!f.endsWith('.json'))
83
+ continue;
84
+ const doc = file_helper_1.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(path.join(full, f)));
85
+ if (doc && typeof doc === 'object') {
86
+ out.push(doc);
87
+ break;
88
+ }
89
+ }
90
+ }
91
+ catch (_d) {
92
+ /* skip */
93
+ }
94
+ }
95
+ return out;
96
+ }
97
+ /**
98
+ * Global fields: prefer `global_fields/globalfields.json` (cm-export v1), then per-file / per-subfolder layouts.
99
+ */
100
+ function readGlobalFieldSchemasFromDir(dir) {
101
+ const base = (0, cli_utilities_1.sanitizePath)(dir);
102
+ const aggPath = path.join(base, 'globalfields.json');
103
+ if (fs.existsSync(aggPath)) {
104
+ try {
105
+ const raw = file_helper_1.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(aggPath));
106
+ const list = normalizeToArray(raw);
107
+ if (list.length > 0)
108
+ return list;
109
+ }
110
+ catch (_a) {
111
+ /* fall through to subdir scan */
112
+ }
113
+ }
114
+ return readGlobalFieldSchemasFromSubdirs(base);
115
+ }
116
+ exports.readGlobalFieldSchemasFromDir = readGlobalFieldSchemasFromDir;
117
+ /**
118
+ * Rebuild `content_types/schema.json` from every per–content-type `*.json` in the folder
119
+ * (excluding `schema.json` itself). Each `cm:stacks:export --module content-types` run
120
+ * overwrites `schema.json` with that run’s batch only; query-export runs that module
121
+ * multiple times, so without this merge the aggregate omits earlier types and the
122
+ * entries module (which only reads `schema.json`) skips their entries.
123
+ */
124
+ function rebuildContentTypesSchemaJson(ctDir) {
125
+ const dir = (0, cli_utilities_1.sanitizePath)(ctDir);
126
+ if (!fs.existsSync(dir))
127
+ return;
128
+ const byUid = new Map();
129
+ for (const name of fs.readdirSync(dir)) {
130
+ if (!name.endsWith('.json') || name === 'schema.json')
131
+ continue;
132
+ const fp = path.join(dir, name);
133
+ let st;
134
+ try {
135
+ st = fs.statSync(fp);
136
+ }
137
+ catch (_a) {
138
+ continue;
139
+ }
140
+ if (!st.isFile())
141
+ continue;
142
+ try {
143
+ const doc = file_helper_1.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(fp));
144
+ if (doc && typeof doc === 'object' && !Array.isArray(doc) && typeof doc.uid === 'string') {
145
+ byUid.set(doc.uid, doc);
146
+ }
147
+ }
148
+ catch (_b) {
149
+ /* skip invalid JSON */
150
+ }
151
+ }
152
+ const merged = Array.from(byUid.values());
153
+ if (merged.length === 0)
154
+ return;
155
+ const schemaPath = path.join(dir, 'schema.json');
156
+ file_helper_1.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(schemaPath), merged);
157
+ }
158
+ exports.rebuildContentTypesSchemaJson = rebuildContentTypesSchemaJson;
@@ -1 +1,75 @@
1
- {}
1
+ {
2
+ "ASSET_EXPORT_COMPLETE": "Asset export process completed successfully",
3
+ "ASSET_FOLDERS_EXPORT_COMPLETE": "Asset folder structure exported successfully",
4
+ "ASSET_METADATA_EXPORT_COMPLETE": "Asset metadata exported successfully",
5
+ "ASSET_VERSIONED_METADATA_EXPORT_COMPLETE": "Versioned asset metadata exported successfully",
6
+ "ASSET_DOWNLOAD_COMPLETE": "Asset download completed successfully",
7
+ "ASSET_DOWNLOAD_SUCCESS": "Asset '%s' (UID: %s) downloaded successfully",
8
+ "ASSET_DOWNLOAD_FAILED": "Failed to download asset '%s' (UID: %s)",
9
+ "ASSET_WRITE_FAILED": "Failed to write asset file '%s' (UID: %s)",
10
+ "ASSET_QUERY_FAILED": "Failed to query asset data from the API",
11
+ "ASSET_VERSIONED_QUERY_FAILED": "Failed to query versioned asset data from the API",
12
+ "ASSET_COUNT_QUERY_FAILED": "Failed to retrieve total asset count",
13
+
14
+ "CONTENT_TYPE_EXPORT_COMPLETE": "Content types exported successfully",
15
+ "CONTENT_TYPE_NO_TYPES": "No content types found",
16
+ "CONTENT_TYPE_EXPORT_FAILED": "Failed to export content types",
17
+ "CONTENT_TYPE_NO_TYPES_RETURNED": "API returned no content types for the given query",
18
+
19
+ "ENVIRONMENT_EXPORT_COMPLETE": "Successfully exported %s environment(s)",
20
+ "ENVIRONMENT_EXPORT_SUCCESS": "Environment '%s' exported successfully",
21
+ "ENVIRONMENT_NOT_FOUND": "No environments found in the current stack",
22
+
23
+ "EXTENSION_EXPORT_COMPLETE": "Successfully exported %s extension(s)",
24
+ "EXTENSION_EXPORT_SUCCESS": "Extension '%s' exported successfully",
25
+ "EXTENSION_NOT_FOUND": "No extensions found in the current stack",
26
+
27
+ "GLOBAL_FIELDS_EXPORT_COMPLETE": "Successfully exported %s global field(s)",
28
+
29
+ "LABELS_EXPORT_COMPLETE": "Successfully exported %s label(s)",
30
+ "LABEL_EXPORT_SUCCESS": "Label '%s' exported successfully",
31
+ "LABELS_NOT_FOUND": "No labels found in the current stack",
32
+
33
+ "LOCALES_EXPORT_COMPLETE": "Successfully exported %s locale(s) including %s master locale(s)",
34
+
35
+ "TAXONOMY_EXPORT_COMPLETE": "Successfully exported %s taxonomy entries",
36
+ "TAXONOMY_EXPORT_SUCCESS": "Taxonomy '%s' exported successfully",
37
+ "TAXONOMY_NOT_FOUND": "No taxonomies found in the current stack",
38
+
39
+ "WEBHOOK_EXPORT_COMPLETE": "Successfully exported %s webhook(s)",
40
+ "WEBHOOK_EXPORT_SUCCESS": "Webhook '%s' exported successfully",
41
+ "WEBHOOK_NOT_FOUND": "No webhooks found in the current stack",
42
+
43
+ "WORKFLOW_EXPORT_COMPLETE": "Successfully exported %s workflow(s)",
44
+ "WORKFLOW_EXPORT_SUCCESS": "Workflow '%s' exported successfully",
45
+ "WORKFLOW_NOT_FOUND": "No workflows found in the current stack",
46
+
47
+ "PERSONALIZE_URL_NOT_SET": "Cannot export Personalize project: URL not configured",
48
+ "PERSONALIZE_SKIPPING_WITH_MANAGEMENT_TOKEN": "Skipping Personalize project export: Management token not supported",
49
+ "PERSONALIZE_MODULE_NOT_IMPLEMENTED": "Module '%s' implementation not found",
50
+ "PERSONALIZE_NOT_ENABLED": "Personalize feature is not enabled for this organization",
51
+
52
+ "MARKETPLACE_APPS_EXPORT_COMPLETE": "Successfully exported %s marketplace app(s)",
53
+ "MARKETPLACE_APP_CONFIG_EXPORT": "Exporting configuration for app '%s'",
54
+ "MARKETPLACE_APP_CONFIG_SUCCESS": "Successfully exported configuration for app '%s'",
55
+ "MARKETPLACE_APP_EXPORT_SUCCESS": "Successfully exported app '%s'",
56
+ "MARKETPLACE_APPS_NOT_FOUND": "No marketplace apps found in the current stack",
57
+ "MARKETPLACE_APP_CONFIG_EXPORT_FAILED": "Failed to export configuration for app '%s'",
58
+ "MARKETPLACE_APP_MANIFEST_EXPORT_FAILED": "Failed to export manifest for app '%s'",
59
+
60
+ "COMPOSABLE_STUDIO_EXPORT_START": "Starting Studio project export...",
61
+ "COMPOSABLE_STUDIO_NOT_FOUND": "No Studio project found for this stack",
62
+ "COMPOSABLE_STUDIO_EXPORT_COMPLETE": "Successfully exported Studio project '%s'",
63
+ "COMPOSABLE_STUDIO_EXPORT_FAILED": "Failed to export Studio project: %s",
64
+ "COMPOSABLE_STUDIO_AUTH_REQUIRED": "To export Studio projects, you must be logged in",
65
+
66
+ "ENTRIES_EXPORT_COMPLETE": "Successfully exported entries (Content Type: %s, Locale: %s)",
67
+ "ENTRIES_EXPORT_SUCCESS": "All entries exported successfully",
68
+ "ENTRIES_VERSIONED_EXPORT_SUCCESS": "Successfully exported versioned entry (Content Type: %s, UID: %s, Locale: %s)",
69
+ "ENTRIES_EXPORT_VERSIONS_FAILED": "Failed to export versions for content type '%s' (UID: %s)",
70
+
71
+ "BRANCH_EXPORT_FAILED": "Failed to export contents from branch (UID: %s)",
72
+
73
+ "ROLES_NO_CUSTOM_ROLES": "No custom roles found in the current stack",
74
+ "ROLES_EXPORTING_ROLE": "Exporting role '%s'"
75
+ }
@@ -115,5 +115,5 @@
115
115
  ]
116
116
  }
117
117
  },
118
- "version": "1.0.0-beta.9"
118
+ "version": "1.0.1"
119
119
  }
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-export-query",
3
3
  "description": "Contentstack CLI plugin to export content from stack",
4
- "version": "1.0.0-beta.9",
4
+ "version": "1.0.1",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
- "@contentstack/cli-cm-export": "~1.23.2",
9
- "@contentstack/cli-command": "~1.7.2",
10
- "@contentstack/cli-utilities": "~1.17.4",
11
- "@oclif/core": "^4.3.0",
8
+ "@contentstack/cli-variants": "~1.5.0",
9
+ "@contentstack/cli-cm-export": "~1.25.0",
10
+ "@contentstack/cli-command": "~1.8.2",
11
+ "@contentstack/cli-utilities": "~1.18.3",
12
+ "@oclif/core": "^4.10.5",
12
13
  "async": "^3.2.6",
13
14
  "big-json": "^3.2.0",
14
15
  "bluebird": "^3.7.2",
15
- "chalk": "^4.1.2",
16
- "lodash": "^4.17.23",
16
+ "lodash": "^4.18.1",
17
17
  "merge": "^2.1.1",
18
18
  "mkdirp": "^1.0.4",
19
19
  "progress-stream": "^2.0.0",
@@ -21,22 +21,25 @@
21
21
  "tslib": "^2.8.1",
22
22
  "winston": "^3.19.0"
23
23
  },
24
+ "overrides": {
25
+ "brace-expansion": "^5.0.5"
26
+ },
24
27
  "devDependencies": {
25
28
  "@contentstack/cli-dev-dependencies": "~1.3.1",
26
- "@oclif/plugin-help": "^6.2.37",
27
- "@oclif/test": "^4.1.16",
29
+ "@oclif/plugin-help": "^6.2.44",
30
+ "@oclif/test": "^4.1.18",
28
31
  "@types/big-json": "^3.2.5",
29
32
  "@types/chai": "^4.3.20",
30
33
  "@types/mkdirp": "^1.0.2",
31
34
  "@types/mocha": "^10.0.10",
32
- "@types/node": "^20.19.37",
35
+ "@types/node": "^20.19.39",
33
36
  "@types/progress-stream": "^2.0.5",
34
37
  "@types/sinon": "^17.0.4",
35
38
  "chai": "^4.5.0",
36
39
  "dotenv": "^16.6.1",
37
40
  "dotenv-expand": "^9.0.0",
38
41
  "eslint": "^8.57.1",
39
- "eslint-config-oclif": "^6.0.148",
42
+ "eslint-config-oclif": "^6.0.157",
40
43
  "husky": "^9.1.7",
41
44
  "mocha": "10.8.2",
42
45
  "nyc": "^15.1.0",
@@ -46,19 +49,23 @@
46
49
  "typescript": "^4.9.5"
47
50
  },
48
51
  "scripts": {
49
- "build": "npm run clean && npm install && npm run compile && cp -r src/config lib/",
50
- "clean": "rm -rf ./lib ./node_modules tsconfig.build.tsbuildinfo",
52
+ "build": "pnpm compile && pnpm copy-config && oclif manifest && oclif readme",
53
+ "clean": "rm -rf ./lib ./node_modules tsconfig.tsbuildinfo",
51
54
  "compile": "tsc -b tsconfig.json",
52
55
  "postpack": "rm -f oclif.manifest.json",
53
- "prepack": "npm run compile && oclif manifest && oclif readme && cp -r src/config lib/",
56
+ "copy-config": "cp -r src/config lib/",
57
+ "prepack": "pnpm compile && pnpm copy-config && oclif manifest && oclif readme",
54
58
  "version": "oclif readme && git add README.md",
55
59
  "test:report": "tsc -p test && nyc --reporter=lcov --extension .ts mocha --forbid-only \"test/**/*.test.ts\"",
56
60
  "pretest": "tsc -p test",
57
61
  "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\"",
62
+ "posttest": "npm run lint",
58
63
  "lint": "eslint src/**/*.ts",
59
64
  "format": "eslint src/**/*.ts --fix",
65
+ "test:integration": "INTEGRATION_TEST=true mocha --config ./test/.mocharc.js --forbid-only \"test/run.test.js\"",
66
+ "test:integration:report": "INTEGRATION_TEST=true nyc --extension .js mocha --forbid-only \"test/run.test.js\"",
60
67
  "test:unit": "mocha --forbid-only \"test/unit/**/*.test.ts\"",
61
- "prepare": "npx husky && chmod +x .husky/pre-commit"
68
+ "test:unit:report": "nyc --reporter=text --extension .ts mocha --forbid-only \"test/unit/**/*.test.ts\""
62
69
  },
63
70
  "engines": {
64
71
  "node": ">=14.0.0"
@@ -92,4 +99,4 @@
92
99
  }
93
100
  },
94
101
  "repository": "https://github.com/contentstack/cli"
95
- }
102
+ }