@teleporthq/teleport-plugin-next-data-source 0.42.1 → 0.42.3

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 (59) hide show
  1. package/dist/cjs/count-fetchers.d.ts.map +1 -1
  2. package/dist/cjs/count-fetchers.js +1 -1
  3. package/dist/cjs/count-fetchers.js.map +1 -1
  4. package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
  5. package/dist/cjs/fetchers/clickhouse.js +1 -1
  6. package/dist/cjs/fetchers/clickhouse.js.map +1 -1
  7. package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
  8. package/dist/cjs/fetchers/firestore.js +1 -1
  9. package/dist/cjs/fetchers/firestore.js.map +1 -1
  10. package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
  11. package/dist/cjs/fetchers/javascript.js +1 -1
  12. package/dist/cjs/fetchers/javascript.js.map +1 -1
  13. package/dist/cjs/fetchers/redshift.d.ts.map +1 -1
  14. package/dist/cjs/fetchers/redshift.js +3 -1
  15. package/dist/cjs/fetchers/redshift.js.map +1 -1
  16. package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
  17. package/dist/cjs/fetchers/rest-api.js +2 -2
  18. package/dist/cjs/fetchers/rest-api.js.map +1 -1
  19. package/dist/cjs/fetchers/turso.d.ts.map +1 -1
  20. package/dist/cjs/fetchers/turso.js +1 -1
  21. package/dist/cjs/fetchers/turso.js.map +1 -1
  22. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  23. package/dist/cjs/pagination-plugin.js +151 -119
  24. package/dist/cjs/pagination-plugin.js.map +1 -1
  25. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  26. package/dist/esm/count-fetchers.d.ts.map +1 -1
  27. package/dist/esm/count-fetchers.js +1 -1
  28. package/dist/esm/count-fetchers.js.map +1 -1
  29. package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
  30. package/dist/esm/fetchers/clickhouse.js +1 -1
  31. package/dist/esm/fetchers/clickhouse.js.map +1 -1
  32. package/dist/esm/fetchers/firestore.d.ts.map +1 -1
  33. package/dist/esm/fetchers/firestore.js +1 -1
  34. package/dist/esm/fetchers/firestore.js.map +1 -1
  35. package/dist/esm/fetchers/javascript.d.ts.map +1 -1
  36. package/dist/esm/fetchers/javascript.js +1 -1
  37. package/dist/esm/fetchers/javascript.js.map +1 -1
  38. package/dist/esm/fetchers/redshift.d.ts.map +1 -1
  39. package/dist/esm/fetchers/redshift.js +3 -1
  40. package/dist/esm/fetchers/redshift.js.map +1 -1
  41. package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
  42. package/dist/esm/fetchers/rest-api.js +2 -2
  43. package/dist/esm/fetchers/rest-api.js.map +1 -1
  44. package/dist/esm/fetchers/turso.d.ts.map +1 -1
  45. package/dist/esm/fetchers/turso.js +1 -1
  46. package/dist/esm/fetchers/turso.js.map +1 -1
  47. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  48. package/dist/esm/pagination-plugin.js +151 -119
  49. package/dist/esm/pagination-plugin.js.map +1 -1
  50. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +2 -2
  52. package/src/count-fetchers.ts +2 -1
  53. package/src/fetchers/clickhouse.ts +12 -6
  54. package/src/fetchers/firestore.ts +45 -13
  55. package/src/fetchers/javascript.ts +48 -13
  56. package/src/fetchers/redshift.ts +32 -9
  57. package/src/fetchers/rest-api.ts +68 -6
  58. package/src/fetchers/turso.ts +46 -16
  59. package/src/pagination-plugin.ts +308 -257
@@ -123,6 +123,8 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
123
123
  const searchConfigMap = opts.paginationConfig?.searchConfigMap || new Map<string, any>()
124
124
  const queryColumnsMap = opts.paginationConfig?.queryColumnsMap || new Map<string, string[]>()
125
125
 
