@teleporthq/teleport-plugin-next-data-source 0.42.5 → 0.42.6

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 (35) hide show
  1. package/dist/cjs/array-mapper-pagination.d.ts +5 -0
  2. package/dist/cjs/array-mapper-pagination.d.ts.map +1 -1
  3. package/dist/cjs/array-mapper-pagination.js.map +1 -1
  4. package/dist/cjs/array-mapper-registry.d.ts +84 -0
  5. package/dist/cjs/array-mapper-registry.d.ts.map +1 -0
  6. package/dist/cjs/array-mapper-registry.js +291 -0
  7. package/dist/cjs/array-mapper-registry.js.map +1 -0
  8. package/dist/cjs/index.d.ts.map +1 -1
  9. package/dist/cjs/index.js +36 -14
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/pagination-plugin.d.ts +1 -3
  12. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  13. package/dist/cjs/pagination-plugin.js +895 -1405
  14. package/dist/cjs/pagination-plugin.js.map +1 -1
  15. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  16. package/dist/esm/array-mapper-pagination.d.ts +5 -0
  17. package/dist/esm/array-mapper-pagination.d.ts.map +1 -1
  18. package/dist/esm/array-mapper-pagination.js.map +1 -1
  19. package/dist/esm/array-mapper-registry.d.ts +84 -0
  20. package/dist/esm/array-mapper-registry.d.ts.map +1 -0
  21. package/dist/esm/array-mapper-registry.js +287 -0
  22. package/dist/esm/array-mapper-registry.js.map +1 -0
  23. package/dist/esm/index.d.ts.map +1 -1
  24. package/dist/esm/index.js +36 -14
  25. package/dist/esm/index.js.map +1 -1
  26. package/dist/esm/pagination-plugin.d.ts +1 -3
  27. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  28. package/dist/esm/pagination-plugin.js +896 -1406
  29. package/dist/esm/pagination-plugin.js.map +1 -1
  30. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +2 -2
  32. package/src/array-mapper-pagination.ts +5 -0
  33. package/src/array-mapper-registry.ts +408 -0
  34. package/src/index.ts +24 -1
  35. package/src/pagination-plugin.ts +1846 -2201
@@ -58,26 +58,167 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
58
58
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
59
59
  }
60
60
  };
61
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
62
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
63
- if (ar || !(i in from)) {
64
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
65
- ar[i] = from[i];
66
- }
67
- }
68
- return to.concat(ar || Array.prototype.slice.call(from));
69
- };
70
61
  Object.defineProperty(exports, "__esModule", { value: true });
71
62
  exports.createNextArrayMapperPaginationPlugin = void 0;
72
63
  var teleport_types_1 = require("@teleporthq/teleport-types");
73
64
  var types = __importStar(require("@babel/types"));
74
- var array_mapper_pagination_1 = require("./array-mapper-pagination");
65
+ var teleport_shared_1 = require("@teleporthq/teleport-shared");
75
66
  var utils_1 = require("./utils");
