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