126
+ const stateDeclarations: types.Statement[] = []
127
+
126
128
  detectedPaginations.forEach((detected, index) => {
127
129
  const paginationNodeId = `pg_${index}`
128
130
  // Use arrayMapperRenderProp if available, otherwise fall back to dataSourceIdentifier
@@ -141,55 +143,27 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
141
143
  )
142
144
  paginationInfos.push(info)
143
145
 
144
- // If both pagination and search are enabled, combine them into a single state object
145
- if (info.searchEnabled && info.searchQueryVar && info.setSearchQueryVar) {
146
- // Combined state: { page: 1, debouncedQuery: '' }
147
- const combinedStateVar = `paginationState_pg_${index}`
148
- const setCombinedStateVar = `setPaginationState_pg_${index}`
149
-
150
- const combinedStateAST = types.variableDeclaration('const', [
151
- types.variableDeclarator(
152
- types.arrayPattern([
153
- types.identifier(combinedStateVar),
154
- types.identifier(setCombinedStateVar),
155
- ]),
156
- types.callExpression(types.identifier('useState'), [
157
- types.objectExpression([
158
- types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
159
- types.objectProperty(types.identifier('debouncedQuery'), types.stringLiteral('')),
160
- ]),
161
- ])
162
- ),
163
- ])
164
- blockStatement.body.unshift(combinedStateAST)
165
-
166
- // Still need the immediate search query state for the input
167
- const searchStateAST = types.variableDeclaration('const', [
146
+ // Add refs to track first render for each useEffect (add first)
147
+ if (info.searchEnabled) {
148
+ const skipCountFetchOnMountRefVar = `skipCountFetchOnMount_pg_${index}`
149
+ const skipCountFetchRefAST = types.variableDeclaration('const', [
168
150
  types.variableDeclarator(
169
- types.arrayPattern([
170
- types.identifier(info.searchQueryVar),
171
- types.identifier(info.setSearchQueryVar),
172
- ]),
173
- types.callExpression(types.identifier('useState'), [types.stringLiteral('')])
151
+ types.identifier(skipCountFetchOnMountRefVar),
152
+ types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])
174
153
  ),
175
154
  ])
176
- blockStatement.body.unshift(searchStateAST)
155
+ stateDeclarations.push(skipCountFetchRefAST)
156
+ ;(info as any).skipCountFetchOnMountRefVar = skipCountFetchOnMountRefVar
177
157
 
178
- // Store the combined state var names
179
- ;(info as any).combinedStateVar = combinedStateVar
180
- ;(info as any).setCombinedStateVar = setCombinedStateVar
181
- } else {
182
- // If search is not enabled, just add regular page state
183
- const pageStateAST = types.variableDeclaration('const', [
158
+ const skipDebounceOnMountRefVar = `skipDebounceOnMount_pg_${index}`
159
+ const skipDebounceRefAST = types.variableDeclaration('const', [
184
160
  types.variableDeclarator(
185
- types.arrayPattern([
186
- types.identifier(info.pageStateVar),
187
- types.identifier(info.setPageStateVar),
188
- ]),
189
- types.callExpression(types.identifier('useState'), [types.numericLiteral(1)])
161
+ types.identifier(skipDebounceOnMountRefVar),
162
+ types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])
190
163
  ),
191
164
  ])
192
- blockStatement.body.unshift(pageStateAST)
165
+ stateDeclarations.push(skipDebounceRefAST)
166
+ ;(info as any).skipDebounceOnMountRefVar = skipDebounceOnMountRefVar
193
167
  }
194
168
 
195
169
  // Add maxPages state
@@ -221,36 +195,69 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
221
195
  types.callExpression(types.identifier('useState'), [maxPagesInitValue])
222
196
  ),
223
197
  ])
224
- blockStatement.body.unshift(maxPagesStateAST)
198
+ stateDeclarations.push(maxPagesStateAST)
225
199
 
226
200
  // Store these for later use
227
201
  ;(info as any).maxPagesStateVar = maxPagesStateVar
228
202
  ;(info as any).setMaxPagesStateVar = setMaxPagesStateVar
229
203
 