67
+ // Scan UIDL to find all data source usages and build a registry
68
+ function buildStateRegistry(uidlNode) {
69
+ var usages = [];
70
+ var byDataSourceId = new Map();
71
+ var byArrayMapperRenderProp = new Map();
72
+ var index = 0;
73
+ var traverse = function (node, parentDataSource) {
74
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
75
+ if (!node || typeof node !== 'object') {
76
+ return;
77
+ }
78
+ // Found a data-source-list (DataProvider)
79
+ if (node.type === 'data-source-list' && ((_a = node.content) === null || _a === void 0 ? void 0 : _a.renderPropIdentifier)) {
80
+ var dsIdentifier = node.content.renderPropIdentifier;
81
+ var resourceDef = node.content.resourceDefinition || {};
82
+ var resourceParams = ((_b = node.content.resource) === null || _b === void 0 ? void 0 : _b.params) || {};
83
+ // Look for cms-list-repeater inside this data-source-list
84
+ var newParent = {
85
+ identifier: dsIdentifier,
86
+ resourceDef: resourceDef,
87
+ resourceParams: resourceParams,
88
+ };
89
+ // Traverse into success/error/loading nodes
90
+ if ((_c = node.content.nodes) === null || _c === void 0 ? void 0 : _c.success) {
91
+ traverse(node.content.nodes.success, newParent);
92
+ }
93
+ if ((_d = node.content.nodes) === null || _d === void 0 ? void 0 : _d.error) {
94
+ traverse(node.content.nodes.error, newParent);
95
+ }
96
+ if ((_e = node.content.nodes) === null || _e === void 0 ? void 0 : _e.loading) {
97
+ traverse(node.content.nodes.loading, newParent);
98
+ }
99
+ return;
100
+ }
101
+ // Found a cms-list-repeater (Repeater with pagination/search config)
102
+ var isCmsListRepeater = node.type === 'cms-list-repeater' ||
103
+ (node.type === 'element' && ((_f = node.content) === null || _f === void 0 ? void 0 : _f.elementType) === 'cms-list-repeater');
104
+ if (isCmsListRepeater && parentDataSource) {
105
+ var content = node.content || node;
106
+ var arrayMapperRenderProp = content.renderPropIdentifier;
107
+ if (arrayMapperRenderProp) {
108
+ // Extract query columns from parent's resource params
109
+ var queryColumns = [];
110
+ if ((_h = (_g = parentDataSource.resourceParams) === null || _g === void 0 ? void 0 : _g.queryColumns) === null || _h === void 0 ? void 0 : _h.content) {
111
+ queryColumns = parentDataSource.resourceParams.queryColumns.content;
112
+ }
113
+ // Extract limit from parent's resource params (for plain array mappers)
114
+ var limit = 0;
115
+ if ((_k = (_j = parentDataSource.resourceParams) === null || _j === void 0 ? void 0 : _j.limit) === null || _k === void 0 ? void 0 : _k.content) {
116
+ limit = parentDataSource.resourceParams.limit.content;
117
+ }
118
+ // For paginated mappers, use perPage from cms-list-repeater
119
+ // For plain mappers, use limit from data-source-list resource params
120
+ var effectivePerPage = content.paginated ? content.perPage : limit || content.perPage;
121
+ var usage = {
122
+ index: index++,
123
+ dataSourceIdentifier: parentDataSource.identifier,
124
+ arrayMapperRenderProp: arrayMapperRenderProp,
125
+ resourceDefinition: {
126
+ dataSourceId: parentDataSource.resourceDef.dataSourceId || '',
127
+ tableName: parentDataSource.resourceDef.tableName || '',
128
+ dataSourceType: parentDataSource.resourceDef.dataSourceType || '',
129
+ },
130
+ paginated: !!content.paginated,
131
+ perPage: effectivePerPage,
132
+ searchEnabled: !!content.searchEnabled,
133
+ searchDebounce: content.searchDebounce || 300,
134
+ queryColumns: queryColumns,
135
+ category: 'plain',
136
+ };
137
+ // Determine category
138
+ if (usage.paginated && usage.searchEnabled) {
139
+ usage.category = 'paginated+search';
140
+ }
141
+ else if (usage.paginated) {
142
+ usage.category = 'paginated-only';
143
+ }
144
+ else if (usage.searchEnabled) {
145
+ usage.category = 'search-only';
146
+ }
147
+ usages.push(usage);
148
+ // Add to maps
149
+ if (!byDataSourceId.has(usage.dataSourceIdentifier)) {
150
+ byDataSourceId.set(usage.dataSourceIdentifier, []);
151
+ }
152
+ byDataSourceId.get(usage.dataSourceIdentifier).push(usage);
153
+ byArrayMapperRenderProp.set(arrayMapperRenderProp, usage);
154
+ }
155
+ // Continue traversing inside the repeater
156
+ if ((_l = content.nodes) === null || _l === void 0 ? void 0 : _l.list) {
157
+ traverse(content.nodes.list, parentDataSource);
158
+ }
159
+ return;
160
+ }
161
+ // Recurse into children
162
+ if (((_m = node.content) === null || _m === void 0 ? void 0 : _m.children) && Array.isArray(node.content.children)) {
163
+ for (var _i = 0, _q = node.content.children; _i < _q.length; _i++) {
164
+ var child = _q[_i];
165
+ traverse(child, parentDataSource);
166
+ }
167
+ }
168
+ if ((_o = node.content) === null || _o === void 0 ? void 0 : _o.node) {
169
+ traverse(node.content.node, parentDataSource);
170
+ }
171
+ if ((_p = node.content) === null || _p === void 0 ? void 0 : _p.nodes) {
172
+ if (node.content.nodes.success) {
173
+ traverse(node.content.nodes.success, parentDataSource);
174
+ }
175
+ if (node.content.nodes.error) {
176
+ traverse(node.content.nodes.error, parentDataSource);
177
+ }
178
+ if (node.content.nodes.loading) {
179
+ traverse(node.content.nodes.loading, parentDataSource);
180
+ }
181
+ if (node.content.nodes.list) {
182
+ traverse(node.content.nodes.list, parentDataSource);
183
+ }
184
+ if (node.content.nodes.empty) {
185
+ traverse(node.content.nodes.empty, parentDataSource);
186
+ }
187
+ }
188
+ if (Array.isArray(node.children)) {
189
+ for (var _r = 0, _s = node.children; _r < _s.length; _r++) {
190
+ var child = _s[_r];
191
+ traverse(child, parentDataSource);
192
+ }
193
+ }
194
+ };
195
+ traverse(uidlNode);
196
+ return { usages: usages, byDataSourceId: byDataSourceId, byArrayMapperRenderProp: byArrayMapperRenderProp };
197
+ }
198
+ // Generate state variable names for a usage
199
+ function getStateVarsForUsage(usage) {
200
+ var idx = usage.index;
201
+ return {
202
+ pageStateVar: "ds_".concat(idx, "_page"),
203
+ setPageStateVar: "setDs_".concat(idx, "_page"),
204
+ maxPagesStateVar: "ds_".concat(idx, "_maxPages"),
205
+ setMaxPagesStateVar: "setDs_".concat(idx, "_maxPages"),
206
+ searchQueryVar: "ds_".concat(idx, "_searchQuery"),
207
+ setSearchQueryVar: "setDs_".concat(idx, "_searchQuery"),
208
+ debouncedSearchQueryVar: "ds_".concat(idx, "_debouncedQuery"),
209
+ setDebouncedSearchQueryVar: "setDs_".concat(idx, "_debouncedQuery"),
210
+ combinedStateVar: "ds_".concat(idx, "_state"),
211
+ setCombinedStateVar: "setDs_".concat(idx, "_state"),
212
+ skipDebounceRefVar: "ds_".concat(idx, "_skipDebounce"),
213
+ skipCountFetchRefVar: "ds_".concat(idx, "_skipCountFetch"),
214
+ propsPrefix: "".concat(usage.dataSourceIdentifier, "_ds_").concat(idx),
215
+ };
216
+ }
217
+ // ==================== MAIN PLUGIN ====================
76
218
  var createNextArrayMapperPaginationPlugin = function () {
77
219
  var paginationPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () {
78
- var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, _a, paginatedMappers, searchOnlyMappers, paginationOnlyMappers, detectedPaginations, detectedSearchOnly, paginationInfos, getStaticPropsChunk, isPage, isComponent, opts, perPageMap, searchConfigMap, queryColumnsMap, stateDeclarations, hasSearchEnabled, firstReturnIndex, insertIndex, dataSourceToInfos_1, componentUseEffects_1, componentReturnIndex, componentEffectsInsertIndex_1, searchOnlyDataSources;
79
- var _b, _c, _d;
80
- return __generator(this, function (_e) {
220
+ var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, registry, getStaticPropsChunk, isPage, stateDeclarations, effectStatements, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, dataProvidersWithoutRepeaters, searchInputs, searchEnabledUsages, paginationNodes, paginatedUsages;
221
+ return __generator(this, function (_a) {
81
222
  uidl = structure.uidl, chunks = structure.chunks, dependencies = structure.dependencies, options = structure.options;
82
223
  componentChunk = chunks.find(function (chunk) { return chunk.name === 'jsx-component'; });
83
224
  if (!componentChunk || componentChunk.type !== teleport_types_1.ChunkType.AST) {
@@ -99,22 +240,19 @@ var createNextArrayMapperPaginationPlugin = function () {
99
240
  return [2 /*return*/, structure];
100
241
  }
101
242
  blockStatement = arrowFunction.body;
102
- _a = detectPaginationsAndSearchFromJSX(blockStatement, uidl.node), paginatedMappers = _a.paginatedMappers, searchOnlyMappers = _a.searchOnlyMappers, paginationOnlyMappers = _a.paginationOnlyMappers;
103
- if (paginatedMappers.length === 0 &&
104
- searchOnlyMappers.length === 0 &&
105
- paginationOnlyMappers.length === 0) {
243
+ registry = buildStateRegistry(uidl.node);
244
+ if (registry.usages.length === 0) {
106
245
  return [2 /*return*/, structure];
107
246
  }
108
- detectedPaginations = __spreadArray(__spreadArray([], paginatedMappers, true), paginationOnlyMappers, true);
109
- detectedSearchOnly = searchOnlyMappers;
247
+ getStaticPropsChunk = chunks.find(function (chunk) { return chunk.name === 'getStaticProps'; });
248
+ isPage = !!getStaticPropsChunk;
249
+ // Add React dependencies
110
250
  if (!dependencies.useState) {
111
251
  dependencies.useState = {
112
252
  type: 'library',
113
253
  path: 'react',
114
254
  version: '',
115
- meta: {
116
- namedImport: true,
117
- },
255
+ meta: { namedImport: true },
118
256
  };
119
257
  }
120
258
  if (!dependencies.useMemo) {
@@ -122,9 +260,7 @@ var createNextArrayMapperPaginationPlugin = function () {
122
260
  type: 'library',
123
261
  path: 'react',
124
262
  version: '',
125
- meta: {
126
- namedImport: true,
127
- },
263
+ meta: { namedImport: true },
128
264
  };
129
265
  }
130
266
  if (!dependencies.useCallback) {
@@ -132,9 +268,7 @@ var createNextArrayMapperPaginationPlugin = function () {
132
268
  type: 'library',
133
269
  path: 'react',
134
270
  version: '',
135
- meta: {
136
- namedImport: true,
137
- },
271
+ meta: { namedImport: true },
138
272
  };
139
273
  }
140
274
  if (!dependencies.useRef) {
@@ -142,1542 +276,898 @@ var createNextArrayMapperPaginationPlugin = function () {
142
276
  type: 'library',
143
277
  path: 'react',
144
278
  version: '',
145
- meta: {
146
- namedImport: true,
147
- },
279
+ meta: { namedImport: true },
280
+ };
281
+ }
282
+ if (!dependencies.useEffect) {
283
+ dependencies.useEffect = {
284
+ type: 'library',
285
+ path: 'react',
286
+ version: '',
287
+ meta: { namedImport: true },
148
288
  };
149
289
  }
150
290
  if (!componentChunk.meta) {
151
291
  componentChunk.meta = {};
152
292
  }
153
293
  componentChunk.meta.isClientComponent = true;
154
- paginationInfos = [];
155
- getStaticPropsChunk = chunks.find(function (chunk) { return chunk.name === 'getStaticProps'; });
156
- isPage = !!getStaticPropsChunk;
157
- isComponent = !isPage;
158
- opts = options;
159
- perPageMap = ((_b = opts.paginationConfig) === null || _b === void 0 ? void 0 : _b.perPageMap) || new Map();
160
- searchConfigMap = ((_c = opts.paginationConfig) === null || _c === void 0 ? void 0 : _c.searchConfigMap) || new Map();
161
- queryColumnsMap = ((_d = opts.paginationConfig) === null || _d === void 0 ? void 0 : _d.queryColumnsMap) || new Map();
162
294
  stateDeclarations = [];
163
- detectedPaginations.forEach(function (detected, index) {
164
- var paginationNodeId = "pg_".concat(index);
165
- // Use arrayMapperRenderProp if available, otherwise fall back to dataSourceIdentifier
166
- var lookupKey = detected.arrayMapperRenderProp || detected.dataSourceIdentifier;
167
- var perPage = perPageMap.get(lookupKey) || 10;
168
- var searchConfig = searchConfigMap.get(lookupKey);
169
- // queryColumns is keyed by dataSourceIdentifier, not array mapper render prop
170
- var queryColumns = queryColumnsMap.get(detected.dataSourceIdentifier);
171
- var info = (0, array_mapper_pagination_1.generatePaginationLogic)(paginationNodeId, detected.dataSourceIdentifier, perPage, searchConfig, queryColumns);
172
- paginationInfos.push(info);
173
- // Add refs to track first render for each useEffect (add first)
174
- if (info.searchEnabled) {
175
- var skipCountFetchOnMountRefVar = "skipCountFetchOnMount_pg_".concat(index);
176
- var skipCountFetchRefAST = types.variableDeclaration('const', [
177
- types.variableDeclarator(types.identifier(skipCountFetchOnMountRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
178
- ]);
179
- stateDeclarations.push(skipCountFetchRefAST);
180
- info.skipCountFetchOnMountRefVar = skipCountFetchOnMountRefVar;
181
- var skipDebounceOnMountRefVar = "skipDebounceOnMount_pg_".concat(index);
182
- var skipDebounceRefAST = types.variableDeclaration('const', [
183
- types.variableDeclarator(types.identifier(skipDebounceOnMountRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
184
- ]);
185
- stateDeclarations.push(skipDebounceRefAST);
186
- info.skipDebounceOnMountRefVar = skipDebounceOnMountRefVar;
295
+ effectStatements = [];
296
+ registry.usages.forEach(function (usage) {
297
+ if (usage.category === 'plain') {
298
+ return; // Plain mappers don't need state
187
299
  }
188
- // Add maxPages state
189
- var maxPagesStateVar = "".concat(info.pageStateVar.replace('_page', ''), "_maxPages");
190
- var setMaxPagesStateVar = "set".concat(maxPagesStateVar.charAt(0).toUpperCase() + maxPagesStateVar.slice(1));
191
- // For pages: initialize from props (with pagination-specific prop name), for components: initialize to 0
192
- var maxPagesInitValue = isPage
193
- ? types.logicalExpression('||', types.optionalMemberExpression(types.identifier('props'), types.identifier("".concat(info.dataSourceIdentifier, "_pg_").concat(index, "_maxPages")), false, true), types.numericLiteral(0))
194
- : types.numericLiteral(0);
195
- var maxPagesStateAST = types.variableDeclaration('const', [
196
- types.variableDeclarator(types.arrayPattern([
197
- types.identifier(maxPagesStateVar),
198
- types.identifier(setMaxPagesStateVar),
199
- ]), types.callExpression(types.identifier('useState'), [maxPagesInitValue])),
200
- ]);
201
- stateDeclarations.push(maxPagesStateAST);
202
- info.maxPagesStateVar = maxPagesStateVar;
203
- info.setMaxPagesStateVar = setMaxPagesStateVar;
204
- // If both pagination and search are enabled, combine them into a single state object
205
- if (info.searchEnabled && info.searchQueryVar && info.setSearchQueryVar) {
206
- // Combined state: { page: 1, debouncedQuery: '' }
207
- var combinedStateVar = "paginationState_pg_".concat(index);
208
- var setCombinedStateVar = "setPaginationState_pg_".concat(index);
209
- var combinedStateAST = types.variableDeclaration('const', [
300
+ var vars = getStateVarsForUsage(usage);
301
+ if (usage.category === 'paginated+search') {
302
+ // Combined state object for pagination + search
303
+ stateDeclarations.push(types.variableDeclaration('const', [
304
+ types.variableDeclarator(types.identifier(vars.skipDebounceRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
305
+ ]));
306
+ // Only add skipCountFetchRef for pages (where we have server-side count)
307
+ // For components, we need to fetch count on mount
308
+ if (isPage) {
309
+ stateDeclarations.push(types.variableDeclaration('const', [
310
+ types.variableDeclarator(types.identifier(vars.skipCountFetchRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
311
+ ]));
312
+ }
313
+ // maxPages state
314
+ var maxPagesInit = isPage
315
+ ? types.logicalExpression('||', types.optionalMemberExpression(types.identifier('props'), types.identifier("".concat(vars.propsPrefix, "_maxPages")), false, true), types.numericLiteral(0))
316
+ : types.numericLiteral(0);
317
+ stateDeclarations.push(types.variableDeclaration('const', [
210
318
  types.variableDeclarator(types.arrayPattern([
211
- types.identifier(combinedStateVar),
212
- types.identifier(setCombinedStateVar),
319
+ types.identifier(vars.maxPagesStateVar),
320
+ types.identifier(vars.setMaxPagesStateVar),
321
+ ]), types.callExpression(types.identifier('useState'), [maxPagesInit])),
322
+ ]));
323
+ // Combined state { page, debouncedQuery }
324
+ stateDeclarations.push(types.variableDeclaration('const', [
325
+ types.variableDeclarator(types.arrayPattern([
326
+ types.identifier(vars.combinedStateVar),
327
+ types.identifier(vars.setCombinedStateVar),
213
328
  ]), types.callExpression(types.identifier('useState'), [
214
329
  types.objectExpression([
215
330
  types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
216
331
  types.objectProperty(types.identifier('debouncedQuery'), types.stringLiteral('')),
217
332
  ]),
218
333
  ])),
219
- ]);
220
- stateDeclarations.push(combinedStateAST);
221
- // Still need the immediate search query state for the input
222
- var searchStateAST = types.variableDeclaration('const', [
334
+ ]));
335
+ // Immediate search query state
336
+ stateDeclarations.push(types.variableDeclaration('const', [
223
337
  types.variableDeclarator(types.arrayPattern([
224
- types.identifier(info.searchQueryVar),
225
- types.identifier(info.setSearchQueryVar),
338
+ types.identifier(vars.searchQueryVar),
339
+ types.identifier(vars.setSearchQueryVar),
226
340
  ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
227
- ]);
228
- stateDeclarations.push(searchStateAST);
229
- info.combinedStateVar = combinedStateVar;
230
- info.setCombinedStateVar = setCombinedStateVar;
231
- }
232
- else {
233
- // If search is not enabled, just add regular page state
234
- var pageStateAST = types.variableDeclaration('const', [
235
- types.variableDeclarator(types.arrayPattern([
236
- types.identifier(info.pageStateVar),
237
- types.identifier(info.setPageStateVar),
238
- ]), types.callExpression(types.identifier('useState'), [types.numericLiteral(1)])),
239
- ]);
240
- stateDeclarations.push(pageStateAST);
241
- }
242
- });
243
- // Add all state declarations at once to the beginning in correct order
244
- stateDeclarations.reverse().forEach(function (stateDecl) {
245
- blockStatement.body.unshift(stateDecl);
246
- });
247
- hasSearchEnabled = paginationInfos.some(function (info) { return info.searchEnabled; });
248
- if (hasSearchEnabled && !dependencies.useEffect) {
249
- dependencies.useEffect = {
250
- type: 'library',
251
- path: 'react',
252
- version: '',
253
- meta: {
254
- namedImport: true,
255
- },
256
- };
257
- }
258
- firstReturnIndex = blockStatement.body.findIndex(function (stmt) { return stmt.type === 'ReturnStatement'; });
259
- insertIndex = firstReturnIndex !== -1 ? firstReturnIndex : blockStatement.body.length;
260
- // Add effects in reverse order so they appear in correct order
261
- paginationInfos.forEach(function (info) {
262
- if (info.searchEnabled &&
263
- info.searchQueryVar &&
264
- info.debouncedSearchQueryVar &&
265
- info.setDebouncedSearchQueryVar) {
266
- // Add effect that updates debounced search after delay
267
- var skipDebounceOnMountRefVar = info.skipDebounceOnMountRefVar;
268
- var setCombinedStateVar = info.setCombinedStateVar;
269
- var debounceEffect = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
341
+ ]));
342
+ // Debounce effect
343
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
270
344
  types.arrowFunctionExpression([], types.blockStatement([
271
- types.ifStatement(types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.blockStatement([
272
- types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.booleanLiteral(false))),
345
+ types.ifStatement(types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.blockStatement([
346
+ types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.booleanLiteral(false))),
273
347
  types.returnStatement(),
274
348
  ])),
275
349
  types.variableDeclaration('const', [
276
350
  types.variableDeclarator(types.identifier('timer'), types.callExpression(types.identifier('setTimeout'), [
277
351
  types.arrowFunctionExpression([], types.blockStatement([
278
- types.expressionStatement(types.callExpression(types.identifier(setCombinedStateVar), [
352
+ types.expressionStatement(types.callExpression(types.identifier(vars.setCombinedStateVar), [
279
353
  types.objectExpression([
280
354
  types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
281
- types.objectProperty(types.identifier('debouncedQuery'), types.identifier(info.searchQueryVar)),
355
+ types.objectProperty(types.identifier('debouncedQuery'), types.identifier(vars.searchQueryVar)),
282
356
  ]),
283
357
  ])),
284
358
  ])),
285
- types.numericLiteral(info.searchDebounce || 300),
359
+ types.numericLiteral(usage.searchDebounce),
286
360
  ])),
287
361
  ]),
288
362
  types.returnStatement(types.arrowFunctionExpression([], types.callExpression(types.identifier('clearTimeout'), [
289
363
  types.identifier('timer'),
290
364
  ]))),
291
365
  ])),
292
- types.arrayExpression([types.identifier(info.searchQueryVar)]),
293
- ]));
294
- blockStatement.body.splice(insertIndex, 0, debounceEffect);
295
- // Add useEffect to refetch count when search changes (for both pages and components)
296
- var detected = detectedPaginations.find(function (d) { return d.dataSourceIdentifier === info.dataSourceIdentifier; });
297
- if (!detected) {
298
- return;
366
+ types.arrayExpression([types.identifier(vars.searchQueryVar)]),
367
+ ])));
368
+ // Count refetch effect
369
+ var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
370
+ var urlParams = [
371
+ types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery'))),
372
+ ];
373
+ if (usage.queryColumns.length > 0) {
374
+ urlParams.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
299
375
  }
300
- var resourceDefAttr = detected.dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'; });
301
- if (resourceDefAttr &&
302
- resourceDefAttr.value &&
303
- resourceDefAttr.value.type === 'JSXExpressionContainer') {
304
- var resourceDef = resourceDefAttr.value.expression;
305
- if (resourceDef.type === 'ObjectExpression') {
306
- var dataSourceIdProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'; });
307
- var tableNameProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'tableName'; });
308
- var dataSourceTypeProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'; });
309
- if (dataSourceIdProp && tableNameProp && dataSourceTypeProp) {
310
- var dataSourceId = dataSourceIdProp.value.value;
311
- var tableName = tableNameProp.value.value;
312
- var dataSourceType = dataSourceTypeProp.value.value;
313
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
314
- var setMaxPagesStateVar = info.setMaxPagesStateVar;
315
- // Create useEffect to refetch count when debounced search changes
316
- var skipCountFetchOnMountRefVar = info.skipCountFetchOnMountRefVar;
317
- var combinedStateVar = info.combinedStateVar;
318
- // Build URLSearchParams properties - query is always included, queryColumns is optional
319
- var urlSearchParamsProperties = [
320
- types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery'))),
321
- ];
322
- // Add queryColumns only if they exist
323
- if (info.queryColumns && info.queryColumns.length > 0) {
324
- urlSearchParamsProperties.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [
325
- types.arrayExpression(info.queryColumns.map(function (col) { return types.stringLiteral(col); })),
326
- ])));
327
- }
328
- var refetchCountEffect = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
329
- types.arrowFunctionExpression([], types.blockStatement([
330
- types.ifStatement(types.memberExpression(types.identifier(skipCountFetchOnMountRefVar), types.identifier('current')), types.blockStatement([
331
- types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(skipCountFetchOnMountRefVar), types.identifier('current')), types.booleanLiteral(false))),
332
- types.returnStatement(),
333
- ])),
334
- types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
335
- types.templateLiteral([
336
- types.templateElement({
337
- raw: "/api/".concat(fileName, "-count?"),
338
- cooked: "/api/".concat(fileName, "-count?"),
339
- }),
340
- types.templateElement({ raw: '', cooked: '' }),
341
- ], [
342
- types.newExpression(types.identifier('URLSearchParams'), [
343
- types.objectExpression(urlSearchParamsProperties),
344
- ]),
345
- ]),
346
- ]), types.identifier('then')), [
347
- types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
348
- ]), types.identifier('then')), [
349
- types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
350
- types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.binaryExpression('in', types.stringLiteral('count'), types.identifier('data'))), types.blockStatement([
351
- types.expressionStatement(types.callExpression(types.identifier(setMaxPagesStateVar), [
352
- types.conditionalExpression(types.binaryExpression('===', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(0)), types.numericLiteral(0), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
353
- types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(info.perPage)),
354
- ])),
355
- ])),
376
+ // Build the count fetch effect body
377
+ var countFetchEffectBody = [];
378
+ // Only add skip-on-mount check for pages (where we have server-side count)
379
+ if (isPage) {
380
+ countFetchEffectBody.push(types.ifStatement(types.memberExpression(types.identifier(vars.skipCountFetchRefVar), types.identifier('current')), types.blockStatement([
381
+ types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(vars.skipCountFetchRefVar), types.identifier('current')), types.booleanLiteral(false))),
382
+ types.returnStatement(),
383
+ ])));
384
+ }
385
+ // Add the fetch call
386
+ countFetchEffectBody.push(types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
387
+ types.templateLiteral([
388
+ types.templateElement({
389
+ raw: "/api/".concat(fileName, "-count?"),
390
+ cooked: "/api/".concat(fileName, "-count?"),
391
+ }),
392
+ types.templateElement({ raw: '', cooked: '' }),
393
+ ], [
394
+ types.newExpression(types.identifier('URLSearchParams'), [
395
+ types.objectExpression(urlParams),
396
+ ]),
397
+ ]),
398
+ ]), types.identifier('then')), [
399
+ types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
400
+ ]), types.identifier('then')), [
401
+ types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
402
+ types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.binaryExpression('in', types.stringLiteral('count'), types.identifier('data'))), types.blockStatement([
403
+ types.expressionStatement(types.callExpression(types.identifier(vars.setMaxPagesStateVar), [
404
+ types.conditionalExpression(types.binaryExpression('===', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(0)), types.numericLiteral(0), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
405
+ types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(usage.perPage)),
406
+ ])),
407
+ ])),
408
+ ])),
409
+ ])),
410
+ ])));
411
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
412
+ types.arrowFunctionExpression([], types.blockStatement(countFetchEffectBody)),
413
+ types.arrayExpression([
414
+ types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')),
415
+ ]),
416
+ ])));
417
+ }
418
+ else if (usage.category === 'paginated-only') {
419
+ // Simple page state
420
+ var maxPagesInit = isPage
421
+ ? types.logicalExpression('||', types.optionalMemberExpression(types.identifier('props'), types.identifier("".concat(vars.propsPrefix, "_maxPages")), false, true), types.numericLiteral(0))
422
+ : types.numericLiteral(0);
423
+ stateDeclarations.push(types.variableDeclaration('const', [
424
+ types.variableDeclarator(types.arrayPattern([
425
+ types.identifier(vars.maxPagesStateVar),
426
+ types.identifier(vars.setMaxPagesStateVar),
427
+ ]), types.callExpression(types.identifier('useState'), [maxPagesInit])),
428
+ ]));
429
+ stateDeclarations.push(types.variableDeclaration('const', [
430
+ types.variableDeclarator(types.arrayPattern([
431
+ types.identifier(vars.pageStateVar),
432
+ types.identifier(vars.setPageStateVar),
433
+ ]), types.callExpression(types.identifier('useState'), [types.numericLiteral(1)])),
434
+ ]));
435
+ // For components (not pages), add a useEffect to fetch count on mount
436
+ // Pages get count from getStaticProps, but components need to fetch it client-side
437
+ if (!isPage) {
438
+ var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
439
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
440
+ types.arrowFunctionExpression([], types.blockStatement([
441
+ types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
442
+ types.stringLiteral("/api/".concat(fileName, "-count")),
443
+ ]), types.identifier('then')), [
444
+ types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
445
+ ]), types.identifier('then')), [
446
+ types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
447
+ types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.binaryExpression('in', types.stringLiteral('count'), types.identifier('data'))), types.blockStatement([
448
+ types.expressionStatement(types.callExpression(types.identifier(vars.setMaxPagesStateVar), [
449
+ types.conditionalExpression(types.binaryExpression('===', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(0)), types.numericLiteral(0), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
450
+ types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(usage.perPage)),
356
451
  ])),
357
452
  ])),
