Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
export const resolveNavlinks = (uidlNode: UIDLNode, routesDefinition: UIDLStateDefinition) => {
UIDLUtils.traverseElements(uidlNode, (element) => {
if (element.elementType === 'navlink') {
const transitionAttribute = element.attrs.transitionTo
if (!transitionAttribute) {
// Fallback for when transitionTo is not present
console.warn(
`transitionTo was missing from element: '${element.elementType}'. Falling back to navlink: '/'`
)
element.attrs.transitionTo = {
type: 'static',
content: '/',
}
return
}
if (transitionAttribute.type !== 'static') {
export const extractPageOptions = (
routeDefinitions: UIDLStateDefinition,
routeName: string,
useFileNameForNavigation = false
): UIDLPageOptions => {
const isHomePage = routeDefinitions.defaultValue === routeName
const pageDefinitions = routeDefinitions.values || []
const pageDefinition = pageDefinitions.find((stateDef) => stateDef.value === routeName)
// If no meta object is defined, the stateName is used
const defaultPageName = 'AppPage'
const friendlyStateName = StringUtils.removeIllegalCharacters(routeName) || defaultPageName // remove space, leading numbers, etc.
const friendlyComponentName = StringUtils.dashCaseToUpperCamelCase(friendlyStateName) // component name in UpperCamelCase
const friendlyFileName = StringUtils.camelCaseToDashCase(friendlyStateName) // file name in dash-case
let pageOptions: UIDLPageOptions = {
// default values extracted from state name
fileName: friendlyFileName,
componentName: friendlyComponentName,
navLink: '/' + (isHomePage ? '' : friendlyFileName),
}
if (pageDefinition && pageDefinition.pageOptions) {
// The pageDefinition values have precedence, defaults are fallbacks
pageOptions = {
...pageOptions,
...pageDefinition.pageOptions,
}
}
UIDLUtils.traverseElements(node, (element) => {
const { style, key } = element
if (!style) {
return
}
const { staticStyles, dynamicStyles } = UIDLUtils.splitDynamicAndStaticStyles(style)
const root = templateLookup[key]
if (Object.keys(staticStyles).length > 0) {
const elementClassName = StringUtils.camelCaseToDashCase(key)
const componentFileName = UIDLUtils.getComponentFileName(uidl) // Filename used to enforce dash case naming
const className = forceScoping // when the framework doesn't provide automating scoping for classNames
? `${componentFileName}-${elementClassName}`
: elementClassName
jssStylesArray.push(
StyleBuilders.createCSSClass(className, StyleUtils.getContentOfStyleObject(staticStyles))
)
if (templateStyle === 'html') {
HASTUtils.addClassToNode(root, className)
} else {
ASTUtils.addClassStringOnJSXTag(root, className, classAttributeName)
}
}
Object.keys(components).forEach((componentKey) => {
const component = components[componentKey]
// values coming from the input UIDL
const { fileName, componentClassName } = component.outputOptions || {
fileName: '',
componentClassName: '',
}
const defaultComponentName = 'AppComponent'
const friendlyName = StringUtils.removeIllegalCharacters(component.name) || defaultComponentName
const friendlyFileName = fileName || StringUtils.camelCaseToDashCase(friendlyName) // ex: primary-button
const friendlyComponentName =
componentClassName || StringUtils.dashCaseToUpperCamelCase(friendlyName) // ex: PrimaryButton
const folderPath = UIDLUtils.getComponentFolderPath(component)
const {
customComponentFileName,
customStyleFileName,
customTemplateFileName,
} = componentStrategyOptions
// If the component has its own folder, name is 'index' or an override from the strategy.
// In this case, the file name (dash converted) is used as the folder name
if (componentStrategyOptions.createFolderForEachComponent) {
component.outputOptions = {
componentClassName: friendlyComponentName,
fileName: (customComponentFileName && customComponentFileName(friendlyFileName)) || 'index',
UIDLUtils.traverseElements(node, (element) => {
const { style, key } = element
if (style && Object.keys(style).length > 0) {
const root = jsxNodesLookup[key]
const className = StringUtils.camelCaseToDashCase(key)
// Generating the string templates for the dynamic styles
const styleRules = UIDLUtils.transformDynamicStyles(style, (styleValue) => {
if (styleValue.content.referenceType === 'prop') {
return `\$\{${propsPrefix}.${styleValue.content.id}\}`
}
throw new Error(
`Error running transformDynamicStyles in reactStyledJSXChunkPlugin. Unsupported styleValue.content.referenceType value ${styleValue.content.referenceType}`
)
})
styleJSXString.push(StyleBuilders.createCSSClass(className, styleRules))
ASTUtils.addClassStringOnJSXTag(root, className)
}
})
const resolveDependency = (
mappedElement: UIDLElement,
uidlDependency?: UIDLDependency,
localDependenciesPrefix = './'
) => {
// If dependency is specified at UIDL level it will have priority over the mapping one
const nodeDependency = uidlDependency || mappedElement.dependency
if (nodeDependency && nodeDependency.type === 'local') {
// When a dependency is specified without a path, we infer it is a local import.
// ex: PrimaryButton component should be written in a file called primary-button
// This is just a fallback for when the dependency path is not set by a project generator
const componentName = mappedElement.elementType
const componentFileName = StringUtils.camelCaseToDashCase(componentName)
// concatenate a trailing slash in case it's missing
if (localDependenciesPrefix[localDependenciesPrefix.length - 1] !== '/') {
localDependenciesPrefix = localDependenciesPrefix + '/'
}
nodeDependency.path = nodeDependency.path || localDependenciesPrefix + componentFileName
}
return nodeDependency
}
UIDLUtils.traverseElements(uidl.node, (element) => {
const { style, key } = element
if (style) {
const root = astNodesLookup[key]
const { staticStyles, dynamicStyles } = UIDLUtils.splitDynamicAndStaticStyles(style)
if (Object.keys(staticStyles).length > 0) {
const className = StringUtils.camelCaseToDashCase(key)
const jsFriendlyClassName = StringUtils.dashCaseToCamelCase(className)
cssClasses.push(
StyleBuilders.createCSSClass(
className,
StyleUtils.getContentOfStyleObject(staticStyles)
)
)
// When the className is equal to the jsFriendlyClassName, it can be safely addressed with `styles.`
const classNameIsJSFriendly = className === jsFriendlyClassName
const classReferenceIdentifier =
camelCaseClassNames || classNameIsJSFriendly
? `styles.${jsFriendlyClassName}`
: `styles['${className}']`
hastUtils.addAttributeToNode(htmlNode, dynamicAttrKey, attrValue.content.id)
break
case 'static':
if (Array.isArray(attrValue.content)) {
// This handles the cases when arrays are sent as props or passed as attributes
// The array will be placed on the dataObject and the data reference is placed on the node
const dataObjectIdentifier = `${elementName}${StringUtils.capitalize(attrKey)}`
dataObject[dataObjectIdentifier] = attrValue.content
hastUtils.addAttributeToNode(htmlNode, dynamicAttrKey, dataObjectIdentifier)
} else if (typeof attrValue.content === 'boolean') {
hastUtils.addBooleanAttributeToNode(htmlNode, attrKey)
} else if (typeof attrValue.content === 'string') {
hastUtils.addAttributeToNode(
htmlNode,
attrKey,
StringUtils.encode(attrValue.content.toString())
)
} else {
// For numbers and values that are passed to components and maintain their type
hastUtils.addAttributeToNode(htmlNode, dynamicAttrKey, attrValue.content.toString())
}
break
default:
throw new Error(
`generateElementNode could not generate code for attribute of type ${JSON.stringify(
attrValue
)}`
)
}
}
export const generateExportAST = (
uidl: ComponentUIDL,
propDefinitions: Record,
stateDefinitions: Record,
dataObject: Record,
methodsObject: Record,
t = types
) => {
const componentName = UIDLUtils.getComponentClassName(uidl)
let angularMethodsAST: types.ClassMethod[] = []
if (Object.keys(methodsObject).length > 0) {
angularMethodsAST = createMethodsObject(methodsObject, propDefinitions)
}
const propDeclaration = Object.keys(propDefinitions).map((propKey) => {
const definition = propDefinitions[propKey]
// By default any prop with type function is used to emitting events to the callee
if (definition.type === 'func') {
return t.classProperty(
t.identifier(propKey),
t.newExpression(t.identifier('EventEmitter'), []),
t.typeAnnotation(
t.genericTypeAnnotation(
t.identifier('EventEmitter'),
t.typeParameterInstantiation([t.anyTypeAnnotation()])
{
dependencies.BrowserModule = ANGULAR_PLATFORM_BROWSER
dependencies.ComponentsModule = constructRouteForComponentsModule('.')
dependencies.AppComponent = APP_COMPONENT
const routes = UIDLUtils.extractRoutes(uidl)
routesAST = createRoutesAST(routes, stateDefinitions)
ngModuleAST = createRootModuleDecorator()
moduleDecoratorAST = createExportModuleAST('AppModule')
}
break
case 'page':
{
dependencies.ComponentsModule = constructRouteForComponentsModule('../..')
dependencies.CommonModule = ANGULAR_COMMON_MODULE
const componentName = UIDLUtils.getComponentClassName(uidl)
const fileName = UIDLUtils.getComponentFileName(uidl)
dependencies[componentName] = constructLocalDependency(fileName)
routesAST = createPageRouteAST(componentName)
ngModuleAST = createPageModuleModuleDecorator(componentName)
moduleDecoratorAST = createExportModuleAST(uidl.outputOptions.moduleName)
// Acording to widely followed convention module should have .module in its name
uidl.outputOptions.fileName = fileName.replace('.component', '.module')
}
break
case 'component':
{
dependencies.CommonModule = ANGULAR_COMMON_MODULE
// Looping through all components and importing them into component module