@teleporthq/teleport-plugin-common
Advanced tools
Comparing version
@@ -1,2 +0,2 @@ | ||
import { createCSSClass } from '../../src/builders/style-builders' | ||
import { createCSSClass, createCSSClassWithSelector } from '../../src/builders/style-builders' | ||
@@ -18,2 +18,13 @@ describe('CSS Class Generation', () => { | ||
}) | ||
it('with subselectors', () => { | ||
const result = createCSSClassWithSelector('name', '& h1 > h2 .ab.cd #id', { | ||
someKey: 'value', | ||
otherKey: 'otherValue', | ||
}) | ||
expect(result).toEqual(`.name h1 > h2 .ab.cd #id { | ||
some-key: value; | ||
other-key: otherValue; | ||
}`) | ||
}) | ||
}) |
@@ -17,4 +17,4 @@ import * as types from '@babel/types' | ||
dependencies: {}, | ||
propDefinitions: uidl.propDefinitions, | ||
stateDefinitions: uidl.stateDefinitions, | ||
propDefinitions: uidl.propDefinitions || {}, | ||
stateDefinitions: uidl.stateDefinitions || {}, | ||
nodesLookup: {}, | ||
@@ -28,2 +28,3 @@ } | ||
local: '', | ||
ctx: '', | ||
}, | ||
@@ -30,0 +31,0 @@ } |
@@ -6,9 +6,9 @@ import * as types from '@babel/types'; | ||
export declare const createCSSClassWithSelector: (key: string, selector: string, styleObject: Record<string, string | number>) => string; | ||
export declare const createCSSClassWithMediaQuery: (mediaOffset: string, styleObject: Record<string, string | number>) => string; | ||
export declare const createCSSClassWithMediaQuery: (mediaOffset: string, styleObject: Record<string, string | number | Record<string, string | number>>) => string; | ||
export declare const createDynamicStyleExpression: (styleValue: UIDLDynamicReference, propsPrefix?: string, t?: typeof types) => string | ParsedASTNode; | ||
export declare const generateMediaStyle: (styleMap: Record<string, { | ||
[x: string]: Record<string, string | number>; | ||
[x: string]: Record<string, string | number | Record<string, string | number>>; | ||
}[]>) => string[]; | ||
export declare const generateStylesFromStyleSetDefinitions: (styleSetDefinitions: Record<string, UIDLStyleSetDefinition>, cssMap: string[], mediaStylesMap: Record<string, { | ||
[x: string]: Record<string, string | number>; | ||
[x: string]: Record<string, string | number | Record<string, string | number>>; | ||
}[]>, className: (val: string) => string) => void; | ||
@@ -15,0 +15,0 @@ export declare const setPropValueForCompStyle: (params: { |
@@ -114,10 +114,15 @@ "use strict"; | ||
var content = style.content, _a = style.conditions, conditions = _a === void 0 ? [] : _a, type = style.type; | ||
var name = className(styleId); | ||
var name = className(style.className || styleId); | ||
var subselectors = style.subselectors; | ||
var _b = teleport_shared_1.UIDLUtils.splitDynamicAndStaticStyles(content), staticStyles = _b.staticStyles, tokenStyles = _b.tokenStyles; | ||
var collectedStyles = __assign(__assign({}, (0, style_utils_1.getContentOfStyleObject)(staticStyles)), (0, style_utils_1.getCSSVariablesContentFromTokenStyles)(tokenStyles)); | ||
// & is required by jss, otherwise the final result will be empty | ||
var cls = subselectors | ||
? (0, exports.createCSSClassWithSelector)(name, "&".concat(subselectors), collectedStyles) | ||
: (0, exports.createCSSClass)(name, collectedStyles); | ||
if (type === 'reusable-component-style-map') { | ||
cssMap.unshift((0, exports.createCSSClass)(name, collectedStyles)); | ||
cssMap.unshift(cls); | ||
} | ||
else { | ||
cssMap.push((0, exports.createCSSClass)(name, collectedStyles)); | ||
cssMap.push(cls); | ||
} | ||
@@ -128,11 +133,11 @@ if (conditions.length === 0) { | ||
conditions.forEach(function (styleRef) { | ||
var _a, _b; | ||
var _c = teleport_shared_1.UIDLUtils.splitDynamicAndStaticStyles(styleRef.content), staticValues = _c.staticStyles, tokenValues = _c.tokenStyles; | ||
var _a, _b, _c; | ||
var _d = teleport_shared_1.UIDLUtils.splitDynamicAndStaticStyles(styleRef.content), staticValues = _d.staticStyles, tokenValues = _d.tokenStyles; | ||
var collecedMediaStyles = __assign(__assign({}, (0, style_utils_1.getContentOfStyleObject)(staticValues)), (0, style_utils_1.getCSSVariablesContentFromTokenStyles)(tokenValues)); | ||
if (styleRef.type === 'element-state') { | ||
if (type === 'reusable-component-style-map') { | ||
cssMap.unshift((0, exports.createCSSClassWithSelector)(name, "&:".concat(styleRef.meta.state), collecedMediaStyles)); | ||
cssMap.unshift((0, exports.createCSSClassWithSelector)(name, "&".concat(subselectors || '', ":").concat(styleRef.meta.state), collecedMediaStyles)); | ||
} | ||
else { | ||
cssMap.push((0, exports.createCSSClassWithSelector)(name, "&:".concat(styleRef.meta.state), collecedMediaStyles)); | ||
cssMap.push((0, exports.createCSSClassWithSelector)(name, "&".concat(subselectors || '', ":").concat(styleRef.meta.state), collecedMediaStyles)); | ||
} | ||
@@ -145,7 +150,9 @@ } | ||
} | ||
var mediaStyleMap = subselectors | ||
? (_a = {}, _a["&".concat(subselectors)] = collecedMediaStyles, _a) : collecedMediaStyles; | ||
if (type === 'reusable-component-style-map') { | ||
mediaStylesMap[String(maxWidth)].unshift((_a = {}, _a[name] = collecedMediaStyles, _a)); | ||
mediaStylesMap[String(maxWidth)].unshift((_b = {}, _b[name] = mediaStyleMap, _b)); | ||
} | ||
else { | ||
mediaStylesMap[String(maxWidth)].push((_b = {}, _b[name] = collecedMediaStyles, _b)); | ||
mediaStylesMap[String(maxWidth)].push((_c = {}, _c[name] = mediaStyleMap, _c)); | ||
} | ||
@@ -152,0 +159,0 @@ } |
@@ -9,2 +9,3 @@ "use strict"; | ||
local: '', | ||
ctx: '', | ||
}, | ||
@@ -11,0 +12,0 @@ dependencyHandling: 'import', |
@@ -36,2 +36,11 @@ "use strict"; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -45,5 +54,5 @@ var types = __importStar(require("@babel/types")); | ||
var generateElementNode = function (node, params, jsxOptions) { | ||
var options = __assign(__assign({}, constants_1.DEFAULT_JSX_OPTIONS), jsxOptions); | ||
var dependencies = params.dependencies, nodesLookup = params.nodesLookup; | ||
var _a = node.content, elementType = _a.elementType, selfClosing = _a.selfClosing, children = _a.children, key = _a.key, attrs = _a.attrs, dependency = _a.dependency, events = _a.events; | ||
var dependencies = params.dependencies, nodesLookup = params.nodesLookup, _a = params.projectContexts, projectContexts = _a === void 0 ? {} : _a, _b = params.projectResources, projectResources = _b === void 0 ? {} : _b; | ||
var options = __assign(__assign(__assign({}, constants_1.DEFAULT_JSX_OPTIONS), jsxOptions), { projectContexts: projectContexts, projectResources: projectResources }); | ||
var _c = node.content, elementType = _c.elementType, selfClosing = _c.selfClosing, children = _c.children, key = _c.key, attrs = _c.attrs, dependency = _c.dependency, events = _c.events; | ||
var originalElementName = elementType || 'component'; | ||
@@ -80,2 +89,16 @@ var tagName = originalElementName; | ||
var prefix = options.dynamicReferencePrefixMap[referenceType]; | ||
if (referenceType === 'expr') { | ||
(0, ast_utils_1.addDynamicExpressionAttributeToJSXTag)(elementTag, attributeValue, params); | ||
break; | ||
} | ||
if (referenceType === 'ctx') { | ||
(0, ast_utils_1.addDynamicCtxAttributeToJSXTag)({ | ||
jsxASTNode: elementTag, | ||
name: attrKey, | ||
attrValue: attributeValue, | ||
options: jsxOptions, | ||
generationParams: params, | ||
}); | ||
break; | ||
} | ||
(0, ast_utils_1.addDynamicAttributeToJSXTag)(elementTag, attrKey, id, prefix); | ||
@@ -106,12 +129,14 @@ break; | ||
children.forEach(function (child) { | ||
var childTag = generateNode(child, params, options); | ||
if (typeof childTag === 'string') { | ||
(0, ast_utils_1.addChildJSXText)(elementTag, childTag); | ||
} | ||
else if (childTag.type === 'JSXExpressionContainer' || childTag.type === 'JSXElement') { | ||
(0, ast_utils_1.addChildJSXTag)(elementTag, childTag); | ||
} | ||
else { | ||
(0, ast_utils_1.addChildJSXTag)(elementTag, types.jsxExpressionContainer(childTag)); | ||
} | ||
var childTags = generateNode(child, params, options); | ||
childTags.forEach(function (childTag) { | ||
if (typeof childTag === 'string') { | ||
(0, ast_utils_1.addChildJSXText)(elementTag, childTag); | ||
} | ||
else if (childTag.type === 'JSXExpressionContainer' || childTag.type === 'JSXElement') { | ||
(0, ast_utils_1.addChildJSXTag)(elementTag, childTag); | ||
} | ||
else { | ||
(0, ast_utils_1.addChildJSXTag)(elementTag, types.jsxExpressionContainer(childTag)); | ||
} | ||
}); | ||
}); | ||
@@ -126,11 +151,17 @@ } | ||
case 'raw': | ||
return options.domHTMLInjection | ||
? options.domHTMLInjection(node.content.toString()) | ||
: node.content.toString(); | ||
return [ | ||
options.domHTMLInjection | ||
? options.domHTMLInjection(node.content.toString()) | ||
: node.content.toString(), | ||
]; | ||
case 'static': | ||
return teleport_shared_1.StringUtils.encode(node.content.toString()); | ||
return [teleport_shared_1.StringUtils.encode(node.content.toString())]; | ||
case 'dynamic': | ||
return (0, utils_1.createDynamicValueExpression)(node, options); | ||
return [(0, utils_1.createDynamicValueExpression)(node, options, undefined, params)]; | ||
case 'cms-item': | ||
return generateCMSItemNode(node, params, options); | ||
case 'cms-list': | ||
return generateCMSListNode(node, params, options); | ||
case 'element': | ||
return generateElementNode(node, params, options); | ||
return [generateElementNode(node, params, options)]; | ||
case 'repeat': | ||
@@ -142,3 +173,3 @@ return generateRepeatNode(node, params, options); | ||
if (options.slotHandling === 'native') { | ||
return generateNativeSlotNode(node, params, options); | ||
return [generateNativeSlotNode(node, params, options)]; | ||
} | ||
@@ -152,8 +183,75 @@ else { | ||
}; | ||
var generateCMSItemNode = function (node, params, options) { | ||
var _a = node.content.nodes, success = _a.success, error = _a.error, loading = _a.loading; | ||
/* | ||
* TODO: | ||
* Adding `loading` and `error` states at the moment are being conntrolled by the UIDL. | ||
* But this needs to be changed, the generators itself should make the decision. Depending | ||
* on the style flavour that is being ued. | ||
*/ | ||
var statePersistanceName = node.content.statePersistanceName; | ||
var loadingState = teleport_shared_1.StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Loading")); | ||
var errorState = teleport_shared_1.StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Error")); | ||
var errorNodeAST = error | ||
? types.logicalExpression('&&', types.identifier(errorState), generateElementNode(error, params, options)) | ||
: null; | ||
var loadingNodeAST = loading | ||
? types.logicalExpression('&&', types.identifier(loadingState), generateElementNode(loading, params, options)) | ||
: null; | ||
var successElementAST = generateElementNode(success, params, options); | ||
var successAST = !loading || !error | ||
? successElementAST | ||
: types.logicalExpression('&&', types.logicalExpression('&&', types.unaryExpression('!', types.identifier(loadingState)), types.unaryExpression('!', types.identifier(errorState))), successElementAST); | ||
return __spreadArray(__spreadArray(__spreadArray([], (loading ? [loadingNodeAST] : []), true), (error ? [errorNodeAST] : []), true), [successAST], false); | ||
}; | ||
var generateCMSListNode = function (node, params, options) { | ||
var _a = node.content.nodes, success = _a.success, empty = _a.empty, error = _a.error, loading = _a.loading; | ||
var statePersistanceName = node.content.statePersistanceName; | ||
var loadingStatePersistanceName = teleport_shared_1.StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Loading")); | ||
var errorStatePersistanceName = teleport_shared_1.StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Error")); | ||
var listNodeAST = !!success | ||
? generateNode(success, params, options)[0] | ||
: null; | ||
var source = (0, utils_1.getRepeatSourceIdentifier)(node.content.loopItemsReference, options); | ||
var emptyNodeAST = !!empty | ||
? generateNode(empty, params, options)[0] | ||
: null; | ||
var emptyNodeExpressionAST = empty | ||
? types.logicalExpression('&&', types.unaryExpression('!', types.memberExpression(source, types.identifier('length'))), emptyNodeAST) | ||
: null; | ||
var errorNodeAST = !!error | ||
? generateNode(error, params, options)[0] | ||
: null; | ||
var errorNodeExpressionAST = error && errorStatePersistanceName | ||
? types.logicalExpression('&&', types.identifier(errorStatePersistanceName), errorNodeAST) | ||
: null; | ||
var loadingNodeAST = !!loading | ||
? generateNode(loading, params, options)[0] | ||
: null; | ||
var loadingNodeExpressionAST = loading && loadingStatePersistanceName | ||
? types.logicalExpression('&&', types.identifier(loadingStatePersistanceName), loadingNodeAST) | ||
: null; | ||
var _b = teleport_shared_1.UIDLUtils.getRepeatIteratorNameAndKey({ | ||
useIndex: true, | ||
iteratorName: 'item', | ||
}), iteratorName = _b.iteratorName, iteratorKey = _b.iteratorKey; | ||
var localIteratorPrefix = options.dynamicReferencePrefixMap.local; | ||
(0, ast_utils_1.addDynamicAttributeToJSXTag)(listNodeAST, 'key', iteratorKey, localIteratorPrefix); | ||
(0, ast_utils_1.addDynamicAttributeToJSXTag)(listNodeAST, 'value', __spreadArray(['item'], (node.content.itemValuePath || []), true).join('.'), localIteratorPrefix); | ||
var arrowFunctionArguments = [types.identifier(iteratorName)]; | ||
arrowFunctionArguments.push(types.identifier('index')); | ||
return __spreadArray(__spreadArray(__spreadArray(__spreadArray([], (emptyNodeExpressionAST ? [emptyNodeExpressionAST] : []), true), (errorNodeExpressionAST ? [errorNodeExpressionAST] : []), true), (loadingNodeExpressionAST ? [loadingNodeExpressionAST] : []), true), [ | ||
types.logicalExpression('&&', types.memberExpression(source, types.identifier('length')), types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, listNodeAST), | ||
])), | ||
], false); | ||
}; | ||
var generateRepeatNode = function (node, params, options) { | ||
var _a = node.content, repeatContent = _a.node, dataSource = _a.dataSource, meta = _a.meta; | ||
var contentAST = generateElementNode(repeatContent, params, options); | ||
var contentASTs = generateNode(repeatContent, params, options); | ||
var _b = teleport_shared_1.UIDLUtils.getRepeatIteratorNameAndKey(meta), iteratorName = _b.iteratorName, iteratorKey = _b.iteratorKey; | ||
var localIteratorPrefix = options.dynamicReferencePrefixMap.local; | ||
(0, ast_utils_1.addDynamicAttributeToJSXTag)(contentAST, 'key', iteratorKey, localIteratorPrefix); | ||
contentASTs.forEach(function (contentAST) { | ||
(0, ast_utils_1.addDynamicAttributeToJSXTag)(contentAST, 'key', iteratorKey, localIteratorPrefix); | ||
}); | ||
var source = (0, utils_1.getRepeatSourceIdentifier)(dataSource, options); | ||
@@ -164,5 +262,7 @@ var arrowFunctionArguments = [types.identifier(iteratorName)]; | ||
} | ||
return types.jsxExpressionContainer(types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, contentAST), | ||
])); | ||
return contentASTs.map(function (contentAST) { | ||
return types.jsxExpressionContainer(types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, contentAST), | ||
])); | ||
}); | ||
}; | ||
@@ -172,7 +272,9 @@ var generateConditionalNode = function (node, params, options) { | ||
var conditionIdentifier = (0, utils_1.createConditionIdentifier)(reference, params, options); | ||
var subTree = generateNode(node.content.node, params, options); | ||
var subTrees = generateNode(node.content.node, params, options); | ||
var condition = value !== undefined && value !== null | ||
? { conditions: [{ operand: value, operation: '===' }] } | ||
: node.content.condition; | ||
return (0, utils_1.createConditionalJSXExpression)(subTree, condition, conditionIdentifier); | ||
return subTrees.map(function (subTree) { | ||
return (0, utils_1.createConditionalJSXExpression)(subTree, condition, conditionIdentifier); | ||
}); | ||
}; | ||
@@ -191,11 +293,13 @@ var generatePropsSlotNode = function (node, params, options) { | ||
if (node.content.fallback) { | ||
var fallbackContent = generateNode(node.content.fallback, params, options); | ||
var fallbackContents = generateNode(node.content.fallback, params, options); | ||
// only static dynamic or element are allowed here | ||
var fallbackNode = typeof fallbackContent === 'string' | ||
? types.stringLiteral(fallbackContent) | ||
: fallbackContent; | ||
// props.children with fallback | ||
return types.jsxExpressionContainer(types.logicalExpression('||', childrenExpression, fallbackNode)); | ||
return fallbackContents.map(function (fallbackContent) { | ||
var fallbackNode = typeof fallbackContent === 'string' | ||
? types.stringLiteral(fallbackContent) | ||
: fallbackContent; | ||
// props.children with fallback | ||
return types.jsxExpressionContainer(types.logicalExpression('||', childrenExpression, fallbackNode)); | ||
}); | ||
} | ||
return types.jsxExpressionContainer(childrenExpression); | ||
return [types.jsxExpressionContainer(childrenExpression)]; | ||
}; | ||
@@ -208,12 +312,14 @@ var generateNativeSlotNode = function (node, params, options) { | ||
if (node.content.fallback) { | ||
var fallbackContent = generateNode(node.content.fallback, params, options); | ||
if (typeof fallbackContent === 'string') { | ||
(0, ast_utils_1.addChildJSXText)(slotNode, fallbackContent); | ||
} | ||
else if (fallbackContent.type === 'MemberExpression') { | ||
(0, ast_utils_1.addChildJSXTag)(slotNode, types.jsxExpressionContainer(fallbackContent)); | ||
} | ||
else { | ||
(0, ast_utils_1.addChildJSXTag)(slotNode, fallbackContent); | ||
} | ||
var fallbackContents = generateNode(node.content.fallback, params, options); | ||
fallbackContents.forEach(function (fallbackContent) { | ||
if (typeof fallbackContent === 'string') { | ||
(0, ast_utils_1.addChildJSXText)(slotNode, fallbackContent); | ||
} | ||
else if (fallbackContent.type === 'MemberExpression') { | ||
(0, ast_utils_1.addChildJSXTag)(slotNode, types.jsxExpressionContainer(fallbackContent)); | ||
} | ||
else { | ||
(0, ast_utils_1.addChildJSXTag)(slotNode, fallbackContent); | ||
} | ||
}); | ||
} | ||
@@ -220,0 +326,0 @@ return slotNode; |
import * as types from '@babel/types'; | ||
import { UIDLPropDefinition, UIDLDependency, UIDLStateDefinition } from '@teleporthq/teleport-types'; | ||
import { UIDLPropDefinition, UIDLDependency, UIDLStateDefinition, ProjectContext, ProjectResource } from '@teleporthq/teleport-types'; | ||
export interface JSXGenerationParams { | ||
@@ -9,2 +9,4 @@ propDefinitions: Record<string, UIDLPropDefinition>; | ||
windowImports: Record<string, types.ExpressionStatement>; | ||
projectContexts?: Record<string, ProjectContext>; | ||
projectResources?: Record<string, ProjectResource>; | ||
} | ||
@@ -16,2 +18,3 @@ export interface JSXGenerationOptions { | ||
local: string; | ||
ctx: string; | ||
}; | ||
@@ -18,0 +21,0 @@ dependencyHandling?: 'import' | 'ignore'; |
@@ -5,3 +5,3 @@ import * as types from '@babel/types'; | ||
export declare const addEventHandlerToTag: (tag: types.JSXElement, eventKey: string, eventHandlerStatements: UIDLEventHandlerStatement[], params: JSXGenerationParams, options: JSXGenerationOptions, t?: typeof types) => void; | ||
export declare const createDynamicValueExpression: (identifier: UIDLDynamicReference, options: JSXGenerationOptions, t?: typeof types) => types.Identifier | types.MemberExpression; | ||
export declare const createDynamicValueExpression: (identifier: UIDLDynamicReference, options: JSXGenerationOptions, t?: typeof types, params?: JSXGenerationParams) => types.Identifier | types.MemberExpression; | ||
export declare const createConditionIdentifier: (dynamicReference: UIDLDynamicReference, params: JSXGenerationParams, options: JSXGenerationOptions) => ConditionalIdentifier; | ||
@@ -8,0 +8,0 @@ export declare const createConditionalJSXExpression: (content: JSXASTReturnType, conditionalExpression: UIDLConditionalExpression, conditionalIdentifier: ConditionalIdentifier, t?: typeof types) => types.LogicalExpression; |
@@ -106,3 +106,5 @@ "use strict"; | ||
case 'hooks': | ||
return t.expressionStatement(t.callExpression(t.identifier("set".concat(teleport_shared_1.StringUtils.capitalize(stateKey))), [newStateValue])); | ||
return t.expressionStatement(t.callExpression(t.identifier(teleport_shared_1.StringUtils.createStateStoringFunction(stateKey)), [ | ||
newStateValue, | ||
])); | ||
case 'function': | ||
@@ -117,9 +119,26 @@ return t.expressionStatement(t.callExpression(t.identifier('this.setState'), [ | ||
}; | ||
var createDynamicValueExpression = function (identifier, options, t) { | ||
var createDynamicValueExpression = function (identifier, options, t, params) { | ||
var _a, _b; | ||
if (t === void 0) { t = types; } | ||
var refType = identifier.content.referenceType; | ||
var prefix = options.dynamicReferencePrefixMap[refType] || ''; | ||
var _c = (params || {}).projectContexts, projectContexts = _c === void 0 ? {} : _c; | ||
var identifierContent = identifier.content; | ||
if (identifierContent.referenceType === 'expr' || | ||
identifierContent.referenceType === 'attr' || | ||
identifierContent.referenceType === 'children' || | ||
identifierContent.referenceType === 'token') { | ||
throw new Error("Dynamic reference type \"".concat(identifierContent.referenceType, "\" is not supported yet")); | ||
} | ||
if (identifierContent.referenceType === 'ctx') { | ||
// TODO handle situation when context is not using path | ||
// TODO only allow ctxID not id for context references | ||
var contextMeta = projectContexts[(_a = identifierContent.ctxId) !== null && _a !== void 0 ? _a : identifierContent.id]; | ||
if (!contextMeta) { | ||
throw new Error("Could not find the referenced context: ".concat((_b = identifierContent.ctxId) !== null && _b !== void 0 ? _b : identifierContent.id, " on node ").concat(JSON.stringify(identifierContent))); | ||
} | ||
return t.memberExpression(t.identifier(teleport_shared_1.StringUtils.camelize(contextMeta.providerName)), t.identifier(identifierContent.path.join('?.'))); | ||
} | ||
var prefix = options.dynamicReferencePrefixMap[identifierContent.referenceType] || ''; | ||
return prefix === '' | ||
? t.identifier(identifier.content.id) | ||
: t.memberExpression(t.identifier(prefix), t.identifier(identifier.content.id)); | ||
? t.identifier(identifierContent.id) | ||
: t.memberExpression(t.identifier(prefix), t.identifier(identifierContent.id)); | ||
}; | ||
@@ -126,0 +145,0 @@ exports.createDynamicValueExpression = createDynamicValueExpression; |
import * as types from '@babel/types'; | ||
import ParsedASTNode from './parsed-ast'; | ||
import { UIDLStateDefinition, UIDLPropDefinition, UIDLRawValue } from '@teleporthq/teleport-types'; | ||
import { UIDLStateDefinition, UIDLPropDefinition, UIDLRawValue, Resource, UIDLDynamicReference } from '@teleporthq/teleport-types'; | ||
import { JSXGenerationOptions, JSXGenerationParams } from '../node-handlers/node-to-jsx/types'; | ||
/** | ||
@@ -10,4 +11,23 @@ * Adds a class definition string to an existing string of classes | ||
* Makes `${name}={${prefix}.${value}}` happen in AST | ||
* doesn't handle ctx or expr referenceType | ||
*/ | ||
export declare const addDynamicAttributeToJSXTag: (jsxASTNode: types.JSXElement, name: string, value: string, prefix?: string, t?: typeof types) => void; | ||
/** | ||
* Makes `${name}={${ContextName}.${path}}` happen in AST | ||
*/ | ||
export declare const addDynamicCtxAttributeToJSXTag: (params: { | ||
jsxASTNode: types.JSXElement; | ||
name: string; | ||
attrValue: UIDLDynamicReference; | ||
options: JSXGenerationOptions; | ||
generationParams: JSXGenerationParams; | ||
t?: typeof types; | ||
}) => void; | ||
/** | ||
* Make code expressions happen in AST | ||
* Replace variables that are found in AST with | ||
* the corresponding value from the contexts for now | ||
* and in the future with other sources. | ||
*/ | ||
export declare const addDynamicExpressionAttributeToJSXTag: (jsxASTNode: types.JSXElement, dynamicRef: UIDLDynamicReference, params: JSXGenerationParams, t?: typeof types) => void; | ||
export declare const addMultipleDynamicAttributesToJSXTag: (jsxASTNode: types.JSXElement, name: string, attrValues?: Array<types.MemberExpression | types.Identifier>, t?: typeof types) => void; | ||
@@ -39,3 +59,6 @@ export declare const stringAsTemplateLiteral: (str: string, t?: typeof types) => types.TemplateLiteral; | ||
export declare const wrapObjectPropertiesWithExpression: (properties: types.ObjectProperty[]) => types.ObjectExpression; | ||
export declare const generateRemoteResourceASTs: (resource: Resource, propsPrefix?: string, extraUrlParamsGenerator?: () => types.ObjectProperty[]) => types.VariableDeclaration[]; | ||
export declare const generateMemberExpressionASTFromBase: (base: types.MemberExpression | types.Identifier, path: string[]) => types.MemberExpression; | ||
export declare const generateMemberExpressionASTFromPath: (path: string[]) => types.MemberExpression | types.Identifier; | ||
export {}; | ||
//# sourceMappingURL=ast-utils.d.ts.map |
@@ -38,6 +38,8 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.wrapObjectPropertiesWithExpression = exports.generateDynamicWindowImport = exports.createStateHookAST = exports.createReturnExpressionSyntax = exports.createPureComponent = exports.createClassComponent = exports.removeAttributeByName = exports.findAttributeByName = exports.getTSAnnotationForType = exports.addPropertyToASTObject = exports.convertValueToLiteral = exports.objectToObjectExpression = exports.renameJSXTag = exports.addSpreadAttributeToJSXTag = exports.addChildJSXText = exports.addChildJSXTag = exports.addRawAttributeToJSXTag = exports.addAttributeToJSXTag = exports.stringAsTemplateLiteral = exports.addMultipleDynamicAttributesToJSXTag = exports.addDynamicAttributeToJSXTag = exports.addClassStringOnJSXTag = void 0; | ||
exports.generateMemberExpressionASTFromPath = exports.generateMemberExpressionASTFromBase = exports.generateRemoteResourceASTs = exports.wrapObjectPropertiesWithExpression = exports.generateDynamicWindowImport = exports.createStateHookAST = exports.createReturnExpressionSyntax = exports.createPureComponent = exports.createClassComponent = exports.removeAttributeByName = exports.findAttributeByName = exports.getTSAnnotationForType = exports.addPropertyToASTObject = exports.convertValueToLiteral = exports.objectToObjectExpression = exports.renameJSXTag = exports.addSpreadAttributeToJSXTag = exports.addChildJSXText = exports.addChildJSXTag = exports.addRawAttributeToJSXTag = exports.addAttributeToJSXTag = exports.stringAsTemplateLiteral = exports.addMultipleDynamicAttributesToJSXTag = exports.addDynamicExpressionAttributeToJSXTag = exports.addDynamicCtxAttributeToJSXTag = exports.addDynamicAttributeToJSXTag = exports.addClassStringOnJSXTag = void 0; | ||
var types = __importStar(require("@babel/types")); | ||
var core_1 = require("@babel/core"); | ||
var parsed_ast_1 = __importDefault(require("./parsed-ast")); | ||
var teleport_shared_1 = require("@teleporthq/teleport-shared"); | ||
var utils_1 = require("../node-handlers/node-to-jsx/utils"); | ||
/** | ||
@@ -99,2 +101,3 @@ * Adds a class definition string to an existing string of classes | ||
* Makes `${name}={${prefix}.${value}}` happen in AST | ||
* doesn't handle ctx or expr referenceType | ||
*/ | ||
@@ -110,2 +113,62 @@ var addDynamicAttributeToJSXTag = function (jsxASTNode, name, value, prefix, t) { | ||
exports.addDynamicAttributeToJSXTag = addDynamicAttributeToJSXTag; | ||
/** | ||
* Makes `${name}={${ContextName}.${path}}` happen in AST | ||
*/ | ||
var addDynamicCtxAttributeToJSXTag = function (params) { | ||
var jsxASTNode = params.jsxASTNode, name = params.name, _a = params.t, t = _a === void 0 ? types : _a, attrValue = params.attrValue, options = params.options, generationParams = params.generationParams; | ||
var content = (0, utils_1.createDynamicValueExpression)(attrValue, options, t, generationParams); | ||
jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier(name), t.jsxExpressionContainer(content))); | ||
}; | ||
exports.addDynamicCtxAttributeToJSXTag = addDynamicCtxAttributeToJSXTag; | ||
/** | ||
* Make code expressions happen in AST | ||
* Replace variables that are found in AST with | ||
* the corresponding value from the contexts for now | ||
* and in the future with other sources. | ||
*/ | ||
var addDynamicExpressionAttributeToJSXTag = function (jsxASTNode, dynamicRef, params, t) { | ||
if (t === void 0) { t = types; } | ||
var dynamicContent = dynamicRef.content; | ||
if (dynamicContent.referenceType !== 'expr') { | ||
throw new Error("This method only works with dynamic nodes that have code expressions"); | ||
} | ||
var code = dynamicContent.expression; | ||
var options = { | ||
sourceType: 'module', | ||
}; | ||
var ast = (0, core_1.parse)(code, options); | ||
replaceIdentifiersWithScopes(ast, dynamicContent.scope, function (_, name) { | ||
var entityToResolve = dynamicContent.scope[name]; | ||
if (entityToResolve.type === 'dynamic') { | ||
var projectContexts = params.projectContexts; | ||
var contextMeta = projectContexts[entityToResolve.content.ctxId]; | ||
var nameOfContext = teleport_shared_1.StringUtils.camelize(contextMeta.providerName); | ||
return nameOfContext; | ||
} | ||
return name; | ||
}); | ||
if (!('program' in ast)) { | ||
throw new Error("The AST does not have a program node in the expression inside addDynamicExpressionAttributeToJSXTag"); | ||
} | ||
var theStatementOnlyWihtoutTheProgram = ast.program.body[0]; | ||
if (theStatementOnlyWihtoutTheProgram.type !== 'ExpressionStatement') { | ||
throw new Error("Expr dynamic attribute only support expressions statements at the moment."); | ||
} | ||
jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier('href'), t.jsxExpressionContainer(theStatementOnlyWihtoutTheProgram.expression))); | ||
}; | ||
exports.addDynamicExpressionAttributeToJSXTag = addDynamicExpressionAttributeToJSXTag; | ||
function replaceIdentifiersWithScopes(node, scopes, callback) { | ||
var visitor = { | ||
Identifier: function (path) { | ||
var name = path.node.name; | ||
if (scopes[name]) { | ||
var newName = callback(path, name); | ||
if (newName !== name) { | ||
path.replaceWith(types.identifier(newName)); | ||
} | ||
} | ||
}, | ||
}; | ||
(0, core_1.traverse)(node, visitor); | ||
} | ||
/* | ||
@@ -361,4 +424,4 @@ Use, when we need to add a mix of dynamic and static values to | ||
t.variableDeclarator(t.arrayPattern([ | ||
t.identifier(stateKey), | ||
t.identifier("set".concat(teleport_shared_1.StringUtils.capitalize(stateKey))), | ||
t.identifier(teleport_shared_1.StringUtils.createStateOrPropStoringValue(stateKey)), | ||
t.identifier(teleport_shared_1.StringUtils.createStateStoringFunction(stateKey)), | ||
]), t.callExpression(t.identifier('useState'), [defaultValueArgument])), | ||
@@ -380,2 +443,193 @@ ]); | ||
exports.wrapObjectPropertiesWithExpression = wrapObjectPropertiesWithExpression; | ||
var generateRemoteResourceASTs = function (resource, propsPrefix, extraUrlParamsGenerator) { | ||
if (propsPrefix === void 0) { propsPrefix = ''; } | ||
var fetchUrl = computeFetchUrl(resource); | ||
var authHeaderAST = computeAuthorizationHeaderAST(resource); | ||
var queryParams = generateURLParamsAST(resource.urlParams, propsPrefix, extraUrlParamsGenerator); | ||
var fetchUrlQuasis = fetchUrl.quasis; | ||
var queryParamsQuasis = queryParams.quasis; | ||
if (queryParams.expressions.length > 0) { | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.raw = | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.raw + '?'; | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.cooked = | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.cooked + '?'; | ||
queryParamsQuasis.pop(); | ||
} | ||
var url = queryParams | ||
? types.templateLiteral(__spreadArray(__spreadArray([], fetchUrlQuasis, true), queryParamsQuasis, true), __spreadArray([], fetchUrl.expressions.concat(queryParams.expressions), true)) | ||
: fetchUrl; | ||
var fetchAST = types.variableDeclaration('const', [ | ||
types.variableDeclarator(types.identifier('data'), types.awaitExpression(types.callExpression(types.identifier('fetch'), [ | ||
url, | ||
types.objectExpression([ | ||
types.objectProperty(types.identifier('headers'), types.objectExpression([ | ||
types.objectProperty(types.identifier('"Content-Type"'), types.stringLiteral('application/json'), false, false), | ||
authHeaderAST, | ||
])), | ||
]), | ||
]))), | ||
]); | ||
var responseJSONAST = types.variableDeclaration('const', [ | ||
types.variableDeclarator(types.identifier('response'), types.awaitExpression(types.callExpression(types.memberExpression(types.identifier('data'), types.identifier('json'), false), []))), | ||
]); | ||
return [fetchAST, responseJSONAST]; | ||
}; | ||
exports.generateRemoteResourceASTs = generateRemoteResourceASTs; | ||
var generateMemberExpressionASTFromBase = function (base, path) { | ||
if (path.length === 1) { | ||
return types.memberExpression(base, types.identifier(path[0]), false); | ||
} | ||
var pathClone = __spreadArray([], path, true); | ||
pathClone.pop(); | ||
return types.memberExpression((0, exports.generateMemberExpressionASTFromBase)(base, pathClone), types.identifier(path[path.length - 1]), false); | ||
}; | ||
exports.generateMemberExpressionASTFromBase = generateMemberExpressionASTFromBase; | ||
var generateMemberExpressionASTFromPath = function (path) { | ||
var pathClone = __spreadArray([], path, true); | ||
if (path.length === 1) { | ||
return types.identifier(path[0]); | ||
} | ||
pathClone.pop(); | ||
return types.memberExpression((0, exports.generateMemberExpressionASTFromPath)(pathClone), types.identifier(path[path.length - 1]), false); | ||
}; | ||
exports.generateMemberExpressionASTFromPath = generateMemberExpressionASTFromPath; | ||
var generateURLParamsAST = function (urlParams, propsPrefix, extraUrlParamsGenerator) { | ||
var queryString = {}; | ||
Object.keys(urlParams).forEach(function (key) { | ||
resolveDynamicValuesFromUrlParams(urlParams[key], queryString, key, propsPrefix); | ||
}); | ||
var urlObject = types.objectExpression(__spreadArray(__spreadArray([], Object.keys(queryString).map(function (key) { | ||
return types.objectProperty(types.stringLiteral("".concat(key)), queryString[key]); | ||
}), true), (extraUrlParamsGenerator ? extraUrlParamsGenerator() : []), true)); | ||
return types.templateLiteral([ | ||
types.templateElement({ raw: '', cooked: '' }, false), | ||
types.templateElement({ raw: '', cooked: '' }, true), | ||
], [types.newExpression(types.identifier('URLSearchParams'), [urlObject])]); | ||
}; | ||
var resolveDynamicValuesFromUrlParams = function (field, query, prefix, propsPrefix) { | ||
if (prefix === void 0) { prefix = null; } | ||
if (propsPrefix === void 0) { propsPrefix = ''; } | ||
if (Array.isArray(field)) { | ||
var arrayValues = field.map(function (value) { | ||
return resolveUrlParamsValue(value, propsPrefix); | ||
}); | ||
query[prefix] = types.arrayExpression(arrayValues); | ||
return; | ||
} | ||
if (field.type === 'dynamic' || field.type === 'static' || field.type === 'expr') { | ||
query[prefix] = resolveUrlParamsValue(field, propsPrefix); | ||
return; | ||
} | ||
Object.keys(field).forEach(function (key) { | ||
var value = field[key]; | ||
var newPrefix = prefix ? "".concat(prefix, "[").concat(key, "]") : key; | ||
if (typeof value === 'object') { | ||
resolveDynamicValuesFromUrlParams(value, query, newPrefix, propsPrefix); | ||
return; | ||
} | ||
query[newPrefix] = resolveUrlParamsValue(value, propsPrefix); | ||
}); | ||
}; | ||
var resolveUrlParamsValue = function (urlParams, propsPrefix) { | ||
if (propsPrefix === void 0) { propsPrefix = ''; } | ||
if (urlParams.type === 'static') { | ||
return types.stringLiteral("".concat(urlParams.content)); | ||
} | ||
if (urlParams.type === 'expr') { | ||
return types.identifier(urlParams.content); | ||
} | ||
if (urlParams.content.referenceType !== 'prop') { | ||
throw new Error('Only prop references are supported for url params'); | ||
} | ||
var paramPath = __spreadArray(__spreadArray([], (propsPrefix ? [propsPrefix] : []), true), (urlParams.content.path || []), true); | ||
var templateLiteralElements = paramPath | ||
.map(function (_, index) { | ||
if (index === paramPath.length - 1) { | ||
return null; | ||
} | ||
var isTail = index === paramPath.length - 2; | ||
return types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, isTail); | ||
}) | ||
.filter(function (el) { return el; }); | ||
return types.templateLiteral(templateLiteralElements, [ | ||
(0, exports.generateMemberExpressionASTFromPath)(paramPath), | ||
]); | ||
}; | ||
var computeAuthorizationHeaderAST = function (resource) { | ||
var _a; | ||
var authToken = resolveResourceValue(resource.authToken); | ||
if (!authToken) { | ||
return null; | ||
} | ||
var authTokenType = (_a = resource.authToken) === null || _a === void 0 ? void 0 : _a.type; | ||
return types.objectProperty(types.identifier('Authorization'), types.templateLiteral(__spreadArray([ | ||
types.templateElement({ | ||
cooked: authTokenType === 'static' ? "Bearer ".concat(authToken) : 'Bearer ', | ||
raw: authTokenType === 'static' ? "Bearer ".concat(authToken) : 'Bearer ', | ||
}, false) | ||
], (authTokenType === 'static' | ||
? [] | ||
: [ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, true), | ||
]), true), __spreadArray([], (authTokenType === 'static' ? [] : [types.identifier(authToken)]), true)), false, false); | ||
}; | ||
var computeFetchUrl = function (resource) { | ||
var _a, _b; | ||
var fetchBaseUrl = resolveResourceValue(resource.baseUrl); | ||
var resourceRoute = resolveResourceValue(resource.route); | ||
var baseUrlType = (_a = resource.baseUrl) === null || _a === void 0 ? void 0 : _a.type; | ||
var routeType = (_b = resource.route) === null || _b === void 0 ? void 0 : _b.type; | ||
if (baseUrlType === 'static' && routeType === 'static') { | ||
var stringsToJoin = [fetchBaseUrl, resourceRoute].filter(function (item) { return item; }).join('/'); | ||
return types.templateLiteral([types.templateElement({ cooked: "".concat(stringsToJoin), raw: "".concat(stringsToJoin) }, true)], []); | ||
} | ||
if (!routeType) { | ||
return baseUrlType === 'static' | ||
? types.templateLiteral([types.templateElement({ cooked: "".concat(fetchBaseUrl), raw: "".concat(fetchBaseUrl) }, true)], []) | ||
: types.templateLiteral([ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, false), | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, true), | ||
], [types.identifier(fetchBaseUrl)]); | ||
} | ||
return types.templateLiteral(__spreadArray([ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, false), | ||
types.templateElement({ | ||
cooked: routeType === 'static' ? "/".concat(resourceRoute) : '/', | ||
raw: routeType === 'static' ? "/".concat(resourceRoute) : '/', | ||
}, false) | ||
], (routeType === 'static' | ||
? [] | ||
: [ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, false), | ||
]), true), __spreadArray([ | ||
types.identifier(fetchBaseUrl) | ||
], (routeType === 'static' ? [] : [types.identifier(resourceRoute)]), true)); | ||
}; | ||
var resolveResourceValue = function (value) { | ||
if (!value) { | ||
return ''; | ||
} | ||
if (value.type === 'static') { | ||
return value.value; | ||
} | ||
return "process.env.".concat(value.value) || value.fallback; | ||
}; | ||
//# sourceMappingURL=ast-utils.js.map |
@@ -6,9 +6,9 @@ import * as types from '@babel/types'; | ||
export declare const createCSSClassWithSelector: (key: string, selector: string, styleObject: Record<string, string | number>) => string; | ||
export declare const createCSSClassWithMediaQuery: (mediaOffset: string, styleObject: Record<string, string | number>) => string; | ||
export declare const createCSSClassWithMediaQuery: (mediaOffset: string, styleObject: Record<string, string | number | Record<string, string | number>>) => string; | ||
export declare const createDynamicStyleExpression: (styleValue: UIDLDynamicReference, propsPrefix?: string, t?: typeof types) => string | ParsedASTNode; | ||
export declare const generateMediaStyle: (styleMap: Record<string, { | ||
[x: string]: Record<string, string | number>; | ||
[x: string]: Record<string, string | number | Record<string, string | number>>; | ||
}[]>) => string[]; | ||
export declare const generateStylesFromStyleSetDefinitions: (styleSetDefinitions: Record<string, UIDLStyleSetDefinition>, cssMap: string[], mediaStylesMap: Record<string, { | ||
[x: string]: Record<string, string | number>; | ||
[x: string]: Record<string, string | number | Record<string, string | number>>; | ||
}[]>, className: (val: string) => string) => void; | ||
@@ -15,0 +15,0 @@ export declare const setPropValueForCompStyle: (params: { |
@@ -80,10 +80,15 @@ var __assign = (this && this.__assign) || function () { | ||
var content = style.content, _a = style.conditions, conditions = _a === void 0 ? [] : _a, type = style.type; | ||
var name = className(styleId); | ||
var name = className(style.className || styleId); | ||
var subselectors = style.subselectors; | ||
var _b = UIDLUtils.splitDynamicAndStaticStyles(content), staticStyles = _b.staticStyles, tokenStyles = _b.tokenStyles; | ||
var collectedStyles = __assign(__assign({}, getContentOfStyleObject(staticStyles)), getCSSVariablesContentFromTokenStyles(tokenStyles)); | ||
// & is required by jss, otherwise the final result will be empty | ||
var cls = subselectors | ||
? createCSSClassWithSelector(name, "&".concat(subselectors), collectedStyles) | ||
: createCSSClass(name, collectedStyles); | ||
if (type === 'reusable-component-style-map') { | ||
cssMap.unshift(createCSSClass(name, collectedStyles)); | ||
cssMap.unshift(cls); | ||
} | ||
else { | ||
cssMap.push(createCSSClass(name, collectedStyles)); | ||
cssMap.push(cls); | ||
} | ||
@@ -94,11 +99,11 @@ if (conditions.length === 0) { | ||
conditions.forEach(function (styleRef) { | ||
var _a, _b; | ||
var _c = UIDLUtils.splitDynamicAndStaticStyles(styleRef.content), staticValues = _c.staticStyles, tokenValues = _c.tokenStyles; | ||
var _a, _b, _c; | ||
var _d = UIDLUtils.splitDynamicAndStaticStyles(styleRef.content), staticValues = _d.staticStyles, tokenValues = _d.tokenStyles; | ||
var collecedMediaStyles = __assign(__assign({}, getContentOfStyleObject(staticValues)), getCSSVariablesContentFromTokenStyles(tokenValues)); | ||
if (styleRef.type === 'element-state') { | ||
if (type === 'reusable-component-style-map') { | ||
cssMap.unshift(createCSSClassWithSelector(name, "&:".concat(styleRef.meta.state), collecedMediaStyles)); | ||
cssMap.unshift(createCSSClassWithSelector(name, "&".concat(subselectors || '', ":").concat(styleRef.meta.state), collecedMediaStyles)); | ||
} | ||
else { | ||
cssMap.push(createCSSClassWithSelector(name, "&:".concat(styleRef.meta.state), collecedMediaStyles)); | ||
cssMap.push(createCSSClassWithSelector(name, "&".concat(subselectors || '', ":").concat(styleRef.meta.state), collecedMediaStyles)); | ||
} | ||
@@ -111,7 +116,9 @@ } | ||
} | ||
var mediaStyleMap = subselectors | ||
? (_a = {}, _a["&".concat(subselectors)] = collecedMediaStyles, _a) : collecedMediaStyles; | ||
if (type === 'reusable-component-style-map') { | ||
mediaStylesMap[String(maxWidth)].unshift((_a = {}, _a[name] = collecedMediaStyles, _a)); | ||
mediaStylesMap[String(maxWidth)].unshift((_b = {}, _b[name] = mediaStyleMap, _b)); | ||
} | ||
else { | ||
mediaStylesMap[String(maxWidth)].push((_b = {}, _b[name] = collecedMediaStyles, _b)); | ||
mediaStylesMap[String(maxWidth)].push((_c = {}, _c[name] = mediaStyleMap, _c)); | ||
} | ||
@@ -118,0 +125,0 @@ } |
@@ -6,2 +6,3 @@ export var DEFAULT_JSX_OPTIONS = { | ||
local: '', | ||
ctx: '', | ||
}, | ||
@@ -8,0 +9,0 @@ dependencyHandling: 'import', |
@@ -12,12 +12,21 @@ var __assign = (this && this.__assign) || function () { | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
import * as types from '@babel/types'; | ||
import { UIDLUtils, StringUtils } from '@teleporthq/teleport-shared'; | ||
import { addEventHandlerToTag, createConditionIdentifier, createDynamicValueExpression, createConditionalJSXExpression, getRepeatSourceIdentifier, } from './utils'; | ||
import { addChildJSXText, addChildJSXTag, addAttributeToJSXTag, addDynamicAttributeToJSXTag, addRawAttributeToJSXTag, generateDynamicWindowImport, } from '../../utils/ast-utils'; | ||
import { addChildJSXText, addChildJSXTag, addAttributeToJSXTag, addDynamicAttributeToJSXTag, addRawAttributeToJSXTag, generateDynamicWindowImport, addDynamicExpressionAttributeToJSXTag, addDynamicCtxAttributeToJSXTag, } from '../../utils/ast-utils'; | ||
import { createJSXTag, createSelfClosingJSXTag } from '../../builders/ast-builders'; | ||
import { DEFAULT_JSX_OPTIONS } from './constants'; | ||
var generateElementNode = function (node, params, jsxOptions) { | ||
var options = __assign(__assign({}, DEFAULT_JSX_OPTIONS), jsxOptions); | ||
var dependencies = params.dependencies, nodesLookup = params.nodesLookup; | ||
var _a = node.content, elementType = _a.elementType, selfClosing = _a.selfClosing, children = _a.children, key = _a.key, attrs = _a.attrs, dependency = _a.dependency, events = _a.events; | ||
var dependencies = params.dependencies, nodesLookup = params.nodesLookup, _a = params.projectContexts, projectContexts = _a === void 0 ? {} : _a, _b = params.projectResources, projectResources = _b === void 0 ? {} : _b; | ||
var options = __assign(__assign(__assign({}, DEFAULT_JSX_OPTIONS), jsxOptions), { projectContexts: projectContexts, projectResources: projectResources }); | ||
var _c = node.content, elementType = _c.elementType, selfClosing = _c.selfClosing, children = _c.children, key = _c.key, attrs = _c.attrs, dependency = _c.dependency, events = _c.events; | ||
var originalElementName = elementType || 'component'; | ||
@@ -54,2 +63,16 @@ var tagName = originalElementName; | ||
var prefix = options.dynamicReferencePrefixMap[referenceType]; | ||
if (referenceType === 'expr') { | ||
addDynamicExpressionAttributeToJSXTag(elementTag, attributeValue, params); | ||
break; | ||
} | ||
if (referenceType === 'ctx') { | ||
addDynamicCtxAttributeToJSXTag({ | ||
jsxASTNode: elementTag, | ||
name: attrKey, | ||
attrValue: attributeValue, | ||
options: jsxOptions, | ||
generationParams: params, | ||
}); | ||
break; | ||
} | ||
addDynamicAttributeToJSXTag(elementTag, attrKey, id, prefix); | ||
@@ -80,12 +103,14 @@ break; | ||
children.forEach(function (child) { | ||
var childTag = generateNode(child, params, options); | ||
if (typeof childTag === 'string') { | ||
addChildJSXText(elementTag, childTag); | ||
} | ||
else if (childTag.type === 'JSXExpressionContainer' || childTag.type === 'JSXElement') { | ||
addChildJSXTag(elementTag, childTag); | ||
} | ||
else { | ||
addChildJSXTag(elementTag, types.jsxExpressionContainer(childTag)); | ||
} | ||
var childTags = generateNode(child, params, options); | ||
childTags.forEach(function (childTag) { | ||
if (typeof childTag === 'string') { | ||
addChildJSXText(elementTag, childTag); | ||
} | ||
else if (childTag.type === 'JSXExpressionContainer' || childTag.type === 'JSXElement') { | ||
addChildJSXTag(elementTag, childTag); | ||
} | ||
else { | ||
addChildJSXTag(elementTag, types.jsxExpressionContainer(childTag)); | ||
} | ||
}); | ||
}); | ||
@@ -100,11 +125,17 @@ } | ||
case 'raw': | ||
return options.domHTMLInjection | ||
? options.domHTMLInjection(node.content.toString()) | ||
: node.content.toString(); | ||
return [ | ||
options.domHTMLInjection | ||
? options.domHTMLInjection(node.content.toString()) | ||
: node.content.toString(), | ||
]; | ||
case 'static': | ||
return StringUtils.encode(node.content.toString()); | ||
return [StringUtils.encode(node.content.toString())]; | ||
case 'dynamic': | ||
return createDynamicValueExpression(node, options); | ||
return [createDynamicValueExpression(node, options, undefined, params)]; | ||
case 'cms-item': | ||
return generateCMSItemNode(node, params, options); | ||
case 'cms-list': | ||
return generateCMSListNode(node, params, options); | ||
case 'element': | ||
return generateElementNode(node, params, options); | ||
return [generateElementNode(node, params, options)]; | ||
case 'repeat': | ||
@@ -116,3 +147,3 @@ return generateRepeatNode(node, params, options); | ||
if (options.slotHandling === 'native') { | ||
return generateNativeSlotNode(node, params, options); | ||
return [generateNativeSlotNode(node, params, options)]; | ||
} | ||
@@ -126,8 +157,75 @@ else { | ||
}; | ||
var generateCMSItemNode = function (node, params, options) { | ||
var _a = node.content.nodes, success = _a.success, error = _a.error, loading = _a.loading; | ||
/* | ||
* TODO: | ||
* Adding `loading` and `error` states at the moment are being conntrolled by the UIDL. | ||
* But this needs to be changed, the generators itself should make the decision. Depending | ||
* on the style flavour that is being ued. | ||
*/ | ||
var statePersistanceName = node.content.statePersistanceName; | ||
var loadingState = StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Loading")); | ||
var errorState = StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Error")); | ||
var errorNodeAST = error | ||
? types.logicalExpression('&&', types.identifier(errorState), generateElementNode(error, params, options)) | ||
: null; | ||
var loadingNodeAST = loading | ||
? types.logicalExpression('&&', types.identifier(loadingState), generateElementNode(loading, params, options)) | ||
: null; | ||
var successElementAST = generateElementNode(success, params, options); | ||
var successAST = !loading || !error | ||
? successElementAST | ||
: types.logicalExpression('&&', types.logicalExpression('&&', types.unaryExpression('!', types.identifier(loadingState)), types.unaryExpression('!', types.identifier(errorState))), successElementAST); | ||
return __spreadArray(__spreadArray(__spreadArray([], (loading ? [loadingNodeAST] : []), true), (error ? [errorNodeAST] : []), true), [successAST], false); | ||
}; | ||
var generateCMSListNode = function (node, params, options) { | ||
var _a = node.content.nodes, success = _a.success, empty = _a.empty, error = _a.error, loading = _a.loading; | ||
var statePersistanceName = node.content.statePersistanceName; | ||
var loadingStatePersistanceName = StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Loading")); | ||
var errorStatePersistanceName = StringUtils.createStateOrPropStoringValue("".concat(statePersistanceName, "Error")); | ||
var listNodeAST = !!success | ||
? generateNode(success, params, options)[0] | ||
: null; | ||
var source = getRepeatSourceIdentifier(node.content.loopItemsReference, options); | ||
var emptyNodeAST = !!empty | ||
? generateNode(empty, params, options)[0] | ||
: null; | ||
var emptyNodeExpressionAST = empty | ||
? types.logicalExpression('&&', types.unaryExpression('!', types.memberExpression(source, types.identifier('length'))), emptyNodeAST) | ||
: null; | ||
var errorNodeAST = !!error | ||
? generateNode(error, params, options)[0] | ||
: null; | ||
var errorNodeExpressionAST = error && errorStatePersistanceName | ||
? types.logicalExpression('&&', types.identifier(errorStatePersistanceName), errorNodeAST) | ||
: null; | ||
var loadingNodeAST = !!loading | ||
? generateNode(loading, params, options)[0] | ||
: null; | ||
var loadingNodeExpressionAST = loading && loadingStatePersistanceName | ||
? types.logicalExpression('&&', types.identifier(loadingStatePersistanceName), loadingNodeAST) | ||
: null; | ||
var _b = UIDLUtils.getRepeatIteratorNameAndKey({ | ||
useIndex: true, | ||
iteratorName: 'item', | ||
}), iteratorName = _b.iteratorName, iteratorKey = _b.iteratorKey; | ||
var localIteratorPrefix = options.dynamicReferencePrefixMap.local; | ||
addDynamicAttributeToJSXTag(listNodeAST, 'key', iteratorKey, localIteratorPrefix); | ||
addDynamicAttributeToJSXTag(listNodeAST, 'value', __spreadArray(['item'], (node.content.itemValuePath || []), true).join('.'), localIteratorPrefix); | ||
var arrowFunctionArguments = [types.identifier(iteratorName)]; | ||
arrowFunctionArguments.push(types.identifier('index')); | ||
return __spreadArray(__spreadArray(__spreadArray(__spreadArray([], (emptyNodeExpressionAST ? [emptyNodeExpressionAST] : []), true), (errorNodeExpressionAST ? [errorNodeExpressionAST] : []), true), (loadingNodeExpressionAST ? [loadingNodeExpressionAST] : []), true), [ | ||
types.logicalExpression('&&', types.memberExpression(source, types.identifier('length')), types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, listNodeAST), | ||
])), | ||
], false); | ||
}; | ||
var generateRepeatNode = function (node, params, options) { | ||
var _a = node.content, repeatContent = _a.node, dataSource = _a.dataSource, meta = _a.meta; | ||
var contentAST = generateElementNode(repeatContent, params, options); | ||
var contentASTs = generateNode(repeatContent, params, options); | ||
var _b = UIDLUtils.getRepeatIteratorNameAndKey(meta), iteratorName = _b.iteratorName, iteratorKey = _b.iteratorKey; | ||
var localIteratorPrefix = options.dynamicReferencePrefixMap.local; | ||
addDynamicAttributeToJSXTag(contentAST, 'key', iteratorKey, localIteratorPrefix); | ||
contentASTs.forEach(function (contentAST) { | ||
addDynamicAttributeToJSXTag(contentAST, 'key', iteratorKey, localIteratorPrefix); | ||
}); | ||
var source = getRepeatSourceIdentifier(dataSource, options); | ||
@@ -138,5 +236,7 @@ var arrowFunctionArguments = [types.identifier(iteratorName)]; | ||
} | ||
return types.jsxExpressionContainer(types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, contentAST), | ||
])); | ||
return contentASTs.map(function (contentAST) { | ||
return types.jsxExpressionContainer(types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, contentAST), | ||
])); | ||
}); | ||
}; | ||
@@ -146,7 +246,9 @@ var generateConditionalNode = function (node, params, options) { | ||
var conditionIdentifier = createConditionIdentifier(reference, params, options); | ||
var subTree = generateNode(node.content.node, params, options); | ||
var subTrees = generateNode(node.content.node, params, options); | ||
var condition = value !== undefined && value !== null | ||
? { conditions: [{ operand: value, operation: '===' }] } | ||
: node.content.condition; | ||
return createConditionalJSXExpression(subTree, condition, conditionIdentifier); | ||
return subTrees.map(function (subTree) { | ||
return createConditionalJSXExpression(subTree, condition, conditionIdentifier); | ||
}); | ||
}; | ||
@@ -165,11 +267,13 @@ var generatePropsSlotNode = function (node, params, options) { | ||
if (node.content.fallback) { | ||
var fallbackContent = generateNode(node.content.fallback, params, options); | ||
var fallbackContents = generateNode(node.content.fallback, params, options); | ||
// only static dynamic or element are allowed here | ||
var fallbackNode = typeof fallbackContent === 'string' | ||
? types.stringLiteral(fallbackContent) | ||
: fallbackContent; | ||
// props.children with fallback | ||
return types.jsxExpressionContainer(types.logicalExpression('||', childrenExpression, fallbackNode)); | ||
return fallbackContents.map(function (fallbackContent) { | ||
var fallbackNode = typeof fallbackContent === 'string' | ||
? types.stringLiteral(fallbackContent) | ||
: fallbackContent; | ||
// props.children with fallback | ||
return types.jsxExpressionContainer(types.logicalExpression('||', childrenExpression, fallbackNode)); | ||
}); | ||
} | ||
return types.jsxExpressionContainer(childrenExpression); | ||
return [types.jsxExpressionContainer(childrenExpression)]; | ||
}; | ||
@@ -182,12 +286,14 @@ var generateNativeSlotNode = function (node, params, options) { | ||
if (node.content.fallback) { | ||
var fallbackContent = generateNode(node.content.fallback, params, options); | ||
if (typeof fallbackContent === 'string') { | ||
addChildJSXText(slotNode, fallbackContent); | ||
} | ||
else if (fallbackContent.type === 'MemberExpression') { | ||
addChildJSXTag(slotNode, types.jsxExpressionContainer(fallbackContent)); | ||
} | ||
else { | ||
addChildJSXTag(slotNode, fallbackContent); | ||
} | ||
var fallbackContents = generateNode(node.content.fallback, params, options); | ||
fallbackContents.forEach(function (fallbackContent) { | ||
if (typeof fallbackContent === 'string') { | ||
addChildJSXText(slotNode, fallbackContent); | ||
} | ||
else if (fallbackContent.type === 'MemberExpression') { | ||
addChildJSXTag(slotNode, types.jsxExpressionContainer(fallbackContent)); | ||
} | ||
else { | ||
addChildJSXTag(slotNode, fallbackContent); | ||
} | ||
}); | ||
} | ||
@@ -194,0 +300,0 @@ return slotNode; |
import * as types from '@babel/types'; | ||
import { UIDLPropDefinition, UIDLDependency, UIDLStateDefinition } from '@teleporthq/teleport-types'; | ||
import { UIDLPropDefinition, UIDLDependency, UIDLStateDefinition, ProjectContext, ProjectResource } from '@teleporthq/teleport-types'; | ||
export interface JSXGenerationParams { | ||
@@ -9,2 +9,4 @@ propDefinitions: Record<string, UIDLPropDefinition>; | ||
windowImports: Record<string, types.ExpressionStatement>; | ||
projectContexts?: Record<string, ProjectContext>; | ||
projectResources?: Record<string, ProjectResource>; | ||
} | ||
@@ -16,2 +18,3 @@ export interface JSXGenerationOptions { | ||
local: string; | ||
ctx: string; | ||
}; | ||
@@ -18,0 +21,0 @@ dependencyHandling?: 'import' | 'ignore'; |
@@ -5,3 +5,3 @@ import * as types from '@babel/types'; | ||
export declare const addEventHandlerToTag: (tag: types.JSXElement, eventKey: string, eventHandlerStatements: UIDLEventHandlerStatement[], params: JSXGenerationParams, options: JSXGenerationOptions, t?: typeof types) => void; | ||
export declare const createDynamicValueExpression: (identifier: UIDLDynamicReference, options: JSXGenerationOptions, t?: typeof types) => types.Identifier | types.MemberExpression; | ||
export declare const createDynamicValueExpression: (identifier: UIDLDynamicReference, options: JSXGenerationOptions, t?: typeof types, params?: JSXGenerationParams) => types.Identifier | types.MemberExpression; | ||
export declare const createConditionIdentifier: (dynamicReference: UIDLDynamicReference, params: JSXGenerationParams, options: JSXGenerationOptions) => ConditionalIdentifier; | ||
@@ -8,0 +8,0 @@ export declare const createConditionalJSXExpression: (content: JSXASTReturnType, conditionalExpression: UIDLConditionalExpression, conditionalIdentifier: ConditionalIdentifier, t?: typeof types) => types.LogicalExpression; |
@@ -79,3 +79,5 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
case 'hooks': | ||
return t.expressionStatement(t.callExpression(t.identifier("set".concat(StringUtils.capitalize(stateKey))), [newStateValue])); | ||
return t.expressionStatement(t.callExpression(t.identifier(StringUtils.createStateStoringFunction(stateKey)), [ | ||
newStateValue, | ||
])); | ||
case 'function': | ||
@@ -90,9 +92,26 @@ return t.expressionStatement(t.callExpression(t.identifier('this.setState'), [ | ||
}; | ||
export var createDynamicValueExpression = function (identifier, options, t) { | ||
export var createDynamicValueExpression = function (identifier, options, t, params) { | ||
var _a, _b; | ||
if (t === void 0) { t = types; } | ||
var refType = identifier.content.referenceType; | ||
var prefix = options.dynamicReferencePrefixMap[refType] || ''; | ||
var _c = (params || {}).projectContexts, projectContexts = _c === void 0 ? {} : _c; | ||
var identifierContent = identifier.content; | ||
if (identifierContent.referenceType === 'expr' || | ||
identifierContent.referenceType === 'attr' || | ||
identifierContent.referenceType === 'children' || | ||
identifierContent.referenceType === 'token') { | ||
throw new Error("Dynamic reference type \"".concat(identifierContent.referenceType, "\" is not supported yet")); | ||
} | ||
if (identifierContent.referenceType === 'ctx') { | ||
// TODO handle situation when context is not using path | ||
// TODO only allow ctxID not id for context references | ||
var contextMeta = projectContexts[(_a = identifierContent.ctxId) !== null && _a !== void 0 ? _a : identifierContent.id]; | ||
if (!contextMeta) { | ||
throw new Error("Could not find the referenced context: ".concat((_b = identifierContent.ctxId) !== null && _b !== void 0 ? _b : identifierContent.id, " on node ").concat(JSON.stringify(identifierContent))); | ||
} | ||
return t.memberExpression(t.identifier(StringUtils.camelize(contextMeta.providerName)), t.identifier(identifierContent.path.join('?.'))); | ||
} | ||
var prefix = options.dynamicReferencePrefixMap[identifierContent.referenceType] || ''; | ||
return prefix === '' | ||
? t.identifier(identifier.content.id) | ||
: t.memberExpression(t.identifier(prefix), t.identifier(identifier.content.id)); | ||
? t.identifier(identifierContent.id) | ||
: t.memberExpression(t.identifier(prefix), t.identifier(identifierContent.id)); | ||
}; | ||
@@ -99,0 +118,0 @@ // Prepares an identifier (from props or state) to be used as a conditional rendering identifier |
import * as types from '@babel/types'; | ||
import ParsedASTNode from './parsed-ast'; | ||
import { UIDLStateDefinition, UIDLPropDefinition, UIDLRawValue } from '@teleporthq/teleport-types'; | ||
import { UIDLStateDefinition, UIDLPropDefinition, UIDLRawValue, Resource, UIDLDynamicReference } from '@teleporthq/teleport-types'; | ||
import { JSXGenerationOptions, JSXGenerationParams } from '../node-handlers/node-to-jsx/types'; | ||
/** | ||
@@ -10,4 +11,23 @@ * Adds a class definition string to an existing string of classes | ||
* Makes `${name}={${prefix}.${value}}` happen in AST | ||
* doesn't handle ctx or expr referenceType | ||
*/ | ||
export declare const addDynamicAttributeToJSXTag: (jsxASTNode: types.JSXElement, name: string, value: string, prefix?: string, t?: typeof types) => void; | ||
/** | ||
* Makes `${name}={${ContextName}.${path}}` happen in AST | ||
*/ | ||
export declare const addDynamicCtxAttributeToJSXTag: (params: { | ||
jsxASTNode: types.JSXElement; | ||
name: string; | ||
attrValue: UIDLDynamicReference; | ||
options: JSXGenerationOptions; | ||
generationParams: JSXGenerationParams; | ||
t?: typeof types; | ||
}) => void; | ||
/** | ||
* Make code expressions happen in AST | ||
* Replace variables that are found in AST with | ||
* the corresponding value from the contexts for now | ||
* and in the future with other sources. | ||
*/ | ||
export declare const addDynamicExpressionAttributeToJSXTag: (jsxASTNode: types.JSXElement, dynamicRef: UIDLDynamicReference, params: JSXGenerationParams, t?: typeof types) => void; | ||
export declare const addMultipleDynamicAttributesToJSXTag: (jsxASTNode: types.JSXElement, name: string, attrValues?: Array<types.MemberExpression | types.Identifier>, t?: typeof types) => void; | ||
@@ -39,3 +59,6 @@ export declare const stringAsTemplateLiteral: (str: string, t?: typeof types) => types.TemplateLiteral; | ||
export declare const wrapObjectPropertiesWithExpression: (properties: types.ObjectProperty[]) => types.ObjectExpression; | ||
export declare const generateRemoteResourceASTs: (resource: Resource, propsPrefix?: string, extraUrlParamsGenerator?: () => types.ObjectProperty[]) => types.VariableDeclaration[]; | ||
export declare const generateMemberExpressionASTFromBase: (base: types.MemberExpression | types.Identifier, path: string[]) => types.MemberExpression; | ||
export declare const generateMemberExpressionASTFromPath: (path: string[]) => types.MemberExpression | types.Identifier; | ||
export {}; | ||
//# sourceMappingURL=ast-utils.d.ts.map |
@@ -11,4 +11,6 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
import * as types from '@babel/types'; | ||
import { parse, traverse } from '@babel/core'; | ||
import ParsedASTNode from './parsed-ast'; | ||
import { StringUtils } from '@teleporthq/teleport-shared'; | ||
import { createDynamicValueExpression } from '../node-handlers/node-to-jsx/utils'; | ||
/** | ||
@@ -69,2 +71,3 @@ * Adds a class definition string to an existing string of classes | ||
* Makes `${name}={${prefix}.${value}}` happen in AST | ||
* doesn't handle ctx or expr referenceType | ||
*/ | ||
@@ -79,2 +82,60 @@ export var addDynamicAttributeToJSXTag = function (jsxASTNode, name, value, prefix, t) { | ||
}; | ||
/** | ||
* Makes `${name}={${ContextName}.${path}}` happen in AST | ||
*/ | ||
export var addDynamicCtxAttributeToJSXTag = function (params) { | ||
var jsxASTNode = params.jsxASTNode, name = params.name, _a = params.t, t = _a === void 0 ? types : _a, attrValue = params.attrValue, options = params.options, generationParams = params.generationParams; | ||
var content = createDynamicValueExpression(attrValue, options, t, generationParams); | ||
jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier(name), t.jsxExpressionContainer(content))); | ||
}; | ||
/** | ||
* Make code expressions happen in AST | ||
* Replace variables that are found in AST with | ||
* the corresponding value from the contexts for now | ||
* and in the future with other sources. | ||
*/ | ||
export var addDynamicExpressionAttributeToJSXTag = function (jsxASTNode, dynamicRef, params, t) { | ||
if (t === void 0) { t = types; } | ||
var dynamicContent = dynamicRef.content; | ||
if (dynamicContent.referenceType !== 'expr') { | ||
throw new Error("This method only works with dynamic nodes that have code expressions"); | ||
} | ||
var code = dynamicContent.expression; | ||
var options = { | ||
sourceType: 'module', | ||
}; | ||
var ast = parse(code, options); | ||
replaceIdentifiersWithScopes(ast, dynamicContent.scope, function (_, name) { | ||
var entityToResolve = dynamicContent.scope[name]; | ||
if (entityToResolve.type === 'dynamic') { | ||
var projectContexts = params.projectContexts; | ||
var contextMeta = projectContexts[entityToResolve.content.ctxId]; | ||
var nameOfContext = StringUtils.camelize(contextMeta.providerName); | ||
return nameOfContext; | ||
} | ||
return name; | ||
}); | ||
if (!('program' in ast)) { | ||
throw new Error("The AST does not have a program node in the expression inside addDynamicExpressionAttributeToJSXTag"); | ||
} | ||
var theStatementOnlyWihtoutTheProgram = ast.program.body[0]; | ||
if (theStatementOnlyWihtoutTheProgram.type !== 'ExpressionStatement') { | ||
throw new Error("Expr dynamic attribute only support expressions statements at the moment."); | ||
} | ||
jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier('href'), t.jsxExpressionContainer(theStatementOnlyWihtoutTheProgram.expression))); | ||
}; | ||
function replaceIdentifiersWithScopes(node, scopes, callback) { | ||
var visitor = { | ||
Identifier: function (path) { | ||
var name = path.node.name; | ||
if (scopes[name]) { | ||
var newName = callback(path, name); | ||
if (newName !== name) { | ||
path.replaceWith(types.identifier(newName)); | ||
} | ||
} | ||
}, | ||
}; | ||
traverse(node, visitor); | ||
} | ||
/* | ||
@@ -313,4 +374,4 @@ Use, when we need to add a mix of dynamic and static values to | ||
t.variableDeclarator(t.arrayPattern([ | ||
t.identifier(stateKey), | ||
t.identifier("set".concat(StringUtils.capitalize(stateKey))), | ||
t.identifier(StringUtils.createStateOrPropStoringValue(stateKey)), | ||
t.identifier(StringUtils.createStateStoringFunction(stateKey)), | ||
]), t.callExpression(t.identifier('useState'), [defaultValueArgument])), | ||
@@ -329,2 +390,190 @@ ]); | ||
}; | ||
export var generateRemoteResourceASTs = function (resource, propsPrefix, extraUrlParamsGenerator) { | ||
if (propsPrefix === void 0) { propsPrefix = ''; } | ||
var fetchUrl = computeFetchUrl(resource); | ||
var authHeaderAST = computeAuthorizationHeaderAST(resource); | ||
var queryParams = generateURLParamsAST(resource.urlParams, propsPrefix, extraUrlParamsGenerator); | ||
var fetchUrlQuasis = fetchUrl.quasis; | ||
var queryParamsQuasis = queryParams.quasis; | ||
if (queryParams.expressions.length > 0) { | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.raw = | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.raw + '?'; | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.cooked = | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.cooked + '?'; | ||
queryParamsQuasis.pop(); | ||
} | ||
var url = queryParams | ||
? types.templateLiteral(__spreadArray(__spreadArray([], fetchUrlQuasis, true), queryParamsQuasis, true), __spreadArray([], fetchUrl.expressions.concat(queryParams.expressions), true)) | ||
: fetchUrl; | ||
var fetchAST = types.variableDeclaration('const', [ | ||
types.variableDeclarator(types.identifier('data'), types.awaitExpression(types.callExpression(types.identifier('fetch'), [ | ||
url, | ||
types.objectExpression([ | ||
types.objectProperty(types.identifier('headers'), types.objectExpression([ | ||
types.objectProperty(types.identifier('"Content-Type"'), types.stringLiteral('application/json'), false, false), | ||
authHeaderAST, | ||
])), | ||
]), | ||
]))), | ||
]); | ||
var responseJSONAST = types.variableDeclaration('const', [ | ||
types.variableDeclarator(types.identifier('response'), types.awaitExpression(types.callExpression(types.memberExpression(types.identifier('data'), types.identifier('json'), false), []))), | ||
]); | ||
return [fetchAST, responseJSONAST]; | ||
}; | ||
export var generateMemberExpressionASTFromBase = function (base, path) { | ||
if (path.length === 1) { | ||
return types.memberExpression(base, types.identifier(path[0]), false); | ||
} | ||
var pathClone = __spreadArray([], path, true); | ||
pathClone.pop(); | ||
return types.memberExpression(generateMemberExpressionASTFromBase(base, pathClone), types.identifier(path[path.length - 1]), false); | ||
}; | ||
export var generateMemberExpressionASTFromPath = function (path) { | ||
var pathClone = __spreadArray([], path, true); | ||
if (path.length === 1) { | ||
return types.identifier(path[0]); | ||
} | ||
pathClone.pop(); | ||
return types.memberExpression(generateMemberExpressionASTFromPath(pathClone), types.identifier(path[path.length - 1]), false); | ||
}; | ||
var generateURLParamsAST = function (urlParams, propsPrefix, extraUrlParamsGenerator) { | ||
var queryString = {}; | ||
Object.keys(urlParams).forEach(function (key) { | ||
resolveDynamicValuesFromUrlParams(urlParams[key], queryString, key, propsPrefix); | ||
}); | ||
var urlObject = types.objectExpression(__spreadArray(__spreadArray([], Object.keys(queryString).map(function (key) { | ||
return types.objectProperty(types.stringLiteral("".concat(key)), queryString[key]); | ||
}), true), (extraUrlParamsGenerator ? extraUrlParamsGenerator() : []), true)); | ||
return types.templateLiteral([ | ||
types.templateElement({ raw: '', cooked: '' }, false), | ||
types.templateElement({ raw: '', cooked: '' }, true), | ||
], [types.newExpression(types.identifier('URLSearchParams'), [urlObject])]); | ||
}; | ||
var resolveDynamicValuesFromUrlParams = function (field, query, prefix, propsPrefix) { | ||
if (prefix === void 0) { prefix = null; } | ||
if (propsPrefix === void 0) { propsPrefix = ''; } | ||
if (Array.isArray(field)) { | ||
var arrayValues = field.map(function (value) { | ||
return resolveUrlParamsValue(value, propsPrefix); | ||
}); | ||
query[prefix] = types.arrayExpression(arrayValues); | ||
return; | ||
} | ||
if (field.type === 'dynamic' || field.type === 'static' || field.type === 'expr') { | ||
query[prefix] = resolveUrlParamsValue(field, propsPrefix); | ||
return; | ||
} | ||
Object.keys(field).forEach(function (key) { | ||
var value = field[key]; | ||
var newPrefix = prefix ? "".concat(prefix, "[").concat(key, "]") : key; | ||
if (typeof value === 'object') { | ||
resolveDynamicValuesFromUrlParams(value, query, newPrefix, propsPrefix); | ||
return; | ||
} | ||
query[newPrefix] = resolveUrlParamsValue(value, propsPrefix); | ||
}); | ||
}; | ||
var resolveUrlParamsValue = function (urlParams, propsPrefix) { | ||
if (propsPrefix === void 0) { propsPrefix = ''; } | ||
if (urlParams.type === 'static') { | ||
return types.stringLiteral("".concat(urlParams.content)); | ||
} | ||
if (urlParams.type === 'expr') { | ||
return types.identifier(urlParams.content); | ||
} | ||
if (urlParams.content.referenceType !== 'prop') { | ||
throw new Error('Only prop references are supported for url params'); | ||
} | ||
var paramPath = __spreadArray(__spreadArray([], (propsPrefix ? [propsPrefix] : []), true), (urlParams.content.path || []), true); | ||
var templateLiteralElements = paramPath | ||
.map(function (_, index) { | ||
if (index === paramPath.length - 1) { | ||
return null; | ||
} | ||
var isTail = index === paramPath.length - 2; | ||
return types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, isTail); | ||
}) | ||
.filter(function (el) { return el; }); | ||
return types.templateLiteral(templateLiteralElements, [ | ||
generateMemberExpressionASTFromPath(paramPath), | ||
]); | ||
}; | ||
var computeAuthorizationHeaderAST = function (resource) { | ||
var _a; | ||
var authToken = resolveResourceValue(resource.authToken); | ||
if (!authToken) { | ||
return null; | ||
} | ||
var authTokenType = (_a = resource.authToken) === null || _a === void 0 ? void 0 : _a.type; | ||
return types.objectProperty(types.identifier('Authorization'), types.templateLiteral(__spreadArray([ | ||
types.templateElement({ | ||
cooked: authTokenType === 'static' ? "Bearer ".concat(authToken) : 'Bearer ', | ||
raw: authTokenType === 'static' ? "Bearer ".concat(authToken) : 'Bearer ', | ||
}, false) | ||
], (authTokenType === 'static' | ||
? [] | ||
: [ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, true), | ||
]), true), __spreadArray([], (authTokenType === 'static' ? [] : [types.identifier(authToken)]), true)), false, false); | ||
}; | ||
var computeFetchUrl = function (resource) { | ||
var _a, _b; | ||
var fetchBaseUrl = resolveResourceValue(resource.baseUrl); | ||
var resourceRoute = resolveResourceValue(resource.route); | ||
var baseUrlType = (_a = resource.baseUrl) === null || _a === void 0 ? void 0 : _a.type; | ||
var routeType = (_b = resource.route) === null || _b === void 0 ? void 0 : _b.type; | ||
if (baseUrlType === 'static' && routeType === 'static') { | ||
var stringsToJoin = [fetchBaseUrl, resourceRoute].filter(function (item) { return item; }).join('/'); | ||
return types.templateLiteral([types.templateElement({ cooked: "".concat(stringsToJoin), raw: "".concat(stringsToJoin) }, true)], []); | ||
} | ||
if (!routeType) { | ||
return baseUrlType === 'static' | ||
? types.templateLiteral([types.templateElement({ cooked: "".concat(fetchBaseUrl), raw: "".concat(fetchBaseUrl) }, true)], []) | ||
: types.templateLiteral([ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, false), | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, true), | ||
], [types.identifier(fetchBaseUrl)]); | ||
} | ||
return types.templateLiteral(__spreadArray([ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, false), | ||
types.templateElement({ | ||
cooked: routeType === 'static' ? "/".concat(resourceRoute) : '/', | ||
raw: routeType === 'static' ? "/".concat(resourceRoute) : '/', | ||
}, false) | ||
], (routeType === 'static' | ||
? [] | ||
: [ | ||
types.templateElement({ | ||
cooked: '', | ||
raw: '', | ||
}, false), | ||
]), true), __spreadArray([ | ||
types.identifier(fetchBaseUrl) | ||
], (routeType === 'static' ? [] : [types.identifier(resourceRoute)]), true)); | ||
}; | ||
var resolveResourceValue = function (value) { | ||
if (!value) { | ||
return ''; | ||
} | ||
if (value.type === 'static') { | ||
return value.value; | ||
} | ||
return "process.env.".concat(value.value) || value.fallback; | ||
}; | ||
//# sourceMappingURL=ast-utils.js.map |
{ | ||
"name": "@teleporthq/teleport-plugin-common", | ||
"version": "0.27.3", | ||
"version": "0.27.4-alpha.0", | ||
"description": "Common building and modelating functions for ASTs and HASTs", | ||
@@ -27,9 +27,9 @@ "author": "teleportHQ", | ||
"dependencies": { | ||
"@babel/types": "^7.14.5", | ||
"@teleporthq/teleport-shared": "^0.27.3", | ||
"@teleporthq/teleport-types": "^0.27.3", | ||
"@babel/types": "^7.5.5", | ||
"@teleporthq/teleport-shared": "^0.27.4-alpha.0", | ||
"@teleporthq/teleport-types": "^0.27.4-alpha.0", | ||
"jss": "^10.0.0", | ||
"jss-preset-default": "^10.0.0" | ||
}, | ||
"gitHead": "14f69b861cb0838d502a5ba226bb7cb5c1291fbb" | ||
"gitHead": "182513645c9074b0739b30e28a0a45d04805e72d" | ||
} |
@@ -52,3 +52,3 @@ import jss from 'jss' | ||
mediaOffset: string, | ||
styleObject: Record<string, string | number> | ||
styleObject: Record<string, string | number | Record<string, string | number>> | ||
) => { | ||
@@ -89,3 +89,6 @@ return jss | ||
export const generateMediaStyle = ( | ||
styleMap: Record<string, Array<{ [x: string]: Record<string, string | number> }>> | ||
styleMap: Record< | ||
string, | ||
Array<{ [x: string]: Record<string, string | number | Record<string, string | number>> }> | ||
> | ||
) => { | ||
@@ -116,3 +119,6 @@ const styles: string[] = [] | ||
cssMap: string[], | ||
mediaStylesMap: Record<string, Array<{ [x: string]: Record<string, string | number> }>>, | ||
mediaStylesMap: Record< | ||
string, | ||
Array<{ [x: string]: Record<string, string | number | Record<string, string | number>> }> | ||
>, | ||
className: (val: string) => string | ||
@@ -123,3 +129,4 @@ ) => { | ||
const { content, conditions = [], type } = style | ||
const name = className(styleId) | ||
const name = className(style.className || styleId) | ||
const subselectors = style.subselectors | ||
@@ -132,6 +139,10 @@ const { staticStyles, tokenStyles } = UIDLUtils.splitDynamicAndStaticStyles(content) | ||
// & is required by jss, otherwise the final result will be empty | ||
const cls = subselectors | ||
? createCSSClassWithSelector(name, `&${subselectors}`, collectedStyles) | ||
: createCSSClass(name, collectedStyles) | ||
if (type === 'reusable-component-style-map') { | ||
cssMap.unshift(createCSSClass(name, collectedStyles)) | ||
cssMap.unshift(cls) | ||
} else { | ||
cssMap.push(createCSSClass(name, collectedStyles)) | ||
cssMap.push(cls) | ||
} | ||
@@ -154,7 +165,15 @@ | ||
cssMap.unshift( | ||
createCSSClassWithSelector(name, `&:${styleRef.meta.state}`, collecedMediaStyles) | ||
createCSSClassWithSelector( | ||
name, | ||
`&${subselectors || ''}:${styleRef.meta.state}`, | ||
collecedMediaStyles | ||
) | ||
) | ||
} else { | ||
cssMap.push( | ||
createCSSClassWithSelector(name, `&:${styleRef.meta.state}`, collecedMediaStyles) | ||
createCSSClassWithSelector( | ||
name, | ||
`&${subselectors || ''}:${styleRef.meta.state}`, | ||
collecedMediaStyles | ||
) | ||
) | ||
@@ -170,6 +189,10 @@ } | ||
const mediaStyleMap = subselectors | ||
? { [`&${subselectors}`]: collecedMediaStyles } | ||
: collecedMediaStyles | ||
if (type === 'reusable-component-style-map') { | ||
mediaStylesMap[String(maxWidth)].unshift({ [name]: collecedMediaStyles }) | ||
mediaStylesMap[String(maxWidth)].unshift({ [name]: mediaStyleMap }) | ||
} else { | ||
mediaStylesMap[String(maxWidth)].push({ [name]: collecedMediaStyles }) | ||
mediaStylesMap[String(maxWidth)].push({ [name]: mediaStyleMap }) | ||
} | ||
@@ -176,0 +199,0 @@ } |
@@ -24,3 +24,2 @@ import * as hastUtils from '../../utils/hast-utils' | ||
const dynamicAttrKey = templateSyntax.valueBinding(attrKey, node) | ||
switch (attrValue.type) { | ||
@@ -27,0 +26,0 @@ case 'dynamic': |
@@ -8,2 +8,3 @@ import { JSXGenerationOptions } from './types' | ||
local: '', | ||
ctx: '', | ||
}, | ||
@@ -10,0 +11,0 @@ dependencyHandling: 'import', |
@@ -10,2 +10,4 @@ import * as types from '@babel/types' | ||
UIDLNode, | ||
UIDLCMSListNode, | ||
UIDLCMSItemNode, | ||
} from '@teleporthq/teleport-types' | ||
@@ -29,2 +31,4 @@ import { UIDLUtils, StringUtils } from '@teleporthq/teleport-shared' | ||
generateDynamicWindowImport, | ||
addDynamicExpressionAttributeToJSXTag, | ||
addDynamicCtxAttributeToJSXTag, | ||
} from '../../utils/ast-utils' | ||
@@ -39,4 +43,4 @@ import { createJSXTag, createSelfClosingJSXTag } from '../../builders/ast-builders' | ||
) => { | ||
const options = { ...DEFAULT_JSX_OPTIONS, ...jsxOptions } | ||
const { dependencies, nodesLookup } = params | ||
const { dependencies, nodesLookup, projectContexts = {}, projectResources = {} } = params | ||
const options = { ...DEFAULT_JSX_OPTIONS, ...jsxOptions, projectContexts, projectResources } | ||
const { elementType, selfClosing, children, key, attrs, dependency, events } = node.content | ||
@@ -92,3 +96,20 @@ | ||
const prefix = | ||
options.dynamicReferencePrefixMap[referenceType as 'prop' | 'state' | 'local'] | ||
options.dynamicReferencePrefixMap[referenceType as 'prop' | 'state' | 'local' | 'ctx'] | ||
if (referenceType === 'expr') { | ||
addDynamicExpressionAttributeToJSXTag(elementTag, attributeValue, params) | ||
break | ||
} | ||
if (referenceType === 'ctx') { | ||
addDynamicCtxAttributeToJSXTag({ | ||
jsxASTNode: elementTag, | ||
name: attrKey, | ||
attrValue: attributeValue, | ||
options: jsxOptions, | ||
generationParams: params, | ||
}) | ||
break | ||
} | ||
addDynamicAttributeToJSXTag(elementTag, attrKey, id, prefix) | ||
@@ -125,11 +146,12 @@ break | ||
children.forEach((child) => { | ||
const childTag = generateNode(child, params, options) | ||
if (typeof childTag === 'string') { | ||
addChildJSXText(elementTag, childTag) | ||
} else if (childTag.type === 'JSXExpressionContainer' || childTag.type === 'JSXElement') { | ||
addChildJSXTag(elementTag, childTag) | ||
} else { | ||
addChildJSXTag(elementTag, types.jsxExpressionContainer(childTag)) | ||
} | ||
const childTags = generateNode(child, params, options) | ||
childTags.forEach((childTag) => { | ||
if (typeof childTag === 'string') { | ||
addChildJSXText(elementTag, childTag) | ||
} else if (childTag.type === 'JSXExpressionContainer' || childTag.type === 'JSXElement') { | ||
addChildJSXTag(elementTag, childTag) | ||
} else { | ||
addChildJSXTag(elementTag, types.jsxExpressionContainer(childTag)) | ||
} | ||
}) | ||
}) | ||
@@ -144,16 +166,24 @@ } | ||
const generateNode: NodeToJSX<UIDLNode, JSXASTReturnType> = (node, params, options) => { | ||
const generateNode: NodeToJSX<UIDLNode, JSXASTReturnType[]> = (node, params, options) => { | ||
switch (node.type) { | ||
case 'raw': | ||
return options.domHTMLInjection | ||
? options.domHTMLInjection(node.content.toString()) | ||
: node.content.toString() | ||
return [ | ||
options.domHTMLInjection | ||
? options.domHTMLInjection(node.content.toString()) | ||
: node.content.toString(), | ||
] | ||
case 'static': | ||
return StringUtils.encode(node.content.toString()) | ||
return [StringUtils.encode(node.content.toString())] | ||
case 'dynamic': | ||
return createDynamicValueExpression(node, options) | ||
return [createDynamicValueExpression(node, options, undefined, params)] | ||
case 'cms-item': | ||
return generateCMSItemNode(node, params, options) | ||
case 'cms-list': | ||
return generateCMSListNode(node, params, options) | ||
case 'element': | ||
return generateElementNode(node, params, options) | ||
return [generateElementNode(node, params, options)] | ||
@@ -168,3 +198,3 @@ case 'repeat': | ||
if (options.slotHandling === 'native') { | ||
return generateNativeSlotNode(node, params, options) | ||
return [generateNativeSlotNode(node, params, options)] | ||
} else { | ||
@@ -185,3 +215,128 @@ return generatePropsSlotNode(node, params, options) | ||
const generateRepeatNode: NodeToJSX<UIDLRepeatNode, types.JSXExpressionContainer> = ( | ||
const generateCMSItemNode: NodeToJSX< | ||
UIDLCMSItemNode, | ||
Array<types.JSXElement | types.LogicalExpression> | ||
> = (node, params, options) => { | ||
const { success, error, loading } = node.content.nodes | ||
/* | ||
* TODO: | ||
* Adding `loading` and `error` states at the moment are being conntrolled by the UIDL. | ||
* But this needs to be changed, the generators itself should make the decision. Depending | ||
* on the style flavour that is being ued. | ||
*/ | ||
const { statePersistanceName } = node.content | ||
const loadingState = StringUtils.createStateOrPropStoringValue(`${statePersistanceName}Loading`) | ||
const errorState = StringUtils.createStateOrPropStoringValue(`${statePersistanceName}Error`) | ||
const errorNodeAST = error | ||
? types.logicalExpression( | ||
'&&', | ||
types.identifier(errorState), | ||
generateElementNode(error, params, options) as types.JSXElement | ||
) | ||
: null | ||
const loadingNodeAST = loading | ||
? types.logicalExpression( | ||
'&&', | ||
types.identifier(loadingState), | ||
generateElementNode(loading, params, options) as types.JSXElement | ||
) | ||
: null | ||
const successElementAST = generateElementNode(success, params, options) | ||
const successAST = | ||
!loading || !error | ||
? successElementAST | ||
: types.logicalExpression( | ||
'&&', | ||
types.logicalExpression( | ||
'&&', | ||
types.unaryExpression('!', types.identifier(loadingState)), | ||
types.unaryExpression('!', types.identifier(errorState)) | ||
), | ||
successElementAST | ||
) | ||
return [...(loading ? [loadingNodeAST] : []), ...(error ? [errorNodeAST] : []), successAST] | ||
} | ||
const generateCMSListNode: NodeToJSX< | ||
UIDLCMSListNode, | ||
Array<types.JSXExpressionContainer | types.LogicalExpression> | ||
> = (node, params, options) => { | ||
const { success, empty, error, loading } = node.content.nodes | ||
const { statePersistanceName } = node.content | ||
const loadingStatePersistanceName = StringUtils.createStateOrPropStoringValue( | ||
`${statePersistanceName}Loading` | ||
) | ||
const errorStatePersistanceName = StringUtils.createStateOrPropStoringValue( | ||
`${statePersistanceName}Error` | ||
) | ||
const listNodeAST = !!success | ||
? (generateNode(success, params, options) as types.JSXElement[])[0] | ||
: null | ||
const source = getRepeatSourceIdentifier(node.content.loopItemsReference, options) | ||
const emptyNodeAST = !!empty | ||
? (generateNode(empty, params, options)[0] as types.JSXElement) | ||
: null | ||
const emptyNodeExpressionAST = empty | ||
? types.logicalExpression( | ||
'&&', | ||
types.unaryExpression('!', types.memberExpression(source, types.identifier('length'))), | ||
emptyNodeAST | ||
) | ||
: null | ||
const errorNodeAST = !!error | ||
? (generateNode(error, params, options)[0] as types.JSXElement) | ||
: null | ||
const errorNodeExpressionAST = | ||
error && errorStatePersistanceName | ||
? types.logicalExpression('&&', types.identifier(errorStatePersistanceName), errorNodeAST) | ||
: null | ||
const loadingNodeAST = !!loading | ||
? (generateNode(loading, params, options)[0] as types.JSXElement) | ||
: null | ||
const loadingNodeExpressionAST = | ||
loading && loadingStatePersistanceName | ||
? types.logicalExpression('&&', types.identifier(loadingStatePersistanceName), loadingNodeAST) | ||
: null | ||
const { iteratorName, iteratorKey } = UIDLUtils.getRepeatIteratorNameAndKey({ | ||
useIndex: true, | ||
iteratorName: 'item', | ||
}) | ||
const localIteratorPrefix = options.dynamicReferencePrefixMap.local | ||
addDynamicAttributeToJSXTag(listNodeAST, 'key', iteratorKey, localIteratorPrefix) | ||
addDynamicAttributeToJSXTag( | ||
listNodeAST, | ||
'value', | ||
['item', ...(node.content.itemValuePath || [])].join('.'), | ||
localIteratorPrefix | ||
) | ||
const arrowFunctionArguments = [types.identifier(iteratorName)] | ||
arrowFunctionArguments.push(types.identifier('index')) | ||
return [ | ||
...(emptyNodeExpressionAST ? [emptyNodeExpressionAST] : []), | ||
...(errorNodeExpressionAST ? [errorNodeExpressionAST] : []), | ||
...(loadingNodeExpressionAST ? [loadingNodeExpressionAST] : []), | ||
types.logicalExpression( | ||
'&&', | ||
types.memberExpression(source, types.identifier('length')), | ||
types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, listNodeAST), | ||
]) | ||
), | ||
] | ||
} | ||
const generateRepeatNode: NodeToJSX<UIDLRepeatNode, types.JSXExpressionContainer[]> = ( | ||
node, | ||
@@ -192,9 +347,10 @@ params, | ||
const { node: repeatContent, dataSource, meta } = node.content | ||
const contentASTs = generateNode(repeatContent, params, options) as types.JSXElement[] | ||
const contentAST = generateElementNode(repeatContent, params, options) | ||
const { iteratorName, iteratorKey } = UIDLUtils.getRepeatIteratorNameAndKey(meta) | ||
const localIteratorPrefix = options.dynamicReferencePrefixMap.local | ||
addDynamicAttributeToJSXTag(contentAST, 'key', iteratorKey, localIteratorPrefix) | ||
contentASTs.forEach((contentAST) => { | ||
addDynamicAttributeToJSXTag(contentAST, 'key', iteratorKey, localIteratorPrefix) | ||
}) | ||
@@ -208,10 +364,12 @@ const source = getRepeatSourceIdentifier(dataSource, options) | ||
return types.jsxExpressionContainer( | ||
types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, contentAST), | ||
]) | ||
return contentASTs.map((contentAST) => | ||
types.jsxExpressionContainer( | ||
types.callExpression(types.memberExpression(source, types.identifier('map')), [ | ||
types.arrowFunctionExpression(arrowFunctionArguments, contentAST), | ||
]) | ||
) | ||
) | ||
} | ||
const generateConditionalNode: NodeToJSX<UIDLConditionalNode, types.LogicalExpression> = ( | ||
const generateConditionalNode: NodeToJSX<UIDLConditionalNode, types.LogicalExpression[]> = ( | ||
node, | ||
@@ -224,3 +382,3 @@ params, | ||
const subTree = generateNode(node.content.node, params, options) | ||
const subTrees = generateNode(node.content.node, params, options) | ||
@@ -232,6 +390,8 @@ const condition: UIDLConditionalExpression = | ||
return createConditionalJSXExpression(subTree, condition, conditionIdentifier) | ||
return subTrees.map((subTree) => | ||
createConditionalJSXExpression(subTree, condition, conditionIdentifier) | ||
) | ||
} | ||
const generatePropsSlotNode: NodeToJSX<UIDLSlotNode, types.JSXExpressionContainer> = ( | ||
const generatePropsSlotNode: NodeToJSX<UIDLSlotNode, types.JSXExpressionContainer[]> = ( | ||
node: UIDLSlotNode, | ||
@@ -254,16 +414,19 @@ params, | ||
if (node.content.fallback) { | ||
const fallbackContent = generateNode(node.content.fallback, params, options) | ||
const fallbackContents = generateNode(node.content.fallback, params, options) | ||
// only static dynamic or element are allowed here | ||
const fallbackNode = | ||
typeof fallbackContent === 'string' | ||
? types.stringLiteral(fallbackContent) | ||
: (fallbackContent as types.JSXElement | types.MemberExpression) | ||
// props.children with fallback | ||
return types.jsxExpressionContainer( | ||
types.logicalExpression('||', childrenExpression, fallbackNode) | ||
) | ||
return fallbackContents.map((fallbackContent) => { | ||
const fallbackNode = | ||
typeof fallbackContent === 'string' | ||
? types.stringLiteral(fallbackContent) | ||
: (fallbackContent as types.JSXElement | types.MemberExpression) | ||
// props.children with fallback | ||
return types.jsxExpressionContainer( | ||
types.logicalExpression('||', childrenExpression, fallbackNode) | ||
) | ||
}) | ||
} | ||
return types.jsxExpressionContainer(childrenExpression) | ||
return [types.jsxExpressionContainer(childrenExpression)] | ||
} | ||
@@ -283,10 +446,13 @@ | ||
if (node.content.fallback) { | ||
const fallbackContent = generateNode(node.content.fallback, params, options) | ||
if (typeof fallbackContent === 'string') { | ||
addChildJSXText(slotNode, fallbackContent) | ||
} else if (fallbackContent.type === 'MemberExpression') { | ||
addChildJSXTag(slotNode, types.jsxExpressionContainer(fallbackContent)) | ||
} else { | ||
addChildJSXTag(slotNode, fallbackContent as types.JSXElement) | ||
} | ||
const fallbackContents = generateNode(node.content.fallback, params, options) | ||
fallbackContents.forEach((fallbackContent) => { | ||
if (typeof fallbackContent === 'string') { | ||
addChildJSXText(slotNode, fallbackContent) | ||
} else if (fallbackContent.type === 'MemberExpression') { | ||
addChildJSXTag(slotNode, types.jsxExpressionContainer(fallbackContent)) | ||
} else { | ||
addChildJSXTag(slotNode, fallbackContent as types.JSXElement) | ||
} | ||
}) | ||
} | ||
@@ -293,0 +459,0 @@ |
import * as types from '@babel/types' | ||
import { UIDLPropDefinition, UIDLDependency, UIDLStateDefinition } from '@teleporthq/teleport-types' | ||
import { | ||
UIDLPropDefinition, | ||
UIDLDependency, | ||
UIDLStateDefinition, | ||
ProjectContext, | ||
ProjectResource, | ||
} from '@teleporthq/teleport-types' | ||
@@ -11,2 +17,4 @@ export interface JSXGenerationParams { | ||
windowImports: Record<string, types.ExpressionStatement> | ||
projectContexts?: Record<string, ProjectContext> | ||
projectResources?: Record<string, ProjectResource> | ||
} | ||
@@ -27,2 +35,3 @@ | ||
local: string | ||
ctx: string | ||
} | ||
@@ -29,0 +38,0 @@ |
@@ -127,3 +127,5 @@ import * as types from '@babel/types' | ||
return t.expressionStatement( | ||
t.callExpression(t.identifier(`set${StringUtils.capitalize(stateKey)}`), [newStateValue]) | ||
t.callExpression(t.identifier(StringUtils.createStateStoringFunction(stateKey)), [ | ||
newStateValue, | ||
]) | ||
) | ||
@@ -147,9 +149,42 @@ case 'function': | ||
options: JSXGenerationOptions, | ||
t = types | ||
t = types, | ||
params?: JSXGenerationParams | ||
) => { | ||
const refType = identifier.content.referenceType as 'prop' | 'state' | 'local' | ||
const prefix = options.dynamicReferencePrefixMap[refType] || '' | ||
const { projectContexts = {} } = params || {} | ||
const identifierContent = identifier.content | ||
if ( | ||
identifierContent.referenceType === 'expr' || | ||
identifierContent.referenceType === 'attr' || | ||
identifierContent.referenceType === 'children' || | ||
identifierContent.referenceType === 'token' | ||
) { | ||
throw new Error( | ||
`Dynamic reference type "${identifierContent.referenceType}" is not supported yet` | ||
) | ||
} | ||
if (identifierContent.referenceType === 'ctx') { | ||
// TODO handle situation when context is not using path | ||
// TODO only allow ctxID not id for context references | ||
const contextMeta = projectContexts[identifierContent.ctxId ?? identifierContent.id] | ||
if (!contextMeta) { | ||
throw new Error( | ||
`Could not find the referenced context: ${ | ||
identifierContent.ctxId ?? identifierContent.id | ||
} on node ${JSON.stringify(identifierContent)}` | ||
) | ||
} | ||
return t.memberExpression( | ||
t.identifier(StringUtils.camelize(contextMeta.providerName)), | ||
t.identifier(identifierContent.path.join('?.')) | ||
) | ||
} | ||
const prefix = options.dynamicReferencePrefixMap[identifierContent.referenceType] || '' | ||
return prefix === '' | ||
? t.identifier(identifier.content.id) | ||
: t.memberExpression(t.identifier(prefix), t.identifier(identifier.content.id)) | ||
? t.identifier(identifierContent.id) | ||
: t.memberExpression(t.identifier(prefix), t.identifier(identifierContent.id)) | ||
} | ||
@@ -156,0 +191,0 @@ |
declare module 'jss-preset-default' | ||
declare module 'qs' |
import * as types from '@babel/types' | ||
import { parse, traverse } from '@babel/core' | ||
import ParsedASTNode from './parsed-ast' | ||
import { StringUtils } from '@teleporthq/teleport-shared' | ||
import { UIDLStateDefinition, UIDLPropDefinition, UIDLRawValue } from '@teleporthq/teleport-types' | ||
import { | ||
UIDLStateDefinition, | ||
UIDLPropDefinition, | ||
UIDLRawValue, | ||
Resource, | ||
ResourceValue, | ||
ResourceUrlParams, | ||
UIDLStaticValue, | ||
UIDLDynamicReference, | ||
ResourceUrlValues, | ||
UIDLExpressionValue, | ||
} from '@teleporthq/teleport-types' | ||
import { JSXGenerationOptions, JSXGenerationParams } from '../node-handlers/node-to-jsx/types' | ||
import { createDynamicValueExpression } from '../node-handlers/node-to-jsx/utils' | ||
/** | ||
@@ -83,2 +97,3 @@ * Adds a class definition string to an existing string of classes | ||
* Makes `${name}={${prefix}.${value}}` happen in AST | ||
* doesn't handle ctx or expr referenceType | ||
*/ | ||
@@ -102,2 +117,99 @@ export const addDynamicAttributeToJSXTag = ( | ||
/** | ||
* Makes `${name}={${ContextName}.${path}}` happen in AST | ||
*/ | ||
export const addDynamicCtxAttributeToJSXTag = (params: { | ||
jsxASTNode: types.JSXElement | ||
name: string | ||
attrValue: UIDLDynamicReference | ||
options: JSXGenerationOptions | ||
generationParams: JSXGenerationParams | ||
t?: typeof types | ||
}) => { | ||
const { jsxASTNode, name, t = types, attrValue, options, generationParams } = params | ||
const content = createDynamicValueExpression(attrValue, options, t, generationParams) | ||
jsxASTNode.openingElement.attributes.push( | ||
t.jsxAttribute(t.jsxIdentifier(name), t.jsxExpressionContainer(content)) | ||
) | ||
} | ||
/** | ||
* Make code expressions happen in AST | ||
* Replace variables that are found in AST with | ||
* the corresponding value from the contexts for now | ||
* and in the future with other sources. | ||
*/ | ||
export const addDynamicExpressionAttributeToJSXTag = ( | ||
jsxASTNode: types.JSXElement, | ||
dynamicRef: UIDLDynamicReference, | ||
params: JSXGenerationParams, | ||
t = types | ||
) => { | ||
const dynamicContent = dynamicRef.content | ||
if (dynamicContent.referenceType !== 'expr') { | ||
throw new Error(`This method only works with dynamic nodes that have code expressions`) | ||
} | ||
const code = dynamicContent.expression | ||
const options = { | ||
sourceType: 'module' as const, | ||
} | ||
const ast = parse(code, options) | ||
replaceIdentifiersWithScopes(ast, dynamicContent.scope, (_, name) => { | ||
const entityToResolve = dynamicContent.scope[name] | ||
if (entityToResolve.type === 'dynamic') { | ||
const { projectContexts } = params | ||
const contextMeta = projectContexts[entityToResolve.content.ctxId] | ||
const nameOfContext = StringUtils.camelize(contextMeta.providerName) | ||
return nameOfContext | ||
} | ||
return name | ||
}) | ||
if (!('program' in ast)) { | ||
throw new Error( | ||
`The AST does not have a program node in the expression inside addDynamicExpressionAttributeToJSXTag` | ||
) | ||
} | ||
const theStatementOnlyWihtoutTheProgram = ast.program.body[0] | ||
if (theStatementOnlyWihtoutTheProgram.type !== 'ExpressionStatement') { | ||
throw new Error(`Expr dynamic attribute only support expressions statements at the moment.`) | ||
} | ||
jsxASTNode.openingElement.attributes.push( | ||
t.jsxAttribute( | ||
t.jsxIdentifier('href'), | ||
t.jsxExpressionContainer(theStatementOnlyWihtoutTheProgram.expression) | ||
) | ||
) | ||
} | ||
type ReplacementCallback = (path: babel.NodePath<types.Identifier>, name: string) => string | ||
type ExpressionScopes = Record<string, UIDLStaticValue | UIDLDynamicReference> | ||
function replaceIdentifiersWithScopes( | ||
node: babel.Node, | ||
scopes: ExpressionScopes, | ||
callback: ReplacementCallback | ||
) { | ||
const visitor = { | ||
Identifier(path: babel.NodePath<types.Identifier>) { | ||
const { name } = path.node | ||
if (scopes[name]) { | ||
const newName = callback(path, name) | ||
if (newName !== name) { | ||
path.replaceWith(types.identifier(newName)) | ||
} | ||
} | ||
}, | ||
} | ||
traverse(node, visitor) | ||
} | ||
/* | ||
@@ -461,4 +573,4 @@ Use, when we need to add a mix of dynamic and static values to | ||
t.arrayPattern([ | ||
t.identifier(stateKey), | ||
t.identifier(`set${StringUtils.capitalize(stateKey)}`), | ||
t.identifier(StringUtils.createStateOrPropStoringValue(stateKey)), | ||
t.identifier(StringUtils.createStateStoringFunction(stateKey)), | ||
]), | ||
@@ -487,1 +599,334 @@ t.callExpression(t.identifier('useState'), [defaultValueArgument]) | ||
types.objectExpression(properties) | ||
export const generateRemoteResourceASTs = ( | ||
resource: Resource, | ||
propsPrefix: string = '', | ||
extraUrlParamsGenerator?: () => types.ObjectProperty[] | ||
) => { | ||
const fetchUrl = computeFetchUrl(resource) | ||
const authHeaderAST = computeAuthorizationHeaderAST(resource) | ||
const queryParams = generateURLParamsAST( | ||
resource.urlParams as ResourceUrlParams, | ||
propsPrefix, | ||
extraUrlParamsGenerator | ||
) | ||
const fetchUrlQuasis = fetchUrl.quasis | ||
const queryParamsQuasis = queryParams.quasis | ||
if (queryParams.expressions.length > 0) { | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.raw = | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.raw + '?' | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.cooked = | ||
fetchUrlQuasis[fetchUrlQuasis.length - 1].value.cooked + '?' | ||
queryParamsQuasis.pop() | ||
} | ||
const url = queryParams | ||
? types.templateLiteral( | ||
[...fetchUrlQuasis, ...queryParamsQuasis], | ||
[...fetchUrl.expressions.concat(queryParams.expressions)] | ||
) | ||
: fetchUrl | ||
const fetchAST = types.variableDeclaration('const', [ | ||
types.variableDeclarator( | ||
types.identifier('data'), | ||
types.awaitExpression( | ||
types.callExpression(types.identifier('fetch'), [ | ||
url, | ||
types.objectExpression([ | ||
types.objectProperty( | ||
types.identifier('headers'), | ||
types.objectExpression([ | ||
types.objectProperty( | ||
types.identifier('"Content-Type"'), | ||
types.stringLiteral('application/json'), | ||
false, | ||
false | ||
), | ||
authHeaderAST, | ||
]) | ||
), | ||
]), | ||
]) | ||
) | ||
), | ||
]) | ||
const responseJSONAST = types.variableDeclaration('const', [ | ||
types.variableDeclarator( | ||
types.identifier('response'), | ||
types.awaitExpression( | ||
types.callExpression( | ||
types.memberExpression(types.identifier('data'), types.identifier('json'), false), | ||
[] | ||
) | ||
) | ||
), | ||
]) | ||
return [fetchAST, responseJSONAST] | ||
} | ||
export const generateMemberExpressionASTFromBase = ( | ||
base: types.MemberExpression | types.Identifier, | ||
path: string[] | ||
): types.MemberExpression => { | ||
if (path.length === 1) { | ||
return types.memberExpression(base, types.identifier(path[0]), false) | ||
} | ||
const pathClone = [...path] | ||
pathClone.pop() | ||
return types.memberExpression( | ||
generateMemberExpressionASTFromBase(base, pathClone), | ||
types.identifier(path[path.length - 1]), | ||
false | ||
) | ||
} | ||
export const generateMemberExpressionASTFromPath = ( | ||
path: string[] | ||
): types.MemberExpression | types.Identifier => { | ||
const pathClone = [...path] | ||
if (path.length === 1) { | ||
return types.identifier(path[0]) | ||
} | ||
pathClone.pop() | ||
return types.memberExpression( | ||
generateMemberExpressionASTFromPath(pathClone), | ||
types.identifier(path[path.length - 1]), | ||
false | ||
) | ||
} | ||
const generateURLParamsAST = ( | ||
urlParams: ResourceUrlParams, | ||
propsPrefix?: string, | ||
extraUrlParamsGenerator?: () => types.ObjectProperty[] | ||
) => { | ||
const queryString: Record<string, types.Expression> = {} | ||
Object.keys(urlParams).forEach((key) => { | ||
resolveDynamicValuesFromUrlParams(urlParams[key], queryString, key, propsPrefix) | ||
}) | ||
const urlObject = types.objectExpression([ | ||
...Object.keys(queryString).map((key) => { | ||
return types.objectProperty(types.stringLiteral(`${key}`), queryString[key]) | ||
}), | ||
...(extraUrlParamsGenerator ? extraUrlParamsGenerator() : []), | ||
]) | ||
return types.templateLiteral( | ||
[ | ||
types.templateElement({ raw: '', cooked: '' }, false), | ||
types.templateElement({ raw: '', cooked: '' }, true), | ||
], | ||
[types.newExpression(types.identifier('URLSearchParams'), [urlObject])] | ||
) | ||
} | ||
const resolveDynamicValuesFromUrlParams = ( | ||
field: ResourceUrlValues, | ||
query: Record<string, types.Expression>, | ||
prefix: string = null, | ||
propsPrefix: string = '' | ||
) => { | ||
if (Array.isArray(field)) { | ||
const arrayValues = field.map((value) => { | ||
return resolveUrlParamsValue(value, propsPrefix) | ||
}) | ||
query[prefix] = types.arrayExpression(arrayValues) | ||
return | ||
} | ||
if (field.type === 'dynamic' || field.type === 'static' || field.type === 'expr') { | ||
query[prefix] = resolveUrlParamsValue(field, propsPrefix) | ||
return | ||
} | ||
Object.keys(field).forEach((key) => { | ||
const value = field[key] | ||
const newPrefix = prefix ? `${prefix}[${key}]` : key | ||
if (typeof value === 'object') { | ||
resolveDynamicValuesFromUrlParams(value, query, newPrefix, propsPrefix) | ||
return | ||
} | ||
query[newPrefix] = resolveUrlParamsValue(value, propsPrefix) | ||
}) | ||
} | ||
const resolveUrlParamsValue = ( | ||
urlParams: UIDLStaticValue | UIDLDynamicReference | UIDLExpressionValue, | ||
propsPrefix: string = '' | ||
) => { | ||
if (urlParams.type === 'static') { | ||
return types.stringLiteral(`${urlParams.content}`) | ||
} | ||
if (urlParams.type === 'expr') { | ||
return types.identifier(urlParams.content) | ||
} | ||
if (urlParams.content.referenceType !== 'prop') { | ||
throw new Error('Only prop references are supported for url params') | ||
} | ||
const paramPath = [...(propsPrefix ? [propsPrefix] : []), ...(urlParams.content.path || [])] | ||
const templateLiteralElements = paramPath | ||
.map((_, index) => { | ||
if (index === paramPath.length - 1) { | ||
return null | ||
} | ||
const isTail = index === paramPath.length - 2 | ||
return types.templateElement( | ||
{ | ||
cooked: '', | ||
raw: '', | ||
}, | ||
isTail | ||
) | ||
}) | ||
.filter((el) => el) | ||
return types.templateLiteral(templateLiteralElements, [ | ||
generateMemberExpressionASTFromPath(paramPath), | ||
]) | ||
} | ||
const computeAuthorizationHeaderAST = (resource: Resource) => { | ||
const authToken = resolveResourceValue(resource.authToken) | ||
if (!authToken) { | ||
return null | ||
} | ||
const authTokenType = resource.authToken?.type | ||
return types.objectProperty( | ||
types.identifier('Authorization'), | ||
types.templateLiteral( | ||
[ | ||
types.templateElement( | ||
{ | ||
cooked: authTokenType === 'static' ? `Bearer ${authToken}` : 'Bearer ', | ||
raw: authTokenType === 'static' ? `Bearer ${authToken}` : 'Bearer ', | ||
}, | ||
false | ||
), | ||
...(authTokenType === 'static' | ||
? [] | ||
: [ | ||
types.templateElement( | ||
{ | ||
cooked: '', | ||
raw: '', | ||
}, | ||
true | ||
), | ||
]), | ||
], | ||
[...(authTokenType === 'static' ? [] : [types.identifier(authToken)])] | ||
), | ||
false, | ||
false | ||
) | ||
} | ||
const computeFetchUrl = (resource: Resource) => { | ||
const fetchBaseUrl = resolveResourceValue(resource.baseUrl) | ||
const resourceRoute = resolveResourceValue(resource.route) | ||
const baseUrlType = resource.baseUrl?.type | ||
const routeType = resource.route?.type | ||
if (baseUrlType === 'static' && routeType === 'static') { | ||
const stringsToJoin = [fetchBaseUrl, resourceRoute].filter((item) => item).join('/') | ||
return types.templateLiteral( | ||
[types.templateElement({ cooked: `${stringsToJoin}`, raw: `${stringsToJoin}` }, true)], | ||
[] | ||
) | ||
} | ||
if (!routeType) { | ||
return baseUrlType === 'static' | ||
? types.templateLiteral( | ||
[types.templateElement({ cooked: `${fetchBaseUrl}`, raw: `${fetchBaseUrl}` }, true)], | ||
[] | ||
) | ||
: types.templateLiteral( | ||
[ | ||
types.templateElement( | ||
{ | ||
cooked: '', | ||
raw: '', | ||
}, | ||
false | ||
), | ||
types.templateElement( | ||
{ | ||
cooked: '', | ||
raw: '', | ||
}, | ||
true | ||
), | ||
], | ||
[types.identifier(fetchBaseUrl)] | ||
) | ||
} | ||
return types.templateLiteral( | ||
[ | ||
types.templateElement( | ||
{ | ||
cooked: '', | ||
raw: '', | ||
}, | ||
false | ||
), | ||
types.templateElement( | ||
{ | ||
cooked: routeType === 'static' ? `/${resourceRoute}` : '/', | ||
raw: routeType === 'static' ? `/${resourceRoute}` : '/', | ||
}, | ||
false | ||
), | ||
...(routeType === 'static' | ||
? [] | ||
: [ | ||
types.templateElement( | ||
{ | ||
cooked: '', | ||
raw: '', | ||
}, | ||
false | ||
), | ||
]), | ||
], | ||
[ | ||
types.identifier(fetchBaseUrl), | ||
...(routeType === 'static' ? [] : [types.identifier(resourceRoute)]), | ||
] | ||
) | ||
} | ||
const resolveResourceValue = (value: ResourceValue) => { | ||
if (!value) { | ||
return '' | ||
} | ||
if (value.type === 'static') { | ||
return value.value | ||
} | ||
return `process.env.${value.value}` || value.fallback | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
568762
21.26%7697
22.88%