358
453
  ])),
359
454
  ])),
360
- types.arrayExpression([
361
- types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery')),
362
- ]),
363
- ]));
364
- blockStatement.body.splice(insertIndex, 0, refetchCountEffect);
365
- }
366
- }
455
+ ])),
456
+ ])),
457
+ types.arrayExpression([]), // Empty dependency array - fetch on mount only
458
+ ])));
367
459
  }
368
460
  }
369
- });
370
- // For components, add useEffect to fetch count on mount
371
- if (isComponent) {
372
- if (!dependencies.useEffect) {
373
- dependencies.useEffect = {
374
- type: 'library',
375
- path: 'react',
376
- version: '',
377
- meta: {
378
- namedImport: true,
379
- },
380
- };
381
- }
382
- dataSourceToInfos_1 = new Map();
383
- paginationInfos.forEach(function (info) {
384
- var detected = detectedPaginations.find(function (d) { return d.dataSourceIdentifier === info.dataSourceIdentifier; });
385
- if (!detected) {
386
- return;
387
- }
388
- var resourceDefAttr = detected.dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'; });
389
- if (!resourceDefAttr ||
390
- !resourceDefAttr.value ||
391
- resourceDefAttr.value.type !== 'JSXExpressionContainer') {
392
- return;
393
- }
394
- var resourceDef = resourceDefAttr.value.expression;
395
- if (resourceDef.type !== 'ObjectExpression') {
396
- return;
397
- }
398
- var dataSourceIdProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'; });
399
- var tableNameProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'tableName'; });
400
- var dataSourceTypeProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'; });
401
- if (!dataSourceIdProp || !tableNameProp || !dataSourceTypeProp) {
402
- return;
403
- }
404
- var dataSourceId = dataSourceIdProp.value.value;
405
- var tableName = tableNameProp.value.value;
406
- var dataSourceType = dataSourceTypeProp.value.value;
407
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
408
- // Group by data source identifier
409
- if (!dataSourceToInfos_1.has(info.dataSourceIdentifier)) {
410
- dataSourceToInfos_1.set(info.dataSourceIdentifier, []);
411
- }
412
- dataSourceToInfos_1.get(info.dataSourceIdentifier).push({ info: info, detected: detected, fileName: fileName });
413
- });
414
- componentUseEffects_1 = [];
415
- dataSourceToInfos_1.forEach(function (infos) {
416
- var fileName = infos[0].fileName;
417
- // Create array of setState calls - one for each pagination using this data source
418
- var setStateStatements = infos.map(function (_a) {
419
- var info = _a.info;
420
- var setMaxPagesStateVar = info.setMaxPagesStateVar;
421
- return types.expressionStatement(types.callExpression(types.identifier(setMaxPagesStateVar), [
422
- types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
423
- types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(info.perPage)),
424
- ]),
425
- ]));
426
- });
427
- // Create useEffect to fetch count on mount - sets ALL maxPages for this data source
428
- var useEffectAST = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
461
+ else if (usage.category === 'search-only') {
462
+ // Search-only state
463
+ stateDeclarations.push(types.variableDeclaration('const', [
464
+ types.variableDeclarator(types.identifier(vars.skipDebounceRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
465
+ ]));
466
+ stateDeclarations.push(types.variableDeclaration('const', [
467
+ types.variableDeclarator(types.arrayPattern([
468
+ types.identifier(vars.debouncedSearchQueryVar),
469
+ types.identifier(vars.setDebouncedSearchQueryVar),
470
+ ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
471
+ ]));
472
+ stateDeclarations.push(types.variableDeclaration('const', [
473
+ types.variableDeclarator(types.arrayPattern([
474
+ types.identifier(vars.searchQueryVar),
475
+ types.identifier(vars.setSearchQueryVar),
476
+ ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
477
+ ]));
478
+ // Debounce effect
479
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
429
480
  types.arrowFunctionExpression([], types.blockStatement([
430
- types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
431
- types.stringLiteral("/api/".concat(fileName, "-count")),
432
- ]), types.identifier('then')), [
433
- types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
434
- ]), types.identifier('then')), [
435
- types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
436
- types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.memberExpression(types.identifier('data'), types.identifier('count'))), types.blockStatement(setStateStatements)),
437
- ])),
481
+ types.ifStatement(types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.blockStatement([
482
+ types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.booleanLiteral(false))),
483
+ types.returnStatement(),
438
484
  ])),
485
+ types.variableDeclaration('const', [
486
+ types.variableDeclarator(types.identifier('timer'), types.callExpression(types.identifier('setTimeout'), [
487
+ types.arrowFunctionExpression([], types.blockStatement([
488
+ types.expressionStatement(types.callExpression(types.identifier(vars.setDebouncedSearchQueryVar), [types.identifier(vars.searchQueryVar)])),
489
+ ])),
490
+ types.numericLiteral(usage.searchDebounce),
491
+ ])),
492
+ ]),
493
+ types.returnStatement(types.arrowFunctionExpression([], types.callExpression(types.identifier('clearTimeout'), [
494
+ types.identifier('timer'),
495
+ ]))),
439
496
  ])),
440
- types.arrayExpression([]),
441
- ]));
442
- componentUseEffects_1.push(useEffectAST);
443
- });
444
- componentReturnIndex = blockStatement.body.findIndex(function (stmt) { return stmt.type === 'ReturnStatement'; });
445
- componentEffectsInsertIndex_1 = componentReturnIndex !== -1 ? componentReturnIndex : blockStatement.body.length;
446
- // Insert in reverse order to maintain correct order
447
- componentUseEffects_1.reverse().forEach(function (effect) {
448
- blockStatement.body.splice(componentEffectsInsertIndex_1, 0, effect);
449
- });
450
- }
451
- createAPIRoutesForPaginatedDataSources(uidl.node, options.dataSources, componentChunk, options.extractedResources, paginationInfos, isComponent);
452
- detectedPaginations.forEach(function (detected, index) {
453
- addPaginationParamsToDataProvider(detected.dataProviderJSX, paginationInfos[index], index);
497
+ types.arrayExpression([types.identifier(vars.searchQueryVar)]),
498
+ ])));
499
+ }
454
500
  });
455
- modifyPaginationButtons(blockStatement, detectedPaginations, paginationInfos);
456
- modifySearchInputs(blockStatement, detectedPaginations, paginationInfos);
501
+ // Insert state declarations at the beginning
502
+ stateDeclarations.reverse().forEach(function (s) { return blockStatement.body.unshift(s); });
503
+ returnIndex = blockStatement.body.findIndex(function (s) { return s.type === 'ReturnStatement'; });
504
+ insertIndex = returnIndex !== -1 ? returnIndex : blockStatement.body.length;
505
+ effectStatements.reverse().forEach(function (e) { return blockStatement.body.splice(insertIndex, 0, e); });
506
+ dataProviders = findAllDataProvidersInJSX(blockStatement);
507
+ dataProvidersWithRepeaters = dataProviders.filter(function (dp) {
508
+ var hasRepeater = findArrayMapperRenderPropInDataProvider(dp) !== undefined;
509
+ return hasRepeater;
510
+ });
511
+ usageIndexByDataSourceId = new Map();
512
+ dataProvidersWithRepeaters.forEach(function (dp) {
513
+ var _a, _b;
514
+ var nameAttr = dp.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'name'; });
515
+ if (!((_b = (_a = nameAttr === null || nameAttr === void 0 ? void 0 : nameAttr.value) === null || _a === void 0 ? void 0 : _a.expression) === null || _b === void 0 ? void 0 : _b.value)) {
516
+ return;
517
+ }
518
+ var dataSourceIdentifier = nameAttr.value.expression.value;
519
+ // Use pure order-based matching within each dataSourceIdentifier
520
+ var usages = registry.byDataSourceId.get(dataSourceIdentifier) || [];
521
+ var currentIndex = usageIndexByDataSourceId.get(dataSourceIdentifier) || 0;
522
+ if (currentIndex >= usages.length) {
523
+ return;
524
+ }
525
+ var usage = usages[currentIndex];
526
+ usageIndexByDataSourceId.set(dataSourceIdentifier, currentIndex + 1);
527
+ var vars = getStateVarsForUsage(usage);
528
+ var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
529
+ // Update DataProvider based on category
530
+ if (usage.category === 'paginated+search') {
531
+ updateDataProviderForPaginatedSearch(dp, usage, vars, fileName);
532
+ }
533
+ else if (usage.category === 'paginated-only') {
534
+ updateDataProviderForPaginationOnly(dp, usage, vars, fileName);
535
+ }
536
+ else if (usage.category === 'search-only') {
537
+ updateDataProviderForSearchOnly(dp, usage, vars, fileName);
538
+ }
539
+ else {
540
+ updateDataProviderForPlain(dp, vars);
541
+ }
542
+ // Create API route if needed
543
+ if (usage.category !== 'plain') {
544
+ ensureAPIRouteExists(options.extractedResources, usage);
545
+ }
546
+ });
547
+ dataProvidersWithoutRepeaters = dataProviders.filter(function (dp) {
548
+ var hasRepeater = findArrayMapperRenderPropInDataProvider(dp) !== undefined;
549
+ return !hasRepeater;
550
+ });
551
+ dataProvidersWithoutRepeaters.forEach(function (dp) {
552
+ stabilizeDataProviderWithoutRepeater(dp);
553
+ });
554
+ searchInputs = findAllSearchInputsInJSX(blockStatement);
555
+ searchEnabledUsages = registry.usages.filter(function (u) { return u.searchEnabled; });
556
+ // Match by order - search input 0 -> searchEnabledUsages[0], etc.
557
+ searchInputs.forEach(function (input, idx) {
558
+ if (idx >= searchEnabledUsages.length) {
559
+ return;
560
+ }
561
+ var usage = searchEnabledUsages[idx];
562
+ var vars = getStateVarsForUsage(usage);
563
+ wireSearchInput(input.node, vars);
564
+ });
565
+ paginationNodes = findAllPaginationNodesInJSX(blockStatement);
566
+ paginatedUsages = registry.usages.filter(function (u) { return u.paginated; });
567
+ // Match by order - pagination node 0 -> paginatedUsages[0], etc.
568
+ paginationNodes.forEach(function (paginationNode, idx) {
569
+ if (idx >= paginatedUsages.length) {
570
+ return;
571
+ }
572
+ var usage = paginatedUsages[idx];
573
+ var vars = getStateVarsForUsage(usage);
574
+ wirePaginationButtons(paginationNode.node, usage, vars);
575
+ });
576
+ // STEP 6: Update getStaticProps if this is a page
457
577
  if (isPage) {
458
- modifyGetStaticPropsForPagination(chunks, paginationInfos);
459
- }
460
- searchOnlyDataSources = detectedSearchOnly;
461
- if (searchOnlyDataSources.length > 0) {
462
- handleSearchOnlyArrayMappers(blockStatement, searchOnlyDataSources, searchConfigMap, queryColumnsMap, dependencies);
463
- // Create API routes for search-only data sources
464
- createAPIRoutesForSearchOnlyDataSources(uidl.node, options.dataSources, componentChunk, options.extractedResources, searchOnlyDataSources);
578
+ updateGetStaticProps(chunks, registry);
465
579
  }
466
- cleanupStaticDataProviders(blockStatement);
467
580
  return [2 /*return*/, structure];
468
581
  });
469
582
  }); };
470
583
  return paginationPlugin;
471
584
  };
472
585
  exports.createNextArrayMapperPaginationPlugin = createNextArrayMapperPaginationPlugin;