230
- // Add refs to track first render for each useEffect
231
- if (info.searchEnabled) {
232
- const skipDebounceOnMountRefVar = `skipDebounceOnMount_pg_${index}`
233
- const skipDebounceRefAST = types.variableDeclaration('const', [
204
+ // If both pagination and search are enabled, combine them into a single state object
205
+ if (info.searchEnabled && info.searchQueryVar && info.setSearchQueryVar) {
206
+ // Combined state: { page: 1, debouncedQuery: '' }
207
+ const combinedStateVar = `paginationState_pg_${index}`
208
+ const setCombinedStateVar = `setPaginationState_pg_${index}`
209
+
210
+ const combinedStateAST = types.variableDeclaration('const', [
234
211
  types.variableDeclarator(
235
- types.identifier(skipDebounceOnMountRefVar),
236
- types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])
212
+ types.arrayPattern([
213
+ types.identifier(combinedStateVar),
214
+ types.identifier(setCombinedStateVar),
215
+ ]),
216
+ types.callExpression(types.identifier('useState'), [
217
+ types.objectExpression([
218
+ types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
219
+ types.objectProperty(types.identifier('debouncedQuery'), types.stringLiteral('')),
220
+ ]),
221
+ ])
237
222
  ),
238
223
  ])
239
- blockStatement.body.unshift(skipDebounceRefAST)
240
- ;(info as any).skipDebounceOnMountRefVar = skipDebounceOnMountRefVar
224
+ stateDeclarations.push(combinedStateAST)
241
225
 
242
- const skipCountFetchOnMountRefVar = `skipCountFetchOnMount_pg_${index}`
243
- const skipCountFetchRefAST = types.variableDeclaration('const', [
226
+ // Still need the immediate search query state for the input
227
+ const searchStateAST = types.variableDeclaration('const', [
244
228
  types.variableDeclarator(
245
- types.identifier(skipCountFetchOnMountRefVar),
246
- types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])
229
+ types.arrayPattern([
230
+ types.identifier(info.searchQueryVar),
231
+ types.identifier(info.setSearchQueryVar),
232
+ ]),
233
+ types.callExpression(types.identifier('useState'), [types.stringLiteral('')])
247
234
  ),
248
235
  ])
249
- blockStatement.body.unshift(skipCountFetchRefAST)
250
- ;(info as any).skipCountFetchOnMountRefVar = skipCountFetchOnMountRefVar
236
+ stateDeclarations.push(searchStateAST)
237
+
238
+ // Store the combined state var names
239
+ ;(info as any).combinedStateVar = combinedStateVar
240
+ ;(info as any).setCombinedStateVar = setCombinedStateVar
241
+ } else {
242
+ // If search is not enabled, just add regular page state
243
+ const pageStateAST = types.variableDeclaration('const', [
244
+ types.variableDeclarator(
245
+ types.arrayPattern([
246
+ types.identifier(info.pageStateVar),
247
+ types.identifier(info.setPageStateVar),
248
+ ]),
249
+ types.callExpression(types.identifier('useState'), [types.numericLiteral(1)])
250
+ ),
251
+ ])
252
+ stateDeclarations.push(pageStateAST)
251
253
  }
252
254
  })
253
255
 
256
+ // Add all state declarations at once to the beginning in correct order
257
+ stateDeclarations.reverse().forEach((stateDecl) => {
258
+ blockStatement.body.unshift(stateDecl)
259
+ })
260
+
254
261
  // Add useEffect dependency if any pagination has search enabled
255
262
  const hasSearchEnabled = paginationInfos.some((info) => info.searchEnabled)
