@teleporthq/teleport-plugin-next-data-source 0.40.15
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/ARRAY_MAPPER_PAGINATION.md +1128 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/SEARCH_IMPLEMENTATION_SUMMARY.md +983 -0
- package/__tests__/fetchers.test.ts +545 -0
- package/__tests__/integration.test.ts +561 -0
- package/__tests__/mocks.ts +241 -0
- package/__tests__/pagination.test.ts +31 -0
- package/__tests__/plugin.test.ts +577 -0
- package/__tests__/utils.test.ts +430 -0
- package/__tests__/validation.test.ts +348 -0
- package/dist/cjs/array-mapper-pagination.d.ts +32 -0
- package/dist/cjs/array-mapper-pagination.d.ts.map +1 -0
- package/dist/cjs/array-mapper-pagination.js +77 -0
- package/dist/cjs/array-mapper-pagination.js.map +1 -0
- package/dist/cjs/count-fetchers.d.ts +12 -0
- package/dist/cjs/count-fetchers.d.ts.map +1 -0
- package/dist/cjs/count-fetchers.js +46 -0
- package/dist/cjs/count-fetchers.js.map +1 -0
- package/dist/cjs/data-source-fetchers.d.ts +14 -0
- package/dist/cjs/data-source-fetchers.d.ts.map +1 -0
- package/dist/cjs/data-source-fetchers.js +185 -0
- package/dist/cjs/data-source-fetchers.js.map +1 -0
- package/dist/cjs/fetchers/airtable.d.ts +6 -0
- package/dist/cjs/fetchers/airtable.d.ts.map +1 -0
- package/dist/cjs/fetchers/airtable.js +27 -0
- package/dist/cjs/fetchers/airtable.js.map +1 -0
- package/dist/cjs/fetchers/clickhouse.d.ts +6 -0
- package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -0
- package/dist/cjs/fetchers/clickhouse.js +29 -0
- package/dist/cjs/fetchers/clickhouse.js.map +1 -0
- package/dist/cjs/fetchers/csv-file.d.ts +7 -0
- package/dist/cjs/fetchers/csv-file.d.ts.map +1 -0
- package/dist/cjs/fetchers/csv-file.js +36 -0
- package/dist/cjs/fetchers/csv-file.js.map +1 -0
- package/dist/cjs/fetchers/firestore.d.ts +6 -0
- package/dist/cjs/fetchers/firestore.d.ts.map +1 -0
- package/dist/cjs/fetchers/firestore.js +35 -0
- package/dist/cjs/fetchers/firestore.js.map +1 -0
- package/dist/cjs/fetchers/google-sheets.d.ts +6 -0
- package/dist/cjs/fetchers/google-sheets.d.ts.map +1 -0
- package/dist/cjs/fetchers/google-sheets.js +30 -0
- package/dist/cjs/fetchers/google-sheets.js.map +1 -0
- package/dist/cjs/fetchers/index.d.ts +17 -0
- package/dist/cjs/fetchers/index.d.ts.map +1 -0
- package/dist/cjs/fetchers/index.js +56 -0
- package/dist/cjs/fetchers/index.js.map +1 -0
- package/dist/cjs/fetchers/javascript.d.ts +7 -0
- package/dist/cjs/fetchers/javascript.d.ts.map +1 -0
- package/dist/cjs/fetchers/javascript.js +40 -0
- package/dist/cjs/fetchers/javascript.js.map +1 -0
- package/dist/cjs/fetchers/mariadb.d.ts +3 -0
- package/dist/cjs/fetchers/mariadb.d.ts.map +1 -0
- package/dist/cjs/fetchers/mariadb.js +23 -0
- package/dist/cjs/fetchers/mariadb.js.map +1 -0
- package/dist/cjs/fetchers/mongodb.d.ts +7 -0
- package/dist/cjs/fetchers/mongodb.d.ts.map +1 -0
- package/dist/cjs/fetchers/mongodb.js +52 -0
- package/dist/cjs/fetchers/mongodb.js.map +1 -0
- package/dist/cjs/fetchers/mysql.d.ts +3 -0
- package/dist/cjs/fetchers/mysql.d.ts.map +1 -0
- package/dist/cjs/fetchers/mysql.js +30 -0
- package/dist/cjs/fetchers/mysql.js.map +1 -0
- package/dist/cjs/fetchers/postgresql.d.ts +3 -0
- package/dist/cjs/fetchers/postgresql.d.ts.map +1 -0
- package/dist/cjs/fetchers/postgresql.js +25 -0
- package/dist/cjs/fetchers/postgresql.js.map +1 -0
- package/dist/cjs/fetchers/redis.d.ts +6 -0
- package/dist/cjs/fetchers/redis.d.ts.map +1 -0
- package/dist/cjs/fetchers/redis.js +46 -0
- package/dist/cjs/fetchers/redis.js.map +1 -0
- package/dist/cjs/fetchers/redshift.d.ts +2 -0
- package/dist/cjs/fetchers/redshift.d.ts.map +1 -0
- package/dist/cjs/fetchers/redshift.js +24 -0
- package/dist/cjs/fetchers/redshift.js.map +1 -0
- package/dist/cjs/fetchers/rest-api.d.ts +6 -0
- package/dist/cjs/fetchers/rest-api.d.ts.map +1 -0
- package/dist/cjs/fetchers/rest-api.js +58 -0
- package/dist/cjs/fetchers/rest-api.js.map +1 -0
- package/dist/cjs/fetchers/static-collection.d.ts +7 -0
- package/dist/cjs/fetchers/static-collection.d.ts.map +1 -0
- package/dist/cjs/fetchers/static-collection.js +24 -0
- package/dist/cjs/fetchers/static-collection.js.map +1 -0
- package/dist/cjs/fetchers/supabase.d.ts +7 -0
- package/dist/cjs/fetchers/supabase.d.ts.map +1 -0
- package/dist/cjs/fetchers/supabase.js +42 -0
- package/dist/cjs/fetchers/supabase.js.map +1 -0
- package/dist/cjs/fetchers/turso.d.ts +6 -0
- package/dist/cjs/fetchers/turso.d.ts.map +1 -0
- package/dist/cjs/fetchers/turso.js +25 -0
- package/dist/cjs/fetchers/turso.js.map +1 -0
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +325 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/pagination-plugin.d.ts +5 -0
- package/dist/cjs/pagination-plugin.d.ts.map +1 -0
- package/dist/cjs/pagination-plugin.js +1484 -0
- package/dist/cjs/pagination-plugin.js.map +1 -0
- package/dist/cjs/pagination-with-count.d.ts +6 -0
- package/dist/cjs/pagination-with-count.d.ts.map +1 -0
- package/dist/cjs/pagination-with-count.js +63 -0
- package/dist/cjs/pagination-with-count.js.map +1 -0
- package/dist/cjs/tsconfig.tsbuildinfo +1 -0
- package/dist/cjs/utils.d.ts +31 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +763 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/cjs/validation.d.ts +5 -0
- package/dist/cjs/validation.d.ts.map +1 -0
- package/dist/cjs/validation.js +29 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/esm/array-mapper-pagination.d.ts +32 -0
- package/dist/esm/array-mapper-pagination.d.ts.map +1 -0
- package/dist/esm/array-mapper-pagination.js +72 -0
- package/dist/esm/array-mapper-pagination.js.map +1 -0
- package/dist/esm/count-fetchers.d.ts +12 -0
- package/dist/esm/count-fetchers.d.ts.map +1 -0
- package/dist/esm/count-fetchers.js +35 -0
- package/dist/esm/count-fetchers.js.map +1 -0
- package/dist/esm/data-source-fetchers.d.ts +14 -0
- package/dist/esm/data-source-fetchers.d.ts.map +1 -0
- package/dist/esm/data-source-fetchers.js +179 -0
- package/dist/esm/data-source-fetchers.js.map +1 -0
- package/dist/esm/fetchers/airtable.d.ts +6 -0
- package/dist/esm/fetchers/airtable.d.ts.map +1 -0
- package/dist/esm/fetchers/airtable.js +22 -0
- package/dist/esm/fetchers/airtable.js.map +1 -0
- package/dist/esm/fetchers/clickhouse.d.ts +6 -0
- package/dist/esm/fetchers/clickhouse.d.ts.map +1 -0
- package/dist/esm/fetchers/clickhouse.js +24 -0
- package/dist/esm/fetchers/clickhouse.js.map +1 -0
- package/dist/esm/fetchers/csv-file.d.ts +7 -0
- package/dist/esm/fetchers/csv-file.d.ts.map +1 -0
- package/dist/esm/fetchers/csv-file.js +30 -0
- package/dist/esm/fetchers/csv-file.js.map +1 -0
- package/dist/esm/fetchers/firestore.d.ts +6 -0
- package/dist/esm/fetchers/firestore.d.ts.map +1 -0
- package/dist/esm/fetchers/firestore.js +30 -0
- package/dist/esm/fetchers/firestore.js.map +1 -0
- package/dist/esm/fetchers/google-sheets.d.ts +6 -0
- package/dist/esm/fetchers/google-sheets.d.ts.map +1 -0
- package/dist/esm/fetchers/google-sheets.js +25 -0
- package/dist/esm/fetchers/google-sheets.js.map +1 -0
- package/dist/esm/fetchers/index.d.ts +17 -0
- package/dist/esm/fetchers/index.d.ts.map +1 -0
- package/dist/esm/fetchers/index.js +17 -0
- package/dist/esm/fetchers/index.js.map +1 -0
- package/dist/esm/fetchers/javascript.d.ts +7 -0
- package/dist/esm/fetchers/javascript.d.ts.map +1 -0
- package/dist/esm/fetchers/javascript.js +34 -0
- package/dist/esm/fetchers/javascript.js.map +1 -0
- package/dist/esm/fetchers/mariadb.d.ts +3 -0
- package/dist/esm/fetchers/mariadb.d.ts.map +1 -0
- package/dist/esm/fetchers/mariadb.js +18 -0
- package/dist/esm/fetchers/mariadb.js.map +1 -0
- package/dist/esm/fetchers/mongodb.d.ts +7 -0
- package/dist/esm/fetchers/mongodb.d.ts.map +1 -0
- package/dist/esm/fetchers/mongodb.js +46 -0
- package/dist/esm/fetchers/mongodb.js.map +1 -0
- package/dist/esm/fetchers/mysql.d.ts +3 -0
- package/dist/esm/fetchers/mysql.d.ts.map +1 -0
- package/dist/esm/fetchers/mysql.js +25 -0
- package/dist/esm/fetchers/mysql.js.map +1 -0
- package/dist/esm/fetchers/postgresql.d.ts +3 -0
- package/dist/esm/fetchers/postgresql.d.ts.map +1 -0
- package/dist/esm/fetchers/postgresql.js +20 -0
- package/dist/esm/fetchers/postgresql.js.map +1 -0
- package/dist/esm/fetchers/redis.d.ts +6 -0
- package/dist/esm/fetchers/redis.d.ts.map +1 -0
- package/dist/esm/fetchers/redis.js +41 -0
- package/dist/esm/fetchers/redis.js.map +1 -0
- package/dist/esm/fetchers/redshift.d.ts +2 -0
- package/dist/esm/fetchers/redshift.d.ts.map +1 -0
- package/dist/esm/fetchers/redshift.js +20 -0
- package/dist/esm/fetchers/redshift.js.map +1 -0
- package/dist/esm/fetchers/rest-api.d.ts +6 -0
- package/dist/esm/fetchers/rest-api.d.ts.map +1 -0
- package/dist/esm/fetchers/rest-api.js +53 -0
- package/dist/esm/fetchers/rest-api.js.map +1 -0
- package/dist/esm/fetchers/static-collection.d.ts +7 -0
- package/dist/esm/fetchers/static-collection.d.ts.map +1 -0
- package/dist/esm/fetchers/static-collection.js +18 -0
- package/dist/esm/fetchers/static-collection.js.map +1 -0
- package/dist/esm/fetchers/supabase.d.ts +7 -0
- package/dist/esm/fetchers/supabase.d.ts.map +1 -0
- package/dist/esm/fetchers/supabase.js +36 -0
- package/dist/esm/fetchers/supabase.js.map +1 -0
- package/dist/esm/fetchers/turso.d.ts +6 -0
- package/dist/esm/fetchers/turso.d.ts.map +1 -0
- package/dist/esm/fetchers/turso.js +20 -0
- package/dist/esm/fetchers/turso.js.map +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +306 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/pagination-plugin.d.ts +5 -0
- package/dist/esm/pagination-plugin.d.ts.map +1 -0
- package/dist/esm/pagination-plugin.js +1457 -0
- package/dist/esm/pagination-plugin.js.map +1 -0
- package/dist/esm/pagination-with-count.d.ts +6 -0
- package/dist/esm/pagination-with-count.d.ts.map +1 -0
- package/dist/esm/pagination-with-count.js +34 -0
- package/dist/esm/pagination-with-count.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -0
- package/dist/esm/utils.d.ts +31 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +722 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/validation.d.ts +5 -0
- package/dist/esm/validation.d.ts.map +1 -0
- package/dist/esm/validation.js +25 -0
- package/dist/esm/validation.js.map +1 -0
- package/package.json +33 -0
- package/src/array-mapper-pagination.ts +113 -0
- package/src/count-fetchers.ts +99 -0
- package/src/data-source-fetchers.ts +313 -0
- package/src/fetchers/airtable.ts +153 -0
- package/src/fetchers/clickhouse.ts +127 -0
- package/src/fetchers/csv-file.ts +163 -0
- package/src/fetchers/firestore.ts +138 -0
- package/src/fetchers/google-sheets.ts +189 -0
- package/src/fetchers/index.ts +32 -0
- package/src/fetchers/javascript.ts +150 -0
- package/src/fetchers/mariadb.ts +230 -0
- package/src/fetchers/mongodb.ts +239 -0
- package/src/fetchers/mysql.ts +237 -0
- package/src/fetchers/postgresql.ts +247 -0
- package/src/fetchers/redis.ts +152 -0
- package/src/fetchers/redshift.ts +138 -0
- package/src/fetchers/rest-api.ts +148 -0
- package/src/fetchers/static-collection.ts +149 -0
- package/src/fetchers/supabase.ts +246 -0
- package/src/fetchers/turso.ts +131 -0
- package/src/index.ts +352 -0
- package/src/pagination-plugin.ts +2335 -0
- package/src/pagination-with-count.ts +89 -0
- package/src/utils.ts +1013 -0
- package/src/validation.ts +32 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import * as types from '@babel/types'
|
|
2
|
+
import { createNextPagesDataSourcePlugin, createNextComponentDataSourcePlugin } from '../src/index'
|
|
3
|
+
import { FileType } from '@teleporthq/teleport-types'
|
|
4
|
+
import {
|
|
5
|
+
createComponentStructure,
|
|
6
|
+
createDataSourceNode,
|
|
7
|
+
createDataSourceListNode,
|
|
8
|
+
createPostgreSQLDataSource,
|
|
9
|
+
createRESTAPIDataSource,
|
|
10
|
+
createJavaScriptDataSource,
|
|
11
|
+
createComponentChunk,
|
|
12
|
+
createMockJSXElementWithResourceDef,
|
|
13
|
+
} from './mocks'
|
|
14
|
+
import { component, elementNode } from '@teleporthq/teleport-uidl-builders'
|
|
15
|
+
|
|
16
|
+
describe('createNextComponentDataSourcePlugin', () => {
|
|
17
|
+
const plugin = createNextComponentDataSourcePlugin()
|
|
18
|
+
|
|
19
|
+
it('returns structure unchanged if no data sources', async () => {
|
|
20
|
+
const structure = createComponentStructure({}, undefined)
|
|
21
|
+
const result = await plugin(structure)
|
|
22
|
+
|
|
23
|
+
expect(result).toBe(structure)
|
|
24
|
+
expect(Object.keys(result.options.extractedResources || {})).toHaveLength(0)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('returns structure unchanged if no options', async () => {
|
|
28
|
+
const structure: any = {
|
|
29
|
+
uidl: component('Test', elementNode('div')),
|
|
30
|
+
chunks: [createComponentChunk()],
|
|
31
|
+
dependencies: {},
|
|
32
|
+
options: {},
|
|
33
|
+
}
|
|
34
|
+
const result = await plugin(structure)
|
|
35
|
+
|
|
36
|
+
expect(result).toBe(structure)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('returns structure unchanged if no jsx-component chunk', async () => {
|
|
40
|
+
const structure: any = {
|
|
41
|
+
uidl: component('Test', elementNode('div')),
|
|
42
|
+
chunks: [],
|
|
43
|
+
dependencies: {},
|
|
44
|
+
options: {
|
|
45
|
+
dataSources: {},
|
|
46
|
+
extractedResources: {},
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
const result = await plugin(structure)
|
|
50
|
+
|
|
51
|
+
expect(result).toBe(structure)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('extracts API route for data-source-item node', async () => {
|
|
55
|
+
const dataSource = createPostgreSQLDataSource('ds-1')
|
|
56
|
+
const node = createDataSourceNode('ds-1', 'users', 'postgresql')
|
|
57
|
+
|
|
58
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-1', 'users')
|
|
59
|
+
const componentChunk = createComponentChunk()
|
|
60
|
+
componentChunk.meta!.nodesLookup = {
|
|
61
|
+
'ds-1': jsxElement,
|
|
62
|
+
}
|
|
63
|
+
componentChunk.content = jsxElement
|
|
64
|
+
|
|
65
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
66
|
+
const uidl = component('Test', rootNode)
|
|
67
|
+
|
|
68
|
+
const structure = {
|
|
69
|
+
uidl,
|
|
70
|
+
chunks: [componentChunk],
|
|
71
|
+
dependencies: {},
|
|
72
|
+
options: {
|
|
73
|
+
dataSources: { 'ds-1': dataSource },
|
|
74
|
+
extractedResources: {},
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const result = await plugin(structure)
|
|
79
|
+
const apiFiles = Object.keys(result.options.extractedResources || {}).filter((key) =>
|
|
80
|
+
key.startsWith('api/')
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
expect(apiFiles.length).toBeGreaterThan(0)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('extracts API route for data-source-list node', async () => {
|
|
87
|
+
const dataSource = createRESTAPIDataSource('ds-2')
|
|
88
|
+
const node = createDataSourceListNode('ds-2', 'data', 'rest-api')
|
|
89
|
+
|
|
90
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-2', 'data', 'rest-api', 'items')
|
|
91
|
+
const componentChunk = createComponentChunk()
|
|
92
|
+
componentChunk.meta!.nodesLookup = {
|
|
93
|
+
'ds-2': jsxElement,
|
|
94
|
+
}
|
|
95
|
+
componentChunk.content = jsxElement
|
|
96
|
+
|
|
97
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
98
|
+
const uidl = component('Test', rootNode)
|
|
99
|
+
|
|
100
|
+
const structure = {
|
|
101
|
+
uidl,
|
|
102
|
+
chunks: [componentChunk],
|
|
103
|
+
dependencies: {},
|
|
104
|
+
options: {
|
|
105
|
+
dataSources: { 'ds-2': dataSource },
|
|
106
|
+
extractedResources: {},
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const result = await plugin(structure)
|
|
111
|
+
const apiFiles = Object.keys(result.options.extractedResources || {})
|
|
112
|
+
|
|
113
|
+
expect(apiFiles.length).toBeGreaterThan(0)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('generates correct file name and path', async () => {
|
|
117
|
+
const dataSource = createPostgreSQLDataSource('ds-unique-123')
|
|
118
|
+
const node = createDataSourceNode('ds-unique-123', 'users', 'postgresql')
|
|
119
|
+
|
|
120
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-unique-123', 'users')
|
|
121
|
+
const componentChunk = createComponentChunk()
|
|
122
|
+
componentChunk.meta!.nodesLookup = {
|
|
123
|
+
'ds-unique-123': jsxElement,
|
|
124
|
+
}
|
|
125
|
+
componentChunk.content = jsxElement
|
|
126
|
+
|
|
127
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
128
|
+
const uidl = component('Test', rootNode)
|
|
129
|
+
|
|
130
|
+
const structure = {
|
|
131
|
+
uidl,
|
|
132
|
+
chunks: [componentChunk],
|
|
133
|
+
dependencies: {},
|
|
134
|
+
options: {
|
|
135
|
+
dataSources: { 'ds-unique-123': dataSource },
|
|
136
|
+
extractedResources: {},
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const result = await plugin(structure)
|
|
141
|
+
const extractedKeys = Object.keys(result.options.extractedResources || {})
|
|
142
|
+
|
|
143
|
+
expect(extractedKeys.some((key) => key.includes('postgresql'))).toBe(true)
|
|
144
|
+
expect(extractedKeys.some((key) => key.includes('users'))).toBe(true)
|
|
145
|
+
|
|
146
|
+
const apiFile = extractedKeys.find((key) => key.startsWith('api/'))
|
|
147
|
+
if (apiFile) {
|
|
148
|
+
const resource = result.options.extractedResources![apiFile]
|
|
149
|
+
expect(resource.path).toContain('pages')
|
|
150
|
+
expect(resource.path).toContain('api')
|
|
151
|
+
expect(resource.fileType).toBe(FileType.JS)
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('handles multiple data sources', async () => {
|
|
156
|
+
const ds1 = createPostgreSQLDataSource('ds-1')
|
|
157
|
+
const ds2 = createRESTAPIDataSource('ds-2')
|
|
158
|
+
|
|
159
|
+
const node1 = createDataSourceNode('ds-1', 'users', 'postgresql')
|
|
160
|
+
const node2 = createDataSourceNode('ds-2', '', 'rest-api')
|
|
161
|
+
|
|
162
|
+
const jsxElement1 = createMockJSXElementWithResourceDef('ds-1', 'users', 'postgresql')
|
|
163
|
+
const jsxElement2 = createMockJSXElementWithResourceDef('ds-2', '', 'rest-api')
|
|
164
|
+
|
|
165
|
+
const componentChunk = createComponentChunk()
|
|
166
|
+
componentChunk.meta!.nodesLookup = {
|
|
167
|
+
'ds-1': jsxElement1,
|
|
168
|
+
'ds-2': jsxElement2,
|
|
169
|
+
}
|
|
170
|
+
componentChunk.content = types.jsxFragment(
|
|
171
|
+
types.jsxOpeningFragment(),
|
|
172
|
+
types.jsxClosingFragment(),
|
|
173
|
+
[jsxElement1, jsxElement2]
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
const uidl = component('Test', elementNode('div'))
|
|
177
|
+
uidl.node = {
|
|
178
|
+
type: 'element',
|
|
179
|
+
content: {
|
|
180
|
+
elementType: 'div',
|
|
181
|
+
children: [node1 as any, node2 as any],
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const structure = {
|
|
186
|
+
uidl,
|
|
187
|
+
chunks: [componentChunk],
|
|
188
|
+
dependencies: {},
|
|
189
|
+
options: {
|
|
190
|
+
dataSources: { 'ds-1': ds1, 'ds-2': ds2 },
|
|
191
|
+
extractedResources: {},
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const result = await plugin(structure)
|
|
196
|
+
const apiFiles = Object.keys(result.options.extractedResources || {}).filter((key) =>
|
|
197
|
+
key.startsWith('api/')
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
expect(apiFiles.length).toBeGreaterThan(0)
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
describe('createNextPagesDataSourcePlugin', () => {
|
|
205
|
+
const plugin = createNextPagesDataSourcePlugin()
|
|
206
|
+
|
|
207
|
+
it('returns structure unchanged if no data sources', async () => {
|
|
208
|
+
const structure = createComponentStructure({}, undefined)
|
|
209
|
+
const result = await plugin(structure)
|
|
210
|
+
|
|
211
|
+
expect(result).toBe(structure)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('extracts to getStaticProps for static data', async () => {
|
|
215
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
216
|
+
const node = createDataSourceNode('ds-js', 'data', 'javascript', false)
|
|
217
|
+
|
|
218
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-js', 'data', 'javascript')
|
|
219
|
+
const componentChunk = createComponentChunk()
|
|
220
|
+
componentChunk.meta!.nodesLookup = {
|
|
221
|
+
'ds-js': jsxElement,
|
|
222
|
+
}
|
|
223
|
+
componentChunk.content = types.arrowFunctionExpression(
|
|
224
|
+
[],
|
|
225
|
+
types.blockStatement([types.returnStatement(jsxElement)])
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
229
|
+
const uidl = component('Test', rootNode)
|
|
230
|
+
|
|
231
|
+
const structure = {
|
|
232
|
+
uidl,
|
|
233
|
+
chunks: [componentChunk],
|
|
234
|
+
dependencies: {},
|
|
235
|
+
options: {
|
|
236
|
+
dataSources: { 'ds-js': dataSource },
|
|
237
|
+
extractedResources: {},
|
|
238
|
+
},
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const result = await plugin(structure)
|
|
242
|
+
|
|
243
|
+
const getStaticPropsChunk = result.chunks.find((chunk) => chunk.name === 'getStaticProps')
|
|
244
|
+
expect(getStaticPropsChunk).toBeDefined()
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('extracts to API route for dynamic params', async () => {
|
|
248
|
+
const dataSource = createPostgreSQLDataSource('ds-pg')
|
|
249
|
+
const node = createDataSourceNode('ds-pg', 'users', 'postgresql', true)
|
|
250
|
+
|
|
251
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-pg', 'users')
|
|
252
|
+
const componentChunk = createComponentChunk()
|
|
253
|
+
componentChunk.meta!.nodesLookup = {
|
|
254
|
+
'ds-pg': jsxElement,
|
|
255
|
+
}
|
|
256
|
+
componentChunk.content = jsxElement
|
|
257
|
+
|
|
258
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
259
|
+
const uidl = component('Test', rootNode)
|
|
260
|
+
|
|
261
|
+
const structure = {
|
|
262
|
+
uidl,
|
|
263
|
+
chunks: [componentChunk],
|
|
264
|
+
dependencies: {},
|
|
265
|
+
options: {
|
|
266
|
+
dataSources: { 'ds-pg': dataSource },
|
|
267
|
+
extractedResources: {},
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const result = await plugin(structure)
|
|
272
|
+
|
|
273
|
+
const apiFiles = Object.keys(result.options.extractedResources || {}).filter((key) =>
|
|
274
|
+
key.startsWith('api/')
|
|
275
|
+
)
|
|
276
|
+
expect(apiFiles.length).toBeGreaterThan(0)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('creates utils file for getStaticProps data sources', async () => {
|
|
280
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
281
|
+
const node = createDataSourceNode('ds-js', 'data', 'javascript', false)
|
|
282
|
+
|
|
283
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-js', 'data', 'javascript')
|
|
284
|
+
const componentChunk = createComponentChunk()
|
|
285
|
+
componentChunk.meta!.nodesLookup = {
|
|
286
|
+
'ds-js': jsxElement,
|
|
287
|
+
}
|
|
288
|
+
componentChunk.content = types.arrowFunctionExpression(
|
|
289
|
+
[],
|
|
290
|
+
types.blockStatement([types.returnStatement(jsxElement)])
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
294
|
+
const uidl = component('Test', rootNode)
|
|
295
|
+
|
|
296
|
+
const structure = {
|
|
297
|
+
uidl,
|
|
298
|
+
chunks: [componentChunk],
|
|
299
|
+
dependencies: {},
|
|
300
|
+
options: {
|
|
301
|
+
dataSources: { 'ds-js': dataSource },
|
|
302
|
+
extractedResources: {},
|
|
303
|
+
},
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const result = await plugin(structure)
|
|
307
|
+
|
|
308
|
+
const utilsFiles = Object.keys(result.options.extractedResources || {}).filter((key) =>
|
|
309
|
+
key.startsWith('utils/')
|
|
310
|
+
)
|
|
311
|
+
expect(utilsFiles.length).toBeGreaterThan(0)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it('adds dependencies for fetcher imports', async () => {
|
|
315
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
316
|
+
const node = createDataSourceNode('ds-js', 'data', 'javascript', false)
|
|
317
|
+
|
|
318
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-js', 'data', 'javascript')
|
|
319
|
+
const componentChunk = createComponentChunk()
|
|
320
|
+
componentChunk.meta!.nodesLookup = {
|
|
321
|
+
'ds-js': jsxElement,
|
|
322
|
+
}
|
|
323
|
+
componentChunk.content = types.arrowFunctionExpression(
|
|
324
|
+
[],
|
|
325
|
+
types.blockStatement([types.returnStatement(jsxElement)])
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
329
|
+
const uidl = component('Test', rootNode)
|
|
330
|
+
|
|
331
|
+
const structure = {
|
|
332
|
+
uidl,
|
|
333
|
+
chunks: [componentChunk],
|
|
334
|
+
dependencies: {},
|
|
335
|
+
options: {
|
|
336
|
+
dataSources: { 'ds-js': dataSource },
|
|
337
|
+
extractedResources: {},
|
|
338
|
+
},
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const result = await plugin(structure)
|
|
342
|
+
|
|
343
|
+
expect(Object.keys(result.dependencies).length).toBeGreaterThan(0)
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it('does not duplicate data sources with same ID and table', async () => {
|
|
347
|
+
const dataSource = createPostgreSQLDataSource('ds-same')
|
|
348
|
+
const node1 = createDataSourceNode('ds-same', 'users', 'postgresql', false)
|
|
349
|
+
const node2 = createDataSourceNode('ds-same', 'users', 'postgresql', false)
|
|
350
|
+
|
|
351
|
+
const jsxElement1 = createMockJSXElementWithResourceDef('ds-same', 'users')
|
|
352
|
+
const jsxElement2 = createMockJSXElementWithResourceDef('ds-same', 'users')
|
|
353
|
+
|
|
354
|
+
const componentChunk = createComponentChunk()
|
|
355
|
+
componentChunk.meta!.nodesLookup = {
|
|
356
|
+
'ds-same-1': jsxElement1,
|
|
357
|
+
'ds-same-2': jsxElement2,
|
|
358
|
+
}
|
|
359
|
+
componentChunk.content = types.jsxFragment(
|
|
360
|
+
types.jsxOpeningFragment(),
|
|
361
|
+
types.jsxClosingFragment(),
|
|
362
|
+
[jsxElement1, jsxElement2]
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
const uidl = component('Test', elementNode('div'))
|
|
366
|
+
uidl.node = {
|
|
367
|
+
type: 'element',
|
|
368
|
+
content: {
|
|
369
|
+
elementType: 'div',
|
|
370
|
+
children: [node1 as any, node2 as any],
|
|
371
|
+
},
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const structure = {
|
|
375
|
+
uidl,
|
|
376
|
+
chunks: [componentChunk],
|
|
377
|
+
dependencies: {},
|
|
378
|
+
options: {
|
|
379
|
+
dataSources: { 'ds-same': dataSource },
|
|
380
|
+
extractedResources: {},
|
|
381
|
+
},
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const result = await plugin(structure)
|
|
385
|
+
|
|
386
|
+
const utilsFiles = Object.keys(result.options.extractedResources || {}).filter((key) =>
|
|
387
|
+
key.startsWith('utils/')
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
expect(utilsFiles.length).toBe(1)
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('creates getStaticProps chunk with correct structure', async () => {
|
|
394
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
395
|
+
const node = createDataSourceNode('ds-js', 'data', 'javascript', false)
|
|
396
|
+
|
|
397
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-js', 'data', 'javascript')
|
|
398
|
+
const componentChunk = createComponentChunk()
|
|
399
|
+
componentChunk.meta!.nodesLookup = {
|
|
400
|
+
'ds-js': jsxElement,
|
|
401
|
+
}
|
|
402
|
+
componentChunk.content = types.arrowFunctionExpression(
|
|
403
|
+
[],
|
|
404
|
+
types.blockStatement([types.returnStatement(jsxElement)])
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
408
|
+
const uidl = component('Test', rootNode)
|
|
409
|
+
|
|
410
|
+
const structure = {
|
|
411
|
+
uidl,
|
|
412
|
+
chunks: [componentChunk],
|
|
413
|
+
dependencies: {},
|
|
414
|
+
options: {
|
|
415
|
+
dataSources: { 'ds-js': dataSource },
|
|
416
|
+
extractedResources: {},
|
|
417
|
+
},
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const result = await plugin(structure)
|
|
421
|
+
|
|
422
|
+
const getStaticPropsChunk = result.chunks.find((chunk) => chunk.name === 'getStaticProps')
|
|
423
|
+
|
|
424
|
+
expect(getStaticPropsChunk).toBeDefined()
|
|
425
|
+
expect(getStaticPropsChunk!.type).toBe('ast')
|
|
426
|
+
expect(getStaticPropsChunk!.fileType).toBe(FileType.JS)
|
|
427
|
+
expect(getStaticPropsChunk!.linkAfter).toContain('jsx-component')
|
|
428
|
+
|
|
429
|
+
const declaration = (getStaticPropsChunk!.content as types.ExportNamedDeclaration)
|
|
430
|
+
.declaration as types.FunctionDeclaration
|
|
431
|
+
expect(declaration.id?.name).toBe('getStaticProps')
|
|
432
|
+
expect(declaration.async).toBe(true)
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
it('adds initialData attribute to JSX elements', async () => {
|
|
436
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
437
|
+
const node = createDataSourceNode('ds-js', 'data', 'javascript', false)
|
|
438
|
+
|
|
439
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-js', 'data', 'javascript')
|
|
440
|
+
const componentChunk = createComponentChunk()
|
|
441
|
+
componentChunk.meta!.nodesLookup = {
|
|
442
|
+
'ds-js': jsxElement,
|
|
443
|
+
}
|
|
444
|
+
// Wrap in a return statement inside an arrow function (simulating component structure)
|
|
445
|
+
componentChunk.content = types.arrowFunctionExpression(
|
|
446
|
+
[],
|
|
447
|
+
types.blockStatement([types.returnStatement(jsxElement)])
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
451
|
+
const uidl = component('Test', rootNode)
|
|
452
|
+
|
|
453
|
+
const structure = {
|
|
454
|
+
uidl,
|
|
455
|
+
chunks: [componentChunk],
|
|
456
|
+
dependencies: {},
|
|
457
|
+
options: {
|
|
458
|
+
dataSources: { 'ds-js': dataSource },
|
|
459
|
+
extractedResources: {},
|
|
460
|
+
},
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
await plugin(structure)
|
|
464
|
+
|
|
465
|
+
const hasInitialData = jsxElement.openingElement.attributes.some(
|
|
466
|
+
(attr) => (attr as types.JSXAttribute).name?.name === 'initialData'
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
expect(hasInitialData).toBe(true)
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
it('adds persistDataDuringLoading attribute', async () => {
|
|
473
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
474
|
+
const node = createDataSourceNode('ds-js', 'data', 'javascript', false)
|
|
475
|
+
|
|
476
|
+
const jsxElement = createMockJSXElementWithResourceDef('ds-js', 'data', 'javascript')
|
|
477
|
+
const componentChunk = createComponentChunk()
|
|
478
|
+
componentChunk.meta!.nodesLookup = {
|
|
479
|
+
'ds-js': jsxElement,
|
|
480
|
+
}
|
|
481
|
+
// Wrap in a return statement inside an arrow function (simulating component structure)
|
|
482
|
+
componentChunk.content = types.arrowFunctionExpression(
|
|
483
|
+
[],
|
|
484
|
+
types.blockStatement([types.returnStatement(jsxElement)])
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
const rootNode = elementNode('div', {}, [node as any])
|
|
488
|
+
const uidl = component('Test', rootNode)
|
|
489
|
+
|
|
490
|
+
const structure = {
|
|
491
|
+
uidl,
|
|
492
|
+
chunks: [componentChunk],
|
|
493
|
+
dependencies: {},
|
|
494
|
+
options: {
|
|
495
|
+
dataSources: { 'ds-js': dataSource },
|
|
496
|
+
extractedResources: {},
|
|
497
|
+
},
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
await plugin(structure)
|
|
501
|
+
|
|
502
|
+
const persistDataAttr = jsxElement.openingElement.attributes.find(
|
|
503
|
+
(attr) => (attr as types.JSXAttribute).name?.name === 'persistDataDuringLoading'
|
|
504
|
+
) as types.JSXAttribute
|
|
505
|
+
|
|
506
|
+
expect(persistDataAttr).toBeDefined()
|
|
507
|
+
expect((persistDataAttr.value as types.JSXExpressionContainer).expression).toMatchObject({
|
|
508
|
+
type: 'BooleanLiteral',
|
|
509
|
+
value: true,
|
|
510
|
+
})
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
it('skips nodes with existing initialData', async () => {
|
|
514
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
515
|
+
const node = createDataSourceNode('ds-js', '', 'javascript', false)
|
|
516
|
+
;(node.content as any).initialData = []
|
|
517
|
+
|
|
518
|
+
const structure = createComponentStructure({ 'ds-js': dataSource }, node)
|
|
519
|
+
const initialChunkCount = structure.chunks.length
|
|
520
|
+
|
|
521
|
+
const result = await plugin(structure)
|
|
522
|
+
|
|
523
|
+
expect(result.chunks.length).toBe(initialChunkCount)
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
it('skips nodes without resource', async () => {
|
|
527
|
+
const dataSource = createJavaScriptDataSource('ds-js')
|
|
528
|
+
const node = createDataSourceNode('ds-js', '', 'javascript', false)
|
|
529
|
+
delete (node.content as any).resource
|
|
530
|
+
|
|
531
|
+
const structure = createComponentStructure({ 'ds-js': dataSource }, node)
|
|
532
|
+
const initialChunkCount = structure.chunks.length
|
|
533
|
+
|
|
534
|
+
const result = await plugin(structure)
|
|
535
|
+
|
|
536
|
+
expect(result.chunks.length).toBe(initialChunkCount)
|
|
537
|
+
})
|
|
538
|
+
})
|
|
539
|
+
|
|
540
|
+
describe('plugin error handling', () => {
|
|
541
|
+
it('handles missing resourceDefinition gracefully', async () => {
|
|
542
|
+
const plugin = createNextComponentDataSourcePlugin()
|
|
543
|
+
const node = createDataSourceNode('ds-1', 'users', 'postgresql')
|
|
544
|
+
delete (node.content as any).resourceDefinition
|
|
545
|
+
|
|
546
|
+
const structure = createComponentStructure({}, node)
|
|
547
|
+
|
|
548
|
+
expect(async () => {
|
|
549
|
+
await plugin(structure)
|
|
550
|
+
}).not.toThrow()
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
it('handles invalid data source ID gracefully', async () => {
|
|
554
|
+
const plugin = createNextComponentDataSourcePlugin()
|
|
555
|
+
const dataSource = createPostgreSQLDataSource('ds-1')
|
|
556
|
+
const node = createDataSourceNode('ds-invalid', 'users', 'postgresql')
|
|
557
|
+
|
|
558
|
+
const structure = createComponentStructure({ 'ds-1': dataSource }, node)
|
|
559
|
+
|
|
560
|
+
expect(async () => {
|
|
561
|
+
await plugin(structure)
|
|
562
|
+
}).not.toThrow()
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
it('handles missing nodesLookup gracefully', async () => {
|
|
566
|
+
const plugin = createNextComponentDataSourcePlugin()
|
|
567
|
+
const dataSource = createPostgreSQLDataSource('ds-1')
|
|
568
|
+
const node = createDataSourceNode('ds-1', 'users', 'postgresql')
|
|
569
|
+
|
|
570
|
+
const structure = createComponentStructure({ 'ds-1': dataSource }, node)
|
|
571
|
+
structure.chunks[0].meta = {}
|
|
572
|
+
|
|
573
|
+
expect(async () => {
|
|
574
|
+
await plugin(structure)
|
|
575
|
+
}).not.toThrow()
|
|
576
|
+
})
|
|
577
|
+
})
|