473
- function cleanupStaticDataProviders(blockStatement) {
474
- var findAllDataProviders = function (node, results) {
586
+ // ==================== HELPER FUNCTIONS ====================
587
+ function findAllDataProvidersInJSX(blockStatement) {
588
+ var results = [];
589
+ var traverse = function (node) {
475
590
  var _a, _b;
476
- if (results === void 0) { results = []; }
477
591
  if (!node) {
478
- return results;
592
+ return;
479
593
  }
480
594
  if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'DataProvider') {
481
595
  results.push(node);
482
596
  }
483
- if (node.type === 'ReturnStatement' && node.argument) {
484
- findAllDataProviders(node.argument, results);
597
+ if (node.children && Array.isArray(node.children)) {
598
+ node.children.forEach(function (c) { return traverse(c); });
485
599
  }
486
- else if (node.type === 'JSXElement' || node.type === 'JSXFragment') {
487
- if (node.children && Array.isArray(node.children)) {
488
- node.children.forEach(function (child) { return findAllDataProviders(child, results); });
600
+ if (node.body) {
601
+ if (Array.isArray(node.body)) {
602
+ node.body.forEach(function (s) { return traverse(s); });
489
603
  }
490
- }
491
- else if (node.type === 'JSXExpressionContainer') {
492
- if (node.expression &&
493
- (node.expression.type === 'JSXElement' || node.expression.type === 'JSXFragment')) {
494
- findAllDataProviders(node.expression, results);
604
+ else {
605
+ traverse(node.body);
495
606
  }
496
607
  }
497
- else if (node.type === 'BlockStatement') {
498
- if (node.body && Array.isArray(node.body)) {
499
- node.body.forEach(function (stmt) { return findAllDataProviders(stmt, results); });
500
- }
608
+ if (node.consequent) {
609
+ traverse(node.consequent);
501
610
  }
502
- else if (node.type === 'ConditionalExpression') {
503
- findAllDataProviders(node.consequent, results);
504
- findAllDataProviders(node.alternate, results);
611
+ if (node.alternate) {
612
+ traverse(node.alternate);
505
613
  }
506
- return results;
507
- };
508
- var allDataProviders = findAllDataProviders(blockStatement);
509
- allDataProviders.forEach(function (dataProvider) {
510
- var _a;
511
- var hasInitialData = dataProvider.openingElement.attributes.some(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'initialData'; });
512
- var hasFetchData = dataProvider.openingElement.attributes.some(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'fetchData'; });
513
- var paramsAttr = dataProvider.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'params'; });
514
- // Case 1: Static SSR/SSG DataProviders (initialData, no fetchData, params)
515
- // Remove params to prevent refetch attempts - data was already fetched in getStaticProps
516
- if (hasInitialData && !hasFetchData && paramsAttr) {
517
- dataProvider.openingElement.attributes = dataProvider.openingElement.attributes.filter(function (attr) { return attr.type !== 'JSXAttribute' || attr.name.name !== 'params'; });
614
+ if (node.expression) {
615
+ traverse(node.expression);
518
616
  }
519
- // Case 2: Client-side DataProviders with plain object params (fetchData, non-memoized params)
520
- // Wrap params in useMemo to prevent infinite refetch loops
521
- else if (hasFetchData && paramsAttr && ((_a = paramsAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer') {
522
- var paramsExpression = paramsAttr.value.expression;
523
- // Check if params are already memoized (useMemo or useCallback call)
524
- var isAlreadyMemoized = paramsExpression.type === 'CallExpression' &&
525
- paramsExpression.callee.type === 'Identifier' &&
526
- (paramsExpression.callee.name === 'useMemo' ||
527
- paramsExpression.callee.name === 'useCallback');
528
- // If params are a plain ObjectExpression, wrap in useMemo
529
- if (!isAlreadyMemoized && paramsExpression.type === 'ObjectExpression') {
530
- var memoizedParams = types.callExpression(types.identifier('useMemo'), [
531
- types.arrowFunctionExpression([], paramsExpression),
532
- types.arrayExpression([]), // Empty deps - params are static
533
- ]);
534
- paramsAttr.value.expression = memoizedParams;
535
- }
617
+ if (node.argument) {
618
+ traverse(node.argument);
536
619
  }
537
- });
620
+ if (node.arguments) {
621
+ node.arguments.forEach(function (a) { return traverse(a); });
622
+ }
623
+ };
624
+ traverse(blockStatement);
625
+ return results;
538
626
  }
539
- function findParentNode(root, target, currentParent) {
540
- if (currentParent === void 0) { currentParent = null; }
541
- if (!root || !target) {
542
- return null;
543
- }
544
- if (root === target) {
545
- return currentParent;
627
+ function findArrayMapperRenderPropInDataProvider(dataProvider) {
628
+ var _a, _b, _c, _d, _e;
629
+ var renderSuccessAttr = dataProvider.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderSuccess'; });
630
+ if (!((_a = renderSuccessAttr === null || renderSuccessAttr === void 0 ? void 0 : renderSuccessAttr.value) === null || _a === void 0 ? void 0 : _a.expression)) {
631
+ return undefined;
546
632
  }
547
- if (root.type === 'JSXElement' || root.type === 'JSXFragment') {
548
- if (root.children && Array.isArray(root.children)) {
549
- for (var _i = 0, _a = root.children; _i < _a.length; _i++) {
550
- var child = _a[_i];
551
- var found = findParentNode(child, target, root);
552
- if (found !== null) {
553
- return found;
554
- }
555
- }
633
+ var findRepeater = function (node) {
634
+ var _a, _b;
635
+ if (!node) {
636
+ return null;
556
637
  }
557
- }
558
- else if (root.type === 'JSXExpressionContainer') {
559
- if (root.expression) {
560
- var found = findParentNode(root.expression, target, root);
561
- if (found !== null) {
562
- return found;
563
- }
638
+ if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'Repeater') {
639
+ return node;
564
640
  }
565
- }
566
- else if (root.type === 'BlockStatement') {
567
- if (root.body && Array.isArray(root.body)) {
568
- for (var _b = 0, _c = root.body; _b < _c.length; _b++) {
569
- var stmt = _c[_b];
570
- var found = findParentNode(stmt, target, root);
571
- if (found !== null) {
572
- return found;
573
- }
574
- }
641
+ if (node.body) {
642
+ return findRepeater(node.body);
575
643
  }
576
- }
577
- else if (root.type === 'ReturnStatement') {
578
- if (root.argument) {
579
- var found = findParentNode(root.argument, target, root);
580
- if (found !== null) {
581
- return found;
644
+ if (node.children && Array.isArray(node.children)) {
645
+ for (var _i = 0, _c = node.children; _i < _c.length; _i++) {
646
+ var c = _c[_i];
647
+ var r = findRepeater(c);
648
+ if (r) {
649
+ return r;
650
+ }
582
651
  }
583
652
  }
653
+ return null;
654
+ };
655
+ var repeater = findRepeater(renderSuccessAttr.value.expression);
656
+ if (!repeater) {
657
+ return undefined;
584
658
  }
585
- else if (root.type === 'ConditionalExpression') {
586
- var foundConsequent = findParentNode(root.consequent, target, root);
587
- if (foundConsequent !== null) {
588
- return foundConsequent;
589
- }
590
- var foundAlternate = findParentNode(root.alternate, target, root);
591
- if (foundAlternate !== null) {
592
- return foundAlternate;
593
- }
659
+ var renderItemAttr = repeater.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderItem'; });
660
+ if (!((_e = (_d = (_c = (_b = renderItemAttr === null || renderItemAttr === void 0 ? void 0 : renderItemAttr.value) === null || _b === void 0 ? void 0 : _b.expression) === null || _c === void 0 ? void 0 : _c.params) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.name)) {
661
+ return undefined;
594
662
  }
595
- return null;
663
+ return renderItemAttr.value.expression.params[0].name;
596
664
  }
597
- function detectPaginationsAndSearchFromJSX(blockStatement, uidlNode) {
598
- var dataProviderList = [];
599
- var arrayMapperInfoMap = new Map();
600
- if (uidlNode) {
601
- var collectArrayMapperInfo_1 = function (node) {
602
- var _a, _b, _c, _d, _e;
603
- if (!node) {
604
- return;
605
- }
606
- if (node.type === 'data-source-list' && ((_a = node.content) === null || _a === void 0 ? void 0 : _a.renderPropIdentifier)) {
607
- var dataSourceIdentifier_1 = node.content.renderPropIdentifier;
608
- if ((_d = (_c = (_b = node.content.nodes) === null || _b === void 0 ? void 0 : _b.success) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.children) {
609
- node.content.nodes.success.content.children.forEach(function (child) {
610
- var _a;
611
- if (child.type === 'cms-list-repeater' && ((_a = child.content) === null || _a === void 0 ? void 0 : _a.renderPropIdentifier)) {
612
- var arrayMapperRenderProp = child.content.renderPropIdentifier;
613
- // Key by array mapper render prop (unique), not data source identifier
614
- arrayMapperInfoMap.set(arrayMapperRenderProp, {
615
- dataSourceIdentifier: dataSourceIdentifier_1,
616
- renderProp: arrayMapperRenderProp,
617
- paginated: child.content.paginated || false,
618
- searchEnabled: child.content.searchEnabled || false,
619
- });
620
- }
621
- });
622
- }
623
- }
624
- if ((_e = node.content) === null || _e === void 0 ? void 0 : _e.children) {
625
- node.content.children.forEach(function (child) { return collectArrayMapperInfo_1(child); });
626
- }
627
- if (node.children && Array.isArray(node.children)) {
628
- node.children.forEach(function (child) { return collectArrayMapperInfo_1(child); });
629
- }
630
- };
631
- collectArrayMapperInfo_1(uidlNode);
632
- }
633
- var dataProvidersWithParents = [];
634
- var findDataProvidersAndParents = function (node, parent) {
635
- var _a, _b;
636
- if (parent === void 0) { parent = null; }
665
+ function findAllSearchInputsInJSX(blockStatement) {
666
+ var results = [];
667
+ var traverse = function (node) {
668
+ var _a, _b, _c, _d, _e, _f;
637
669
  if (!node) {
638
670
  return;
639
671
  }
640
- // Check if this is a DataProvider
641
- if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'DataProvider') {
642
- dataProvidersWithParents.push({
643
- dataProvider: node,
644
- parent: parent,
645
- });
672
+ if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'input') {
673
+ var classAttr = (_c = node.openingElement.attributes) === null || _c === void 0 ? void 0 : _c.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
674
+ var className = ((_d = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _d === void 0 ? void 0 : _d.value) || ((_f = (_e = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _e === void 0 ? void 0 : _e.expression) === null || _f === void 0 ? void 0 : _f.value) || '';
675
+ if (className.includes('search-input')) {
676
+ results.push({ node: node, className: className });
677
+ }
646
678
  }
647
- // Only recurse through JSX structure, not into embedded expressions or code
648
- if (node.type === 'ReturnStatement' && node.argument) {
649
- findDataProvidersAndParents(node.argument, parent);
679
+ if (node.children && Array.isArray(node.children)) {
680
+ node.children.forEach(function (c) { return traverse(c); });
650
681
  }
651
- else if (node.type === 'JSXElement' || node.type === 'JSXFragment') {
652
- // Recurse through JSX children
653
- if (node.children && Array.isArray(node.children)) {
654
- node.children.forEach(function (child) { return findDataProvidersAndParents(child, node); });
682
+ if (node.body) {
683
+ if (Array.isArray(node.body)) {
684
+ node.body.forEach(function (s) { return traverse(s); });
655
685
  }
656
- }
657
- else if (node.type === 'JSXExpressionContainer') {
658
- // For expression containers, continue but don't go into the expression itself
659
- if (node.expression &&
660
- (node.expression.type === 'JSXElement' || node.expression.type === 'JSXFragment')) {
661
- findDataProvidersAndParents(node.expression, parent);
686
+ else {
687
+ traverse(node.body);
662
688
  }
663
689
  }
664
- else if (node.type === 'BlockStatement') {
665
- // For block statements (function bodies), look through body array
666
- if (node.body && Array.isArray(node.body)) {
667
- node.body.forEach(function (stmt) { return findDataProvidersAndParents(stmt, node); });
668
- }
690
+ if (node.consequent) {
691
+ traverse(node.consequent);
669
692
  }
670
- else if (node.type === 'ConditionalExpression') {
671
- // Check both branches of conditional
672
- findDataProvidersAndParents(node.consequent, parent);
673
- findDataProvidersAndParents(node.alternate, parent);
693
+ if (node.alternate) {
694
+ traverse(node.alternate);
674
695
  }
675
- };
676
- findDataProvidersAndParents(blockStatement);
677
- // Now process each DataProvider and find its siblings
678
- dataProvidersWithParents.forEach(function (_a) {
679
- var _b, _c;
680
- var dataProvider = _a.dataProvider, parent = _a.parent;
681
- var nameAttr = dataProvider.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'name'; });
682
- // Find the array mapper render prop by looking inside renderSuccess -> Repeater -> renderItem param
683
- var renderSuccessAttr = dataProvider.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderSuccess'; });
684
- var arrayMapperRenderProp;
685
- if (renderSuccessAttr && ((_b = renderSuccessAttr.value) === null || _b === void 0 ? void 0 : _b.type) === 'JSXExpressionContainer') {
686
- var renderFunc = renderSuccessAttr.value.expression;
687
- if (renderFunc.type === 'ArrowFunctionExpression') {
688
- // Look for Repeater inside the render function
689
- var findRepeater_1 = function (node) {
690
- var _a, _b;
691
- if (!node) {
692
- return null;
693
- }
694
- if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'Repeater') {
695
- return node;
696
- }
697
- if (node.body) {
698
- return findRepeater_1(node.body);
699
- }
700
- if (node.children && Array.isArray(node.children)) {
701
- for (var _i = 0, _c = node.children; _i < _c.length; _i++) {
702
- var child = _c[_i];
703
- var result = findRepeater_1(child);
704
- if (result) {
705
- return result;
706
- }
707
- }
708
- }
709
- if (node.type === 'JSXFragment' || node.type === 'JSXElement') {
710
- if (node.children && Array.isArray(node.children)) {
711
- for (var _d = 0, _e = node.children; _d < _e.length; _d++) {
712
- var child = _e[_d];
713
- var result = findRepeater_1(child);
714
- if (result) {
715
- return result;
716
- }
717
- }
718
- }
719
- }
720
- if (node.type === 'JSXExpressionContainer') {
721
- return findRepeater_1(node.expression);
722
- }
723
- if (node.expression) {
724
- return findRepeater_1(node.expression);
725
- }
726
- if (node.consequent) {
727
- var result = findRepeater_1(node.consequent);
728
- if (result) {
729
- return result;
730
- }
731
- }
732
- if (node.alternate) {
733
- return findRepeater_1(node.alternate);
734
- }
735
- return null;
736
- };
737
- var repeater = findRepeater_1(renderFunc);
738
- if (repeater) {
739
- // Find renderItem attribute on Repeater
740
- var renderItemAttr = repeater.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderItem'; });
741
- if (renderItemAttr && ((_c = renderItemAttr.value) === null || _c === void 0 ? void 0 : _c.type) === 'JSXExpressionContainer') {
742
- var renderItemFunc = renderItemAttr.value.expression;
743
- if (renderItemFunc.type === 'ArrowFunctionExpression' &&
744
- renderItemFunc.params &&
745
- renderItemFunc.params.length > 0) {
746
- var param = renderItemFunc.params[0];
747
- if (param.type === 'Identifier') {
748
- arrayMapperRenderProp = param.name;
749
- }
750
- }
751
- }
752
- }
753
- }
696
+ if (node.expression) {
697
+ traverse(node.expression);
754
698
  }
755
- if (!nameAttr ||
756
- !nameAttr.value ||
757
- nameAttr.value.type !== 'JSXExpressionContainer' ||
758
- !arrayMapperRenderProp) {
699
+ if (node.argument) {
700
+ traverse(node.argument);
701
+ }
702
+ };
703
+ traverse(blockStatement);
704
+ return results;
705
+ }
706
+ function findAllPaginationNodesInJSX(blockStatement) {
707
+ var results = [];
708
+ var traverse = function (node) {
709
+ var _a, _b, _c, _d, _e;
710
+ if (!node) {
759
711
  return;
760
712
  }
761
- var dataProviderIdentifier = nameAttr.value.expression.value;
762
- var paginationNodeInfo = null;
763
- var searchInputInfo = null;
764
- var findSearchAndPaginationInScope = function (scopeNode, skipNode) {
765
- var _a, _b, _c, _d, _e, _f;
766
- if (skipNode === void 0) { skipNode = null; }
767
- if (!scopeNode || !scopeNode.children || !Array.isArray(scopeNode.children)) {
768
- return false;
713
+ if (node.type === 'JSXElement') {
714
+ var classAttr = (_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) === null || _b === void 0 ? void 0 : _b.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
715
+ var className = ((_c = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _c === void 0 ? void 0 : _c.value) || ((_e = (_d = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _d === void 0 ? void 0 : _d.expression) === null || _e === void 0 ? void 0 : _e.value) || '';
716
+ if (className.includes('cms-pagination-node')) {
717
+ results.push({ node: node, className: className });
769
718
  }
770
- var foundSomething = false;
771
- for (var _i = 0, _g = scopeNode.children; _i < _g.length; _i++) {
772
- var child = _g[_i];
773
- if (child === skipNode) {
774
- continue;
775
- }
776
- if (child.type === 'JSXElement') {
777
- var childClassName = getClassName(((_a = child.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) || []);
778
- var childElementName = (_c = (_b = child.openingElement) === null || _b === void 0 ? void 0 : _b.name) === null || _c === void 0 ? void 0 : _c.name;
779
- // Found pagination node
780
- if (childClassName && childClassName.includes('cms-pagination-node')) {
781
- var prevClass = findChildWithClass(child, 'previous');
782
- var nextClass = findChildWithClass(child, 'next');
783
- if (prevClass || nextClass) {
784
- paginationNodeInfo = {
785
- class: childClassName,
786
- prevClass: prevClass,
787
- nextClass: nextClass,
788
- };
789
- foundSomething = true;
790
- }
791
- }
792
- // Found search container - search for input inside it
793
- if (childClassName && childClassName.includes('data-source-search-node')) {
794
- if (child.children && Array.isArray(child.children)) {
795
- for (var _h = 0, _j = child.children; _h < _j.length; _h++) {
796
- var searchChild = _j[_h];
797
- if (searchChild.type === 'JSXElement') {
798
- var searchChildElementName = (_e = (_d = searchChild.openingElement) === null || _d === void 0 ? void 0 : _d.name) === null || _e === void 0 ? void 0 : _e.name;
799
- var searchChildClassName = getClassName(((_f = searchChild.openingElement) === null || _f === void 0 ? void 0 : _f.attributes) || []);
800
- if (searchChildClassName &&
801
- searchChildClassName.includes('search-input') &&
802
- searchChildElementName === 'input') {
803
- searchInputInfo = {
804
- class: searchChildClassName,
805
- jsx: searchChild,
806
- };
807
- foundSomething = true;
808
- }
809
- }
810
- }
811
- }
812
- }
813
- // Also check if search input is a direct child
814
- if (childClassName &&
815
- childClassName.includes('search-input') &&
816
- childElementName === 'input') {
817
- searchInputInfo = {
818
- class: childClassName,
819
- jsx: child,
820
- };
821
- foundSomething = true;
822
- }
823
- // Stop searching if we found both or if we found what we're looking for
824
- if (foundSomething && (searchInputInfo || paginationNodeInfo)) {
825
- return true;
826
- }
827
- // Only recurse if we haven't found what we're looking for yet
828
- if (!searchInputInfo || !paginationNodeInfo) {
829
- if (findSearchAndPaginationInScope(child, skipNode)) {
830
- return true;
831
- }
832
- }
833
- }
719
+ }
720
+ if (node.children && Array.isArray(node.children)) {
721
+ node.children.forEach(function (c) { return traverse(c); });
722
+ }
723
+ if (node.body) {
724
+ if (Array.isArray(node.body)) {
725
+ node.body.forEach(function (s) { return traverse(s); });
834
726
  }
835
- return foundSomething;
836
- };
837
- var currentScope = parent;
838
- var depth = 0;
839
- var maxDepth = 5;
840
- while (currentScope && (!searchInputInfo || !paginationNodeInfo) && depth < maxDepth) {
841
- var found = findSearchAndPaginationInScope(currentScope, depth === 0 ? dataProvider : null);
842
- // Stop searching up the tree if we found a pagination node at this level
843
- if (found && paginationNodeInfo) {
844
- break;
727
+ else {
728
+ traverse(node.body);
845
729
  }
846
- currentScope = findParentNode(blockStatement, currentScope);
847
- depth++;
848
730
  }
849
- // Record the DataProvider with its pagination/search info
850
- // Use array instead of Map to handle multiple DataProviders with same name
851
- dataProviderList.push({
852
- identifier: dataProviderIdentifier,
853
- dataProvider: dataProvider,
854
- arrayMapperRenderProp: arrayMapperRenderProp,
855
- paginationNode: paginationNodeInfo || undefined,
856
- searchInput: searchInputInfo || undefined,
857
- hasPagination: !!paginationNodeInfo,
858
- hasSearch: !!searchInputInfo,
859
- });
860
- });
861
- // Categorize data providers
862
- var paginatedMappers = [];
863
- var searchOnlyMappers = [];
864
- var paginationOnlyMappers = [];
865
- var plainMappers = [];
866
- dataProviderList.forEach(function (info) {
867
- var _a, _b, _c, _d;
868
- // Check UIDL flags for this array mapper
869
- var uidlInfo = info.arrayMapperRenderProp
870
- ? arrayMapperInfoMap.get(info.arrayMapperRenderProp)
871
- : null;
872
- // Only process pagination/search if UIDL explicitly enables it
873
- var shouldHavePagination = (uidlInfo === null || uidlInfo === void 0 ? void 0 : uidlInfo.paginated) && info.hasPagination;
874
- var shouldHaveSearch = (uidlInfo === null || uidlInfo === void 0 ? void 0 : uidlInfo.searchEnabled) && info.hasSearch;
875
- if (shouldHavePagination && shouldHaveSearch) {
876
- // Pagination + Search
877
- paginatedMappers.push({
878
- paginationNodeClass: info.paginationNode.class,
879
- prevButtonClass: info.paginationNode.prevClass,
880
- nextButtonClass: info.paginationNode.nextClass,
881
- dataSourceIdentifier: info.identifier,
882
- dataProviderJSX: info.dataProvider,
883
- arrayMapperRenderProp: info.arrayMapperRenderProp,
884
- searchInputClass: (_a = info.searchInput) === null || _a === void 0 ? void 0 : _a.class,
885
- searchInputJSX: (_b = info.searchInput) === null || _b === void 0 ? void 0 : _b.jsx,
886
- });
731
+ if (node.consequent) {
732
+ traverse(node.consequent);
887
733
  }
888
- else if (shouldHavePagination && !shouldHaveSearch) {
889
- // Pagination only
890
- paginationOnlyMappers.push({
891
- paginationNodeClass: info.paginationNode.class,
892
- prevButtonClass: info.paginationNode.prevClass,
893
- nextButtonClass: info.paginationNode.nextClass,
894
- dataSourceIdentifier: info.identifier,
895
- dataProviderJSX: info.dataProvider,
896
- arrayMapperRenderProp: info.arrayMapperRenderProp,
897
- searchInputClass: undefined,
898
- searchInputJSX: undefined,
899
- });
734
+ if (node.alternate) {
735
+ traverse(node.alternate);
900
736
  }
901
- else if (!shouldHavePagination && shouldHaveSearch) {
902
- // Search only
903
- searchOnlyMappers.push({
904
- paginationNodeClass: '',
905
- prevButtonClass: null,
906
- nextButtonClass: null,
907
- dataSourceIdentifier: info.identifier,
908
- dataProviderJSX: info.dataProvider,
909
- arrayMapperRenderProp: info.arrayMapperRenderProp,
910
- searchInputClass: (_c = info.searchInput) === null || _c === void 0 ? void 0 : _c.class,
911
- searchInputJSX: (_d = info.searchInput) === null || _d === void 0 ? void 0 : _d.jsx,
912
- });
737
+ if (node.expression) {
738
+ traverse(node.expression);
913
739
  }
914
- else {
915
- // Plain (no pagination, no search) - UIDL doesn't enable it or no controls found
916
- plainMappers.push({
917
- paginationNodeClass: '',
918
- prevButtonClass: null,
919
- nextButtonClass: null,
920
- dataSourceIdentifier: info.identifier,
921
- dataProviderJSX: info.dataProvider,
922
- arrayMapperRenderProp: info.arrayMapperRenderProp,
923
- searchInputClass: undefined,
924
- searchInputJSX: undefined,
925
- });
740
+ if (node.argument) {
741
+ traverse(node.argument);
926
742
  }
927
- });
928
- return { paginatedMappers: paginatedMappers, searchOnlyMappers: searchOnlyMappers, paginationOnlyMappers: paginationOnlyMappers, plainMappers: plainMappers };
743
+ };
744
+ traverse(blockStatement);
745
+ return results;
929
746
  }
930
- function handleSearchOnlyArrayMappers(blockStatement, searchOnlyDataSources, searchConfigMap, queryColumnsMap, dependencies) {
931
- var searchOnlyStates = [];
932
- var searchOnlyEffects = [];
933
- searchOnlyDataSources.forEach(function (detected, index) {
934
- var searchId = "search_".concat(index);
935
- var searchQueryVar = "".concat(searchId, "_query");
936
- var setSearchQueryVar = "set".concat(searchQueryVar.charAt(0).toUpperCase() + searchQueryVar.slice(1));
937
- var debouncedSearchQueryVar = "debounced".concat(searchQueryVar.charAt(0).toUpperCase() + searchQueryVar.slice(1));
938
- var setDebouncedSearchQueryVar = "set".concat(debouncedSearchQueryVar.charAt(0).toUpperCase() + debouncedSearchQueryVar.slice(1));
939
- var skipDebounceOnMountRefVar = "skipDebounceOnMount".concat(searchId);
940
- var searchConfig = searchConfigMap.get(detected.dataSourceIdentifier);
941
- var searchDebounce = (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.searchDebounce) || 300;
942
- var queryColumns = queryColumnsMap.get(detected.dataSourceIdentifier);
943
- // Add skip ref
944
- var skipRefAST = types.variableDeclaration('const', [
945
- types.variableDeclarator(types.identifier(skipDebounceOnMountRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
946
- ]);
947
- searchOnlyStates.push(skipRefAST);
948
- // Add debounced search state
949
- var debouncedSearchStateAST = types.variableDeclaration('const', [
950
- types.variableDeclarator(types.arrayPattern([
951
- types.identifier(debouncedSearchQueryVar),
952
- types.identifier(setDebouncedSearchQueryVar),
953
- ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
954
- ]);
955
- searchOnlyStates.push(debouncedSearchStateAST);
956
- // Add search query state
957
- var searchStateAST = types.variableDeclaration('const', [
958
- types.variableDeclarator(types.arrayPattern([types.identifier(searchQueryVar), types.identifier(setSearchQueryVar)]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
959
- ]);
960
- searchOnlyStates.push(searchStateAST);
961
- // Add useEffect for debouncing
962
- if (!dependencies.useEffect) {
963
- dependencies.useEffect = {
964
- type: 'library',
965
- path: 'react',
966
- version: '',
967
- meta: {
968
- namedImport: true,
969
- },
970
- };
971
- }
972
- var debounceEffect = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
973
- types.arrowFunctionExpression([], types.blockStatement([
974
- types.ifStatement(types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.blockStatement([
975
- types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.booleanLiteral(false))),
976
- types.returnStatement(),
977
- ])),
978
- types.variableDeclaration('const', [
979
- types.variableDeclarator(types.identifier('timer'), types.callExpression(types.identifier('setTimeout'), [
980
- types.arrowFunctionExpression([], types.blockStatement([
981
- types.expressionStatement(types.callExpression(types.identifier(setDebouncedSearchQueryVar), [
982
- types.identifier(searchQueryVar),
983
- ])),
984
- ])),
985
- types.numericLiteral(searchDebounce),
986
- ])),
987
- ]),
988
- types.returnStatement(types.arrowFunctionExpression([], types.callExpression(types.identifier('clearTimeout'), [types.identifier('timer')]))),
989
- ])),
990
- types.arrayExpression([types.identifier(searchQueryVar)]),
991
- ]));
992
- searchOnlyEffects.push(debounceEffect);
993
- // Modify DataProvider to include search params (even without queryColumns)
994
- if (detected.dataProviderJSX) {
995
- addSearchParamsToDataProvider(detected.dataProviderJSX, {
996
- debouncedSearchQueryVar: debouncedSearchQueryVar,
997
- queryColumns: queryColumns || [],
998
- });
999
- }
1000
- // Modify search input
1001
- if (detected.searchInputJSX) {
1002
- addSearchInputHandlers(detected.searchInputJSX, {
1003
- searchQueryVar: searchQueryVar,
1004
- setSearchQueryVar: setSearchQueryVar,
1005
- searchEnabled: true,
1006
- });
1007
- }
1008
- });
1009
- // Add all state declarations at the beginning in correct order
1010
- searchOnlyStates.reverse().forEach(function (stateDecl) {
1011
- blockStatement.body.unshift(stateDecl);
747
+ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
748
+ var attrs = dp.openingElement.attributes;
749
+ // Remove existing params, key, initialData, fetchData, persistDataDuringLoading
750
+ dp.openingElement.attributes = attrs.filter(function (attr) {
751
+ var _a;
752
+ return !['params', 'key', 'initialData', 'fetchData', 'persistDataDuringLoading'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name);
1012
753
  });
1013
- // Recalculate insertIndex after adding states (since unshift shifted everything)
1014
- var newInsertIndex = blockStatement.body.findIndex(function (stmt) { return stmt.type === 'ReturnStatement'; });
1015
- var finalInsertIndex = newInsertIndex !== -1 ? newInsertIndex : blockStatement.body.length;
1016
- // Add all useEffect hooks before the return statement
1017
- searchOnlyEffects.reverse().forEach(function (effect) {
1018
- blockStatement.body.splice(finalInsertIndex, 0, effect);
754
+ // Add params with useMemo
755
+ var paramsProps = [
756
+ types.objectProperty(types.identifier('page'), types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page'))),
757
+ types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)),
758
+ types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery'))),
759
+ ];
760
+ if (usage.queryColumns.length > 0) {
761
+ paramsProps.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
762
+ }
763
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
764
+ types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
765
+ types.arrayExpression([types.identifier(vars.combinedStateVar)]),
766
+ ]))));
767
+ // Add initialData
768
+ var initialDataCondition = types.logicalExpression('&&', types.binaryExpression('===', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')), types.numericLiteral(1)), types.unaryExpression('!', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')), true));
769
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(initialDataCondition, types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
770
+ // Add key
771
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
772
+ types.templateElement({
773
+ raw: "".concat(usage.dataSourceIdentifier, "-"),
774
+ cooked: "".concat(usage.dataSourceIdentifier, "-"),
775
+ }),
776
+ types.templateElement({ raw: '-', cooked: '-' }),
777
+ types.templateElement({ raw: '', cooked: '' }),
778
+ ], [
779
+ types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')),
780
+ types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')),
781
+ ]))));
782
+ // Add fetchData
783
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
784
+ // Add persistDataDuringLoading
785
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
786
+ }
787
+ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
788
+ var attrs = dp.openingElement.attributes;
789
+ dp.openingElement.attributes = attrs.filter(function (attr) {
790
+ var _a;
791
+ return !['params', 'key', 'initialData', 'fetchData', 'persistDataDuringLoading'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name);
1019
792
  });
793
+ // Add params
794
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
795
+ types.arrowFunctionExpression([], types.objectExpression([
796
+ types.objectProperty(types.identifier('page'), types.identifier(vars.pageStateVar)),
797
+ types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)),
798
+ ])),
799
+ types.arrayExpression([types.identifier(vars.pageStateVar)]),
800
+ ]))));
801
+ // Add initialData
802
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(types.binaryExpression('===', types.identifier(vars.pageStateVar), types.numericLiteral(1)), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
803
+ // Add key
804
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
805
+ types.templateElement({
806
+ raw: "".concat(usage.dataSourceIdentifier, "-page-"),
807
+ cooked: "".concat(usage.dataSourceIdentifier, "-page-"),
808
+ }),
809
+ types.templateElement({ raw: '', cooked: '' }),
810
+ ], [types.identifier(vars.pageStateVar)]))));
811
+ // Add fetchData
812
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
813
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
1020
814
  }
1021
- function addSearchParamsToDataProvider(dataProviderJSX, config) {
1022
- var _a, _b;
1023
- if (!dataProviderJSX || !dataProviderJSX.openingElement) {
1024
- return;
1025
- }
1026
- var debouncedSearchQueryVar = config.debouncedSearchQueryVar, queryColumns = config.queryColumns;
1027
- // 1. Update params to be wrapped in useMemo
1028
- var existingParamsAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'params'; });
1029
- if (existingParamsAttr && ((_a = existingParamsAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer') {
1030
- var paramsObj = existingParamsAttr.value.expression;
1031
- if (paramsObj.type === 'ObjectExpression') {
1032
- // Add query to existing params properties
1033
- paramsObj.properties.push(types.objectProperty(types.identifier('query'), types.identifier(debouncedSearchQueryVar)));
1034
- // Add queryColumns only if they exist
1035
- if (queryColumns.length > 0) {
1036
- paramsObj.properties.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(queryColumns.map(function (col) { return types.stringLiteral(col); }))])));
1037
- }
1038
- // Wrap in useMemo with debouncedSearchQueryVar as dependency
1039
- var memoizedParamsValue = types.callExpression(types.identifier('useMemo'), [
1040
- types.arrowFunctionExpression([], paramsObj),
1041
- types.arrayExpression([types.identifier(debouncedSearchQueryVar)]),
1042
- ]);
1043
- existingParamsAttr.value.expression = memoizedParamsValue;
1044
- }
1045
- }
1046
- // 2. Update initialData to be conditional on empty search
1047
- var existingInitialDataAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'initialData'; });
1048
- if (existingInitialDataAttr && ((_b = existingInitialDataAttr.value) === null || _b === void 0 ? void 0 : _b.type) === 'JSXExpressionContainer') {
1049
- var currentInitialData = existingInitialDataAttr.value.expression;
1050
- // Make it conditional: only use initialData if search is empty
1051
- existingInitialDataAttr.value.expression = types.conditionalExpression(types.unaryExpression('!', types.identifier(debouncedSearchQueryVar), true), currentInitialData, types.identifier('undefined'));
815
+ function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
816
+ var attrs = dp.openingElement.attributes;
817
+ dp.openingElement.attributes = attrs.filter(function (attr) {
818
+ var _a;
819
+ return !['params', 'key', 'initialData', 'fetchData', 'persistDataDuringLoading'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name);
820
+ });
821
+ // Add params
822
+ var paramsProps = [
823
+ types.objectProperty(types.identifier('query'), types.identifier(vars.debouncedSearchQueryVar)),
824
+ ];
825
+ if (usage.queryColumns.length > 0) {
826
+ paramsProps.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
1052
827
  }
1053
- // 3. Update key to include search query
1054
- var existingKeyAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'key'; });
1055
- var keyExpression = types.templateLiteral([
828
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
829
+ types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
830
+ types.arrayExpression([types.identifier(vars.debouncedSearchQueryVar)]),
831
+ ]))));
832
+ // Add initialData
833
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(types.unaryExpression('!', types.identifier(vars.debouncedSearchQueryVar), true), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
834
+ // Add key
835
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
1056
836
  types.templateElement({ raw: 'search-', cooked: 'search-' }),
1057
837
  types.templateElement({ raw: '', cooked: '' }),
1058
- ], [types.identifier(debouncedSearchQueryVar)]);
1059
- var keyAttr = types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(keyExpression));
1060
- if (existingKeyAttr) {
1061
- var index = dataProviderJSX.openingElement.attributes.indexOf(existingKeyAttr);
1062
- dataProviderJSX.openingElement.attributes[index] = keyAttr;
1063
- }
1064
- else {
1065
- dataProviderJSX.openingElement.attributes.push(keyAttr);
838
+ ], [types.identifier(vars.debouncedSearchQueryVar)]))));
839
+ // Add fetchData
840
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
841
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
842
+ }
843
+ function updateDataProviderForPlain(dp, vars) {
844
+ var attrs = dp.openingElement.attributes;
845
+ // Remove params and fetchData - plain mappers only use initialData
846
+ dp.openingElement.attributes = attrs.filter(function (attr) { var _a; return !['params', 'fetchData'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name); });
847
+ // Update initialData to use correct prop
848
+ var existingInitialData = dp.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'initialData'; });
849
+ if (existingInitialData) {
850
+ existingInitialData.value = types.jsxExpressionContainer(types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true));
1066
851
  }
