@teleporthq/teleport-plugin-next-data-source 0.42.9 → 0.42.10
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.
- package/__tests__/csv-header-detection.test.ts +212 -0
- package/__tests__/validation.test.ts +33 -2
- package/dist/cjs/data-source-fetchers.d.ts +2 -2
- package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
- package/dist/cjs/data-source-fetchers.js +30 -7
- package/dist/cjs/data-source-fetchers.js.map +1 -1
- package/dist/cjs/fetchers/airtable.d.ts.map +1 -1
- package/dist/cjs/fetchers/airtable.js +1 -1
- package/dist/cjs/fetchers/airtable.js.map +1 -1
- package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
- package/dist/cjs/fetchers/clickhouse.js +1 -1
- package/dist/cjs/fetchers/clickhouse.js.map +1 -1
- package/dist/cjs/fetchers/csv-file.d.ts.map +1 -1
- package/dist/cjs/fetchers/csv-file.js +22 -3
- package/dist/cjs/fetchers/csv-file.js.map +1 -1
- package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
- package/dist/cjs/fetchers/firestore.js +1 -1
- package/dist/cjs/fetchers/firestore.js.map +1 -1
- package/dist/cjs/fetchers/google-sheets.d.ts.map +1 -1
- package/dist/cjs/fetchers/google-sheets.js +6 -1
- package/dist/cjs/fetchers/google-sheets.js.map +1 -1
- package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
- package/dist/cjs/fetchers/javascript.js +1 -1
- package/dist/cjs/fetchers/javascript.js.map +1 -1
- package/dist/cjs/fetchers/mariadb.d.ts.map +1 -1
- package/dist/cjs/fetchers/mariadb.js +3 -3
- package/dist/cjs/fetchers/mariadb.js.map +1 -1
- package/dist/cjs/fetchers/mongodb.d.ts +1 -1
- package/dist/cjs/fetchers/mongodb.d.ts.map +1 -1
- package/dist/cjs/fetchers/mongodb.js +11 -3
- package/dist/cjs/fetchers/mongodb.js.map +1 -1
- package/dist/cjs/fetchers/mysql.d.ts.map +1 -1
- package/dist/cjs/fetchers/mysql.js +2 -2
- package/dist/cjs/fetchers/mysql.js.map +1 -1
- package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
- package/dist/cjs/fetchers/postgresql.js +3 -3
- package/dist/cjs/fetchers/postgresql.js.map +1 -1
- package/dist/cjs/fetchers/redis.d.ts.map +1 -1
- package/dist/cjs/fetchers/redis.js +1 -1
- package/dist/cjs/fetchers/redis.js.map +1 -1
- package/dist/cjs/fetchers/redshift.d.ts.map +1 -1
- package/dist/cjs/fetchers/redshift.js +2 -2
- package/dist/cjs/fetchers/redshift.js.map +1 -1
- package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
- package/dist/cjs/fetchers/rest-api.js +2 -2
- package/dist/cjs/fetchers/rest-api.js.map +1 -1
- package/dist/cjs/fetchers/static-collection.d.ts.map +1 -1
- package/dist/cjs/fetchers/static-collection.js +1 -1
- package/dist/cjs/fetchers/static-collection.js.map +1 -1
- package/dist/cjs/fetchers/supabase.d.ts.map +1 -1
- package/dist/cjs/fetchers/supabase.js +2 -2
- package/dist/cjs/fetchers/supabase.js.map +1 -1
- package/dist/cjs/fetchers/turso.d.ts.map +1 -1
- package/dist/cjs/fetchers/turso.js +1 -1
- package/dist/cjs/fetchers/turso.js.map +1 -1
- package/dist/cjs/fetchers/utils/header-detection.d.ts +2 -0
- package/dist/cjs/fetchers/utils/header-detection.d.ts.map +1 -0
- package/dist/cjs/fetchers/utils/header-detection.js +8 -0
- package/dist/cjs/fetchers/utils/header-detection.js.map +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +168 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/pagination-plugin.d.ts.map +1 -1
- package/dist/cjs/pagination-plugin.js +320 -65
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts +2 -0
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +214 -46
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/data-source-fetchers.d.ts +2 -2
- package/dist/esm/data-source-fetchers.d.ts.map +1 -1
- package/dist/esm/data-source-fetchers.js +29 -6
- package/dist/esm/data-source-fetchers.js.map +1 -1
- package/dist/esm/fetchers/airtable.d.ts.map +1 -1
- package/dist/esm/fetchers/airtable.js +2 -2
- package/dist/esm/fetchers/airtable.js.map +1 -1
- package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
- package/dist/esm/fetchers/clickhouse.js +2 -2
- package/dist/esm/fetchers/clickhouse.js.map +1 -1
- package/dist/esm/fetchers/csv-file.d.ts.map +1 -1
- package/dist/esm/fetchers/csv-file.js +23 -4
- package/dist/esm/fetchers/csv-file.js.map +1 -1
- package/dist/esm/fetchers/firestore.d.ts.map +1 -1
- package/dist/esm/fetchers/firestore.js +2 -2
- package/dist/esm/fetchers/firestore.js.map +1 -1
- package/dist/esm/fetchers/google-sheets.d.ts.map +1 -1
- package/dist/esm/fetchers/google-sheets.js +6 -1
- package/dist/esm/fetchers/google-sheets.js.map +1 -1
- package/dist/esm/fetchers/javascript.d.ts.map +1 -1
- package/dist/esm/fetchers/javascript.js +2 -2
- package/dist/esm/fetchers/javascript.js.map +1 -1
- package/dist/esm/fetchers/mariadb.d.ts.map +1 -1
- package/dist/esm/fetchers/mariadb.js +4 -4
- package/dist/esm/fetchers/mariadb.js.map +1 -1
- package/dist/esm/fetchers/mongodb.d.ts +1 -1
- package/dist/esm/fetchers/mongodb.d.ts.map +1 -1
- package/dist/esm/fetchers/mongodb.js +12 -4
- package/dist/esm/fetchers/mongodb.js.map +1 -1
- package/dist/esm/fetchers/mysql.d.ts.map +1 -1
- package/dist/esm/fetchers/mysql.js +3 -3
- package/dist/esm/fetchers/mysql.js.map +1 -1
- package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
- package/dist/esm/fetchers/postgresql.js +4 -4
- package/dist/esm/fetchers/postgresql.js.map +1 -1
- package/dist/esm/fetchers/redis.d.ts.map +1 -1
- package/dist/esm/fetchers/redis.js +2 -2
- package/dist/esm/fetchers/redis.js.map +1 -1
- package/dist/esm/fetchers/redshift.d.ts.map +1 -1
- package/dist/esm/fetchers/redshift.js +3 -3
- package/dist/esm/fetchers/redshift.js.map +1 -1
- package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
- package/dist/esm/fetchers/rest-api.js +3 -3
- package/dist/esm/fetchers/rest-api.js.map +1 -1
- package/dist/esm/fetchers/static-collection.d.ts.map +1 -1
- package/dist/esm/fetchers/static-collection.js +2 -2
- package/dist/esm/fetchers/static-collection.js.map +1 -1
- package/dist/esm/fetchers/supabase.d.ts.map +1 -1
- package/dist/esm/fetchers/supabase.js +3 -3
- package/dist/esm/fetchers/supabase.js.map +1 -1
- package/dist/esm/fetchers/turso.d.ts.map +1 -1
- package/dist/esm/fetchers/turso.js +2 -2
- package/dist/esm/fetchers/turso.js.map +1 -1
- package/dist/esm/fetchers/utils/header-detection.d.ts +2 -0
- package/dist/esm/fetchers/utils/header-detection.d.ts.map +1 -0
- package/dist/esm/fetchers/utils/header-detection.js +4 -0
- package/dist/esm/fetchers/utils/header-detection.js.map +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +169 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pagination-plugin.d.ts.map +1 -1
- package/dist/esm/pagination-plugin.js +320 -65
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts +2 -0
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +211 -45
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/data-source-fetchers.ts +29 -13
- package/src/fetchers/airtable.ts +78 -30
- package/src/fetchers/clickhouse.ts +85 -18
- package/src/fetchers/csv-file.ts +254 -29
- package/src/fetchers/firestore.ts +62 -12
- package/src/fetchers/google-sheets.ts +147 -30
- package/src/fetchers/javascript.ts +102 -23
- package/src/fetchers/mariadb.ts +82 -25
- package/src/fetchers/mongodb.ts +153 -36
- package/src/fetchers/mysql.ts +83 -25
- package/src/fetchers/postgresql.ts +86 -26
- package/src/fetchers/redis.ts +40 -4
- package/src/fetchers/redshift.ts +84 -17
- package/src/fetchers/rest-api.ts +101 -24
- package/src/fetchers/static-collection.ts +96 -18
- package/src/fetchers/supabase.ts +175 -53
- package/src/fetchers/turso.ts +84 -17
- package/src/fetchers/utils/header-detection.ts +200 -0
- package/src/index.ts +248 -2
- package/src/pagination-plugin.ts +708 -191
- package/src/utils.ts +344 -38
package/src/utils.ts
CHANGED
|
@@ -440,10 +440,10 @@ export default dataSourceModule.handler
|
|
|
440
440
|
return
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
-
// Generate fetcher code
|
|
443
|
+
// Generate fetcher code for API route (exports just the handler)
|
|
444
444
|
let fetcherCode: string
|
|
445
445
|
try {
|
|
446
|
-
fetcherCode = generateDataSourceFetcherWithCore(dataSource, tableName || '')
|
|
446
|
+
fetcherCode = generateDataSourceFetcherWithCore(dataSource, tableName || '', true)
|
|
447
447
|
} catch (error) {
|
|
448
448
|
return
|
|
449
449
|
}
|
|
@@ -510,6 +510,19 @@ export const replaceSecretReference = (
|
|
|
510
510
|
}
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
+
export const generateSafeJSONParseCode = (): string => {
|
|
514
|
+
return `const safeJSONParse = (value) => {
|
|
515
|
+
if (!value) return value
|
|
516
|
+
if (typeof value === 'object') return value
|
|
517
|
+
try {
|
|
518
|
+
return JSON.parse(value)
|
|
519
|
+
} catch (e) {
|
|
520
|
+
console.warn('Failed to parse JSON:', e)
|
|
521
|
+
return value
|
|
522
|
+
}
|
|
523
|
+
}`
|
|
524
|
+
}
|
|
525
|
+
|
|
513
526
|
export const generateDateFormatterCode = (): string => {
|
|
514
527
|
return `const formatDateValue = (date) => {
|
|
515
528
|
const options = {
|
|
@@ -540,6 +553,110 @@ const dateReplacer = (key, value) => {
|
|
|
540
553
|
}`
|
|
541
554
|
}
|
|
542
555
|
|
|
556
|
+
export const generateSortFilterHelperCode = (): string => {
|
|
557
|
+
return `function getNestedValue(obj, path) {
|
|
558
|
+
if (!obj || typeof obj !== 'object') return undefined
|
|
559
|
+
const keys = path.split('.')
|
|
560
|
+
let value = obj
|
|
561
|
+
for (const key of keys) {
|
|
562
|
+
if (value && typeof value === 'object' && key in value) {
|
|
563
|
+
value = value[key]
|
|
564
|
+
} else {
|
|
565
|
+
return undefined
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return value
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function compareValues(value, target, operand) {
|
|
572
|
+
if (value === null || value === undefined || target === null || target === undefined) {
|
|
573
|
+
switch (operand) {
|
|
574
|
+
case '=': return value == target
|
|
575
|
+
case '!=': return value != target
|
|
576
|
+
default: return false
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (typeof value === 'number' && typeof target === 'number') {
|
|
581
|
+
switch (operand) {
|
|
582
|
+
case '=': return value === target
|
|
583
|
+
case '!=': return value !== target
|
|
584
|
+
case '>': return value > target
|
|
585
|
+
case '>=': return value >= target
|
|
586
|
+
case '<': return value < target
|
|
587
|
+
case '<=': return value <= target
|
|
588
|
+
default: return true
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (typeof value === 'string' && typeof target === 'string') {
|
|
593
|
+
switch (operand) {
|
|
594
|
+
case '=': return value === target
|
|
595
|
+
case '!=': return value !== target
|
|
596
|
+
case '>': return value > target
|
|
597
|
+
case '>=': return value >= target
|
|
598
|
+
case '<': return value < target
|
|
599
|
+
case '<=': return value <= target
|
|
600
|
+
default: return true
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const valueDate = value instanceof Date ? value : (typeof value === 'string' ? new Date(value) : null)
|
|
605
|
+
const targetDate = target instanceof Date ? target : (typeof target === 'string' ? new Date(target) : null)
|
|
606
|
+
if (valueDate && targetDate && !isNaN(valueDate.getTime()) && !isNaN(targetDate.getTime())) {
|
|
607
|
+
const valueTime = valueDate.getTime()
|
|
608
|
+
const targetTime = targetDate.getTime()
|
|
609
|
+
switch (operand) {
|
|
610
|
+
case '=': return valueTime === targetTime
|
|
611
|
+
case '!=': return valueTime !== targetTime
|
|
612
|
+
case '>': return valueTime > targetTime
|
|
613
|
+
case '>=': return valueTime >= targetTime
|
|
614
|
+
case '<': return valueTime < targetTime
|
|
615
|
+
case '<=': return valueTime <= targetTime
|
|
616
|
+
default: return true
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (Array.isArray(value) && Array.isArray(target)) {
|
|
621
|
+
switch (operand) {
|
|
622
|
+
case '=': return JSON.stringify(value) === JSON.stringify(target)
|
|
623
|
+
case '!=': return JSON.stringify(value) !== JSON.stringify(target)
|
|
624
|
+
case '>': return value.length > target.length
|
|
625
|
+
case '>=': return value.length >= target.length
|
|
626
|
+
case '<': return value.length < target.length
|
|
627
|
+
case '<=': return value.length <= target.length
|
|
628
|
+
default: return true
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (Array.isArray(value) && !Array.isArray(target)) {
|
|
633
|
+
switch (operand) {
|
|
634
|
+
case '=': return value.includes(target)
|
|
635
|
+
case '!=': return !value.includes(target)
|
|
636
|
+
default: return false
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (typeof value === 'object' && typeof target === 'object') {
|
|
641
|
+
switch (operand) {
|
|
642
|
+
case '=': return JSON.stringify(value) === JSON.stringify(target)
|
|
643
|
+
case '!=': return JSON.stringify(value) !== JSON.stringify(target)
|
|
644
|
+
default: return false
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
switch (operand) {
|
|
649
|
+
case '=': return value == target
|
|
650
|
+
case '!=': return value != target
|
|
651
|
+
case '>': return Number(value) > Number(target)
|
|
652
|
+
case '>=': return Number(value) >= Number(target)
|
|
653
|
+
case '<': return Number(value) < Number(target)
|
|
654
|
+
case '<=': return Number(value) <= Number(target)
|
|
655
|
+
default: return true
|
|
656
|
+
}
|
|
657
|
+
}`
|
|
658
|
+
}
|
|
659
|
+
|
|
543
660
|
export const sanitizeNumericParam = (value: unknown, defaultValue: number = 0): number => {
|
|
544
661
|
if (typeof value === 'number' && !isNaN(value) && isFinite(value)) {
|
|
545
662
|
return Math.max(0, Math.floor(value))
|
|
@@ -632,19 +749,42 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
632
749
|
return { success: false }
|
|
633
750
|
}
|
|
634
751
|
|
|
635
|
-
// Generate prop key
|
|
752
|
+
// Generate prop key using renderPropIdentifier and resource ID for uniqueness
|
|
753
|
+
// This ensures each DataProvider instance gets its own fetch and initialData even when
|
|
754
|
+
// multiple instances share the same renderPropIdentifier but have different params (sorts, filters)
|
|
755
|
+
const renderPropIdentifier = node.content?.renderPropIdentifier
|
|
756
|
+
// tslint:disable-next-line:no-any
|
|
757
|
+
const resourceId = (node.content?.resource as any)?.id
|
|
758
|
+
|
|
759
|
+
// Always generate a unique base key from dataSourceId and tableName
|
|
636
760
|
const sanitizedDsName = StringUtils.dashCaseToCamelCase(
|
|
637
761
|
sanitizeFileName(dataSource.name || dataSourceId)
|
|
638
762
|
)
|
|
639
763
|
const sanitizedTableName = StringUtils.dashCaseToCamelCase(
|
|
640
764
|
sanitizeFileName(tableName || 'data')
|
|
641
765
|
)
|
|
642
|
-
const
|
|
766
|
+
const baseKey = `${sanitizedDsName}_${sanitizedTableName}_data`
|
|
643
767
|
|
|
644
|
-
|
|
768
|
+
let propKey: string
|
|
769
|
+
if (renderPropIdentifier && resourceId) {
|
|
770
|
+
// Include resource ID to differentiate between same renderProp but different params
|
|
771
|
+
const sanitizedResourceId = StringUtils.dashCaseToCamelCase(
|
|
772
|
+
sanitizeFileName(resourceId).replace(/^TQ_/, '')
|
|
773
|
+
)
|
|
774
|
+
propKey = `${renderPropIdentifier}_${sanitizedResourceId}`
|
|
775
|
+
} else {
|
|
776
|
+
// Use base key for uniqueness (even if renderPropIdentifier exists, base key ensures uniqueness across different data sources)
|
|
777
|
+
propKey = baseKey
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Find matching JSX nodes for this data source
|
|
781
|
+
// Strategy depends on whether we have a unique resource ID:
|
|
782
|
+
// - With resource ID: each UIDL node updates ONE JSX element (unique data per element)
|
|
783
|
+
// - Without resource ID: one UIDL node can update ALL matching JSX elements (shared data)
|
|
784
|
+
const hasUniqueResourceId = !!resourceId
|
|
645
785
|
const matchingJsxNodes: types.JSXElement[] = []
|
|
646
786
|
|
|
647
|
-
// Helper function to recursively traverse the AST and find
|
|
787
|
+
// Helper function to recursively traverse the AST and find matching JSX elements
|
|
648
788
|
const traverseAST = (astNode: any) => {
|
|
649
789
|
if (!astNode || typeof astNode !== 'object') {
|
|
650
790
|
return
|
|
@@ -660,7 +800,25 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
660
800
|
(attr as types.JSXAttribute).name.name === 'resourceDefinition'
|
|
661
801
|
) as types.JSXAttribute | undefined
|
|
662
802
|
|
|
803
|
+
const nameAttr = attrs.find(
|
|
804
|
+
(attr) =>
|
|
805
|
+
(attr as any).type === 'JSXAttribute' &&
|
|
806
|
+
(attr as types.JSXAttribute).name.name === 'name'
|
|
807
|
+
) as types.JSXAttribute | undefined
|
|
808
|
+
|
|
809
|
+
const paramsAttr = attrs.find(
|
|
810
|
+
(attr) =>
|
|
811
|
+
(attr as any).type === 'JSXAttribute' &&
|
|
812
|
+
(attr as types.JSXAttribute).name.name === 'params'
|
|
813
|
+
) as types.JSXAttribute | undefined
|
|
814
|
+
|
|
815
|
+
// Check if this node already has initialData - if so, skip it
|
|
816
|
+
const hasInitialData = attrs.some(
|
|
817
|
+
(attr) => (attr as types.JSXAttribute).name?.name === 'initialData'
|
|
818
|
+
)
|
|
819
|
+
|
|
663
820
|
if (
|
|
821
|
+
!hasInitialData &&
|
|
664
822
|
resourceDefAttr &&
|
|
665
823
|
resourceDefAttr.value &&
|
|
666
824
|
resourceDefAttr.value.type === 'JSXExpressionContainer'
|
|
@@ -673,27 +831,131 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
673
831
|
// tslint:disable-next-line:no-any
|
|
674
832
|
const idValue = (idProp as any)?.value?.value
|
|
675
833
|
|
|
676
|
-
// Also check tableName to ensure we're matching the right data source
|
|
677
834
|
// tslint:disable-next-line:no-any
|
|
678
835
|
const tableNameProp = props.find((p: any) => p.key?.value === 'tableName')
|
|
679
836
|
// tslint:disable-next-line:no-any
|
|
680
837
|
const tableNameValue = (tableNameProp as any)?.value?.value
|
|
681
838
|
|
|
682
|
-
|
|
839
|
+
// Match by name attribute to ensure we get the right renderPropIdentifier
|
|
840
|
+
let nameMatches = true
|
|
841
|
+
if (renderPropIdentifier && nameAttr && nameAttr.value) {
|
|
842
|
+
nameMatches = false
|
|
843
|
+
if (nameAttr.value.type === 'StringLiteral') {
|
|
844
|
+
nameMatches = nameAttr.value.value === renderPropIdentifier
|
|
845
|
+
} else if (nameAttr.value.type === 'JSXExpressionContainer') {
|
|
846
|
+
const nameExpr = nameAttr.value.expression
|
|
847
|
+
if (nameExpr.type === 'StringLiteral') {
|
|
848
|
+
nameMatches = nameExpr.value === renderPropIdentifier
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Check if params match (for nodes with the same renderPropIdentifier but different params)
|
|
854
|
+
// We only compare simple numeric params that affect data fetching (limit, page, perPage)
|
|
855
|
+
// Other params like queryColumns are handled by pagination plugin and don't affect matching
|
|
856
|
+
// tslint:disable-next-line:no-any
|
|
857
|
+
const nodeResourceParams = (node.content as any).resource?.params || {}
|
|
858
|
+
let paramsMatch = true
|
|
859
|
+
|
|
860
|
+
// Extract numeric params from JSX that affect data fetching
|
|
861
|
+
const jsxLimitParams: Record<string, number | undefined> = {}
|
|
862
|
+
let jsxHasParams = false
|
|
863
|
+
|
|
864
|
+
if (
|
|
865
|
+
paramsAttr &&
|
|
866
|
+
paramsAttr.value &&
|
|
867
|
+
paramsAttr.value.type === 'JSXExpressionContainer'
|
|
868
|
+
) {
|
|
869
|
+
jsxHasParams = true
|
|
870
|
+
const paramsExpr = paramsAttr.value.expression
|
|
871
|
+
let objExpr: types.ObjectExpression | null = null
|
|
872
|
+
|
|
873
|
+
// Handle useMemo wrapper
|
|
874
|
+
if (
|
|
875
|
+
paramsExpr.type === 'CallExpression' &&
|
|
876
|
+
(paramsExpr.callee as any).name === 'useMemo'
|
|
877
|
+
) {
|
|
878
|
+
const memoArgs = paramsExpr.arguments
|
|
879
|
+
if (memoArgs.length > 0 && memoArgs[0].type === 'ArrowFunctionExpression') {
|
|
880
|
+
const arrowFunc = memoArgs[0] as types.ArrowFunctionExpression
|
|
881
|
+
if (arrowFunc.body.type === 'ObjectExpression') {
|
|
882
|
+
objExpr = arrowFunc.body as types.ObjectExpression
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
} else if (paramsExpr.type === 'ObjectExpression') {
|
|
886
|
+
// Direct object expression (before useMemo wrapping)
|
|
887
|
+
objExpr = paramsExpr as types.ObjectExpression
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (objExpr) {
|
|
891
|
+
objExpr.properties.forEach((prop: any) => {
|
|
892
|
+
if (prop.type === 'ObjectProperty') {
|
|
893
|
+
let key: string | undefined
|
|
894
|
+
if (prop.key.type === 'Identifier') {
|
|
895
|
+
key = prop.key.name
|
|
896
|
+
} else if (prop.key.type === 'StringLiteral') {
|
|
897
|
+
key = prop.key.value
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// Only extract limit param - this is what differentiates data fetches
|
|
901
|
+
if (key === 'limit' && prop.value.type === 'NumericLiteral') {
|
|
902
|
+
jsxLimitParams[key] = prop.value.value
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
})
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Extract limit from resource params
|
|
910
|
+
const resourceLimit =
|
|
911
|
+
nodeResourceParams.limit?.type === 'static'
|
|
912
|
+
? nodeResourceParams.limit.content
|
|
913
|
+
: undefined
|
|
914
|
+
|
|
915
|
+
// Compare limit params - this determines if data fetches are equivalent
|
|
916
|
+
const jsxLimit = jsxLimitParams.limit
|
|
917
|
+
if (jsxLimit !== undefined || resourceLimit !== undefined) {
|
|
918
|
+
// If either has limit, both must have the same limit value
|
|
919
|
+
paramsMatch = jsxLimit === resourceLimit
|
|
920
|
+
} else if (!jsxHasParams && Object.keys(nodeResourceParams).length > 0) {
|
|
921
|
+
// JSX has no params but resource has params - check if resource only has non-limit params
|
|
922
|
+
// If resource has limit, no match; otherwise match
|
|
923
|
+
paramsMatch = resourceLimit === undefined
|
|
924
|
+
} else if (jsxHasParams && Object.keys(nodeResourceParams).length === 0) {
|
|
925
|
+
// JSX has params but resource doesn't - check if JSX only has non-limit params
|
|
926
|
+
// If JSX has limit, no match; otherwise match
|
|
927
|
+
paramsMatch = jsxLimit === undefined
|
|
928
|
+
}
|
|
929
|
+
// else: both don't have params or both have equivalent limit - match
|
|
930
|
+
|
|
931
|
+
// Collect matching nodes that don't have initialData yet and have matching params
|
|
932
|
+
if (
|
|
933
|
+
idValue === dataSourceId &&
|
|
934
|
+
tableNameValue === tableName &&
|
|
935
|
+
nameMatches &&
|
|
936
|
+
paramsMatch
|
|
937
|
+
) {
|
|
683
938
|
matchingJsxNodes.push(jsxElement)
|
|
939
|
+
// If we have a unique resource ID, stop after finding the first match
|
|
940
|
+
// Otherwise, collect all matching nodes
|
|
941
|
+
if (hasUniqueResourceId) {
|
|
942
|
+
return
|
|
943
|
+
}
|
|
684
944
|
}
|
|
685
945
|
}
|
|
686
946
|
}
|
|
687
947
|
}
|
|
688
948
|
|
|
689
|
-
// Recursively traverse all properties
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
949
|
+
// Recursively traverse all properties (unless we already found a match with unique resource ID)
|
|
950
|
+
if (!hasUniqueResourceId || matchingJsxNodes.length === 0) {
|
|
951
|
+
for (const key in astNode) {
|
|
952
|
+
if (astNode.hasOwnProperty(key)) {
|
|
953
|
+
const value = astNode[key]
|
|
954
|
+
if (Array.isArray(value)) {
|
|
955
|
+
value.forEach((item) => traverseAST(item))
|
|
956
|
+
} else if (typeof value === 'object') {
|
|
957
|
+
traverseAST(value)
|
|
958
|
+
}
|
|
697
959
|
}
|
|
698
960
|
}
|
|
699
961
|
}
|
|
@@ -702,12 +964,13 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
702
964
|
// Traverse the entire component AST content
|
|
703
965
|
traverseAST(componentChunk.content)
|
|
704
966
|
|
|
705
|
-
if
|
|
706
|
-
|
|
707
|
-
|
|
967
|
+
// Even if all JSX nodes already have initialData, we should still add the fetch to getStaticProps
|
|
968
|
+
// This handles cases where multiple data-source-list nodes share the same renderPropIdentifier
|
|
969
|
+
// but have different params (e.g., one with limit, one without)
|
|
970
|
+
const nodesToUpdate: types.JSXElement[] = matchingJsxNodes
|
|
708
971
|
|
|
709
|
-
// Update
|
|
710
|
-
for (const jsxNode of
|
|
972
|
+
// Update all target JSX nodes with initialData (only those that don't already have it)
|
|
973
|
+
for (const jsxNode of nodesToUpdate) {
|
|
711
974
|
// For SSR/SSG with initialData, rename 'children' to 'renderSuccess'
|
|
712
975
|
const childrenAttrIndex = jsxNode.openingElement.attributes.findIndex(
|
|
713
976
|
(attr) => (attr as types.JSXAttribute).name?.name === 'children'
|
|
@@ -747,6 +1010,7 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
747
1010
|
)
|
|
748
1011
|
jsxNode.openingElement.attributes.push(persistDataAttr)
|
|
749
1012
|
}
|
|
1013
|
+
// End of target node processing
|
|
750
1014
|
|
|
751
1015
|
// Generate safe file name for the fetcher
|
|
752
1016
|
const fileName = generateSafeFileName(dataSourceType, tableName || 'data', dataSourceId)
|
|
@@ -797,23 +1061,64 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
797
1061
|
let astValue: any
|
|
798
1062
|
|
|
799
1063
|
if (value.content === null || value.content === undefined) {
|
|
800
|
-
|
|
1064
|
+
// Skip null/undefined values entirely
|
|
1065
|
+
return
|
|
801
1066
|
} else if (Array.isArray(value.content)) {
|
|
802
|
-
//
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
if (typeof item === 'string') {
|
|
806
|
-
return types.stringLiteral(item)
|
|
807
|
-
}
|
|
808
|
-
if (typeof item === 'number') {
|
|
809
|
-
return types.numericLiteral(item)
|
|
810
|
-
}
|
|
811
|
-
if (typeof item === 'boolean') {
|
|
812
|
-
return types.booleanLiteral(item)
|
|
813
|
-
}
|
|
814
|
-
return types.nullLiteral()
|
|
815
|
-
})
|
|
1067
|
+
// Filter out null/undefined values from the array
|
|
1068
|
+
const validItems = value.content.filter(
|
|
1069
|
+
(item: any) => item !== null && item !== undefined
|
|
816
1070
|
)
|
|
1071
|
+
|
|
1072
|
+
// Skip the array entirely if it's empty or only had null values
|
|
1073
|
+
if (validItems.length === 0) {
|
|
1074
|
+
return
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// For sorts, filters, and queryColumns, stringify the array for consistency with API handler
|
|
1078
|
+
if (key === 'sorts' || key === 'filters' || key === 'queryColumns') {
|
|
1079
|
+
const arrayExpr = types.arrayExpression(
|
|
1080
|
+
validItems.map((item: any) => {
|
|
1081
|
+
if (typeof item === 'string') {
|
|
1082
|
+
return types.stringLiteral(item)
|
|
1083
|
+
}
|
|
1084
|
+
if (typeof item === 'number') {
|
|
1085
|
+
return types.numericLiteral(item)
|
|
1086
|
+
}
|
|
1087
|
+
if (typeof item === 'boolean') {
|
|
1088
|
+
return types.booleanLiteral(item)
|
|
1089
|
+
}
|
|
1090
|
+
if (typeof item === 'object' && item !== null) {
|
|
1091
|
+
return ASTUtils.objectToObjectExpression(item)
|
|
1092
|
+
}
|
|
1093
|
+
return types.nullLiteral()
|
|
1094
|
+
})
|
|
1095
|
+
)
|
|
1096
|
+
// Wrap in JSON.stringify()
|
|
1097
|
+
astValue = types.callExpression(
|
|
1098
|
+
types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
|
|
1099
|
+
[arrayExpr]
|
|
1100
|
+
)
|
|
1101
|
+
} else {
|
|
1102
|
+
// Handle other array values normally
|
|
1103
|
+
astValue = types.arrayExpression(
|
|
1104
|
+
validItems.map((item: any) => {
|
|
1105
|
+
if (typeof item === 'string') {
|
|
1106
|
+
return types.stringLiteral(item)
|
|
1107
|
+
}
|
|
1108
|
+
if (typeof item === 'number') {
|
|
1109
|
+
return types.numericLiteral(item)
|
|
1110
|
+
}
|
|
1111
|
+
if (typeof item === 'boolean') {
|
|
1112
|
+
return types.booleanLiteral(item)
|
|
1113
|
+
}
|
|
1114
|
+
if (typeof item === 'object' && item !== null) {
|
|
1115
|
+
// Handle object items (like sort/filter objects)
|
|
1116
|
+
return ASTUtils.objectToObjectExpression(item)
|
|
1117
|
+
}
|
|
1118
|
+
return types.nullLiteral()
|
|
1119
|
+
})
|
|
1120
|
+
)
|
|
1121
|
+
}
|
|
817
1122
|
} else if (typeof value.content === 'string') {
|
|
818
1123
|
astValue = types.stringLiteral(value.content)
|
|
819
1124
|
} else if (typeof value.content === 'number') {
|
|
@@ -821,7 +1126,8 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
821
1126
|
} else if (typeof value.content === 'boolean') {
|
|
822
1127
|
astValue = types.booleanLiteral(value.content)
|
|
823
1128
|
} else {
|
|
824
|
-
|
|
1129
|
+
// Skip other null-like values
|
|
1130
|
+
return
|
|
825
1131
|
}
|
|
826
1132
|
|
|
827
1133
|
paramsProperties.push(types.objectProperty(types.stringLiteral(key), astValue))
|
|
@@ -932,7 +1238,7 @@ export const extractDataSourceIntoGetStaticProps = (
|
|
|
932
1238
|
const propsValue = propsObject.value as types.ObjectExpression
|
|
933
1239
|
|
|
934
1240
|
// Check if propKey already exists in the parallel fetch metadata
|
|
935
|
-
const parallelFetchMeta = getStaticPropsChunk.meta?.
|
|
1241
|
+
const parallelFetchMeta = getStaticPropsChunk.meta?.parallelFetchData as
|
|
936
1242
|
| ParallelFetchMeta
|
|
937
1243
|
| undefined
|
|
938
1244
|
const existingInFetchMeta = parallelFetchMeta?.names.includes(propKey)
|