256
263
  if (hasSearchEnabled && !dependencies.useEffect) {
@@ -351,201 +358,203 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
351
358
  blockStatement.body.splice(insertIndex, 0, debounceEffect)
352
359
 
353
360
  // Add useEffect to refetch count when search changes (for both pages and components)
354
- if (info.queryColumns && info.queryColumns.length > 0) {
355
- const detected = detectedPaginations.find(
356
- (d) => d.dataSourceIdentifier === info.dataSourceIdentifier
357
- )
358
- if (!detected) {
359
- return
360
- }
361
+ const detected = detectedPaginations.find(
362
+ (d) => d.dataSourceIdentifier === info.dataSourceIdentifier
363
+ )
364
+ if (!detected) {
365
+ return
366
+ }
361
367
 
362
- const resourceDefAttr = detected.dataProviderJSX.openingElement.attributes.find(
363
- (attr: any) => attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'
364
- )
368
+ const resourceDefAttr = detected.dataProviderJSX.openingElement.attributes.find(
369
+ (attr: any) => attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'
370
+ )
365
371
 
366
- if (
367
- resourceDefAttr &&
368
- resourceDefAttr.value &&
369
- resourceDefAttr.value.type === 'JSXExpressionContainer'
370
- ) {
371
- const resourceDef = resourceDefAttr.value.expression
372
- if (resourceDef.type === 'ObjectExpression') {
373
- const dataSourceIdProp = (resourceDef.properties as any[]).find(
374
- (p: any) => p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'
375
- )
376
- const tableNameProp = (resourceDef.properties as any[]).find(
377
- (p: any) => p.type === 'ObjectProperty' && p.key.value === 'tableName'
378
- )
379
- const dataSourceTypeProp = (resourceDef.properties as any[]).find(
380
- (p: any) => p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'
381
- )
372
+ if (
373
+ resourceDefAttr &&
374
+ resourceDefAttr.value &&
375
+ resourceDefAttr.value.type === 'JSXExpressionContainer'
376
+ ) {
377
+ const resourceDef = resourceDefAttr.value.expression
378
+ if (resourceDef.type === 'ObjectExpression') {
379
+ const dataSourceIdProp = (resourceDef.properties as any[]).find(
380
+ (p: any) => p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'
381
+ )
382
+ const tableNameProp = (resourceDef.properties as any[]).find(
383
+ (p: any) => p.type === 'ObjectProperty' && p.key.value === 'tableName'
384
+ )
385
+ const dataSourceTypeProp = (resourceDef.properties as any[]).find(
386
+ (p: any) => p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'
387
+ )
382
388
 
383
- if (dataSourceIdProp && tableNameProp && dataSourceTypeProp) {
384
- const dataSourceId = dataSourceIdProp.value.value
385
- const tableName = tableNameProp.value.value
386
- const dataSourceType = dataSourceTypeProp.value.value
387
- const fileName = `${dataSourceType}-${tableName}-${dataSourceId.substring(0, 8)}`
388
- const setMaxPagesStateVar = (info as any).setMaxPagesStateVar
389
+ if (dataSourceIdProp && tableNameProp && dataSourceTypeProp) {
390
+ const dataSourceId = dataSourceIdProp.value.value
391
+ const tableName = tableNameProp.value.value
392
+ const dataSourceType = dataSourceTypeProp.value.value
393
+ const fileName = `${dataSourceType}-${tableName}-${dataSourceId.substring(0, 8)}`
394
+ const setMaxPagesStateVar = (info as any).setMaxPagesStateVar
395
+
396
+ // Create useEffect to refetch count when debounced search changes
397
+ const skipCountFetchOnMountRefVar = (info as any).skipCountFetchOnMountRefVar
398
+ const combinedStateVar = (info as any).combinedStateVar
399
+
400
+ // Build URLSearchParams properties - query is always included, queryColumns is optional
401
+ const urlSearchParamsProperties: any[] = [
402
+ types.objectProperty(
403
+ types.identifier('query'),
404
+ types.memberExpression(
405
+ types.identifier(combinedStateVar),
406
+ types.identifier('debouncedQuery')
407
+ )
408
+ ),
409
+ ]
389
410
 
390
- // Create useEffect to refetch count when debounced search changes
391
- const skipCountFetchOnMountRefVar = (info as any).skipCountFetchOnMountRefVar
392
- const combinedStateVar = (info as any).combinedStateVar
411
+ // Add queryColumns only if they exist
412
+ if (info.queryColumns && info.queryColumns.length > 0) {
413
+ urlSearchParamsProperties.push(
414
+ types.objectProperty(
415
+ types.identifier('queryColumns'),
416
+ types.callExpression(
417
+ types.memberExpression(
418
+ types.identifier('JSON'),
419
+ types.identifier('stringify')
420
+ ),
421
+ [
422
+ types.arrayExpression(
423
+ info.queryColumns.map((col) => types.stringLiteral(col))
424
+ ),
425
+ ]
426
+ )
427
+ )
428
+ )
429
+ }
393
430
 
394
- const refetchCountEffect = types.expressionStatement(
395
- types.callExpression(types.identifier('useEffect'), [
396
- types.arrowFunctionExpression(
397
- [],
398
- types.blockStatement([
399
- types.ifStatement(
400
- types.memberExpression(
401
- types.identifier(skipCountFetchOnMountRefVar),
402
- types.identifier('current')
403
- ),
404
- types.blockStatement([
405
- types.expressionStatement(
406
- types.assignmentExpression(
407
- '=',
408
- types.memberExpression(
409
- types.identifier(skipCountFetchOnMountRefVar),
410
- types.identifier('current')
411
- ),
412
- types.booleanLiteral(false)
413
- )
414
- ),
415
- types.returnStatement(),
416
- ])
431
+ const refetchCountEffect = types.expressionStatement(
432
+ types.callExpression(types.identifier('useEffect'), [
433
+ types.arrowFunctionExpression(
434
+ [],
435
+ types.blockStatement([
436
+ types.ifStatement(
437
+ types.memberExpression(
438
+ types.identifier(skipCountFetchOnMountRefVar),
439
+ types.identifier('current')
417
440
  ),
418
- types.expressionStatement(
419
- types.callExpression(
420
- types.memberExpression(
421
- types.callExpression(
422
- types.memberExpression(
423
- types.callExpression(types.identifier('fetch'), [
424
- types.templateLiteral(
425
- [
426
- types.templateElement({
427
- raw: `/api/${fileName}-count?`,
428
- cooked: `/api/${fileName}-count?`,
429
- }),
430
- types.templateElement({ raw: '', cooked: '' }),
431
- ],
432
- [
433
- types.newExpression(types.identifier('URLSearchParams'), [
434
- types.objectExpression([
435
- types.objectProperty(
436
- types.identifier('query'),
437
- types.memberExpression(
438
- types.identifier(combinedStateVar),
439
- types.identifier('debouncedQuery')
440
- )
441
- ),
442
- types.objectProperty(
443
- types.identifier('queryColumns'),
444
- types.callExpression(
445
- types.memberExpression(
446
- types.identifier('JSON'),
447
- types.identifier('stringify')
448
- ),
449
- [
450
- types.arrayExpression(
451
- info.queryColumns.map((col) =>
452
- types.stringLiteral(col)
453
- )
454
- ),
455
- ]
456
- )
457
- ),
458
- ]),
459
- ]),
460
- ]
441
+ types.blockStatement([
442
+ types.expressionStatement(
443
+ types.assignmentExpression(
444
+ '=',
445
+ types.memberExpression(
446
+ types.identifier(skipCountFetchOnMountRefVar),
447
+ types.identifier('current')
448
+ ),
449
+ types.booleanLiteral(false)
450
+ )
451
+ ),
452
+ types.returnStatement(),
453
+ ])
454
+ ),
455
+ types.expressionStatement(
456
+ types.callExpression(
457
+ types.memberExpression(
458
+ types.callExpression(
459
+ types.memberExpression(
460
+ types.callExpression(types.identifier('fetch'), [
461
+ types.templateLiteral(
462
+ [
463
+ types.templateElement({
464
+ raw: `/api/${fileName}-count?`,
465
+ cooked: `/api/${fileName}-count?`,
466
+ }),
467
+ types.templateElement({ raw: '', cooked: '' }),
468
+ ],
469
+ [
470
+ types.newExpression(types.identifier('URLSearchParams'), [
471
+ types.objectExpression(urlSearchParamsProperties),
472
+ ]),
473
+ ]
474
+ ),
475
+ ]),
476
+ types.identifier('then')
477
+ ),
478
+ [
479
+ types.arrowFunctionExpression(
480
+ [types.identifier('res')],
481
+ types.callExpression(
482
+ types.memberExpression(
483
+ types.identifier('res'),
484
+ types.identifier('json')
461
485
  ),
462
- ]),
463
- types.identifier('then')
486
+ []
487
+ )
464
488
  ),
465
- [
466
- types.arrowFunctionExpression(
467
- [types.identifier('res')],
468
- types.callExpression(
469
- types.memberExpression(
470
- types.identifier('res'),
471
- types.identifier('json')
472
- ),
473
- []
489
+ ]
490
+ ),
491
+ types.identifier('then')
492
+ ),
493
+ [
494
+ types.arrowFunctionExpression(
495
+ [types.identifier('data')],
496
+ types.blockStatement([
497
+ types.ifStatement(
498
+ types.logicalExpression(
499
+ '&&',
500
+ types.identifier('data'),
501
+ types.binaryExpression(
502
+ 'in',
503
+ types.stringLiteral('count'),
504
+ types.identifier('data')
474
505
  )
475
506
  ),
476
- ]
477
- ),
478
- types.identifier('then')
479
- ),
480
- [
481
- types.arrowFunctionExpression(
482
- [types.identifier('data')],
483
- types.blockStatement([
484
- types.ifStatement(
485
- types.logicalExpression(
486
- '&&',
487
- types.identifier('data'),
488
- types.binaryExpression(
489
- 'in',
490
- types.stringLiteral('count'),
491
- types.identifier('data')
492
- )
493
- ),
494
- types.blockStatement([
495
- types.expressionStatement(
496
- types.callExpression(
497
- types.identifier(setMaxPagesStateVar),
498
- [
499
- types.conditionalExpression(
507
+ types.blockStatement([
508
+ types.expressionStatement(
509
+ types.callExpression(types.identifier(setMaxPagesStateVar), [
510
+ types.conditionalExpression(
511
+ types.binaryExpression(
512
+ '===',
513
+ types.memberExpression(
514
+ types.identifier('data'),
515
+ types.identifier('count')
516
+ ),
517
+ types.numericLiteral(0)
518
+ ),
519
+ types.numericLiteral(0),
520
+ types.callExpression(
521
+ types.memberExpression(
522
+ types.identifier('Math'),
523
+ types.identifier('ceil')
524
+ ),
525
+ [
500
526
  types.binaryExpression(
501
- '===',
527
+ '/',
502
528
  types.memberExpression(
503
529
  types.identifier('data'),
504
530
  types.identifier('count')
505
531
  ),
506
- types.numericLiteral(0)
532
+ types.numericLiteral(info.perPage)
507
533
  ),
508
- types.numericLiteral(0),
509
- types.callExpression(
510
- types.memberExpression(
511
- types.identifier('Math'),
512
- types.identifier('ceil')
513
- ),
514
- [
515
- types.binaryExpression(
516
- '/',
517
- types.memberExpression(
518
- types.identifier('data'),
519
- types.identifier('count')
520
- ),
521
- types.numericLiteral(info.perPage)
522
- ),
523
- ]
524
- )
525
- ),
526
- ]
527
- )
528
- ),
529
- ])
530
- ),
531
- ])
532
- ),
533
- ]
534
- )
535
- ),
536
- ])
537
- ),
538
- types.arrayExpression([
539
- types.memberExpression(
540
- types.identifier(combinedStateVar),
541
- types.identifier('debouncedQuery')
534
+ ]
535
+ )
536
+ ),
537
+ ])
538
+ ),
539
+ ])
540
+ ),
541
+ ])
542
+ ),
543
+ ]
544
+ )
542
545
  ),
543
- ]),
544
- ])
545
- )
546
+ ])
547
+ ),
548
+ types.arrayExpression([
549
+ types.memberExpression(
550
+ types.identifier(combinedStateVar),
551
+ types.identifier('debouncedQuery')
552
+ ),
553
+ ]),
554
+ ])
555
+ )
546
556
 
547
- blockStatement.body.splice(insertIndex, 0, refetchCountEffect)
548
- }
557
+ blockStatement.body.splice(insertIndex, 0, refetchCountEffect)
549
558
  }
550
559
  }
551
560
  }
@@ -623,6 +632,9 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
623
632
  })
624
633
 
625
634
  // Create ONE useEffect per unique data source
635
+ // Collect all useEffect statements first
636
+ const componentUseEffects: types.Statement[] = []
637
+
626
638
  dataSourceToInfos.forEach((infos) => {
627
639
  const { fileName } = infos[0]
628
640
 
@@ -702,7 +714,20 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
702
714
  ])
703
715
  )
704
716
 
705
- blockStatement.body.unshift(useEffectAST)
717
+ componentUseEffects.push(useEffectAST)
718
+ })
719
+
720
+ // Insert all component useEffect hooks after state declarations but before return
721
+ // Find the first return statement
722
+ const componentReturnIndex = blockStatement.body.findIndex(
723
+ (stmt: any) => stmt.type === 'ReturnStatement'
724
+ )
725
+ const componentEffectsInsertIndex =
726
+ componentReturnIndex !== -1 ? componentReturnIndex : blockStatement.body.length
727
+
728
+ // Insert in reverse order to maintain correct order
729
+ componentUseEffects.reverse().forEach((effect) => {
730
+ blockStatement.body.splice(componentEffectsInsertIndex, 0, effect)
706
731
  })
707
732
  }
708
733
 
@@ -736,7 +761,6 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
736
761
  searchOnlyDataSources,
737
762
  searchConfigMap,
738
763
  queryColumnsMap,
739
- insertIndex,
740
764
  dependencies
741
765
  )
742
766
 
@@ -830,7 +854,7 @@ function detectPaginationsAndSearchFromJSX(
830
854
  hasSearch: boolean
831
855
  }
832
856
 
833
- const dataProviderMap = new Map<string, DataProviderInfo>()
857
+ const dataProviderList: DataProviderInfo[] = []
834
858
 
835
859
  // First pass: collect array mapper info from UIDL, keyed by array mapper render prop (unique)
836
860
  interface ArrayMapperInfo {
@@ -1106,8 +1130,8 @@ function detectPaginationsAndSearchFromJSX(
1106
1130
  }
1107
1131
 
1108
1132
  // Record the DataProvider with its pagination/search info
1109
- const uniqueKey = `${dataProviderIdentifier}__${arrayMapperRenderProp}`
1110
- dataProviderMap.set(uniqueKey, {
1133
+ // Use array instead of Map to handle multiple DataProviders with same name
1134
+ dataProviderList.push({
1111
1135
  identifier: dataProviderIdentifier,
1112
1136
  dataProvider,
1113
1137
  arrayMapperRenderProp,
@@ -1124,8 +1148,17 @@ function detectPaginationsAndSearchFromJSX(
1124
1148
  const paginationOnlyMappers: DetectedPagination[] = []
1125
1149
  const plainMappers: DetectedPagination[] = []
1126
1150
 
1127
- dataProviderMap.forEach((info) => {
1128
- if (info.hasPagination && info.hasSearch) {
1151
+ dataProviderList.forEach((info) => {
1152
+ // Check UIDL flags for this array mapper
1153
+ const uidlInfo = info.arrayMapperRenderProp
1154
+ ? arrayMapperInfoMap.get(info.arrayMapperRenderProp)
1155
+ : null
1156
+
1157
+ // Only process pagination/search if UIDL explicitly enables it
1158
+ const shouldHavePagination = uidlInfo?.paginated && info.hasPagination
1159
+ const shouldHaveSearch = uidlInfo?.searchEnabled && info.hasSearch
1160
+
1161
+ if (shouldHavePagination && shouldHaveSearch) {
1129
1162
  // Pagination + Search
1130
1163
  paginatedMappers.push({
1131
1164
  paginationNodeClass: info.paginationNode!.class,
@@ -1137,7 +1170,7 @@ function detectPaginationsAndSearchFromJSX(
1137
1170
  searchInputClass: info.searchInput?.class,
1138
1171
  searchInputJSX: info.searchInput?.jsx,
1139
1172
  })
1140
- } else if (info.hasPagination && !info.hasSearch) {
1173
+ } else if (shouldHavePagination && !shouldHaveSearch) {
1141
1174
  // Pagination only
1142
1175
  paginationOnlyMappers.push({
1143
1176
  paginationNodeClass: info.paginationNode!.class,
@@ -1149,7 +1182,7 @@ function detectPaginationsAndSearchFromJSX(
1149
1182
  searchInputClass: undefined,
1150
1183
  searchInputJSX: undefined,
1151
1184
  })
1152
- } else if (!info.hasPagination && info.hasSearch) {
1185
+ } else if (!shouldHavePagination && shouldHaveSearch) {
1153
1186
  // Search only
1154
1187
  searchOnlyMappers.push({
1155
1188
  paginationNodeClass: '',
@@ -1162,7 +1195,7 @@ function detectPaginationsAndSearchFromJSX(
1162
1195
  searchInputJSX: info.searchInput?.jsx,
1163
1196
  })
1164
1197
  } else {
1165
- // Plain (no pagination, no search)
1198
+ // Plain (no pagination, no search) - UIDL doesn't enable it or no controls found
1166
1199
  plainMappers.push({
1167
1200
  paginationNodeClass: '',
1168
1201
  prevButtonClass: null,
@@ -1184,9 +1217,11 @@ function handleSearchOnlyArrayMappers(
1184
1217
  searchOnlyDataSources: DetectedPagination[],
1185
1218
  searchConfigMap: Map<string, any>,
1186
1219
  queryColumnsMap: Map<string, string[]>,
1187
- insertIndex: number,
1188
1220
  dependencies: any
1189
1221
  ): void {
1222
+ const searchOnlyStates: types.Statement[] = []
1223
+ const searchOnlyEffects: types.Statement[] = []
1224
+
1190
1225
  searchOnlyDataSources.forEach((detected, index) => {
1191
1226
  const searchId = `search_${index}`
1192
1227
  const searchQueryVar = `${searchId}_query`
@@ -1205,14 +1240,14 @@ function handleSearchOnlyArrayMappers(
1205
1240
  const searchDebounce = searchConfig?.searchDebounce || 300
1206
1241
  const queryColumns = queryColumnsMap.get(detected.dataSourceIdentifier)
1207
1242
 
1208
- // Add search query state
1209
- const searchStateAST = types.variableDeclaration('const', [
1243
+ // Add skip ref
1244
+ const skipRefAST = types.variableDeclaration('const', [
1210
1245
  types.variableDeclarator(
1211
- types.arrayPattern([types.identifier(searchQueryVar), types.identifier(setSearchQueryVar)]),
1212
- types.callExpression(types.identifier('useState'), [types.stringLiteral('')])
1246
+ types.identifier(skipDebounceOnMountRefVar),
1247
+ types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])
1213
1248
  ),
1214
1249
  ])
1215
- blockStatement.body.unshift(searchStateAST)
1250
+ searchOnlyStates.push(skipRefAST)
1216
1251
 
1217
1252
  // Add debounced search state
1218
1253
  const debouncedSearchStateAST = types.variableDeclaration('const', [
@@ -1224,16 +1259,16 @@ function handleSearchOnlyArrayMappers(
1224
1259
  types.callExpression(types.identifier('useState'), [types.stringLiteral('')])
1225
1260
  ),
1226
1261
  ])
1227
- blockStatement.body.unshift(debouncedSearchStateAST)
1262
+ searchOnlyStates.push(debouncedSearchStateAST)
1228
1263
 
1229
- // Add skip ref
1230
- const skipRefAST = types.variableDeclaration('const', [
1264
+ // Add search query state
1265
+ const searchStateAST = types.variableDeclaration('const', [
1231
1266
  types.variableDeclarator(
1232
- types.identifier(skipDebounceOnMountRefVar),
1233
- types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])
1267
+ types.arrayPattern([types.identifier(searchQueryVar), types.identifier(setSearchQueryVar)]),
1268
+ types.callExpression(types.identifier('useState'), [types.stringLiteral('')])
1234
1269
  ),
1235
1270
  ])
1236
- blockStatement.body.unshift(skipRefAST)
1271
+ searchOnlyStates.push(searchStateAST)
1237
1272
 
1238
1273
  // Add useEffect for debouncing
1239
1274
  if (!dependencies.useEffect) {
@@ -1300,7 +1335,7 @@ function handleSearchOnlyArrayMappers(
1300
1335
  types.arrayExpression([types.identifier(searchQueryVar)]),
1301
1336
  ])
1302
1337
  )
1303
- blockStatement.body.splice(insertIndex, 0, debounceEffect)
1338
+ searchOnlyEffects.push(debounceEffect)
1304
1339
 
1305
1340
  // Modify DataProvider to include search params (even without queryColumns)
1306
1341
  if (detected.dataProviderJSX) {
@@ -1319,6 +1354,22 @@ function handleSearchOnlyArrayMappers(
1319
1354
  } as any)
1320
1355
  }
1321
1356
  })
1357
+
1358
+ // Add all state declarations at the beginning in correct order
1359
+ searchOnlyStates.reverse().forEach((stateDecl) => {
1360
+ blockStatement.body.unshift(stateDecl)
1361
+ })
1362
+
1363
+ // Recalculate insertIndex after adding states (since unshift shifted everything)
1364
+ const newInsertIndex = blockStatement.body.findIndex(
1365
+ (stmt: any) => stmt.type === 'ReturnStatement'
1366
+ )
1367
+ const finalInsertIndex = newInsertIndex !== -1 ? newInsertIndex : blockStatement.body.length
1368
+
1369
+ // Add all useEffect hooks before the return statement
1370
+ searchOnlyEffects.reverse().forEach((effect) => {
1371
+ blockStatement.body.splice(finalInsertIndex, 0, effect)
1372
+ })
1322
1373
  }
1323
1374
 
1324
1375
  function addSearchParamsToDataProvider(