1067
852
  }
1068
- function addPaginationParamsToDataProvider(dataProviderJSX, info, paginationIndex) {
1069
- var _a;
1070
- if (!dataProviderJSX || !dataProviderJSX.openingElement) {
853
+ function stabilizeDataProviderWithoutRepeater(dp) {
854
+ var _a, _b, _c;
855
+ var attrs = dp.openingElement.attributes;
856
+ // Find the params attribute
857
+ var paramsAttrIndex = attrs.findIndex(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'params'; });
858
+ if (paramsAttrIndex === -1) {
1071
859
  return;
1072
860
  }
1073
- var combinedStateVar = info.combinedStateVar;
1074
- var paramsProperties;
1075
- var dependencies;
1076
- if (info.searchEnabled && combinedStateVar) {
1077
- // Use combined state for both page and query
1078
- paramsProperties = [
1079
- types.objectProperty(types.identifier('page'), types.memberExpression(types.identifier(combinedStateVar), types.identifier('page'))),
1080
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(info.perPage)),
1081
- types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery'))),
1082
- ];
1083
- if (info.queryColumns && info.queryColumns.length > 0) {
1084
- paramsProperties.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(info.queryColumns.map(function (col) { return types.stringLiteral(col); }))])));
1085
- }
1086
- // Single dependency: the combined state object
1087
- dependencies = [types.identifier(combinedStateVar)];
1088
- }
1089
- else {
1090
- // Pagination only (no search)
1091
- paramsProperties = [
1092
- types.objectProperty(types.identifier('page'), types.identifier(info.pageStateVar)),
1093
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(info.perPage)),
1094
- ];
1095
- dependencies = [types.identifier(info.pageStateVar)];
1096
- }
1097
- // Wrap params in useMemo to prevent unnecessary refetches
1098
- var memoizedParamsValue = types.callExpression(types.identifier('useMemo'), [
1099
- types.arrowFunctionExpression([], types.objectExpression(paramsProperties)),
1100
- types.arrayExpression(dependencies),
1101
- ]);
1102
- var paramsAttr = types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(memoizedParamsValue));
1103
- var existingParamsAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'params'; });
1104
- if (existingParamsAttr) {
1105
- var index = dataProviderJSX.openingElement.attributes.indexOf(existingParamsAttr);
1106
- dataProviderJSX.openingElement.attributes[index] = paramsAttr;
1107
- }
1108
- else {
1109
- dataProviderJSX.openingElement.attributes.push(paramsAttr);
1110
- }
1111
- var existingInitialDataAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'initialData'; });
1112
- if (existingInitialDataAttr && existingInitialDataAttr.value) {
1113
- // Update initialData to use the paginated prop name
1114
- var paginatedPropName = "".concat(info.dataSourceIdentifier, "_pg_").concat(paginationIndex);
1115
- // If search is enabled, use combined state; otherwise use page state
1116
- var condition = void 0;
1117
- if (info.searchEnabled && combinedStateVar) {
1118
- condition = types.logicalExpression('&&', types.binaryExpression('===', types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')), types.numericLiteral(1)), types.unaryExpression('!', types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery')), true));
1119
- }
1120
- else {
1121
- condition = types.binaryExpression('===', types.identifier(info.pageStateVar), types.numericLiteral(1));
1122
- }
1123
- existingInitialDataAttr.value.expression = types.conditionalExpression(condition, types.optionalMemberExpression(types.identifier('props'), types.identifier(paginatedPropName), false, true), types.identifier('undefined'));
1124
- }
1125
- var existingKeyAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'key'; });
1126
- // Include page and search in key to trigger refetch when they change
1127
- var keyExpression;
1128
- if (info.searchEnabled && combinedStateVar) {
1129
- keyExpression = types.templateLiteral([
1130
- types.templateElement({
1131
- raw: "".concat(info.dataSourceIdentifier, "-page-"),
1132
- cooked: "".concat(info.dataSourceIdentifier, "-page-"),
1133
- }),
1134
- types.templateElement({ raw: '-search-', cooked: '-search-' }),
1135
- types.templateElement({ raw: '', cooked: '' }),
1136
- ], [
1137
- types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')),
1138
- types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery')),
1139
- ]);
1140
- }
1141
- else {
1142
- keyExpression = types.templateLiteral([
1143
- types.templateElement({
1144
- raw: "".concat(info.dataSourceIdentifier, "-"),
1145
- cooked: "".concat(info.dataSourceIdentifier, "-"),
1146
- }),
1147
- types.templateElement({ raw: '', cooked: '' }),
1148
- ], [types.identifier(info.pageStateVar)]);
1149
- }
1150
- var keyAttr = types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(keyExpression));
1151
- if (existingKeyAttr) {
1152
- var index = dataProviderJSX.openingElement.attributes.indexOf(existingKeyAttr);
1153
- dataProviderJSX.openingElement.attributes[index] = keyAttr;
861
+ var paramsAttr = attrs[paramsAttrIndex];
862
+ // Check if params is already wrapped in useMemo
863
+ if (((_a = paramsAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer' &&
864
+ paramsAttr.value.expression.type === 'CallExpression' &&
865
+ ((_b = paramsAttr.value.expression.callee) === null || _b === void 0 ? void 0 : _b.name) === 'useMemo') {
866
+ return;
1154
867
  }
1155
- else {
1156
- dataProviderJSX.openingElement.attributes.push(keyAttr);
868
+ // Get the current params value expression
869
+ var paramsExpression = null;
870
+ if (((_c = paramsAttr.value) === null || _c === void 0 ? void 0 : _c.type) === 'JSXExpressionContainer') {
871
+ paramsExpression = paramsAttr.value.expression;
1157
872
  }
1158
- // For pagination, always create a fresh fetchData that calls the API route
1159
- // Get the resource definition to build the API URL
1160
- var resourceDefAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'; });
1161
- if (resourceDefAttr && ((_a = resourceDefAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer') {
1162
- var resourceDef = resourceDefAttr.value.expression;
1163
- if (resourceDef.type === 'ObjectExpression') {
1164
- var dataSourceIdProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'; });
1165
- var tableNameProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'tableName'; });
1166
- var dataSourceTypeProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'; });
1167
- if (dataSourceIdProp && tableNameProp && dataSourceTypeProp) {
1168
- var dataSourceId = dataSourceIdProp.value.value;
1169
- var tableName = tableNameProp.value.value;
1170
- var dataSourceType = dataSourceTypeProp.value.value;
1171
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
1172
- // Create fetchData attribute with proper fetch chain wrapped in useCallback
1173
- var fetchDataValue = types.callExpression(types.identifier('useCallback'), [
1174
- types.arrowFunctionExpression([types.identifier('params')], types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
1175
- types.templateLiteral([
1176
- types.templateElement({
1177
- raw: "/api/".concat(fileName, "?"),
1178
- cooked: "/api/".concat(fileName, "?"),
1179
- }),
1180
- types.templateElement({ raw: '', cooked: '' }),
1181
- ], [
1182
- types.newExpression(types.identifier('URLSearchParams'), [
1183
- types.identifier('params'),
1184
- ]),
1185
- ]),
1186
- types.objectExpression([
1187
- types.objectProperty(types.identifier('headers'), types.objectExpression([
1188
- types.objectProperty(types.stringLiteral('Content-Type'), types.stringLiteral('application/json')),
1189
- ])),
1190
- ]),
1191
- ]), types.identifier('then')), [
1192
- types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
1193
- ]), types.identifier('then')), [
1194
- types.arrowFunctionExpression([types.identifier('response')], types.optionalMemberExpression(types.identifier('response'), types.identifier('data'), false, true)),
1195
- ])),
1196
- types.arrayExpression([]),
1197
- ]);
1198
- var newFetchDataAttr = types.jsxAttribute(types.jsxIdentifier('fetchData'), types.jsxExpressionContainer(fetchDataValue));
1199
- // Remove existing fetchData attribute if present
1200
- var existingFetchDataIndex = dataProviderJSX.openingElement.attributes.findIndex(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'fetchData'; });
1201
- if (existingFetchDataIndex !== -1) {
1202
- dataProviderJSX.openingElement.attributes[existingFetchDataIndex] = newFetchDataAttr;
1203
- }
1204
- else {
1205
- dataProviderJSX.openingElement.attributes.push(newFetchDataAttr);
1206
- }
1207
- }
1208
- }
873
+ if (!paramsExpression) {
874
+ return;
1209
875
  }
