@contentstack/cli-cm-export-query 1.0.0-beta.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.
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueryExporter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
6
+ const path = tslib_1.__importStar(require("path"));
7
+ const query_parser_1 = require("../utils/query-parser");
8
+ const module_exporter_1 = require("./module-exporter");
9
+ const logger_1 = require("../utils/logger");
10
+ const utils_1 = require("../utils");
11
+ const utils_2 = require("../utils");
12
+ const utils_3 = require("../utils");
13
+ const utils_4 = require("../utils");
14
+ class QueryExporter {
15
+ constructor(managementAPIClient, exportQueryConfig) {
16
+ this.exportQueryConfig = exportQueryConfig;
17
+ this.stackAPIClient = managementAPIClient.stack({
18
+ api_key: exportQueryConfig.stackApiKey,
19
+ management_token: exportQueryConfig.managementToken,
20
+ });
21
+ // Initialize components
22
+ this.queryParser = new query_parser_1.QueryParser(this.exportQueryConfig);
23
+ this.moduleExporter = new module_exporter_1.ModuleExporter(exportQueryConfig);
24
+ }
25
+ async execute() {
26
+ (0, logger_1.log)(this.exportQueryConfig, 'Starting query-based export...', 'info');
27
+ // Step 1: Parse and validate query
28
+ const parsedQuery = await this.queryParser.parse(this.exportQueryConfig.query);
29
+ (0, logger_1.log)(this.exportQueryConfig, 'Query parsed and validated successfully', 'success');
30
+ // Step 2: Always export general modules
31
+ await this.exportGeneralModules();
32
+ // Step 4: Export queried modules
33
+ 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
+ (0, logger_1.log)(this.exportQueryConfig, 'No content types found, skipping export', 'info');
39
+ process.exit(0);
40
+ }
41
+ // Step 5: export other content types which are referenced in previous step
42
+ await this.exportReferencedContentTypes();
43
+ // Step 6: export dependent modules global fields, extensions, taxonomies
44
+ await this.exportDependentModules();
45
+ // Step 7: export content modules entries, assets
46
+ await this.exportContentModules();
47
+ // Step 9: export all other modules
48
+ (0, logger_1.log)(this.exportQueryConfig, 'Query-based export completed successfully!', 'success');
49
+ }
50
+ // export general modules
51
+ async exportGeneralModules() {
52
+ (0, logger_1.log)(this.exportQueryConfig, 'Exporting general modules...', 'info');
53
+ for (const module of this.exportQueryConfig.modules.general) {
54
+ await this.moduleExporter.exportModule(module);
55
+ }
56
+ }
57
+ async exportQueriedModule(parsedQuery) {
58
+ for (const [moduleName] of Object.entries(parsedQuery.modules)) {
59
+ const module = moduleName;
60
+ if (!this.exportQueryConfig.modules.queryable.includes(module)) {
61
+ (0, logger_1.log)(this.exportQueryConfig, `Module "${module}" is not queryable`, 'error');
62
+ continue;
63
+ }
64
+ (0, logger_1.log)(this.exportQueryConfig, `Exporting ${moduleName} with query...`, 'info');
65
+ // Export the queried module
66
+ await this.moduleExporter.exportModule(module, { query: parsedQuery });
67
+ }
68
+ }
69
+ async exportReferencedContentTypes() {
70
+ (0, logger_1.log)(this.exportQueryConfig, 'Starting export of referenced content types...', 'info');
71
+ try {
72
+ const referencedHandler = new utils_1.ReferencedContentTypesHandler(this.exportQueryConfig);
73
+ const exportedContentTypeUIDs = new Set();
74
+ // Step 1: Read initial content types and mark them as exported
75
+ const contentTypesFilePath = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'content_types', 'schema.json');
76
+ const contentTypes = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath)) || [];
77
+ if (contentTypes.length === 0) {
78
+ (0, logger_1.log)(this.exportQueryConfig, 'No content types found, skipping referenced content types export', 'info');
79
+ return;
80
+ }
81
+ // Step 2: Start with initial batch (all currently exported content types)
82
+ let currentBatch = [...contentTypes];
83
+ (0, logger_1.log)(this.exportQueryConfig, `Starting with ${currentBatch.length} initial content types`, 'info');
84
+ // track reference depth
85
+ let iterationCount = 0;
86
+ // Step 3: Process batches until no new references are found
87
+ while (currentBatch.length > 0 && iterationCount < this.exportQueryConfig.maxCTReferenceDepth) {
88
+ iterationCount++;
89
+ currentBatch.forEach((ct) => exportedContentTypeUIDs.add(ct.uid));
90
+ // Extract referenced content types from current batch
91
+ const referencedUIDs = await referencedHandler.extractReferencedContentTypes(currentBatch);
92
+ // Filter out already exported content types
93
+ const newReferencedUIDs = referencedUIDs.filter((uid) => !exportedContentTypeUIDs.has(uid));
94
+ if (newReferencedUIDs.length > 0) {
95
+ (0, logger_1.log)(this.exportQueryConfig, `Found ${newReferencedUIDs.length} new referenced content types to fetch`, 'info');
96
+ // // Add to exported set to avoid duplicates in future iterations
97
+ // newReferencedUIDs.forEach((uid) => exportedContentTypeUIDs.add(uid));
98
+ // Step 4: Fetch new content types using moduleExporter
99
+ const query = {
100
+ modules: {
101
+ 'content-types': {
102
+ uid: {
103
+ $in: newReferencedUIDs,
104
+ },
105
+ },
106
+ },
107
+ };
108
+ await this.moduleExporter.exportModule('content-types', { query });
109
+ const newContentTypes = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath));
110
+ currentBatch = [...newContentTypes];
111
+ // Push new content types to main array
112
+ contentTypes.push(...newContentTypes);
113
+ (0, logger_1.log)(this.exportQueryConfig, `Fetched ${currentBatch.length} new content types for next iteration`, 'info');
114
+ }
115
+ else {
116
+ (0, logger_1.log)(this.exportQueryConfig, 'No new referenced content types found, stopping recursion', 'info');
117
+ break;
118
+ }
119
+ }
120
+ utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(contentTypesFilePath), contentTypes);
121
+ (0, logger_1.log)(this.exportQueryConfig, 'Referenced content types export completed successfully', 'success');
122
+ }
123
+ catch (error) {
124
+ (0, logger_1.log)(this.exportQueryConfig, `Error exporting referenced content types: ${error.message}`, 'error');
125
+ throw error;
126
+ }
127
+ }
128
+ async exportDependentModules() {
129
+ (0, logger_1.log)(this.exportQueryConfig, 'Starting export of dependent modules...', 'info');
130
+ try {
131
+ const dependenciesHandler = new utils_3.ContentTypeDependenciesHandler(this.stackAPIClient, this.exportQueryConfig);
132
+ // Extract dependencies from all exported content types
133
+ const dependencies = await dependenciesHandler.extractDependencies();
134
+ // Export Global Fields
135
+ if (dependencies.globalFields.size > 0) {
136
+ const globalFieldUIDs = Array.from(dependencies.globalFields);
137
+ (0, logger_1.log)(this.exportQueryConfig, `Exporting ${globalFieldUIDs.length} global fields...`, 'info');
138
+ const query = {
139
+ modules: {
140
+ 'global-fields': {
141
+ uid: { $in: globalFieldUIDs },
142
+ },
143
+ },
144
+ };
145
+ await this.moduleExporter.exportModule('global-fields', { query });
146
+ }
147
+ // Export Extensions
148
+ if (dependencies.extensions.size > 0) {
149
+ const extensionUIDs = Array.from(dependencies.extensions);
150
+ (0, logger_1.log)(this.exportQueryConfig, `Exporting ${extensionUIDs.length} extensions...`, 'info');
151
+ const query = {
152
+ modules: {
153
+ extensions: {
154
+ uid: { $in: extensionUIDs },
155
+ },
156
+ },
157
+ };
158
+ await this.moduleExporter.exportModule('extensions', { query });
159
+ }
160
+ // export marketplace apps
161
+ if (dependencies.marketplaceApps.size > 0) {
162
+ const marketplaceAppInstallationUIDs = Array.from(dependencies.marketplaceApps);
163
+ (0, logger_1.log)(this.exportQueryConfig, `Exporting ${marketplaceAppInstallationUIDs.length} marketplace apps...`, 'info');
164
+ const query = {
165
+ modules: {
166
+ 'marketplace-apps': {
167
+ installation_uid: { $in: marketplaceAppInstallationUIDs },
168
+ },
169
+ },
170
+ };
171
+ await this.moduleExporter.exportModule('marketplace-apps', { query });
172
+ }
173
+ // Export Taxonomies
174
+ if (dependencies.taxonomies.size > 0) {
175
+ const taxonomyUIDs = Array.from(dependencies.taxonomies);
176
+ (0, logger_1.log)(this.exportQueryConfig, `Exporting ${taxonomyUIDs.length} taxonomies...`, 'info');
177
+ const query = {
178
+ modules: {
179
+ taxonomies: {
180
+ uid: { $in: taxonomyUIDs },
181
+ },
182
+ },
183
+ };
184
+ await this.moduleExporter.exportModule('taxonomies', { query });
185
+ }
186
+ // export personalize
187
+ await this.moduleExporter.exportModule('personalize');
188
+ (0, logger_1.log)(this.exportQueryConfig, 'Dependent modules export completed successfully', 'success');
189
+ }
190
+ catch (error) {
191
+ (0, logger_1.log)(this.exportQueryConfig, `Error exporting dependent modules: ${error.message}`, 'error');
192
+ throw error;
193
+ }
194
+ }
195
+ async exportContentModules() {
196
+ (0, logger_1.log)(this.exportQueryConfig, 'Starting export of content modules...', 'info');
197
+ try {
198
+ // Step 1: Export entries for all exported content types
199
+ await this.exportEntries();
200
+ // Step 2: Export referenced assets from entries
201
+ // add a delay of 5 seconds
202
+ const delay = this.exportQueryConfig.exportDelayMs || 5000;
203
+ await new Promise((resolve) => setTimeout(resolve, delay));
204
+ await this.exportReferencedAssets();
205
+ (0, logger_1.log)(this.exportQueryConfig, 'Content modules export completed successfully', 'success');
206
+ }
207
+ catch (error) {
208
+ (0, logger_1.log)(this.exportQueryConfig, `Error exporting content modules: ${error.message}`, 'error');
209
+ throw error;
210
+ }
211
+ }
212
+ async exportEntries() {
213
+ (0, logger_1.log)(this.exportQueryConfig, 'Exporting entries...', 'info');
214
+ try {
215
+ // Export entries - module exporter will automatically read exported content types
216
+ // and export entries for all of them
217
+ await this.moduleExporter.exportModule('entries');
218
+ (0, logger_1.log)(this.exportQueryConfig, 'Entries export completed successfully', 'success');
219
+ }
220
+ catch (error) {
221
+ (0, logger_1.log)(this.exportQueryConfig, `Error exporting entries: ${error.message}`, 'error');
222
+ throw error;
223
+ }
224
+ }
225
+ async exportReferencedAssets() {
226
+ (0, logger_1.log)(this.exportQueryConfig, 'Starting export of referenced assets...', 'info');
227
+ try {
228
+ const assetHandler = new utils_4.AssetReferenceHandler(this.exportQueryConfig);
229
+ // Extract referenced asset UIDs from all entries
230
+ const assetUIDs = assetHandler.extractReferencedAssets();
231
+ if (assetUIDs.length > 0) {
232
+ (0, logger_1.log)(this.exportQueryConfig, `Exporting ${assetUIDs.length} referenced assets...`, 'info');
233
+ const query = {
234
+ modules: {
235
+ assets: {
236
+ uid: { $in: assetUIDs },
237
+ },
238
+ },
239
+ };
240
+ await this.moduleExporter.exportModule('assets', { query });
241
+ (0, logger_1.log)(this.exportQueryConfig, 'Referenced assets exported successfully', 'success');
242
+ }
243
+ else {
244
+ (0, logger_1.log)(this.exportQueryConfig, 'No referenced assets found in entries', 'info');
245
+ }
246
+ }
247
+ catch (error) {
248
+ (0, logger_1.log)(this.exportQueryConfig, `Error exporting referenced assets: ${error.message}`, 'error');
249
+ throw error;
250
+ }
251
+ }
252
+ }
253
+ exports.QueryExporter = QueryExporter;
@@ -0,0 +1,161 @@
1
+ export interface AuthOptions {
2
+ contentstackClient: any;
3
+ }
4
+ export interface ContentStackManagementClient {
5
+ contentstackClient: object;
6
+ }
7
+ export interface PrintOptions {
8
+ color?: string;
9
+ }
10
+ export interface InquirePayload {
11
+ type: string;
12
+ name: string;
13
+ message: string;
14
+ choices?: Array<any>;
15
+ transformer?: Function;
16
+ }
17
+ export interface User {
18
+ email: string;
19
+ authtoken: string;
20
+ }
21
+ export interface Region {
22
+ name: string;
23
+ cma: string;
24
+ cda: string;
25
+ uiHost: string;
26
+ }
27
+ export type Modules = 'stack' | 'locales' | 'environments' | 'content-types' | 'global-fields' | 'extensions' | 'taxonomies' | 'entries' | 'assets' | 'webhooks' | 'workflows' | 'custom-roles' | 'labels' | 'marketplace-apps' | 'personalize';
28
+ export interface ModuleQueryConfig {
29
+ supportedFields: string[];
30
+ supportedOperators: string[];
31
+ defaultLimit: number;
32
+ includeGlobalFieldSchema?: boolean;
33
+ includePublishDetails?: boolean;
34
+ includeDimension?: boolean;
35
+ }
36
+ export interface DependencyAnalysisConfig {
37
+ enabled: boolean;
38
+ fields?: string[];
39
+ extractors?: string[];
40
+ }
41
+ export interface ModuleDefinition {
42
+ dirName: string;
43
+ fileName: string;
44
+ apiEndpoint: string;
45
+ queryable: boolean;
46
+ dependencies: Modules[];
47
+ queryConfig?: ModuleQueryConfig;
48
+ dependencyAnalysis?: DependencyAnalysisConfig;
49
+ limit?: number;
50
+ batchLimit?: number;
51
+ }
52
+ export interface DependencyExtractor {
53
+ fieldType: string;
54
+ extract: (data: any) => string[];
55
+ targetModule: Modules;
56
+ }
57
+ export interface ExportOptions {
58
+ query?: any;
59
+ alias?: string;
60
+ directory?: string;
61
+ branch?: string;
62
+ skipReferences?: boolean;
63
+ skipDependencies?: boolean;
64
+ securedAssets?: boolean;
65
+ includeGlobalFieldSchema?: boolean;
66
+ includePublishDetails?: boolean;
67
+ includeDimension?: boolean;
68
+ contentTypes?: string[];
69
+ uids?: string[];
70
+ configPath?: string;
71
+ fetchConcurrency?: number;
72
+ writeConcurrency?: number;
73
+ batchSize?: number;
74
+ [key: string]: any;
75
+ }
76
+ export interface DefaultConfig {
77
+ contentVersion: number;
78
+ host: string;
79
+ exportDir?: string;
80
+ stackApiKey?: string;
81
+ managementToken?: string;
82
+ region?: Region;
83
+ branchName?: string;
84
+ securedAssets?: boolean;
85
+ query?: string;
86
+ queryInput?: string;
87
+ skipReferences?: boolean;
88
+ skipDependencies?: boolean;
89
+ isQueryBasedExport?: boolean;
90
+ modules: {
91
+ general: Modules[];
92
+ queryable: Modules[];
93
+ dependent: Modules[];
94
+ content: Modules[];
95
+ exportOrder: Modules[];
96
+ definitions?: Record<Modules, ModuleDefinition>;
97
+ };
98
+ queryConfig: {
99
+ maxRecursionDepth?: number;
100
+ batchSize?: number;
101
+ metadataFileName?: string;
102
+ validation: {
103
+ maxQueryDepth?: number;
104
+ maxArraySize?: number;
105
+ allowedDateFormats?: string[];
106
+ };
107
+ };
108
+ dependencyExtractors?: Record<string, DependencyExtractor>;
109
+ fetchConcurrency: number;
110
+ writeConcurrency: number;
111
+ developerHubBaseUrl?: string;
112
+ branches?: Array<{
113
+ uid: string;
114
+ source: string;
115
+ }>;
116
+ branchEnabled?: boolean;
117
+ branchDir?: string;
118
+ apis: {
119
+ stacks: string;
120
+ locales: string;
121
+ environments: string;
122
+ content_types: string;
123
+ global_fields: string;
124
+ extensions: string;
125
+ taxonomies: string;
126
+ entries: string;
127
+ assets: string;
128
+ };
129
+ externalConfigPath?: string;
130
+ maxCTReferenceDepth: number;
131
+ }
132
+ export interface QueryExportConfig extends DefaultConfig {
133
+ query: string;
134
+ skipReferences: boolean;
135
+ skipDependencies: boolean;
136
+ stackApiKey: string;
137
+ managementToken?: string;
138
+ branchName: string;
139
+ securedAssets: boolean;
140
+ logsPath: string;
141
+ dataPath: string;
142
+ exportDelayMs?: number;
143
+ }
144
+ export interface QueryMetadata {
145
+ query: any;
146
+ flags: {
147
+ skipReferences: boolean;
148
+ skipDependencies: boolean;
149
+ };
150
+ timestamp: string;
151
+ cliVersion: string;
152
+ exportedModules: string[];
153
+ contentTypes: Array<{
154
+ uid: string;
155
+ title: string;
156
+ }>;
157
+ summary: {
158
+ totalContentTypes: number;
159
+ totalModules: number;
160
+ };
161
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export declare const askAPIKey: () => Promise<string>;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.askAPIKey = void 0;
4
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
5
+ const askAPIKey = async () => {
6
+ return await cli_utilities_1.cliux.inquire({
7
+ type: 'input',
8
+ message: 'Enter the stack api key',
9
+ name: 'apiKey',
10
+ });
11
+ };
12
+ exports.askAPIKey = askAPIKey;
@@ -0,0 +1,2 @@
1
+ import { QueryExportConfig } from '../types';
2
+ export declare function setupQueryExportConfig(flags: any): Promise<QueryExportConfig>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupQueryExportConfig = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
7
+ const config_1 = tslib_1.__importDefault(require("../config"));
8
+ const common_helper_1 = require("./common-helper");
9
+ async function setupQueryExportConfig(flags) {
10
+ var _a;
11
+ const exportDir = (0, cli_utilities_1.sanitizePath)(flags['data-dir'] || (0, cli_utilities_1.pathValidator)('export'));
12
+ const exportQueryConfig = Object.assign(Object.assign({}, config_1.default), { exportDir, stackApiKey: flags['stack-api-key'] || '', managementToken: flags.alias ? (_a = cli_utilities_1.configHandler.get(`tokens.${flags.alias}`)) === null || _a === void 0 ? void 0 : _a.token : undefined, query: flags.query, skipReferences: flags['skip-references'] || false, skipDependencies: flags['skip-dependencies'] || false, branchName: flags.branch, securedAssets: flags['secured-assets'] || false, isQueryBasedExport: true, logsPath: exportDir, dataPath: exportDir,
13
+ // Todo: accept the path of the config file from the user
14
+ externalConfigPath: path.join(__dirname, '../config/export-config.json') });
15
+ // Handle authentication
16
+ if (flags.alias) {
17
+ const { token, apiKey } = cli_utilities_1.configHandler.get(`tokens.${flags.alias}`) || {};
18
+ config_1.default.managementToken = token;
19
+ config_1.default.stackApiKey = apiKey;
20
+ if (!config_1.default.managementToken) {
21
+ throw new Error(`No management token found on given alias ${flags.alias}`);
22
+ }
23
+ }
24
+ if (!config_1.default.managementToken) {
25
+ if (!(0, cli_utilities_1.isAuthenticated)()) {
26
+ throw new Error('Please login or provide an alias for the management token');
27
+ }
28
+ else {
29
+ config_1.default.stackApiKey = flags['stack-api-key'] || (await (0, common_helper_1.askAPIKey)());
30
+ if (typeof config_1.default.stackApiKey !== 'string') {
31
+ throw new Error('Invalid API key received');
32
+ }
33
+ }
34
+ }
35
+ return exportQueryConfig;
36
+ }
37
+ exports.setupQueryExportConfig = setupQueryExportConfig;
@@ -0,0 +1,19 @@
1
+ import { QueryExportConfig } from '../types';
2
+ export declare class ReferencedContentTypesHandler {
3
+ private exportQueryConfig;
4
+ constructor(exportQueryConfig: QueryExportConfig);
5
+ /**
6
+ * Extract referenced content types from a batch of content types
7
+ * This method only processes the given batch, doesn't orchestrate the entire process
8
+ */
9
+ extractReferencedContentTypes(contentTypeBatch: any[]): Promise<string[]>;
10
+ /**
11
+ * Filter content types to get only newly fetched ones based on UIDs
12
+ */
13
+ filterNewlyFetchedContentTypes(allContentTypes: any[], previousUIDs: Set<string>): any[];
14
+ /**
15
+ * Extract referenced content types from a content type schema
16
+ * Moved from content-type-helper.ts for better encapsulation
17
+ */
18
+ private getReferencedContentTypes;
19
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReferencedContentTypesHandler = void 0;
4
+ const logger_1 = require("./logger");
5
+ class ReferencedContentTypesHandler {
6
+ constructor(exportQueryConfig) {
7
+ this.exportQueryConfig = exportQueryConfig;
8
+ }
9
+ /**
10
+ * Extract referenced content types from a batch of content types
11
+ * This method only processes the given batch, doesn't orchestrate the entire process
12
+ */
13
+ async extractReferencedContentTypes(contentTypeBatch) {
14
+ const allReferencedTypes = new Set();
15
+ (0, logger_1.log)(this.exportQueryConfig, `Extracting references from ${contentTypeBatch.length} content types`, 'info');
16
+ for (const contentType of contentTypeBatch) {
17
+ if (contentType.schema) {
18
+ const referencedTypes = this.getReferencedContentTypes(contentType.schema);
19
+ referencedTypes.forEach((type) => allReferencedTypes.add(type));
20
+ }
21
+ }
22
+ const result = Array.from(allReferencedTypes);
23
+ (0, logger_1.log)(this.exportQueryConfig, `Found ${result.length} referenced content types`, 'info');
24
+ return result;
25
+ }
26
+ /**
27
+ * Filter content types to get only newly fetched ones based on UIDs
28
+ */
29
+ filterNewlyFetchedContentTypes(allContentTypes, previousUIDs) {
30
+ return allContentTypes.filter((ct) => !previousUIDs.has(ct.uid));
31
+ }
32
+ /**
33
+ * Extract referenced content types from a content type schema
34
+ * Moved from content-type-helper.ts for better encapsulation
35
+ */
36
+ getReferencedContentTypes(schema) {
37
+ const referencedTypes = new Set();
38
+ const traverseSchema = (schemaArray) => {
39
+ var _a, _b, _c, _d;
40
+ for (const field of schemaArray) {
41
+ if (field.data_type === 'group' || field.data_type === 'global_field') {
42
+ // Recursively traverse group and global field schemas
43
+ traverseSchema(field.schema);
44
+ }
45
+ else if (field.data_type === 'blocks') {
46
+ // Traverse each block's schema
47
+ for (const blockKey in field.blocks) {
48
+ traverseSchema(field.blocks[blockKey].schema);
49
+ }
50
+ }
51
+ else if (field.data_type === 'reference' && field.reference_to) {
52
+ // Add reference field targets
53
+ field.reference_to.forEach((ref) => {
54
+ if (ref !== 'sys_assets') {
55
+ // Exclude system assets
56
+ referencedTypes.add(ref);
57
+ }
58
+ });
59
+ }
60
+ else if (
61
+ // Handle JSON RTE with embedded entries
62
+ 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) &&
65
+ field.reference_to) {
66
+ field.reference_to.forEach((ref) => {
67
+ if (ref !== 'sys_assets') {
68
+ referencedTypes.add(ref);
69
+ }
70
+ });
71
+ }
72
+ else if (
73
+ // Handle Text RTE with embedded entries
74
+ 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) &&
77
+ field.reference_to) {
78
+ field.reference_to.forEach((ref) => {
79
+ if (ref !== 'sys_assets') {
80
+ referencedTypes.add(ref);
81
+ }
82
+ });
83
+ }
84
+ }
85
+ };
86
+ traverseSchema(schema);
87
+ return Array.from(referencedTypes);
88
+ }
89
+ }
90
+ exports.ReferencedContentTypesHandler = ReferencedContentTypesHandler;
@@ -0,0 +1,17 @@
1
+ import { QueryExportConfig } from '../types';
2
+ export declare class ContentTypeDependenciesHandler {
3
+ private exportQueryConfig;
4
+ private stackAPIClient;
5
+ constructor(stackAPIClient: any, exportQueryConfig: QueryExportConfig);
6
+ extractDependencies(): Promise<{
7
+ globalFields: Set<string>;
8
+ extensions: Set<string>;
9
+ taxonomies: Set<string>;
10
+ marketplaceApps: Set<string>;
11
+ }>;
12
+ fetchExtensionsAndMarketplaceApps(extensionUIDs: string[]): Promise<{
13
+ extensions: string[];
14
+ marketplaceApps: string[];
15
+ }>;
16
+ private traverseSchemaForDependencies;
17
+ }