@teleporthq/teleport-plugin-common 0.41.0 → 0.42.0
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__/builders/html-builders.ts +9 -2
- package/__tests__/node-handlers/node-to-html/index.ts +2 -0
- package/__tests__/node-handlers/node-to-jsx/index.ts +1 -1
- package/__tests__/node-handlers/node-to-jsx/utils.ts +16 -3
- package/dist/cjs/builders/ast-builders.d.ts +1 -0
- package/dist/cjs/builders/ast-builders.d.ts.map +1 -1
- package/dist/cjs/builders/ast-builders.js +19 -3
- package/dist/cjs/builders/ast-builders.js.map +1 -1
- package/dist/cjs/builders/hast-builders.d.ts +1 -0
- package/dist/cjs/builders/hast-builders.d.ts.map +1 -1
- package/dist/cjs/builders/hast-builders.js +11 -1
- package/dist/cjs/builders/hast-builders.js.map +1 -1
- package/dist/cjs/builders/style-builders.d.ts +2 -2
- package/dist/cjs/builders/style-builders.d.ts.map +1 -1
- package/dist/cjs/builders/style-builders.js +39 -19
- package/dist/cjs/builders/style-builders.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/node-handlers/node-to-html/constants.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-html/constants.js +2 -0
- package/dist/cjs/node-handlers/node-to-html/constants.js.map +1 -1
- package/dist/cjs/node-handlers/node-to-html/index.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-html/index.js +53 -1
- package/dist/cjs/node-handlers/node-to-html/index.js.map +1 -1
- package/dist/cjs/node-handlers/node-to-html/types.d.ts +5 -1
- package/dist/cjs/node-handlers/node-to-html/types.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-html/utils.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-html/utils.js +48 -4
- package/dist/cjs/node-handlers/node-to-html/utils.js.map +1 -1
- package/dist/cjs/node-handlers/node-to-jsx/index.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-jsx/index.js +325 -44
- package/dist/cjs/node-handlers/node-to-jsx/index.js.map +1 -1
- package/dist/cjs/node-handlers/node-to-jsx/types.d.ts +5 -5
- package/dist/cjs/node-handlers/node-to-jsx/types.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-jsx/utils.d.ts +5 -5
- package/dist/cjs/node-handlers/node-to-jsx/utils.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-jsx/utils.js +79 -36
- package/dist/cjs/node-handlers/node-to-jsx/utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils/ast-utils.d.ts +16 -6
- package/dist/cjs/utils/ast-utils.d.ts.map +1 -1
- package/dist/cjs/utils/ast-utils.js +182 -40
- package/dist/cjs/utils/ast-utils.js.map +1 -1
- package/dist/cjs/utils/hast-utils.d.ts +8 -6
- package/dist/cjs/utils/hast-utils.d.ts.map +1 -1
- package/dist/cjs/utils/hast-utils.js +28 -4
- package/dist/cjs/utils/hast-utils.js.map +1 -1
- package/dist/cjs/utils/types.d.ts +3 -0
- package/dist/cjs/utils/types.d.ts.map +1 -0
- package/dist/cjs/utils/types.js +3 -0
- package/dist/cjs/utils/types.js.map +1 -0
- package/dist/esm/builders/ast-builders.d.ts +1 -0
- package/dist/esm/builders/ast-builders.d.ts.map +1 -1
- package/dist/esm/builders/ast-builders.js +18 -3
- package/dist/esm/builders/ast-builders.js.map +1 -1
- package/dist/esm/builders/hast-builders.d.ts +1 -0
- package/dist/esm/builders/hast-builders.d.ts.map +1 -1
- package/dist/esm/builders/hast-builders.js +9 -0
- package/dist/esm/builders/hast-builders.js.map +1 -1
- package/dist/esm/builders/style-builders.d.ts +2 -2
- package/dist/esm/builders/style-builders.d.ts.map +1 -1
- package/dist/esm/builders/style-builders.js +37 -18
- package/dist/esm/builders/style-builders.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/node-handlers/node-to-html/constants.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-html/constants.js +2 -0
- package/dist/esm/node-handlers/node-to-html/constants.js.map +1 -1
- package/dist/esm/node-handlers/node-to-html/index.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-html/index.js +54 -2
- package/dist/esm/node-handlers/node-to-html/index.js.map +1 -1
- package/dist/esm/node-handlers/node-to-html/types.d.ts +5 -1
- package/dist/esm/node-handlers/node-to-html/types.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-html/utils.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-html/utils.js +45 -4
- package/dist/esm/node-handlers/node-to-html/utils.js.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/index.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/index.js +326 -45
- package/dist/esm/node-handlers/node-to-jsx/index.js.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/types.d.ts +5 -5
- package/dist/esm/node-handlers/node-to-jsx/types.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/utils.d.ts +5 -5
- package/dist/esm/node-handlers/node-to-jsx/utils.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/utils.js +79 -36
- package/dist/esm/node-handlers/node-to-jsx/utils.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils/ast-utils.d.ts +16 -6
- package/dist/esm/utils/ast-utils.d.ts.map +1 -1
- package/dist/esm/utils/ast-utils.js +176 -39
- package/dist/esm/utils/ast-utils.js.map +1 -1
- package/dist/esm/utils/hast-utils.d.ts +8 -6
- package/dist/esm/utils/hast-utils.d.ts.map +1 -1
- package/dist/esm/utils/hast-utils.js +26 -3
- package/dist/esm/utils/hast-utils.js.map +1 -1
- package/dist/esm/utils/types.d.ts +3 -0
- package/dist/esm/utils/types.d.ts.map +1 -0
- package/dist/esm/utils/types.js +2 -0
- package/dist/esm/utils/types.js.map +1 -0
- package/package.json +4 -4
- package/src/builders/ast-builders.ts +36 -2
- package/src/builders/hast-builders.ts +11 -0
- package/src/builders/style-builders.ts +51 -27
- package/src/index.ts +12 -1
- package/src/node-handlers/node-to-html/constants.ts +2 -0
- package/src/node-handlers/node-to-html/index.ts +95 -5
- package/src/node-handlers/node-to-html/types.ts +6 -0
- package/src/node-handlers/node-to-html/utils.ts +60 -5
- package/src/node-handlers/node-to-jsx/index.ts +566 -62
- package/src/node-handlers/node-to-jsx/types.ts +10 -29
- package/src/node-handlers/node-to-jsx/utils.ts +106 -42
- package/src/utils/ast-utils.ts +283 -82
- package/src/utils/hast-utils.ts +37 -9
- package/src/utils/types.ts +25 -0
|
@@ -11,9 +11,13 @@ import {
|
|
|
11
11
|
UIDLCMSItemNode,
|
|
12
12
|
UIDLExpressionValue,
|
|
13
13
|
UIDLCMSListRepeaterNode,
|
|
14
|
+
UIDLCMSMixedTypeNode,
|
|
15
|
+
UIDLElement,
|
|
16
|
+
UIDLDataSourceItemNode,
|
|
17
|
+
UIDLDataSourceListNode,
|
|
14
18
|
} from '@teleporthq/teleport-types'
|
|
15
19
|
import { UIDLUtils, StringUtils } from '@teleporthq/teleport-shared'
|
|
16
|
-
import { JSXASTReturnType, NodeToJSX } from './types'
|
|
20
|
+
import { JSXASTReturnType, JSXGenerationOptions, JSXGenerationParams, NodeToJSX } from './types'
|
|
17
21
|
|
|
18
22
|
import {
|
|
19
23
|
addEventHandlerToTag,
|
|
@@ -31,23 +35,113 @@ import {
|
|
|
31
35
|
generateDynamicWindowImport,
|
|
32
36
|
addDynamicExpressionAttributeToJSXTag,
|
|
33
37
|
resolveObjectValue,
|
|
38
|
+
objectToObjectExpression,
|
|
34
39
|
} from '../../utils/ast-utils'
|
|
35
40
|
import { createJSXTag, createSelfClosingJSXTag } from '../../builders/ast-builders'
|
|
36
41
|
import { DEFAULT_JSX_OPTIONS } from './constants'
|
|
37
42
|
import { ASTBuilders, ASTUtils } from '../..'
|
|
38
43
|
|
|
44
|
+
const getElementType = (node: UIDLNode): string | null => {
|
|
45
|
+
if (
|
|
46
|
+
node.type === 'element' &&
|
|
47
|
+
node.content &&
|
|
48
|
+
typeof node.content === 'object' &&
|
|
49
|
+
'elementType' in node.content
|
|
50
|
+
) {
|
|
51
|
+
return (node.content as any).elementType
|
|
52
|
+
}
|
|
53
|
+
if ((node.type === 'data-source-list' || node.type === 'data-source-item') && node.content) {
|
|
54
|
+
return (node.content as any).elementType || 'DataProvider'
|
|
55
|
+
}
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const getClassName = (node: UIDLNode): string | null => {
|
|
60
|
+
if (
|
|
61
|
+
node.type === 'element' &&
|
|
62
|
+
node.content &&
|
|
63
|
+
typeof node.content === 'object' &&
|
|
64
|
+
'key' in node.content
|
|
65
|
+
) {
|
|
66
|
+
return (node.content as any).key || null
|
|
67
|
+
}
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const reorderChildrenForSearch = (children: UIDLNode[]): UIDLNode[] => {
|
|
72
|
+
const searchNodes: UIDLNode[] = []
|
|
73
|
+
const dataProviderNodes: UIDLNode[] = []
|
|
74
|
+
const paginationNodes: UIDLNode[] = []
|
|
75
|
+
const otherNodes: UIDLNode[] = []
|
|
76
|
+
|
|
77
|
+
children.forEach((child) => {
|
|
78
|
+
const elementType = getElementType(child)
|
|
79
|
+
const nodeType = child.type
|
|
80
|
+
const className = getClassName(child)
|
|
81
|
+
|
|
82
|
+
// Check for search nodes - use className since elementType is replaced by semanticType
|
|
83
|
+
if (
|
|
84
|
+
className &&
|
|
85
|
+
(className.includes('data-source-search') || className.includes('search-node'))
|
|
86
|
+
) {
|
|
87
|
+
searchNodes.push(child)
|
|
88
|
+
}
|
|
89
|
+
// Check for DataProvider nodes - these should appear SECOND
|
|
90
|
+
else if (
|
|
91
|
+
nodeType === 'data-source-list' ||
|
|
92
|
+
nodeType === 'data-source-item' ||
|
|
93
|
+
elementType === 'DataProvider'
|
|
94
|
+
) {
|
|
95
|
+
dataProviderNodes.push(child)
|
|
96
|
+
}
|
|
97
|
+
// Check for pagination nodes - use className since elementType is replaced by semanticType
|
|
98
|
+
else if (
|
|
99
|
+
(elementType &&
|
|
100
|
+
(elementType.includes('pagination') || elementType.includes('cms-pagination'))) ||
|
|
101
|
+
(className && (className.includes('pagination') || className.includes('cms-pagination')))
|
|
102
|
+
) {
|
|
103
|
+
paginationNodes.push(child)
|
|
104
|
+
}
|
|
105
|
+
// Everything else goes in the middle
|
|
106
|
+
else {
|
|
107
|
+
otherNodes.push(child)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// Only reorder if we have search or pagination nodes alongside a DataProvider
|
|
112
|
+
// This ensures we only reorder when there's an actual pagination/search group
|
|
113
|
+
// If there's no search/pagination, keep original order to preserve DataProvider positions
|
|
114
|
+
const hasSearchOrPagination = searchNodes.length > 0 || paginationNodes.length > 0
|
|
115
|
+
const hasDataProvider = dataProviderNodes.length > 0
|
|
116
|
+
|
|
117
|
+
if (hasSearchOrPagination && hasDataProvider) {
|
|
118
|
+
// Order: search nodes first, then data providers, then other nodes, then pagination last
|
|
119
|
+
// This ensures: search input -> DataProvider -> content -> pagination buttons
|
|
120
|
+
return [...searchNodes, ...dataProviderNodes, ...otherNodes, ...paginationNodes]
|
|
121
|
+
} else {
|
|
122
|
+
// No reordering needed - preserve original order
|
|
123
|
+
return children
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
39
127
|
const generateElementNode: NodeToJSX<UIDLElementNode, types.JSXElement> = (
|
|
40
128
|
node,
|
|
41
129
|
params,
|
|
42
130
|
jsxOptions
|
|
43
131
|
) => {
|
|
44
|
-
const { dependencies, nodesLookup
|
|
45
|
-
const options = { ...DEFAULT_JSX_OPTIONS, ...jsxOptions
|
|
132
|
+
const { dependencies, nodesLookup } = params
|
|
133
|
+
const options = { ...DEFAULT_JSX_OPTIONS, ...jsxOptions }
|
|
46
134
|
const { elementType, selfClosing, children, key, attrs, dependency, events } = node.content
|
|
47
135
|
|
|
48
136
|
const originalElementName = elementType || 'component'
|
|
49
137
|
let tagName = originalElementName
|
|
50
138
|
|
|
139
|
+
// Check if this is a fragment element - normalize to Fragment before processing
|
|
140
|
+
const isFragment = tagName.toLowerCase() === 'fragment'
|
|
141
|
+
if (isFragment) {
|
|
142
|
+
tagName = 'Fragment'
|
|
143
|
+
}
|
|
144
|
+
|
|
51
145
|
if (dependency) {
|
|
52
146
|
if (
|
|
53
147
|
options.dependencyHandling === 'import' ||
|
|
@@ -75,59 +169,29 @@ const generateElementNode: NodeToJSX<UIDLElementNode, types.JSXElement> = (
|
|
|
75
169
|
const dynamicWindowImport = generateDynamicWindowImport('useEffect', dependency.path)
|
|
76
170
|
params.windowImports[dependency.path] = dynamicWindowImport
|
|
77
171
|
}
|
|
172
|
+
} else if (isFragment) {
|
|
173
|
+
// If no dependency was provided but this is a fragment, add Fragment dependency
|
|
174
|
+
if (options.dependencyHandling === 'import') {
|
|
175
|
+
dependencies.Fragment = {
|
|
176
|
+
type: 'package',
|
|
177
|
+
path: 'react',
|
|
178
|
+
version: 'latest',
|
|
179
|
+
meta: {
|
|
180
|
+
namedImport: true,
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
}
|
|
78
184
|
}
|
|
79
185
|
|
|
80
186
|
const elementName =
|
|
81
187
|
dependency && dependency.type === 'local' && options.customElementTag
|
|
82
188
|
? options.customElementTag(tagName)
|
|
83
189
|
: tagName
|
|
190
|
+
|
|
84
191
|
const elementTag = selfClosing ? createSelfClosingJSXTag(elementName) : createJSXTag(elementName)
|
|
85
192
|
|
|
86
193
|
if (attrs) {
|
|
87
|
-
|
|
88
|
-
const attributeValue = attrs[attrKey]
|
|
89
|
-
|
|
90
|
-
switch (attributeValue.type) {
|
|
91
|
-
case 'dynamic':
|
|
92
|
-
const {
|
|
93
|
-
content: { referenceType },
|
|
94
|
-
} = attributeValue
|
|
95
|
-
|
|
96
|
-
switch (referenceType) {
|
|
97
|
-
default:
|
|
98
|
-
const prefix =
|
|
99
|
-
options.dynamicReferencePrefixMap[referenceType as 'prop' | 'state' | 'local']
|
|
100
|
-
addDynamicAttributeToJSXTag(
|
|
101
|
-
elementTag,
|
|
102
|
-
attrKey,
|
|
103
|
-
(attributeValue as UIDLDynamicReference).content.id,
|
|
104
|
-
prefix
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
break
|
|
108
|
-
}
|
|
109
|
-
break
|
|
110
|
-
case 'import':
|
|
111
|
-
addDynamicAttributeToJSXTag(elementTag, attrKey, attributeValue.content.id)
|
|
112
|
-
break
|
|
113
|
-
case 'raw':
|
|
114
|
-
addRawAttributeToJSXTag(elementTag, attrKey, attributeValue)
|
|
115
|
-
break
|
|
116
|
-
case 'comp-style':
|
|
117
|
-
case 'static':
|
|
118
|
-
addAttributeToJSXTag(elementTag, attrKey, attributeValue.content)
|
|
119
|
-
break
|
|
120
|
-
case 'expr':
|
|
121
|
-
addDynamicExpressionAttributeToJSXTag(elementTag, attributeValue, attrKey)
|
|
122
|
-
break
|
|
123
|
-
default:
|
|
124
|
-
throw new Error(
|
|
125
|
-
`generateElementNode could not generate code for attribute of type ${JSON.stringify(
|
|
126
|
-
attributeValue
|
|
127
|
-
)}`
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
})
|
|
194
|
+
addAttributesToJSXTag(attrs, elementTag, options, params)
|
|
131
195
|
}
|
|
132
196
|
|
|
133
197
|
if (events) {
|
|
@@ -137,7 +201,10 @@ const generateElementNode: NodeToJSX<UIDLElementNode, types.JSXElement> = (
|
|
|
137
201
|
}
|
|
138
202
|
|
|
139
203
|
if (!selfClosing && children) {
|
|
140
|
-
children
|
|
204
|
+
// Reorder children to ensure search nodes appear before DataProvider nodes
|
|
205
|
+
const reorderedChildren = reorderChildrenForSearch(children)
|
|
206
|
+
|
|
207
|
+
reorderedChildren.forEach((child) => {
|
|
141
208
|
const childTags = generateNode(child, params, options)
|
|
142
209
|
childTags.forEach((childTag) => {
|
|
143
210
|
if (typeof childTag === 'string') {
|
|
@@ -157,6 +224,84 @@ const generateElementNode: NodeToJSX<UIDLElementNode, types.JSXElement> = (
|
|
|
157
224
|
|
|
158
225
|
export default generateElementNode
|
|
159
226
|
|
|
227
|
+
const addAttributesToJSXTag = (
|
|
228
|
+
attrs: UIDLElement['attrs'],
|
|
229
|
+
elementTag: types.JSXElement,
|
|
230
|
+
options: JSXGenerationOptions,
|
|
231
|
+
params: JSXGenerationParams
|
|
232
|
+
) => {
|
|
233
|
+
Object.keys(attrs ?? {}).forEach((attrKey) => {
|
|
234
|
+
const attributeValue = attrs[attrKey]
|
|
235
|
+
|
|
236
|
+
if (!attributeValue.type) {
|
|
237
|
+
return
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
switch (attributeValue.type) {
|
|
241
|
+
case 'dynamic':
|
|
242
|
+
const {
|
|
243
|
+
content: { referenceType },
|
|
244
|
+
} = attributeValue
|
|
245
|
+
|
|
246
|
+
switch (referenceType) {
|
|
247
|
+
default:
|
|
248
|
+
const prefix =
|
|
249
|
+
options.dynamicReferencePrefixMap[referenceType as 'prop' | 'state' | 'local']
|
|
250
|
+
addDynamicAttributeToJSXTag(
|
|
251
|
+
elementTag,
|
|
252
|
+
attrKey,
|
|
253
|
+
(attributeValue as UIDLDynamicReference).content.id,
|
|
254
|
+
prefix
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
break
|
|
258
|
+
}
|
|
259
|
+
break
|
|
260
|
+
case 'import':
|
|
261
|
+
addDynamicAttributeToJSXTag(elementTag, attrKey, attributeValue.content.id)
|
|
262
|
+
break
|
|
263
|
+
case 'raw':
|
|
264
|
+
addRawAttributeToJSXTag(elementTag, attrKey, attributeValue)
|
|
265
|
+
break
|
|
266
|
+
case 'comp-style':
|
|
267
|
+
case 'static':
|
|
268
|
+
addAttributeToJSXTag(elementTag, attrKey, attributeValue.content)
|
|
269
|
+
break
|
|
270
|
+
case 'expr':
|
|
271
|
+
addDynamicExpressionAttributeToJSXTag(elementTag, attributeValue, attrKey)
|
|
272
|
+
break
|
|
273
|
+
|
|
274
|
+
case 'element':
|
|
275
|
+
addAttributeToJSXTag(
|
|
276
|
+
elementTag,
|
|
277
|
+
attrKey,
|
|
278
|
+
generateElementNode(attributeValue, params, options)
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
break
|
|
282
|
+
|
|
283
|
+
case 'object': {
|
|
284
|
+
const content = attributeValue.content
|
|
285
|
+
if (typeof content !== 'object') {
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
const expression = objectToObjectExpression(content as Record<string, unknown>)
|
|
289
|
+
elementTag.openingElement.attributes.push(
|
|
290
|
+
types.jsxAttribute(types.jsxIdentifier(attrKey), types.jsxExpressionContainer(expression))
|
|
291
|
+
)
|
|
292
|
+
break
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
default:
|
|
296
|
+
throw new Error(
|
|
297
|
+
`generateElementNode could not generate code for attribute of type ${JSON.stringify(
|
|
298
|
+
attributeValue
|
|
299
|
+
)}`
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
})
|
|
303
|
+
}
|
|
304
|
+
|
|
160
305
|
const generateNode: NodeToJSX<UIDLNode, JSXASTReturnType[]> = (node, params, options) => {
|
|
161
306
|
switch (node.type) {
|
|
162
307
|
case 'expr':
|
|
@@ -171,8 +316,7 @@ const generateNode: NodeToJSX<UIDLNode, JSXASTReturnType[]> = (node, params, opt
|
|
|
171
316
|
|
|
172
317
|
case 'inject':
|
|
173
318
|
if (node?.dependency) {
|
|
174
|
-
|
|
175
|
-
params.dependencies['Script'] = node.dependency
|
|
319
|
+
params.dependencies.Script = node.dependency
|
|
176
320
|
}
|
|
177
321
|
return [node.content.toString()]
|
|
178
322
|
|
|
@@ -180,13 +324,92 @@ const generateNode: NodeToJSX<UIDLNode, JSXASTReturnType[]> = (node, params, opt
|
|
|
180
324
|
return [StringUtils.encode(node.content.toString())]
|
|
181
325
|
|
|
182
326
|
case 'dynamic':
|
|
183
|
-
|
|
327
|
+
switch (node.content.referenceType) {
|
|
328
|
+
case 'prop': {
|
|
329
|
+
// If the dynamic node is a prop and has a default value of type UIDLElementNode,
|
|
330
|
+
// we should use it with a logical expression.
|
|
331
|
+
const prop = params.propDefinitions[node.content.id]
|
|
332
|
+
if (prop?.type === 'element' && prop.defaultValue) {
|
|
333
|
+
const prefix = options.dynamicReferencePrefixMap[node.content.referenceType] || ''
|
|
334
|
+
|
|
335
|
+
const propDefault = prop.defaultValue as UIDLElementNode
|
|
336
|
+
const jsxNode = params.nodesLookup[propDefault.content.key]
|
|
337
|
+
|
|
338
|
+
if (jsxNode === undefined) {
|
|
339
|
+
throw Error(`Prop ${node.content.id} is of type element \n
|
|
340
|
+
The JSXNode of the prop-${node.content.id} is missing from the nodesLookup`)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return [
|
|
344
|
+
types.logicalExpression(
|
|
345
|
+
'??',
|
|
346
|
+
prefix === ''
|
|
347
|
+
? types.identifier(node.content.id)
|
|
348
|
+
: types.memberExpression(
|
|
349
|
+
types.identifier(prefix),
|
|
350
|
+
types.identifier(node.content.id)
|
|
351
|
+
),
|
|
352
|
+
jsxNode as types.JSXElement
|
|
353
|
+
),
|
|
354
|
+
]
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return [createDynamicValueExpression(node, options)]
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
case 'locale': {
|
|
361
|
+
// Locale is not handled the same in all frameworks.
|
|
362
|
+
// So, we need to handle it differently using individual plugins for each framework.
|
|
363
|
+
const emptyExpression = types.jsxEmptyExpression()
|
|
364
|
+
emptyExpression.innerComments = [
|
|
365
|
+
{
|
|
366
|
+
type: 'CommentBlock',
|
|
367
|
+
value: `locale-${node.content.id}`,
|
|
368
|
+
},
|
|
369
|
+
]
|
|
370
|
+
const expression = types.jsxExpressionContainer(emptyExpression)
|
|
371
|
+
const jsxTag = createJSXTag('span')
|
|
372
|
+
addChildJSXTag(jsxTag, expression)
|
|
373
|
+
|
|
374
|
+
params.localeReferences.push(jsxTag)
|
|
375
|
+
return [jsxTag]
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
case 'global': {
|
|
379
|
+
params.globalReferences.push(node.content.id)
|
|
380
|
+
return [createDynamicValueExpression(node, options)]
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
default:
|
|
384
|
+
return [createDynamicValueExpression(node, options)]
|
|
385
|
+
}
|
|
184
386
|
|
|
185
387
|
case 'cms-item':
|
|
186
388
|
case 'cms-list':
|
|
187
389
|
return generateCMSNode(node, params, options)
|
|
188
390
|
|
|
391
|
+
case 'cms-list-repeater':
|
|
392
|
+
return generateCMSListRepeaterNode(node, params, options)
|
|
393
|
+
|
|
394
|
+
case 'cms-mixed-type':
|
|
395
|
+
return generateCMSMixedTypeNode(node, params, options)
|
|
396
|
+
|
|
397
|
+
case 'data-source-item':
|
|
398
|
+
case 'data-source-list':
|
|
399
|
+
return generateDataSourceNode(node, params, options)
|
|
400
|
+
|
|
189
401
|
case 'element':
|
|
402
|
+
// Check if this element node is wrapping a data-source node
|
|
403
|
+
if (
|
|
404
|
+
node.content &&
|
|
405
|
+
typeof node.content === 'object' &&
|
|
406
|
+
'type' in node.content &&
|
|
407
|
+
(node.content.type === 'data-source-item' || node.content.type === 'data-source-list')
|
|
408
|
+
) {
|
|
409
|
+
// Treat it as a data-source node
|
|
410
|
+
// tslint:disable-next-line:no-any
|
|
411
|
+
return generateDataSourceNode(node.content as any, params, options)
|
|
412
|
+
}
|
|
190
413
|
return [generateElementNode(node, params, options)]
|
|
191
414
|
|
|
192
415
|
case 'repeat':
|
|
@@ -195,9 +418,6 @@ const generateNode: NodeToJSX<UIDLNode, JSXASTReturnType[]> = (node, params, opt
|
|
|
195
418
|
case 'conditional':
|
|
196
419
|
return generateConditionalNode(node, params, options)
|
|
197
420
|
|
|
198
|
-
case 'cms-list-repeater':
|
|
199
|
-
return generateCMSListRepeaterNode(node, params, options)
|
|
200
|
-
|
|
201
421
|
case 'slot':
|
|
202
422
|
if (options.slotHandling === 'native') {
|
|
203
423
|
return [generateNativeSlotNode(node, params, options)]
|
|
@@ -220,7 +440,99 @@ const generateExpressionNode: NodeToJSX<UIDLExpressionValue, types.JSXExpression
|
|
|
220
440
|
node
|
|
221
441
|
) => {
|
|
222
442
|
const expression = ASTUtils.getExpressionFromUIDLExpressionNode(node)
|
|
223
|
-
|
|
443
|
+
|
|
444
|
+
// Wrap expression to safely handle objects/arrays: (typeof val === 'object' && val !== null) ? JSON.stringify(val) : val
|
|
445
|
+
const safeExpression = types.conditionalExpression(
|
|
446
|
+
types.logicalExpression(
|
|
447
|
+
'&&',
|
|
448
|
+
types.binaryExpression(
|
|
449
|
+
'===',
|
|
450
|
+
types.unaryExpression('typeof', expression, true),
|
|
451
|
+
types.stringLiteral('object')
|
|
452
|
+
),
|
|
453
|
+
types.binaryExpression('!==', expression, types.nullLiteral())
|
|
454
|
+
),
|
|
455
|
+
types.callExpression(
|
|
456
|
+
types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
|
|
457
|
+
[expression]
|
|
458
|
+
),
|
|
459
|
+
expression
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
return types.jsxExpressionContainer(safeExpression)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const generateCMSMixedTypeNode: NodeToJSX<UIDLCMSMixedTypeNode, types.JSXElement[]> = (
|
|
466
|
+
node,
|
|
467
|
+
params,
|
|
468
|
+
options
|
|
469
|
+
) => {
|
|
470
|
+
const {
|
|
471
|
+
nodes: { error, fallback },
|
|
472
|
+
elementType,
|
|
473
|
+
renderPropIdentifier,
|
|
474
|
+
mappings = {},
|
|
475
|
+
attrs,
|
|
476
|
+
dependency,
|
|
477
|
+
} = node.content
|
|
478
|
+
const jsxTag = StringUtils.dashCaseToUpperCamelCase(elementType)
|
|
479
|
+
const cmsMixedNode = ASTBuilders.createJSXTag(jsxTag, [], true)
|
|
480
|
+
const mappingsObject: types.ObjectProperty[] = []
|
|
481
|
+
|
|
482
|
+
if (attrs) {
|
|
483
|
+
addAttributesToJSXTag(attrs, cmsMixedNode, options, params)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (dependency) {
|
|
487
|
+
params.dependencies[elementType] = dependency
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
Object.keys(mappings).forEach((key) => {
|
|
491
|
+
const element = generateElementNode(mappings[key], params, options)
|
|
492
|
+
mappingsObject.push(
|
|
493
|
+
types.objectProperty(
|
|
494
|
+
types.identifier(`"${key}"`),
|
|
495
|
+
types.arrowFunctionExpression([types.identifier(renderPropIdentifier)], element)
|
|
496
|
+
)
|
|
497
|
+
)
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
cmsMixedNode.openingElement.attributes.push(
|
|
501
|
+
types.jsxAttribute(
|
|
502
|
+
types.jsxIdentifier('mappingConfiguration'),
|
|
503
|
+
types.jsxExpressionContainer(types.objectExpression(mappingsObject))
|
|
504
|
+
)
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
if (fallback) {
|
|
508
|
+
cmsMixedNode.openingElement.attributes.push(
|
|
509
|
+
types.jSXAttribute(
|
|
510
|
+
types.jsxIdentifier('renderDefault'),
|
|
511
|
+
types.jsxExpressionContainer(
|
|
512
|
+
types.arrowFunctionExpression(
|
|
513
|
+
[types.identifier(renderPropIdentifier)],
|
|
514
|
+
generateElementNode(fallback, params, options)
|
|
515
|
+
)
|
|
516
|
+
)
|
|
517
|
+
)
|
|
518
|
+
)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (error) {
|
|
522
|
+
cmsMixedNode.openingElement.attributes.push(
|
|
523
|
+
types.jSXAttribute(
|
|
524
|
+
types.jsxIdentifier('renderError'),
|
|
525
|
+
types.jsxExpressionContainer(
|
|
526
|
+
types.arrowFunctionExpression(
|
|
527
|
+
[types.identifier(renderPropIdentifier)],
|
|
528
|
+
generateElementNode(error, params, options)
|
|
529
|
+
)
|
|
530
|
+
)
|
|
531
|
+
)
|
|
532
|
+
)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return [cmsMixedNode]
|
|
224
536
|
}
|
|
225
537
|
|
|
226
538
|
const generateCMSNode: NodeToJSX<UIDLCMSListNode | UIDLCMSItemNode, types.JSXElement[]> = (
|
|
@@ -396,6 +708,158 @@ const generateCMSNode: NodeToJSX<UIDLCMSListNode | UIDLCMSItemNode, types.JSXEle
|
|
|
396
708
|
return [cmsNode]
|
|
397
709
|
}
|
|
398
710
|
|
|
711
|
+
const generateDataSourceNode: NodeToJSX<
|
|
712
|
+
UIDLDataSourceItemNode | UIDLDataSourceListNode,
|
|
713
|
+
types.JSXElement[]
|
|
714
|
+
> = (node, params, options) => {
|
|
715
|
+
const { renderPropIdentifier, elementType, dependency, resourceDefinition } = node.content
|
|
716
|
+
|
|
717
|
+
const key = node.content.key || `ds-${resourceDefinition.dataSourceId}-${Date.now()}`
|
|
718
|
+
const name = node.content.name || renderPropIdentifier
|
|
719
|
+
|
|
720
|
+
// tslint:disable-next-line:no-any
|
|
721
|
+
const children =
|
|
722
|
+
node.content.children && node.content.children.length > 0
|
|
723
|
+
? node.content.children
|
|
724
|
+
: (node.content as any).nodes?.success
|
|
725
|
+
? [(node.content as any).nodes.success]
|
|
726
|
+
: []
|
|
727
|
+
|
|
728
|
+
const jsxTag = StringUtils.dashCaseToUpperCamelCase(elementType)
|
|
729
|
+
|
|
730
|
+
if (dependency && options.dependencyHandling === 'import') {
|
|
731
|
+
params.dependencies[elementType] = dependency
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const dataSourceNode = ASTBuilders.createJSXTag(jsxTag, [], true)
|
|
735
|
+
|
|
736
|
+
dataSourceNode.openingElement.attributes.push(
|
|
737
|
+
types.jsxAttribute(
|
|
738
|
+
types.jsxIdentifier('resourceDefinition'),
|
|
739
|
+
types.jsxExpressionContainer(
|
|
740
|
+
types.objectExpression([
|
|
741
|
+
types.objectProperty(
|
|
742
|
+
types.stringLiteral('type'),
|
|
743
|
+
types.stringLiteral('external-data-source')
|
|
744
|
+
),
|
|
745
|
+
types.objectProperty(
|
|
746
|
+
types.stringLiteral('dataSourceId'),
|
|
747
|
+
types.stringLiteral(resourceDefinition.dataSourceId)
|
|
748
|
+
),
|
|
749
|
+
types.objectProperty(
|
|
750
|
+
types.stringLiteral('tableName'),
|
|
751
|
+
types.stringLiteral(resourceDefinition.tableName)
|
|
752
|
+
),
|
|
753
|
+
types.objectProperty(
|
|
754
|
+
types.stringLiteral('dataSourceType'),
|
|
755
|
+
types.stringLiteral(resourceDefinition.dataSourceType)
|
|
756
|
+
),
|
|
757
|
+
])
|
|
758
|
+
)
|
|
759
|
+
)
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
dataSourceNode.openingElement.attributes.push(
|
|
763
|
+
types.jsxAttribute(
|
|
764
|
+
types.jsxIdentifier('name'),
|
|
765
|
+
types.jsxExpressionContainer(types.stringLiteral(name))
|
|
766
|
+
)
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
if (children && children.length > 0) {
|
|
770
|
+
const childrenNodes = children.flatMap((child) => generateNode(child, params, options))
|
|
771
|
+
const renderFunction = types.arrowFunctionExpression(
|
|
772
|
+
[types.identifier(renderPropIdentifier)],
|
|
773
|
+
types.jsxFragment(
|
|
774
|
+
types.jsxOpeningFragment(),
|
|
775
|
+
types.jsxClosingFragment(),
|
|
776
|
+
childrenNodes as types.JSXElement[]
|
|
777
|
+
)
|
|
778
|
+
)
|
|
779
|
+
dataSourceNode.openingElement.attributes.push(
|
|
780
|
+
types.jsxAttribute(
|
|
781
|
+
types.jsxIdentifier('renderSuccess'),
|
|
782
|
+
types.jsxExpressionContainer(renderFunction)
|
|
783
|
+
)
|
|
784
|
+
)
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// tslint:disable-next-line:no-any
|
|
788
|
+
if ((node.content as any).nodes?.loading) {
|
|
789
|
+
// tslint:disable-next-line:no-any
|
|
790
|
+
const loadingNode = generateNode((node.content as any).nodes.loading, params, options)[0]
|
|
791
|
+
dataSourceNode.openingElement.attributes.push(
|
|
792
|
+
types.jsxAttribute(
|
|
793
|
+
types.jsxIdentifier('renderLoading'),
|
|
794
|
+
types.jsxExpressionContainer(
|
|
795
|
+
types.arrowFunctionExpression([], loadingNode as types.JSXElement)
|
|
796
|
+
)
|
|
797
|
+
)
|
|
798
|
+
)
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// tslint:disable-next-line:no-any
|
|
802
|
+
if ((node.content as any).nodes?.error) {
|
|
803
|
+
// tslint:disable-next-line:no-any
|
|
804
|
+
const errorNode = generateNode((node.content as any).nodes.error, params, options)[0]
|
|
805
|
+
dataSourceNode.openingElement.attributes.push(
|
|
806
|
+
types.jsxAttribute(
|
|
807
|
+
types.jsxIdentifier('renderError'),
|
|
808
|
+
types.jsxExpressionContainer(
|
|
809
|
+
types.arrowFunctionExpression([], errorNode as types.JSXElement)
|
|
810
|
+
)
|
|
811
|
+
)
|
|
812
|
+
)
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Add resource params if they exist
|
|
816
|
+
// tslint:disable-next-line:no-any
|
|
817
|
+
const resourceParams = (node.content as any).resource?.params
|
|
818
|
+
if (resourceParams && Object.keys(resourceParams).length > 0) {
|
|
819
|
+
const nodeParams: types.ObjectProperty[] = Object.keys(resourceParams).reduce(
|
|
820
|
+
(acc: types.ObjectProperty[], attrKey) => {
|
|
821
|
+
const property = resourceParams[attrKey]
|
|
822
|
+
|
|
823
|
+
if (property.type === 'static') {
|
|
824
|
+
acc.push(types.objectProperty(types.stringLiteral(attrKey), resolveObjectValue(property)))
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (property.type === 'expr') {
|
|
828
|
+
const expression = ASTUtils.getExpressionFromUIDLExpressionNode(property)
|
|
829
|
+
acc.push(types.objectProperty(types.stringLiteral(attrKey), expression))
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (property.type === 'dynamic') {
|
|
833
|
+
const refType = property.content.referenceType as 'prop' | 'state' | 'local'
|
|
834
|
+
acc.push(
|
|
835
|
+
types.objectProperty(
|
|
836
|
+
types.stringLiteral(attrKey),
|
|
837
|
+
property.content.referenceType === 'prop'
|
|
838
|
+
? types.memberExpression(
|
|
839
|
+
types.identifier(options.dynamicReferencePrefixMap[refType]),
|
|
840
|
+
types.identifier(property.content.id)
|
|
841
|
+
)
|
|
842
|
+
: types.identifier(property.content.id)
|
|
843
|
+
)
|
|
844
|
+
)
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
return acc
|
|
848
|
+
},
|
|
849
|
+
[]
|
|
850
|
+
)
|
|
851
|
+
dataSourceNode.openingElement.attributes.push(
|
|
852
|
+
types.jsxAttribute(
|
|
853
|
+
types.jsxIdentifier('params'),
|
|
854
|
+
types.jsxExpressionContainer(types.objectExpression(nodeParams))
|
|
855
|
+
)
|
|
856
|
+
)
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
params.nodesLookup[key] = dataSourceNode
|
|
860
|
+
return [dataSourceNode]
|
|
861
|
+
}
|
|
862
|
+
|
|
399
863
|
const generateRepeatNode: NodeToJSX<UIDLRepeatNode, types.JSXExpressionContainer[]> = (
|
|
400
864
|
node,
|
|
401
865
|
params,
|
|
@@ -433,8 +897,6 @@ const generateConditionalNode: NodeToJSX<UIDLConditionalNode, types.LogicalExpre
|
|
|
433
897
|
options
|
|
434
898
|
) => {
|
|
435
899
|
const { reference, value } = node.content
|
|
436
|
-
const conditionIdentifier = createConditionIdentifier(reference, params, options)
|
|
437
|
-
|
|
438
900
|
const subTrees = generateNode(node.content.node, params, options)
|
|
439
901
|
|
|
440
902
|
const condition: UIDLConditionalExpression =
|
|
@@ -442,9 +904,12 @@ const generateConditionalNode: NodeToJSX<UIDLConditionalNode, types.LogicalExpre
|
|
|
442
904
|
? { conditions: [{ operand: value, operation: '===' }] }
|
|
443
905
|
: node.content.condition
|
|
444
906
|
|
|
445
|
-
|
|
907
|
+
const conditionIdentifier = createConditionIdentifier(reference, params, options)
|
|
908
|
+
const conditionalExpressions: types.LogicalExpression[] = subTrees.map((subTree) =>
|
|
446
909
|
createConditionalJSXExpression(subTree, condition, conditionIdentifier)
|
|
447
910
|
)
|
|
911
|
+
|
|
912
|
+
return conditionalExpressions
|
|
448
913
|
}
|
|
449
914
|
|
|
450
915
|
const generateCMSListRepeaterNode: NodeToJSX<UIDLCMSListRepeaterNode, types.JSXElement[]> = (
|
|
@@ -452,21 +917,52 @@ const generateCMSListRepeaterNode: NodeToJSX<UIDLCMSListRepeaterNode, types.JSXE
|
|
|
452
917
|
params,
|
|
453
918
|
options
|
|
454
919
|
) => {
|
|
455
|
-
const
|
|
920
|
+
const jsxTag = StringUtils.dashCaseToUpperCamelCase(node.content.elementType)
|
|
921
|
+
const repeaterNode = ASTBuilders.createJSXTag(jsxTag, [], true)
|
|
922
|
+
|
|
456
923
|
repeaterNode.openingElement.attributes.push(
|
|
457
924
|
types.jsxAttribute(
|
|
458
925
|
types.jsxIdentifier('items'),
|
|
459
|
-
types.jsxExpressionContainer(types.identifier('params'))
|
|
926
|
+
types.jsxExpressionContainer(types.identifier(node.content.source ?? 'params'))
|
|
460
927
|
)
|
|
461
928
|
)
|
|
462
929
|
|
|
930
|
+
const listElement = generateNode(node.content.nodes.list, params, {
|
|
931
|
+
...options,
|
|
932
|
+
localIdentifier: node.content.renderPropIdentifier,
|
|
933
|
+
})[0] as types.JSXElement
|
|
934
|
+
|
|
935
|
+
// Create key as template literal: `${item?.id}${index}`
|
|
936
|
+
const keyAttribute = types.jsxAttribute(
|
|
937
|
+
types.jsxIdentifier('key'),
|
|
938
|
+
types.jsxExpressionContainer(
|
|
939
|
+
types.templateLiteral(
|
|
940
|
+
[
|
|
941
|
+
types.templateElement({ raw: '', cooked: '' }, false),
|
|
942
|
+
types.templateElement({ raw: '', cooked: '' }, false),
|
|
943
|
+
types.templateElement({ raw: '', cooked: '' }, true),
|
|
944
|
+
],
|
|
945
|
+
[
|
|
946
|
+
types.optionalMemberExpression(
|
|
947
|
+
types.identifier(node.content.renderPropIdentifier),
|
|
948
|
+
types.identifier('id'),
|
|
949
|
+
false,
|
|
950
|
+
true
|
|
951
|
+
),
|
|
952
|
+
types.identifier('index'),
|
|
953
|
+
]
|
|
954
|
+
)
|
|
955
|
+
)
|
|
956
|
+
)
|
|
957
|
+
listElement.openingElement.attributes.push(keyAttribute)
|
|
958
|
+
|
|
463
959
|
repeaterNode.openingElement.attributes.push(
|
|
464
960
|
types.jsxAttribute(
|
|
465
961
|
types.jSXIdentifier('renderItem'),
|
|
466
962
|
types.jsxExpressionContainer(
|
|
467
963
|
types.arrowFunctionExpression(
|
|
468
|
-
[types.identifier(node.content.renderPropIdentifier)],
|
|
469
|
-
|
|
964
|
+
[types.identifier(node.content.renderPropIdentifier), types.identifier('index')],
|
|
965
|
+
listElement
|
|
470
966
|
)
|
|
471
967
|
)
|
|
472
968
|
)
|
|
@@ -486,6 +982,14 @@ const generateCMSListRepeaterNode: NodeToJSX<UIDLCMSListRepeaterNode, types.JSXE
|
|
|
486
982
|
)
|
|
487
983
|
}
|
|
488
984
|
|
|
985
|
+
if ('loading' in node.content.nodes) {
|
|
986
|
+
generateNode(node.content.nodes.loading, params, options)
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
if (node.content?.dependency && options.dependencyHandling === 'import') {
|
|
990
|
+
params.dependencies[jsxTag] = node.content.dependency
|
|
991
|
+
}
|
|
992
|
+
|
|
489
993
|
return [repeaterNode]
|
|
490
994
|
}
|
|
491
995
|
|