876
+ // Wrap params in useMemo with empty dependencies array
877
+ // This ensures the object reference stays stable across re-renders
878
+ var memoizedParams = types.callExpression(types.identifier('useMemo'), [
879
+ types.arrowFunctionExpression([], paramsExpression),
880
+ types.arrayExpression([]),
881
+ ]);
882
+ // Replace the params attribute
883
+ attrs[paramsAttrIndex] = types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(memoizedParams));
1210
884
  }
1211
- function findChildWithClass(node, classSubstring) {
1212
- var _a;
1213
- if (!node) {
1214
- return null;
1215
- }
1216
- if (node.type === 'JSXElement') {
1217
- var className = getClassName(((_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) || []);
1218
- if (className && className.includes(classSubstring)) {
1219
- return className;
1220
- }
1221
- }
1222
- if (node.children) {
1223
- for (var _i = 0, _b = node.children; _i < _b.length; _i++) {
1224
- var child = _b[_i];
1225
- var found = findChildWithClass(child, classSubstring);
1226
- if (found) {
1227
- return found;
1228
- }
1229
- }
1230
- }
1231
- if (typeof node === 'object') {
1232
- for (var _c = 0, _d = Object.values(node); _c < _d.length; _c++) {
1233
- var value = _d[_c];
1234
- if (Array.isArray(value)) {
1235
- for (var _e = 0, value_1 = value; _e < value_1.length; _e++) {
1236
- var item = value_1[_e];
1237
- var found = findChildWithClass(item, classSubstring);
1238
- if (found) {
1239
- return found;
1240
- }
1241
- }
1242
- }
1243
- else if (typeof value === 'object') {
1244
- var found = findChildWithClass(value, classSubstring);
1245
- if (found) {
1246
- return found;
1247
- }
1248
- }
1249
- }
1250
- }
1251
- return null;
885
+ function createFetchDataAttribute(fileName) {
886
+ return types.jsxAttribute(types.jsxIdentifier('fetchData'), types.jsxExpressionContainer(types.callExpression(types.identifier('useCallback'), [
887
+ types.arrowFunctionExpression([types.identifier('params')], types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
888
+ types.templateLiteral([
889
+ types.templateElement({
890
+ raw: "/api/".concat(fileName, "?"),
891
+ cooked: "/api/".concat(fileName, "?"),
892
+ }),
893
+ types.templateElement({ raw: '', cooked: '' }),
894
+ ], [
895
+ types.newExpression(types.identifier('URLSearchParams'), [
896
+ types.identifier('params'),
897
+ ]),
898
+ ]),
899
+ types.objectExpression([
900
+ types.objectProperty(types.identifier('headers'), types.objectExpression([
901
+ types.objectProperty(types.stringLiteral('Content-Type'), types.stringLiteral('application/json')),
902
+ ])),
903
+ ]),
904
+ ]), types.identifier('then')), [
905
+ types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
906
+ ]), types.identifier('then')), [
907
+ types.arrowFunctionExpression([types.identifier('response')], types.optionalMemberExpression(types.identifier('response'), types.identifier('data'), false, true)),
908
+ ])),
909
+ types.arrayExpression([]),
910
+ ])));
1252
911
  }
