@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
package/src/utils/ast-utils.ts
CHANGED
|
@@ -12,9 +12,10 @@ import {
|
|
|
12
12
|
UIDLPropValue,
|
|
13
13
|
UIDLExpressionValue,
|
|
14
14
|
UIDLStateValue,
|
|
15
|
+
HastNode,
|
|
15
16
|
} from '@teleporthq/teleport-types'
|
|
16
17
|
import babelPresetReact from '@babel/preset-react'
|
|
17
|
-
import {
|
|
18
|
+
import { UnaryOperation, BinaryOperator } from './types'
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Adds a class definition string to an existing string of classes
|
|
@@ -23,14 +24,20 @@ export const addClassStringOnJSXTag = (
|
|
|
23
24
|
jsxNode: types.JSXElement,
|
|
24
25
|
classString: string,
|
|
25
26
|
classAttributeName?: string,
|
|
26
|
-
dynamicValues: Array<types.MemberExpression | types.Identifier> = []
|
|
27
|
+
dynamicValues: Array<types.MemberExpression | types.Identifier | types.ConditionalExpression> = []
|
|
27
28
|
) => {
|
|
28
|
-
|
|
29
|
+
if (classString === '' && dynamicValues.length === 0) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
29
32
|
|
|
33
|
+
const classAttribute = getClassAttribute(jsxNode, { createIfNotFound: true, classAttributeName })
|
|
30
34
|
if (dynamicValues.length === 0) {
|
|
31
35
|
if (classAttribute.value && classAttribute.value.type === 'StringLiteral') {
|
|
32
36
|
const classArray = classAttribute.value.value.split(' ')
|
|
33
|
-
|
|
37
|
+
if (classString) {
|
|
38
|
+
classArray.push(classString)
|
|
39
|
+
}
|
|
40
|
+
classArray.filter((item) => item)
|
|
34
41
|
classAttribute.value.value = classArray.join(' ').trim()
|
|
35
42
|
} else {
|
|
36
43
|
throw new Error(
|
|
@@ -43,7 +50,9 @@ export const addClassStringOnJSXTag = (
|
|
|
43
50
|
if (classAttribute.value && classAttribute.value.type === 'StringLiteral') {
|
|
44
51
|
const classArray = classAttribute.value.value.split(' ')
|
|
45
52
|
const quasis: types.TemplateElement[] = []
|
|
46
|
-
const expression: Array<
|
|
53
|
+
const expression: Array<
|
|
54
|
+
types.MemberExpression | types.Identifier | types.ConditionalExpression
|
|
55
|
+
> = []
|
|
47
56
|
|
|
48
57
|
quasis.push(
|
|
49
58
|
types.templateElement({
|
|
@@ -164,17 +173,21 @@ export const addDynamicExpressionAttributeToJSXTag = (
|
|
|
164
173
|
export const addMultipleDynamicAttributesToJSXTag = (
|
|
165
174
|
jsxASTNode: types.JSXElement,
|
|
166
175
|
name: string,
|
|
167
|
-
attrValues: Array<types.MemberExpression | types.Identifier> = [],
|
|
176
|
+
attrValues: Array<types.MemberExpression | types.Identifier | types.StringLiteral> = [],
|
|
168
177
|
t = types
|
|
169
178
|
) => {
|
|
170
|
-
const memberExpressions: Array<types.Identifier | types.MemberExpression> =
|
|
179
|
+
const memberExpressions: Array<types.Identifier | types.MemberExpression | types.StringLiteral> =
|
|
180
|
+
[]
|
|
171
181
|
const templateElements: types.TemplateElement[] = []
|
|
172
|
-
|
|
173
182
|
if (attrValues.length === 0) {
|
|
174
183
|
return
|
|
175
184
|
}
|
|
176
185
|
|
|
177
|
-
let content:
|
|
186
|
+
let content:
|
|
187
|
+
| types.TemplateLiteral
|
|
188
|
+
| types.MemberExpression
|
|
189
|
+
| types.Identifier
|
|
190
|
+
| types.StringLiteral
|
|
178
191
|
if (attrValues.length === 1) {
|
|
179
192
|
content = attrValues[0]
|
|
180
193
|
} else {
|
|
@@ -210,19 +223,36 @@ export const stringAsTemplateLiteral = (str: string): types.TemplateLiteral => {
|
|
|
210
223
|
return container.expression as types.TemplateLiteral
|
|
211
224
|
}
|
|
212
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Converts HTML attribute names to React/JSX camelCase format
|
|
228
|
+
* Preserves data-* and aria-* attributes as-is
|
|
229
|
+
*/
|
|
230
|
+
const convertToReactAttributeName = (attrName: string): string => {
|
|
231
|
+
// Keep data-* and aria-* attributes as-is (React supports these)
|
|
232
|
+
if (attrName.startsWith('data-') || attrName.startsWith('aria-')) {
|
|
233
|
+
return attrName
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Convert hyphenated attributes to camelCase for React
|
|
237
|
+
return attrName.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
|
|
238
|
+
}
|
|
239
|
+
|
|
213
240
|
export const addAttributeToJSXTag = (
|
|
214
241
|
jsxNode: types.JSXElement,
|
|
215
242
|
attrName: string,
|
|
216
243
|
attrValue?: boolean | unknown,
|
|
217
244
|
t = types
|
|
218
245
|
) => {
|
|
219
|
-
const
|
|
246
|
+
const reactAttrName = convertToReactAttributeName(attrName)
|
|
247
|
+
const nameOfAttribute = t.jsxIdentifier(reactAttrName)
|
|
220
248
|
let attributeDefinition
|
|
221
249
|
if (typeof attrValue === 'boolean') {
|
|
222
250
|
attributeDefinition = t.jsxAttribute(
|
|
223
251
|
nameOfAttribute,
|
|
224
252
|
attrValue === true ? undefined : t.jsxExpressionContainer(t.booleanLiteral(attrValue))
|
|
225
253
|
)
|
|
254
|
+
} else if (t.isNode(attrValue) && t.isJSXElement(attrValue)) {
|
|
255
|
+
attributeDefinition = t.jsxAttribute(nameOfAttribute, t.jsxExpressionContainer(attrValue))
|
|
226
256
|
} else {
|
|
227
257
|
attributeDefinition = t.jsxAttribute(
|
|
228
258
|
nameOfAttribute,
|
|
@@ -230,6 +260,17 @@ export const addAttributeToJSXTag = (
|
|
|
230
260
|
)
|
|
231
261
|
}
|
|
232
262
|
|
|
263
|
+
const attribute: types.JSXAttribute = jsxNode.openingElement.attributes.find((attr) => {
|
|
264
|
+
if (attr.type === 'JSXAttribute') {
|
|
265
|
+
return attr.name.name === reactAttrName
|
|
266
|
+
}
|
|
267
|
+
}) as types.JSXAttribute
|
|
268
|
+
|
|
269
|
+
if (attribute && attribute.value && attribute.value.type === 'StringLiteral') {
|
|
270
|
+
attribute.value.value = `${attribute.value.value} ${attrValue}`
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
|
|
233
274
|
jsxNode.openingElement.attributes.push(attributeDefinition)
|
|
234
275
|
}
|
|
235
276
|
|
|
@@ -300,7 +341,18 @@ export const objectToObjectExpression = (
|
|
|
300
341
|
const value = objectMap[key]
|
|
301
342
|
let computedLiteralValue = null
|
|
302
343
|
|
|
303
|
-
if (value
|
|
344
|
+
if (value === undefined) {
|
|
345
|
+
return acc
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Handle null values explicitly - they are valid in array mappers with different schemas
|
|
349
|
+
if (value === null) {
|
|
350
|
+
computedLiteralValue = t.nullLiteral()
|
|
351
|
+
}
|
|
352
|
+
// This is for function props that have successfully been parsed.
|
|
353
|
+
else if (typeof value === 'object' && 'functionExpressionParseResult' in value) {
|
|
354
|
+
computedLiteralValue = value.functionExpressionParseResult
|
|
355
|
+
} else if (value instanceof ParsedASTNode || value.constructor.name === 'ParsedASTNode') {
|
|
304
356
|
computedLiteralValue = (value as ParsedASTNode).ast
|
|
305
357
|
} else if (typeof value === 'boolean') {
|
|
306
358
|
computedLiteralValue = t.booleanLiteral(value)
|
|
@@ -396,7 +448,7 @@ export const getTSAnnotationForType = (type: any, t = types) => {
|
|
|
396
448
|
case 'boolean':
|
|
397
449
|
return t.tsBooleanKeyword()
|
|
398
450
|
default:
|
|
399
|
-
return t.
|
|
451
|
+
return t.tsAnyKeyword()
|
|
400
452
|
}
|
|
401
453
|
}
|
|
402
454
|
|
|
@@ -496,7 +548,7 @@ export const createReturnExpressionSyntax = (
|
|
|
496
548
|
createStateHookAST(stateKey, stateDefinitions[stateKey])
|
|
497
549
|
)
|
|
498
550
|
|
|
499
|
-
return t.blockStatement([...stateHooks, ...Object.values(windowImports), returnStatement]
|
|
551
|
+
return t.blockStatement([...stateHooks, ...Object.values(windowImports), returnStatement])
|
|
500
552
|
}
|
|
501
553
|
|
|
502
554
|
/**
|
|
@@ -543,9 +595,7 @@ export const wrapObjectPropertiesWithExpression = (properties: types.ObjectPrope
|
|
|
543
595
|
|
|
544
596
|
export const generateRemoteResourceASTs = (resource: UIDLResourceItem) => {
|
|
545
597
|
const fetchUrl = computeFetchUrl(resource)
|
|
546
|
-
const authHeaderAST = computeAuthorizationHeaderAST(resource?.headers)
|
|
547
598
|
const headersASTs = resource?.headers ? generateRESTHeadersAST(resource.headers) : []
|
|
548
|
-
|
|
549
599
|
const queryParams = generateURLParamsAST(resource?.params)
|
|
550
600
|
const fetchUrlQuasis = fetchUrl.quasis
|
|
551
601
|
const queryParamsQuasis = queryParams?.quasis || [types.templateElement({ raw: '', cooked: '' })]
|
|
@@ -560,60 +610,8 @@ export const generateRemoteResourceASTs = (resource: UIDLResourceItem) => {
|
|
|
560
610
|
queryParamsQuasis.pop()
|
|
561
611
|
}
|
|
562
612
|
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
).reduce((acc: Array<types.ObjectProperty | types.SpreadElement>, item) => {
|
|
566
|
-
const prop = resource.params[item]
|
|
567
|
-
if (prop.type === 'static') {
|
|
568
|
-
acc.push(types.objectProperty(types.stringLiteral(item), ASTUtils.resolveObjectValue(prop)))
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (prop.type === 'expr') {
|
|
572
|
-
acc.push(
|
|
573
|
-
types.objectProperty(
|
|
574
|
-
types.stringLiteral(item),
|
|
575
|
-
ASTUtils.getExpressionFromUIDLExpressionNode(prop)
|
|
576
|
-
)
|
|
577
|
-
)
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
if (prop.type === 'dynamic') {
|
|
581
|
-
acc.push(
|
|
582
|
-
types.spreadElement(
|
|
583
|
-
types.logicalExpression(
|
|
584
|
-
'&&',
|
|
585
|
-
types.memberExpression(
|
|
586
|
-
types.identifier('params'),
|
|
587
|
-
types.stringLiteral(prop.content.id),
|
|
588
|
-
true,
|
|
589
|
-
false
|
|
590
|
-
),
|
|
591
|
-
types.objectExpression([
|
|
592
|
-
types.objectProperty(
|
|
593
|
-
types.stringLiteral(item),
|
|
594
|
-
types.memberExpression(
|
|
595
|
-
types.identifier('params'),
|
|
596
|
-
types.stringLiteral(prop.content.id),
|
|
597
|
-
true,
|
|
598
|
-
false
|
|
599
|
-
)
|
|
600
|
-
),
|
|
601
|
-
])
|
|
602
|
-
)
|
|
603
|
-
)
|
|
604
|
-
)
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
return acc
|
|
608
|
-
}, [])
|
|
609
|
-
|
|
610
|
-
const paramsAST = types.variableDeclaration('const', [
|
|
611
|
-
types.variableDeclarator(
|
|
612
|
-
types.identifier('urlParams'),
|
|
613
|
-
types.objectExpression(paramsDeclerations)
|
|
614
|
-
),
|
|
615
|
-
])
|
|
616
|
-
|
|
613
|
+
const urlParamsDecleration = generateParamsAST(resource?.params)
|
|
614
|
+
const bodyParamsDecleration = generateParamsAST(resource?.body)
|
|
617
615
|
const url = queryParams?.quasis
|
|
618
616
|
? types.templateLiteral(
|
|
619
617
|
[...fetchUrlQuasis, ...queryParamsQuasis],
|
|
@@ -628,31 +626,113 @@ export const generateRemoteResourceASTs = (resource: UIDLResourceItem) => {
|
|
|
628
626
|
|
|
629
627
|
let allHeaders: types.ObjectProperty[] = []
|
|
630
628
|
|
|
631
|
-
if (
|
|
632
|
-
allHeaders.push(
|
|
629
|
+
if (resource?.headers?.authToken) {
|
|
630
|
+
allHeaders.push(computeAuthorizationHeaderAST(resource?.headers))
|
|
633
631
|
}
|
|
634
632
|
|
|
635
633
|
if (headersASTs.length) {
|
|
636
634
|
allHeaders = allHeaders.concat(headersASTs)
|
|
637
635
|
}
|
|
638
636
|
|
|
639
|
-
const
|
|
640
|
-
types.identifier('headers'),
|
|
641
|
-
types.objectExpression(allHeaders)
|
|
642
|
-
)
|
|
643
|
-
|
|
644
|
-
const fetchAST = types.variableDeclaration('const', [
|
|
637
|
+
const fetchAST = types.variableDeclaration('let', [
|
|
645
638
|
types.variableDeclarator(
|
|
646
639
|
types.identifier('data'),
|
|
647
640
|
types.awaitExpression(
|
|
648
641
|
types.callExpression(types.identifier('fetch'), [
|
|
649
642
|
url,
|
|
650
|
-
types.objectExpression([
|
|
643
|
+
types.objectExpression([
|
|
644
|
+
method,
|
|
645
|
+
...(allHeaders.length > 0
|
|
646
|
+
? [
|
|
647
|
+
types.objectProperty(
|
|
648
|
+
types.identifier('headers'),
|
|
649
|
+
types.objectExpression(allHeaders)
|
|
650
|
+
),
|
|
651
|
+
]
|
|
652
|
+
: []),
|
|
653
|
+
...(bodyParamsDecleration.length > 0 && resource?.method === 'POST'
|
|
654
|
+
? [
|
|
655
|
+
types.objectProperty(
|
|
656
|
+
types.identifier('body'),
|
|
657
|
+
types.callExpression(
|
|
658
|
+
types.memberExpression(
|
|
659
|
+
types.identifier('JSON'),
|
|
660
|
+
types.identifier('stringify')
|
|
661
|
+
),
|
|
662
|
+
[types.identifier('bodyParams')]
|
|
663
|
+
)
|
|
664
|
+
),
|
|
665
|
+
]
|
|
666
|
+
: []),
|
|
667
|
+
]),
|
|
651
668
|
])
|
|
652
669
|
)
|
|
653
670
|
),
|
|
654
671
|
])
|
|
655
672
|
|
|
673
|
+
// Fallback in case i18n interferes with normal CMS flows
|
|
674
|
+
// Only generate fallback if locale parameter exists
|
|
675
|
+
const hasLocaleParam = resource?.params?.locale !== undefined
|
|
676
|
+
let fallbackAST = null
|
|
677
|
+
|
|
678
|
+
if (hasLocaleParam) {
|
|
679
|
+
const fallbackParams = JSON.parse(JSON.stringify(resource))
|
|
680
|
+
delete fallbackParams?.params?.locale
|
|
681
|
+
const fallbackUrlParamsDeclaration = generateParamsAST(fallbackParams?.params)
|
|
682
|
+
const assignmentOfNewUrlParams = types.expressionStatement(
|
|
683
|
+
types.assignmentExpression(
|
|
684
|
+
'=',
|
|
685
|
+
types.identifier('urlParams'),
|
|
686
|
+
types.objectExpression([...fallbackUrlParamsDeclaration])
|
|
687
|
+
)
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
const assignmentExpressionAST = types.expressionStatement(
|
|
691
|
+
types.assignmentExpression(
|
|
692
|
+
'=',
|
|
693
|
+
types.identifier('data'),
|
|
694
|
+
types.awaitExpression(
|
|
695
|
+
types.callExpression(types.identifier('fetch'), [
|
|
696
|
+
url,
|
|
697
|
+
types.objectExpression([
|
|
698
|
+
method,
|
|
699
|
+
...(allHeaders.length > 0
|
|
700
|
+
? [
|
|
701
|
+
types.objectProperty(
|
|
702
|
+
types.identifier('headers'),
|
|
703
|
+
types.objectExpression(allHeaders)
|
|
704
|
+
),
|
|
705
|
+
]
|
|
706
|
+
: []),
|
|
707
|
+
...(bodyParamsDecleration.length > 0 && resource?.method === 'POST'
|
|
708
|
+
? [
|
|
709
|
+
types.objectProperty(
|
|
710
|
+
types.identifier('body'),
|
|
711
|
+
types.callExpression(
|
|
712
|
+
types.memberExpression(
|
|
713
|
+
types.identifier('JSON'),
|
|
714
|
+
types.identifier('stringify')
|
|
715
|
+
),
|
|
716
|
+
[types.identifier('bodyParams')]
|
|
717
|
+
)
|
|
718
|
+
),
|
|
719
|
+
]
|
|
720
|
+
: []),
|
|
721
|
+
]),
|
|
722
|
+
])
|
|
723
|
+
)
|
|
724
|
+
)
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
fallbackAST = types.ifStatement(
|
|
728
|
+
types.binaryExpression(
|
|
729
|
+
'!==',
|
|
730
|
+
types.memberExpression(types.identifier('data'), types.identifier('status')),
|
|
731
|
+
types.numericLiteral(200)
|
|
732
|
+
),
|
|
733
|
+
types.blockStatement([assignmentOfNewUrlParams, assignmentExpressionAST])
|
|
734
|
+
)
|
|
735
|
+
}
|
|
656
736
|
const responseType = resource?.response?.type ?? 'json'
|
|
657
737
|
let responseJSONAST
|
|
658
738
|
|
|
@@ -719,7 +799,80 @@ export const generateRemoteResourceASTs = (resource: UIDLResourceItem) => {
|
|
|
719
799
|
}
|
|
720
800
|
}
|
|
721
801
|
|
|
722
|
-
return [
|
|
802
|
+
return [
|
|
803
|
+
...(urlParamsDecleration.length > 0
|
|
804
|
+
? [
|
|
805
|
+
types.variableDeclaration('let', [
|
|
806
|
+
types.variableDeclarator(
|
|
807
|
+
types.identifier('urlParams'),
|
|
808
|
+
types.objectExpression(urlParamsDecleration)
|
|
809
|
+
),
|
|
810
|
+
]),
|
|
811
|
+
]
|
|
812
|
+
: []),
|
|
813
|
+
...(bodyParamsDecleration.length > 0
|
|
814
|
+
? [
|
|
815
|
+
types.variableDeclaration('const', [
|
|
816
|
+
types.variableDeclarator(
|
|
817
|
+
types.identifier('bodyParams'),
|
|
818
|
+
types.objectExpression(bodyParamsDecleration)
|
|
819
|
+
),
|
|
820
|
+
]),
|
|
821
|
+
]
|
|
822
|
+
: []),
|
|
823
|
+
fetchAST,
|
|
824
|
+
...(fallbackAST ? [fallbackAST] : []),
|
|
825
|
+
responseJSONAST,
|
|
826
|
+
].filter(Boolean)
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const generateParamsAST = (
|
|
830
|
+
props: Record<string, UIDLStaticValue | UIDLPropValue | UIDLStateValue | UIDLExpressionValue>
|
|
831
|
+
): Array<types.ObjectProperty | types.SpreadElement> => {
|
|
832
|
+
return Object.keys(props || {}).reduce(
|
|
833
|
+
(acc: Array<types.ObjectProperty | types.SpreadElement>, item) => {
|
|
834
|
+
const prop = props[item]
|
|
835
|
+
if (prop.type === 'static') {
|
|
836
|
+
acc.push(types.objectProperty(types.stringLiteral(item), resolveObjectValue(prop)))
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (prop.type === 'expr') {
|
|
840
|
+
acc.push(
|
|
841
|
+
types.objectProperty(types.stringLiteral(item), getExpressionFromUIDLExpressionNode(prop))
|
|
842
|
+
)
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (prop.type === 'dynamic') {
|
|
846
|
+
acc.push(
|
|
847
|
+
types.spreadElement(
|
|
848
|
+
types.logicalExpression(
|
|
849
|
+
'&&',
|
|
850
|
+
types.memberExpression(
|
|
851
|
+
types.identifier('params'),
|
|
852
|
+
types.stringLiteral(prop.content.id),
|
|
853
|
+
true,
|
|
854
|
+
false
|
|
855
|
+
),
|
|
856
|
+
types.objectExpression([
|
|
857
|
+
types.objectProperty(
|
|
858
|
+
types.stringLiteral(item),
|
|
859
|
+
types.memberExpression(
|
|
860
|
+
types.identifier('params'),
|
|
861
|
+
types.stringLiteral(prop.content.id),
|
|
862
|
+
true,
|
|
863
|
+
false
|
|
864
|
+
)
|
|
865
|
+
),
|
|
866
|
+
])
|
|
867
|
+
)
|
|
868
|
+
)
|
|
869
|
+
)
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
return acc
|
|
873
|
+
},
|
|
874
|
+
[]
|
|
875
|
+
)
|
|
723
876
|
}
|
|
724
877
|
|
|
725
878
|
const generateRESTHeadersAST = (headers: UIDLResourceItem['headers']): types.ObjectProperty[] => {
|
|
@@ -754,6 +907,22 @@ export const generateMemberExpressionASTFromBase = (
|
|
|
754
907
|
)
|
|
755
908
|
}
|
|
756
909
|
|
|
910
|
+
export const parseValuePath = (valuePath: Array<string | number>): Array<string | number> => {
|
|
911
|
+
return valuePath.map((segment) => {
|
|
912
|
+
if (typeof segment === 'string') {
|
|
913
|
+
const bracketMatch = segment.match(/^\[(\d+)\]$/)
|
|
914
|
+
if (bracketMatch) {
|
|
915
|
+
return parseInt(bracketMatch[1], 10)
|
|
916
|
+
}
|
|
917
|
+
const numericMatch = segment.match(/^\d+$/)
|
|
918
|
+
if (numericMatch) {
|
|
919
|
+
return parseInt(segment, 10)
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return segment
|
|
923
|
+
})
|
|
924
|
+
}
|
|
925
|
+
|
|
757
926
|
export const generateMemberExpressionASTFromPath = (
|
|
758
927
|
path: Array<string | number>
|
|
759
928
|
): types.OptionalMemberExpression | types.Identifier => {
|
|
@@ -769,7 +938,7 @@ export const generateMemberExpressionASTFromPath = (
|
|
|
769
938
|
return types.optionalMemberExpression(
|
|
770
939
|
generateMemberExpressionASTFromPath(pathClone),
|
|
771
940
|
types.numericLiteral(currentPath),
|
|
772
|
-
|
|
941
|
+
true,
|
|
773
942
|
true
|
|
774
943
|
)
|
|
775
944
|
}
|
|
@@ -885,7 +1054,7 @@ const computeAuthorizationHeaderAST = (headers: UIDLResourceItem['headers']) =>
|
|
|
885
1054
|
)
|
|
886
1055
|
}
|
|
887
1056
|
|
|
888
|
-
const computeFetchUrl = (resource: UIDLResourceItem) => {
|
|
1057
|
+
export const computeFetchUrl = (resource: UIDLResourceItem) => {
|
|
889
1058
|
const { path } = resource
|
|
890
1059
|
const fetchBaseUrl = resolveResourceValue(path.baseUrl)
|
|
891
1060
|
const resourceRoute = resolveResourceValue(path.route)
|
|
@@ -894,7 +1063,11 @@ const computeFetchUrl = (resource: UIDLResourceItem) => {
|
|
|
894
1063
|
const routeType = path.route?.type
|
|
895
1064
|
|
|
896
1065
|
if (baseUrlType === 'static' && routeType === 'static') {
|
|
897
|
-
const
|
|
1066
|
+
const baseUrlStr = typeof fetchBaseUrl === 'string' ? fetchBaseUrl : String(fetchBaseUrl || '')
|
|
1067
|
+
const routeStr = typeof resourceRoute === 'string' ? resourceRoute : String(resourceRoute || '')
|
|
1068
|
+
const cleanBaseUrl = baseUrlStr.endsWith('/') ? baseUrlStr.slice(0, -1) : baseUrlStr
|
|
1069
|
+
const cleanRoute = routeStr.startsWith('/') ? routeStr.slice(1) : routeStr
|
|
1070
|
+
const stringsToJoin = [cleanBaseUrl, cleanRoute].filter((item) => item).join('/')
|
|
898
1071
|
return types.templateLiteral(
|
|
899
1072
|
[types.templateElement({ cooked: `${stringsToJoin}`, raw: `${stringsToJoin}` }, true)],
|
|
900
1073
|
[]
|
|
@@ -983,6 +1156,7 @@ export const resolveObjectValue = (
|
|
|
983
1156
|
| types.NumericLiteral
|
|
984
1157
|
| types.BooleanLiteral
|
|
985
1158
|
| types.ObjectExpression
|
|
1159
|
+
| types.ArrayExpression
|
|
986
1160
|
| types.Expression => {
|
|
987
1161
|
if (prop.type === 'static') {
|
|
988
1162
|
const value =
|
|
@@ -992,6 +1166,8 @@ export const resolveObjectValue = (
|
|
|
992
1166
|
? types.booleanLiteral(prop.content)
|
|
993
1167
|
: typeof prop.content === 'number'
|
|
994
1168
|
? types.numericLiteral(prop.content)
|
|
1169
|
+
: Array.isArray(prop.content)
|
|
1170
|
+
? types.arrayExpression(prop.content.map((element) => convertValueToLiteral(element)))
|
|
995
1171
|
: typeof prop.content === 'object'
|
|
996
1172
|
? objectToObjectExpression(prop.content as unknown as Record<string, unknown>)
|
|
997
1173
|
: types.identifier(String(prop.content))
|
|
@@ -1025,3 +1201,28 @@ export const getExpressionFromUIDLExpressionNode = (
|
|
|
1025
1201
|
|
|
1026
1202
|
return theStatementOnlyWihtoutTheProgram.expression
|
|
1027
1203
|
}
|
|
1204
|
+
|
|
1205
|
+
export const isJSXElement = (value: types.JSXElement | HastNode): value is types.JSXElement =>
|
|
1206
|
+
value.type === 'JSXElement'
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* Because of the restrictions of the AST Types we need to have a clear subset of binary operators we can use
|
|
1210
|
+
* @param operation - the operation defined in the UIDL for the current state branch
|
|
1211
|
+
*/
|
|
1212
|
+
export const convertToBinaryOperator = (operation: string): BinaryOperator => {
|
|
1213
|
+
const allowedOperations = ['===', '!==', '>=', '<=', '>', '<']
|
|
1214
|
+
if (allowedOperations.includes(operation)) {
|
|
1215
|
+
return operation as BinaryOperator
|
|
1216
|
+
} else {
|
|
1217
|
+
return '==='
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
export const convertToUnaryOperator = (operation: string): UnaryOperation => {
|
|
1222
|
+
const allowedOperations = ['!']
|
|
1223
|
+
if (allowedOperations.includes(operation)) {
|
|
1224
|
+
return operation as UnaryOperation
|
|
1225
|
+
} else {
|
|
1226
|
+
return '!'
|
|
1227
|
+
}
|
|
1228
|
+
}
|
package/src/utils/hast-utils.ts
CHANGED
|
@@ -1,25 +1,53 @@
|
|
|
1
|
-
import { HastNode } from '@teleporthq/teleport-types'
|
|
1
|
+
import { HastNode, HastText } from '@teleporthq/teleport-types'
|
|
2
2
|
import { createTextNode } from '../builders/hast-builders'
|
|
3
|
+
import type { JSXElement } from '@babel/types'
|
|
4
|
+
import { isJSXElement } from './ast-utils'
|
|
3
5
|
|
|
4
|
-
export const addBooleanAttributeToNode = (
|
|
6
|
+
export const addBooleanAttributeToNode = (
|
|
7
|
+
node: HastNode | HastNode[],
|
|
8
|
+
key: string,
|
|
9
|
+
value: boolean = true
|
|
10
|
+
) => {
|
|
11
|
+
if (Array.isArray(node)) {
|
|
12
|
+
node.forEach((subnode) => (subnode.properties[key] = value === true ? '' : false))
|
|
13
|
+
return
|
|
14
|
+
}
|
|
5
15
|
node.properties[key] = value === true ? '' : false
|
|
6
|
-
|
|
7
|
-
using for generating HTML supports boolean way of adding attributes only for HTML
|
|
8
|
-
attributes but not for Vue*/
|
|
16
|
+
// Adding boolean attributes is currently onyl supported for template generators
|
|
9
17
|
}
|
|
10
18
|
|
|
11
|
-
export const addAttributeToNode = (node: HastNode, key: string, value: string) => {
|
|
19
|
+
export const addAttributeToNode = (node: HastNode | HastNode[], key: string, value: string) => {
|
|
20
|
+
if (Array.isArray(node)) {
|
|
21
|
+
node.forEach((subnode) => (subnode.properties[key] = value))
|
|
22
|
+
return
|
|
23
|
+
}
|
|
12
24
|
node.properties[key] = value
|
|
13
25
|
}
|
|
14
26
|
|
|
15
|
-
export const addClassToNode = (node: HastNode, className: string) => {
|
|
27
|
+
export const addClassToNode = (node: HastNode | HastNode[], className: string) => {
|
|
28
|
+
if (Array.isArray(node)) {
|
|
29
|
+
node.forEach((subnode) => (subnode.properties.class = className))
|
|
30
|
+
return
|
|
31
|
+
}
|
|
16
32
|
node.properties.class = className
|
|
17
33
|
}
|
|
18
34
|
|
|
19
|
-
export const addChildNode = (node: HastNode, child: HastNode) => {
|
|
35
|
+
export const addChildNode = (node: HastNode | HastNode[], child: HastNode | HastText) => {
|
|
36
|
+
if (Array.isArray(node)) {
|
|
37
|
+
node.forEach((subnode) => subnode.children.push(child))
|
|
38
|
+
return
|
|
39
|
+
}
|
|
20
40
|
node.children.push(child)
|
|
21
41
|
}
|
|
22
42
|
|
|
23
|
-
export const addTextNode = (node: HastNode, text: string) => {
|
|
43
|
+
export const addTextNode = (node: HastNode | HastNode[], text: string) => {
|
|
44
|
+
if (Array.isArray(node)) {
|
|
45
|
+
node.forEach((subnode) => subnode.children.push(createTextNode(text)))
|
|
46
|
+
return
|
|
47
|
+
}
|
|
24
48
|
node.children.push(createTextNode(text))
|
|
25
49
|
}
|
|
50
|
+
|
|
51
|
+
export const isHastElement = (value: JSXElement | HastNode): value is HastNode =>
|
|
52
|
+
isJSXElement(value) === false &&
|
|
53
|
+
('properties' in value || 'children' in value || 'tagName' in value)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type BinaryOperator =
|
|
2
|
+
| '==='
|
|
3
|
+
| '+'
|
|
4
|
+
| '-'
|
|
5
|
+
| '/'
|
|
6
|
+
| '%'
|
|
7
|
+
| '*'
|
|
8
|
+
| '**'
|
|
9
|
+
| '&'
|
|
10
|
+
| '|'
|
|
11
|
+
| '>>'
|
|
12
|
+
| '>>>'
|
|
13
|
+
| '<<'
|
|
14
|
+
| '^'
|
|
15
|
+
| '=='
|
|
16
|
+
| '!='
|
|
17
|
+
| '!=='
|
|
18
|
+
| 'in'
|
|
19
|
+
| 'instanceof'
|
|
20
|
+
| '>'
|
|
21
|
+
| '<'
|
|
22
|
+
| '>='
|
|
23
|
+
| '<='
|
|
24
|
+
|
|
25
|
+
export type UnaryOperation = '+' | '-' | 'void' | 'throw' | 'delete' | '!' | '~' | 'typeof'
|