1253
- function modifyPaginationButtons(blockStatement, detectedPaginations, paginationInfos) {
1254
- var modifiedButtons = new Set();
1255
- var modifyNode = function (node) {
912
+ function wireSearchInput(inputNode, vars) {
913
+ // Remove existing onChange and value
914
+ inputNode.openingElement.attributes = inputNode.openingElement.attributes.filter(function (attr) { var _a; return !['onChange', 'value'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name); });
915
+ // Add onChange
916
+ inputNode.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onChange'), types.jsxExpressionContainer(types.arrowFunctionExpression([types.identifier('e')], types.callExpression(types.identifier(vars.setSearchQueryVar), [
917
+ types.memberExpression(types.memberExpression(types.identifier('e'), types.identifier('target')), types.identifier('value')),
918
+ ])))));
919
+ // Add value
920
+ inputNode.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('value'), types.jsxExpressionContainer(types.identifier(vars.searchQueryVar))));
921
+ }
922
+ function wirePaginationButtons(paginationNode, usage, vars) {
923
+ // Find prev and next buttons
924
+ var findButton = function (node, direction) {
925
+ var _a, _b, _c, _d, _e;
1256
926
  if (!node) {
1257
- return;
927
+ return null;
1258
928
  }
1259
929
  if (node.type === 'JSXElement') {
1260
- var openingElement = node.openingElement;
1261
- if (openingElement && openingElement.name && openingElement.name.type === 'JSXIdentifier') {
1262
- var className = getClassName(openingElement.attributes);
1263
- if (className && !modifiedButtons.has(node)) {
1264
- for (var index = 0; index < detectedPaginations.length; index++) {
1265
- var detected = detectedPaginations[index];
1266
- var info = paginationInfos[index];
1267
- if (!info) {
1268
- continue;
1269
- }
1270
- if (className === detected.prevButtonClass) {
1271
- convertToButton(node, info, 'prev');
1272
- modifiedButtons.add(node);
1273
- break;
1274
- }
1275
- else if (className === detected.nextButtonClass) {
1276
- convertToButton(node, info, 'next');
1277
- modifiedButtons.add(node);
1278
- break;
1279
- }
1280
- }
1281
- }
930
+ var classAttr = (_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) === null || _b === void 0 ? void 0 : _b.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
931
+ var className = ((_c = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _c === void 0 ? void 0 : _c.value) || ((_e = (_d = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _d === void 0 ? void 0 : _d.expression) === null || _e === void 0 ? void 0 : _e.value) || '';
932
+ if (className.includes(direction)) {
933
+ return node;
1282
934
  }
1283
935
  }
1284
- if (typeof node === 'object') {
1285
- Object.values(node).forEach(function (value) {
1286
- if (Array.isArray(value)) {
1287
- value.forEach(function (item) { return modifyNode(item); });
1288
- }
1289
- else if (typeof value === 'object') {
1290
- modifyNode(value);
936
+ if (node.children && Array.isArray(node.children)) {
937
+ for (var _i = 0, _f = node.children; _i < _f.length; _i++) {
938
+ var c = _f[_i];
939
+ var found = findButton(c, direction);
940
+ if (found) {
941
+ return found;
1291
942
  }
1292
- });
943
+ }
1293
944
  }
945
+ return null;
1294
946
  };
1295
- modifyNode(blockStatement);
1296
- }
1297
- function modifySearchInputs(blockStatement, detectedPaginations, paginationInfos) {
1298
- var modifiedInputs = new Set();
1299
- var modifyNode = function (node) {
1300
- if (!node) {
1301
- return;
947
+ var prevButton = findButton(paginationNode, 'previous');
948
+ var nextButton = findButton(paginationNode, 'next');
949
+ var isCombinedState = usage.category === 'paginated+search';
950
+ if (prevButton) {
951
+ // Change to button element
952
+ prevButton.openingElement.name.name = 'button';
953
+ if (prevButton.closingElement) {
954
+ prevButton.closingElement.name.name = 'button';
1302
955
  }
1303
- if (node.type === 'JSXElement') {
1304
- var openingElement = node.openingElement;
1305
- if (openingElement && openingElement.name && openingElement.name.type === 'JSXIdentifier') {
1306
- var className = getClassName(openingElement.attributes);
1307
- if (className && !modifiedInputs.has(node)) {
1308
- for (var index = 0; index < detectedPaginations.length; index++) {
1309
- var detected = detectedPaginations[index];
1310
- var info = paginationInfos[index];
1311
- if (!info || !info.searchEnabled) {
1312
- continue;
1313
- }
1314
- if (className === detected.searchInputClass) {
1315
- addSearchInputHandlers(node, info);
1316
- modifiedInputs.add(node);
1317
- break;
1318
- }
1319
- }
1320
- }
1321
- }
1322
- }
1323
- if (typeof node === 'object') {
1324
- Object.values(node).forEach(function (value) {
1325
- if (Array.isArray(value)) {
1326
- value.forEach(function (item) { return modifyNode(item); });
1327
- }
1328
- else if (typeof value === 'object') {
1329
- modifyNode(value);
1330
- }
1331
- });
956
+ // Add type="button"
957
+ var hasType = prevButton.openingElement.attributes.some(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) === 'type'; });
958
+ if (!hasType) {
959
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('type'), types.stringLiteral('button')));
1332
960
  }
1333
- };
1334
- modifyNode(blockStatement);
1335
- }
1336
- function addSearchInputHandlers(jsxElement, info) {
1337
- if (!info.searchQueryVar || !info.setSearchQueryVar) {
1338
- return;
1339
- }
1340
- var openingElement = jsxElement.openingElement;
1341
- removeAttribute(openingElement.attributes, 'onChange');
1342
- removeAttribute(openingElement.attributes, 'value');
1343
- var onChangeHandler = types.arrowFunctionExpression([types.identifier('e')], types.callExpression(types.identifier(info.setSearchQueryVar), [
1344
- types.memberExpression(types.memberExpression(types.identifier('e'), types.identifier('target')), types.identifier('value')),
1345
- ]));
1346
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onChange'), types.jsxExpressionContainer(onChangeHandler)));
1347
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('value'), types.jsxExpressionContainer(types.identifier(info.searchQueryVar))));
1348
- }
1349
- function convertToButton(jsxElement, info, buttonType) {
1350
- var openingElement = jsxElement.openingElement;
1351
- if (openingElement.name.type === 'JSXIdentifier') {
1352
- openingElement.name.name = 'button';
1353
- }
1354
- if (jsxElement.closingElement && jsxElement.closingElement.name.type === 'JSXIdentifier') {
1355
- jsxElement.closingElement.name.name = 'button';
1356
- }
1357
- removeAttribute(openingElement.attributes, 'onClick');
1358
- removeAttribute(openingElement.attributes, 'disabled');
1359
- removeAttribute(openingElement.attributes, 'type');
1360
- var combinedStateVar = info.combinedStateVar;
1361
- var setCombinedStateVar = info.setCombinedStateVar;
1362
- var onClickHandler;
1363
- if (info.searchEnabled && combinedStateVar && setCombinedStateVar) {
1364
- // Use combined state: update only the page property
1365
- onClickHandler =
1366
- buttonType === 'prev'
1367
- ? types.arrowFunctionExpression([], types.callExpression(types.identifier(setCombinedStateVar), [
1368
- types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
1369
- types.spreadElement(types.identifier('state')),
1370
- types.objectProperty(types.identifier('page'), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
1371
- types.numericLiteral(1),
1372
- types.binaryExpression('-', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1)),
1373
- ])),
1374
- ])),
1375
- ]))
1376
- : types.arrowFunctionExpression([], types.callExpression(types.identifier(setCombinedStateVar), [
1377
- types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
1378
- types.spreadElement(types.identifier('state')),
1379
- types.objectProperty(types.identifier('page'), types.binaryExpression('+', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1))),
1380
- ])),
1381
- ]));
1382
- }
1383
- else {
1384
- // Regular pagination (no search)
1385
- onClickHandler =
1386
- buttonType === 'prev'
1387
- ? types.arrowFunctionExpression([], types.callExpression(types.identifier(info.setPageStateVar), [
1388
- types.arrowFunctionExpression([types.identifier('p')], types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
961
+ // Add onClick
962
+ prevButton.openingElement.attributes = prevButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'onClick'; });
963
+ if (isCombinedState) {
964
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setCombinedStateVar), [
965
+ types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
966
+ types.spreadElement(types.identifier('state')),
967
+ types.objectProperty(types.identifier('page'), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
1389
968
  types.numericLiteral(1),
1390
- types.binaryExpression('-', types.identifier('p'), types.numericLiteral(1)),
969
+ types.binaryExpression('-', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1)),
1391
970
  ])),
1392
- ]))
1393
- : types.arrowFunctionExpression([], types.callExpression(types.identifier(info.setPageStateVar), [
1394
- types.arrowFunctionExpression([types.identifier('p')], types.binaryExpression('+', types.identifier('p'), types.numericLiteral(1))),
1395
- ]));
1396
- }
1397
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(onClickHandler)));
1398
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('type'), types.stringLiteral('button')));
1399
- // Add disabled attribute with simple page number checks
1400
- var maxPagesStateVar = info.maxPagesStateVar;
1401
- var disabledExpr;
1402
- if (info.searchEnabled && combinedStateVar) {
1403
- disabledExpr =
1404
- buttonType === 'prev'
1405
- ? types.binaryExpression('<=', types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')), types.numericLiteral(1))
1406
- : types.binaryExpression('>=', types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')), types.identifier(maxPagesStateVar));
1407
- }
1408
- else {
1409
- disabledExpr =
1410
- buttonType === 'prev'
1411
- ? types.binaryExpression('<=', types.identifier(info.pageStateVar), types.numericLiteral(1))
1412
- : types.binaryExpression('>=', types.identifier(info.pageStateVar), types.identifier(maxPagesStateVar));
971
+ ])),
972
+ ])))));
973
+ // Add disabled
974
+ prevButton.openingElement.attributes = prevButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
975
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('<=', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')), types.numericLiteral(1)))));
976
+ }
977
+ else {
978
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setPageStateVar), [
979
+ types.arrowFunctionExpression([types.identifier('page')], types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
980
+ types.numericLiteral(1),
981
+ types.binaryExpression('-', types.identifier('page'), types.numericLiteral(1)),
982
+ ])),
983
+ ])))));
984
+ prevButton.openingElement.attributes = prevButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
985
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('<=', types.identifier(vars.pageStateVar), types.numericLiteral(1)))));
986
+ }
1413
987
  }
1414
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(disabledExpr)));
1415
- }
1416
- function getClassName(attributes) {
1417
- var classNameAttr = attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
1418
- if (classNameAttr && classNameAttr.value && classNameAttr.value.type === 'StringLiteral') {
1419
- return classNameAttr.value.value;
988
+ if (nextButton) {
989
+ nextButton.openingElement.name.name = 'button';
990
+ if (nextButton.closingElement) {
991
+ nextButton.closingElement.name.name = 'button';
992
+ }
993
+ var hasType = nextButton.openingElement.attributes.some(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) === 'type'; });
994
+ if (!hasType) {
995
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('type'), types.stringLiteral('button')));
996
+ }
997
+ nextButton.openingElement.attributes = nextButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'onClick'; });
998
+ if (isCombinedState) {
999
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setCombinedStateVar), [
1000
+ types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
1001
+ types.spreadElement(types.identifier('state')),
1002
+ types.objectProperty(types.identifier('page'), types.binaryExpression('+', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1))),
1003
+ ])),
1004
+ ])))));
1005
+ nextButton.openingElement.attributes = nextButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
1006
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('>=', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')), types.identifier(vars.maxPagesStateVar)))));
1007
+ }
1008
+ else {
1009
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setPageStateVar), [
1010
+ types.arrowFunctionExpression([types.identifier('page')], types.binaryExpression('+', types.identifier('page'), types.numericLiteral(1))),
1011
+ ])))));
1012
+ nextButton.openingElement.attributes = nextButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
1013
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('>=', types.identifier(vars.pageStateVar), types.identifier(vars.maxPagesStateVar)))));
1014
+ }
1420
1015
  }
1421
- return null;
1422
1016
  }
1423
- function removeAttribute(attrs, attributeName) {
1424
- var index = attrs.findIndex(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === attributeName; });
1425
- if (index !== -1) {
1426
- attrs.splice(index, 1);
1017
+ function ensureAPIRouteExists(extractedResources, usage) {
1018
+ // Generate file name for the API route
1019
+ var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
1020
+ // Check if the utils data source file exists - if so, create API routes that re-export from it
1021
+ if (extractedResources["utils/".concat(fileName)]) {
1022
+ // Create main data API route if not exists
1023
+ if (!extractedResources["api/".concat(fileName)]) {
1024
+ var apiRouteCode = "import dataSourceModule from '../../utils/data-sources/".concat(fileName, "'\n\nexport default dataSourceModule.handler\n");
1025
+ extractedResources["api/".concat(fileName)] = {
1026
+ fileName: fileName,
1027
+ fileType: teleport_types_1.FileType.JS,
1028
+ path: ['pages', 'api'],
1029
+ content: apiRouteCode,
1030
+ };
1031
+ }
1032
+ // Create count API route if not exists (needed for paginated+search cases)
1033
+ var countFileName = "".concat(fileName, "-count");
1034
+ if (!extractedResources["api/".concat(countFileName)]) {
1035
+ var countApiRouteCode = "import dataSourceModule from '../../utils/data-sources/".concat(fileName, "'\n\nexport default dataSourceModule.getCount\n");
1036
+ extractedResources["api/".concat(countFileName)] = {
1037
+ fileName: countFileName,
1038
+ fileType: teleport_types_1.FileType.JS,
1039
+ path: ['pages', 'api'],
1040
+ content: countApiRouteCode,
1041
+ };
1042
+ }
1427
1043
  }
1428
1044
  }
1429
- function modifyGetStaticPropsForPagination(chunks, paginationInfos) {
1045
+ function updateGetStaticProps(chunks, registry) {
1430
1046
  var _a;
1431
- var getStaticPropsChunk = chunks.find(function (chunk) { return chunk.name === 'getStaticProps'; });
1432
- if (!getStaticPropsChunk || getStaticPropsChunk.type !== 'ast') {
1047
+ var getStaticPropsChunk = chunks.find(function (c) { return c.name === 'getStaticProps'; });
1048
+ if (!getStaticPropsChunk || getStaticPropsChunk.type !== teleport_types_1.ChunkType.AST) {
1433
1049
  return;
1434
1050
  }
1435
- var exportDeclaration = getStaticPropsChunk.content;
1436
- if (!exportDeclaration || exportDeclaration.type !== 'ExportNamedDeclaration') {
1051
+ var content = getStaticPropsChunk.content;
1052
+ if (!content.declaration || content.declaration.type !== 'FunctionDeclaration') {
1437
1053
  return;
1438
1054
  }
1439
- var functionDeclaration = exportDeclaration.declaration;
1440
- if (!functionDeclaration || functionDeclaration.type !== 'FunctionDeclaration') {
1055
+ var funcBody = content.declaration.body;
1056
+ var tryStmt = funcBody.body.find(function (s) { return s.type === 'TryStatement'; });
1057
+ if (!tryStmt) {
1441
1058
  return;
1442
1059
  }
1443
- // Find Promise.all and add NEW fetchData calls for each paginated DataProvider
1444
- var functionBody = functionDeclaration.body.body;
1445
- var tryBlock = functionBody.find(function (stmt) { return stmt.type === 'TryStatement'; });
1446
- if (!tryBlock) {
1447
- return;
1448
- }
1449
- var tryBody = tryBlock.block.body;
1450
- // Find the Promise.all statement
1451
- var promiseAllStmt = tryBody.find(function (stmt) {
1060
+ var tryBlock = tryStmt.block;
1061
+ // Find existing Promise.all
1062
+ var promiseAllDecl = tryBlock.body.find(function (s) {
1452
1063
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
1453
- return stmt.type === 'VariableDeclaration' &&
1454
- ((_c = (_b = (_a = stmt.declarations) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.init) === null || _c === void 0 ? void 0 : _c.type) === 'AwaitExpression' &&
1455
- ((_g = (_f = (_e = (_d = stmt.declarations) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.init) === null || _f === void 0 ? void 0 : _f.argument) === null || _g === void 0 ? void 0 : _g.type) === 'CallExpression' &&
1456
- ((_m = (_l = (_k = (_j = (_h = stmt.declarations) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.init) === null || _k === void 0 ? void 0 : _k.argument) === null || _l === void 0 ? void 0 : _l.callee) === null || _m === void 0 ? void 0 : _m.type) === 'MemberExpression' &&
1457
- ((_t = (_s = (_r = (_q = (_p = (_o = stmt.declarations) === null || _o === void 0 ? void 0 : _o[0]) === null || _p === void 0 ? void 0 : _p.init) === null || _q === void 0 ? void 0 : _q.argument) === null || _r === void 0 ? void 0 : _r.callee) === null || _s === void 0 ? void 0 : _s.property) === null || _t === void 0 ? void 0 : _t.name) === 'all';
1064
+ return s.type === 'VariableDeclaration' &&
1065
+ ((_c = (_b = (_a = s.declarations) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.init) === null || _c === void 0 ? void 0 : _c.type) === 'AwaitExpression' &&
1066
+ ((_g = (_f = (_e = (_d = s.declarations) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.init) === null || _f === void 0 ? void 0 : _f.argument) === null || _g === void 0 ? void 0 : _g.type) === 'CallExpression' &&
1067
+ ((_m = (_l = (_k = (_j = (_h = s.declarations) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.init) === null || _k === void 0 ? void 0 : _k.argument) === null || _l === void 0 ? void 0 : _l.callee) === null || _m === void 0 ? void 0 : _m.type) === 'MemberExpression' &&
1068
+ ((_t = (_s = (_r = (_q = (_p = (_o = s.declarations) === null || _o === void 0 ? void 0 : _o[0]) === null || _p === void 0 ? void 0 : _p.init) === null || _q === void 0 ? void 0 : _q.argument) === null || _r === void 0 ? void 0 : _r.callee) === null || _s === void 0 ? void 0 : _s.object) === null || _t === void 0 ? void 0 : _t.name) === 'Promise';
1458
1069
  });
1459
- if (!promiseAllStmt) {
1070
+ if (!promiseAllDecl) {
1460
1071
  return;
1461
1072
  }
1462
- var awaitExpr = promiseAllStmt.declarations[0].init;
1073
+ var declarator = promiseAllDecl.declarations[0];
1074
+ var awaitExpr = declarator.init;
1463
1075
  var promiseAllCall = awaitExpr.argument;
1464
- var promiseArray = promiseAllCall.arguments[0];
1465
- var destructuringPattern = promiseAllStmt.declarations[0].id;
1466
- // Map import names to data source identifiers from existing fetchData calls
1467
- // Also track which indices to remove (non-paginated calls that will be replaced)
1468
- var importToDataSource = new Map();
1469
- var indicesToRemove = [];
1470
- promiseArray.elements.forEach(function (element, index) {
1471
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1472
- if (element && element.type === 'CallExpression') {
1473
- var fetchCallExpr = element;
1474
- // If wrapped in .catch(), unwrap it
1475
- if (((_a = element.callee) === null || _a === void 0 ? void 0 : _a.type) === 'MemberExpression' &&
1476
- ((_c = (_b = element.callee) === null || _b === void 0 ? void 0 : _b.property) === null || _c === void 0 ? void 0 : _c.name) === 'catch' &&
1477
- ((_e = (_d = element.callee) === null || _d === void 0 ? void 0 : _d.object) === null || _e === void 0 ? void 0 : _e.type) === 'CallExpression') {
1478
- fetchCallExpr = element.callee.object;
1479
- }
1480
- // Now find the .fetchData() call
1481
- if (((_f = fetchCallExpr.callee) === null || _f === void 0 ? void 0 : _f.type) === 'MemberExpression' &&
1482
- ((_h = (_g = fetchCallExpr.callee) === null || _g === void 0 ? void 0 : _g.property) === null || _h === void 0 ? void 0 : _h.name) === 'fetchData' &&
1483
- ((_k = (_j = fetchCallExpr.callee) === null || _j === void 0 ? void 0 : _j.object) === null || _k === void 0 ? void 0 : _k.type) === 'Identifier') {
1484
- var importName = fetchCallExpr.callee.object.name;
1485
- var dataSourceVar_1 = destructuringPattern.elements[index].name;
1486
- // Check if this fetchData call has page/perPage params
1487
- var params = fetchCallExpr.arguments[0];
1488
- var hasPageParam = params &&
1489
- params.type === 'ObjectExpression' &&
1490
- params.properties.some(function (prop) {
1491
- return prop.type === 'ObjectProperty' &&
1492
- (prop.key.name === 'page' || prop.key.name === 'perPage');
1493
- });
1494
- // If this is a data source that will be paginated but this call has NO pagination params,
1495
- // mark it for removal
1496
- if (!hasPageParam &&
1497
- paginationInfos.some(function (info) { return info.dataSourceIdentifier === dataSourceVar_1; })) {
1498
- indicesToRemove.push(index);
1499
- }
1500
- importToDataSource.set(importName, dataSourceVar_1);
1501
- }
1076
+ var fetchesArray = promiseAllCall.arguments[0];
1077
+ // Find return statement
1078
+ var returnStmt = tryBlock.body.find(function (s) { return s.type === 'ReturnStatement'; });
1079
+ if (!returnStmt || ((_a = returnStmt.argument) === null || _a === void 0 ? void 0 : _a.type) !== 'ObjectExpression') {
1080
+ return;
1081
+ }
1082
+ var returnObj = returnStmt.argument;
1083
+ var propsProperty = returnObj.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.type === 'Identifier' && p.key.name === 'props'; });
1084
+ if (!propsProperty || propsProperty.value.type !== 'ObjectExpression') {
1085
+ return;
1086
+ }
1087
+ var propsObj = propsProperty.value;
1088
+ var arrayPattern = declarator.id;
1089
+ // Track unique data sources for count fetching
1090
+ var dataSourcesNeedingCount = new Set();
1091
+ registry.usages.forEach(function (usage) {
1092
+ var vars = getStateVarsForUsage(usage);
1093
+ var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
1094
+ // Use consistent import name generation (matches extractDataSourceIntoGetStaticProps)
1095
+ var fetcherImportName = teleport_shared_1.StringUtils.dashCaseToCamelCase(fileName);
1096
+ // Add fetch call
1097
+ var fetchParams = [];
1098
+ if (usage.paginated) {
1099
+ // For paginated array mappers, add page and perPage
1100
+ fetchParams.push(types.objectProperty(types.identifier('page'), types.numericLiteral(1)));
1101
+ fetchParams.push(types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)));
1502
1102
  }
1503
- });
1504
- // Remove non-paginated fetchData calls in reverse order to preserve indices
1505
- indicesToRemove.reverse().forEach(function (index) {
1506
- var _a, _b;
1507
- // Get the prop name BEFORE removing it
1508
- var propToRemove = (_a = destructuringPattern.elements[index]) === null || _a === void 0 ? void 0 : _a.name;
1509
- promiseArray.elements.splice(index, 1);
1510
- destructuringPattern.elements.splice(index, 1);
1511
- // Also remove from props in return statement
1512
- if (propToRemove) {
1513
- var foundReturnStmt = tryBody.find(function (stmt) { return stmt.type === 'ReturnStatement'; });
1514
- if (foundReturnStmt && ((_b = foundReturnStmt.argument) === null || _b === void 0 ? void 0 : _b.type) === 'ObjectExpression') {
1515
- var propsProperty = foundReturnStmt.argument.properties.find(function (prop) {
1516
- return prop.type === 'ObjectProperty' && prop.key.name === 'props';
1517
- });
1518
- if (propsProperty && propsProperty.value.type === 'ObjectExpression') {
1519
- var propsObject = propsProperty.value;
1520
- var propIndex = propsObject.properties.findIndex(function (prop) {
1521
- return prop.type === 'ObjectProperty' && prop.key.name === propToRemove;
1522
- });
1523
- if (propIndex !== -1) {
1524
- propsObject.properties.splice(propIndex, 1);
1525
- }
1526
- }
1527
- }
1103
+ else if (usage.perPage > 0) {
1104
+ // For non-paginated array mappers with a limit, add the limit as perPage
1105
+ // This ensures the initial data fetch respects the limit from the UIDL
1106
+ fetchParams.push(types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)));
1528
1107
  }
1529
- });
1530
- // Add NEW fetchData calls for each paginated DataProvider
1531
- paginationInfos.forEach(function (info, index) {
1532
- var _a, _b;
1533
- // Try exact match first, then case-insensitive match
1534
- var importName = (_a = Array.from(importToDataSource.entries()).find(function (_a) {
1535
- var _ = _a[0], dataSourceVar = _a[1];
1536
- return dataSourceVar === info.dataSourceIdentifier;
1537
- })) === null || _a === void 0 ? void 0 : _a[0];
1538
- if (!importName) {
1539
- // Try case-insensitive match
1540
- var normalizedIdentifier_1 = info.dataSourceIdentifier.toLowerCase().replace(/[_-]/g, '');
1541
- importName = (_b = Array.from(importToDataSource.entries()).find(function (_a) {
1542
- var _ = _a[0], dataSourceVar = _a[1];
1543
- return dataSourceVar.toLowerCase().replace(/[_-]/g, '') === normalizedIdentifier_1;
1544
- })) === null || _b === void 0 ? void 0 : _b[0];
1108
+ if (usage.queryColumns.length > 0) {
1109
+ fetchParams.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
1545
1110
  }
1546
- if (importName) {
1547
- var paginatedVarName = "".concat(info.dataSourceIdentifier, "_pg_").concat(index);
1548
- var fetchParams = [
1549
- types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
1550
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(info.perPage)),
1551
- ];
1552
- // Add queryColumns if they exist
1553
- if (info.queryColumns && info.queryColumns.length > 0) {
1554
- fetchParams.push(types.objectProperty(types.identifier('queryColumns'), types.arrayExpression(info.queryColumns.map(function (col) { return types.stringLiteral(col); }))));
1555
- }
1556
- // Create new fetchData call with pagination params
1557
- var newFetchDataCall = types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(importName), types.identifier('fetchData')), [types.objectExpression(fetchParams)]), types.identifier('catch')), [
1111
+ // Check if this fetch already exists
1112
+ var existingFetchIndex = arrayPattern.elements.findIndex(function (el) { return (el === null || el === void 0 ? void 0 : el.type) === 'Identifier' && el.name === vars.propsPrefix; });
1113
+ if (existingFetchIndex === -1) {
1114
+ arrayPattern.elements.push(types.identifier(vars.propsPrefix));
1115
+ fetchesArray.elements.push(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchData')), [types.objectExpression(fetchParams)]), types.identifier('catch')), [
1558
1116
  types.arrowFunctionExpression([types.identifier('error')], types.blockStatement([
1559
1117
  types.expressionStatement(types.callExpression(types.memberExpression(types.identifier('console'), types.identifier('error')), [
1560
- types.stringLiteral("Error fetching ".concat(paginatedVarName, ":")),
1118
+ types.stringLiteral("Error fetching ".concat(vars.propsPrefix, ":")),
1561
1119
  types.identifier('error'),
1562
1120
  ])),
1563
1121
  types.returnStatement(types.arrayExpression([])),
1564
1122
  ])),
1565
- ]);
1566
- promiseArray.elements.push(newFetchDataCall);
1567
- destructuringPattern.elements.push(types.identifier(paginatedVarName));
1568
- }
1569
- });
1570
- // Add fetchCount calls for paginated data sources (deduplicated by data source)
1571
- // Deduplicate by data source identifier
1572
- var uniqueDataSources = new Set(paginationInfos.map(function (info) { return info.dataSourceIdentifier; }));
1573
- var addedCountFetches = new Set();
1574
- uniqueDataSources.forEach(function (dataSourceId) {
1575
- var _a, _b;
1576
- var importName = (_a = Array.from(importToDataSource.entries()).find(function (_a) {
1577
- var _ = _a[0], dataSourceVar = _a[1];
1578
- return dataSourceVar === dataSourceId;
1579
- })) === null || _a === void 0 ? void 0 : _a[0];
1580
- if (!importName) {
1581
- // Try case-insensitive match
1582
- var normalizedIdentifier_2 = dataSourceId.toLowerCase().replace(/[_-]/g, '');
1583
- importName = (_b = Array.from(importToDataSource.entries()).find(function (_a) {
1584
- var _ = _a[0], dataSourceVar = _a[1];
1585
- return dataSourceVar.toLowerCase().replace(/[_-]/g, '') === normalizedIdentifier_2;
1586
- })) === null || _b === void 0 ? void 0 : _b[0];
1123
+ ]));
1124
+ // Add to props
1125
+ propsObj.properties.push(types.objectProperty(types.identifier(vars.propsPrefix), types.identifier(vars.propsPrefix)));
1587
1126
  }
1588
- if (importName && !addedCountFetches.has(dataSourceId)) {
1589
- var fetchCountCall = types.callExpression(types.memberExpression(types.identifier(importName), types.identifier('fetchCount')), []);
1590
- promiseArray.elements.push(fetchCountCall);
1591
- destructuringPattern.elements.push(types.identifier("".concat(dataSourceId, "_count")));
1592
- addedCountFetches.add(dataSourceId);
1127
+ // Track for count fetching
1128
+ if (usage.paginated) {
1129
+ dataSourcesNeedingCount.add("".concat(usage.resourceDefinition.dataSourceType, ":").concat(usage.resourceDefinition.tableName, ":").concat(usage.resourceDefinition.dataSourceId));
1593
1130
  }
1594
- });
1595
- // Calculate and add maxPages before return
1596
- var returnStmt = tryBody.find(function (stmt) { return stmt.type === 'ReturnStatement'; });
1597
- if (returnStmt && ((_a = returnStmt.argument) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
1598
- var propsProperty = returnStmt.argument.properties.find(function (prop) {
1599
- return prop.type === 'ObjectProperty' && prop.key.name === 'props';
1600
- });
1601
- if (propsProperty && propsProperty.value.type === 'ObjectExpression') {
1602
- var propsObject_1 = propsProperty.value;
1603
- var returnIndex_1 = tryBody.indexOf(returnStmt);
1604
- paginationInfos.forEach(function (info, index) {
1605
- var paginatedVarName = "".concat(info.dataSourceIdentifier, "_pg_").concat(index);
1606
- var countVarName = "".concat(info.dataSourceIdentifier, "_count");
1607
- var maxPagesVarName = "".concat(info.dataSourceIdentifier, "_pg_").concat(index, "_maxPages");
1608
- var maxPagesCalc = types.variableDeclaration('const', [
1609
- types.variableDeclarator(types.identifier(maxPagesVarName), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
1610
- types.binaryExpression('/', types.logicalExpression('||', types.identifier(countVarName), types.numericLiteral(0)), types.numericLiteral(info.perPage)),
1131
+ // Add maxPages calculation for paginated
1132
+ if (usage.paginated) {
1133
+ var maxPagesPropName_1 = "".concat(vars.propsPrefix, "_maxPages");
1134
+ var countVarName = "".concat(usage.dataSourceIdentifier, "_count");
1135
+ // Check if maxPages calculation already exists
1136
+ var existingMaxPages = tryBlock.body.find(function (s) { var _a, _b, _c; return s.type === 'VariableDeclaration' && ((_c = (_b = (_a = s.declarations) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id) === null || _c === void 0 ? void 0 : _c.name) === maxPagesPropName_1; });
1137
+ if (!existingMaxPages) {
1138
+ // Insert maxPages calculation before return
1139
+ var returnIndex = tryBlock.body.indexOf(returnStmt);
1140
+ tryBlock.body.splice(returnIndex, 0, types.variableDeclaration('const', [
1141
+ types.variableDeclarator(types.identifier(maxPagesPropName_1), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
1142
+ types.binaryExpression('/', types.logicalExpression('||', types.identifier(countVarName), types.numericLiteral(0)), types.numericLiteral(usage.perPage)),
1611
1143
  ])),
1612
- ]);
1613
- tryBody.splice(returnIndex_1, 0, maxPagesCalc);
1614
- // Add both the paginated data and maxPages to props
1615
- propsObject_1.properties.push(types.objectProperty(types.identifier(paginatedVarName), types.identifier(paginatedVarName)));
1616
- propsObject_1.properties.push(types.objectProperty(types.identifier(maxPagesVarName), types.identifier(maxPagesVarName)));
1617
- });
1618
- }
1619
- }
1620
- }
1621
- function createAPIRoutesForPaginatedDataSources(uidlNode, dataSources, componentChunk, extractedResources, paginationInfos, isComponent) {
1622
- var paginatedDataSourceIds = new Set(paginationInfos.map(function (info) { return info.dataSourceIdentifier; }));
1623
- var searchEnabledDataSources = new Set(paginationInfos.filter(function (info) { return info.searchEnabled; }).map(function (info) { return info.dataSourceIdentifier; }));
1624
- var createdCountRoutes = new Set();
1625
- var traverseForDataSources = function (node) {
1626
- var _a;
1627
- if (!node) {
1628
- return;
1629
- }
1630
- if (node.type === 'data-source-list' || node.type === 'data-source-item') {
1631
- var renderProp = node.content.renderPropIdentifier;
1632
- if (renderProp && paginatedDataSourceIds.has(renderProp)) {
1633
- (0, utils_1.extractDataSourceIntoNextAPIFolder)(node, dataSources, componentChunk, extractedResources);
1634
- var hasSearch = searchEnabledDataSources.has(renderProp);
1635
- var needsCountRoute = isComponent || hasSearch;
1636
- if (needsCountRoute) {
1637
- var resourceDef = node.content.resourceDefinition;
1638
- if (resourceDef) {
1639
- var dataSourceId = resourceDef.dataSourceId;
1640
- var tableName = resourceDef.tableName;
1641
- var dataSourceType = resourceDef.dataSourceType;
1642
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
1643
- var countFileName = "".concat(fileName, "-count");
1644
- if (!createdCountRoutes.has(countFileName)) {
1645
- extractedResources["api/".concat(countFileName)] = {
1646
- fileName: countFileName,
1647
- fileType: teleport_types_1.FileType.JS,
1648
- path: ['pages', 'api'],
1649
- content: "import dataSource from '../../utils/data-sources/".concat(fileName, "'\n\nexport default dataSource.getCount\n"),
1650
- };
1651
- createdCountRoutes.add(countFileName);
1652
- }
1653
- }
1654
- }
1144
+ ]));
1145
+ // Add maxPages to props
1146
+ propsObj.properties.push(types.objectProperty(types.identifier(maxPagesPropName_1), types.identifier(maxPagesPropName_1)));
1655
1147
  }
1656
1148
  }
1657
- if ((_a = node.content) === null || _a === void 0 ? void 0 : _a.children) {
1658
- node.content.children.forEach(function (child) { return traverseForDataSources(child); });
1659
- }
1660
- };
1661
- traverseForDataSources(uidlNode);
1662
- }
1663
- function createAPIRoutesForSearchOnlyDataSources(uidlNode, dataSources, componentChunk, extractedResources, searchOnlyDataSources) {
1664
- var searchOnlyDataSourceIds = new Set(searchOnlyDataSources.map(function (info) { return info.dataSourceIdentifier; }));
1665
- var traverseForDataSources = function (node) {
1666
- var _a;
1667
- if (!node) {
1149
+ });
1150
+ // Add count fetches for unique data sources
1151
+ dataSourcesNeedingCount.forEach(function (key) {
1152
+ var _a = key.split(':'), dataSourceType = _a[0], tableName = _a[1], dataSourceId = _a[2];
1153
+ var fileName = (0, utils_1.generateSafeFileName)(dataSourceType, tableName, dataSourceId);
1154
+ // Use consistent import name generation (matches extractDataSourceIntoGetStaticProps)
1155
+ var fetcherImportName = teleport_shared_1.StringUtils.dashCaseToCamelCase(fileName);
1156
+ // Find usage to get dataSourceIdentifier
1157
+ var usage = registry.usages.find(function (u) {
1158
+ return u.resourceDefinition.dataSourceId === dataSourceId &&
1159
+ u.resourceDefinition.tableName === tableName;
1160
+ });
1161
+ if (!usage) {
1668
1162
  return;
1669
1163
  }
1670
- if (node.type === 'data-source-list' || node.type === 'data-source-item') {
1671
- var renderProp = node.content.renderPropIdentifier;
1672
- if (renderProp && searchOnlyDataSourceIds.has(renderProp)) {
1673
- (0, utils_1.extractDataSourceIntoNextAPIFolder)(node, dataSources, componentChunk, extractedResources);
1674
- }
1675
- }
1676
- if ((_a = node.content) === null || _a === void 0 ? void 0 : _a.children) {
1677
- node.content.children.forEach(function (child) { return traverseForDataSources(child); });
1164
+ var countVarName = "".concat(usage.dataSourceIdentifier, "_count");
1165
+ // Check if count fetch already exists
1166
+ var existingCount = arrayPattern.elements.findIndex(function (el) { return (el === null || el === void 0 ? void 0 : el.type) === 'Identifier' && el.name === countVarName; });
1167
+ if (existingCount === -1) {
1168
+ arrayPattern.elements.push(types.identifier(countVarName));
1169
+ fetchesArray.elements.push(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchCount')), []));
1678
1170
  }
1679
- };
1680
- traverseForDataSources(uidlNode);
1171
+ });
1681
1172
  }
1682
- exports.default = (0, exports.createNextArrayMapperPaginationPlugin)();
1683
1173
  //# sourceMappingURL=pagination-plugin.js.map