@uiengine/core
Version:
Create, document and evolve your design system collaboratively.
101 lines (79 loc) • 3.42 kB
JavaScript
const { basename, join } = require('path')
const R = require('ramda')
const Connector = require('./connector')
const { FileUtil: { glob }, UiengineInputError } = require('@uiengine/util')
const {
DebugUtil: { debug2, debug3 },
MessageUtil: { markSample },
VariantUtil: { componentIdToVariantsPath, variantIdToFilePath, variantIdToTitle },
FileUtil: { extension: fileExtension, read: readFile, relativeToCwd },
StringUtil: { crossPlatformPath }
} = require('@uiengine/util')
const mapIndexed = R.addIndex(R.map)
// convert list of filenames to list of objects
const convertUserProvidedVariants = list =>
R.map(item => typeof item === 'string' ? { file: item } : item, list)
async function findVariants (state, componentId) {
const { config: { adapters, source: { components } } } = state
if (!components) return []
// register only files with adapter extensions
const variantsPath = componentIdToVariantsPath(components, componentId)
const exts = Object.keys(adapters).join(',')
const pattern = crossPlatformPath(join(variantsPath, `*.{${exts}}`))
const variantPaths = await glob(pattern)
const variants = R.map(variantPath => ({ file: basename(variantPath) }), variantPaths)
return variants
}
async function fetchObjects (state, componentId, context, variants) {
debug2(state, `Variant.fetchObjects(${componentId}):start`)
// variants might be populated from the component attributes.
if (variants) {
// ensure a list of objects, convert list of filenames
variants = convertUserProvidedVariants(variants)
} else {
// look up variants from folder if they are not specified.
variants = await findVariants(state, componentId)
}
const fetch = R.partial(fetchObject, [state, componentId, context])
const fetches = mapIndexed(fetch, variants)
const list = await Promise.all(fetches)
debug2(state, `Variant.fetchObjects(${componentId}):end`)
return list
}
async function fetchObject (state, componentId, componentContext, data, index) {
const { file } = data
const id = `${componentId}/${file}-${index + 1}`
debug3(state, `Variant.fetchObject(${id}):start`)
const { source: { components } } = state.config
const themeIds = R.pluck('id', state.config.themes)
const filePath = variantIdToFilePath(components, id)
const extension = fileExtension(filePath)
const context = data.context || componentContext
const title = data.title || variantIdToTitle(id)
// render raw variant, without layout
let raw, rendered
const readTemplate = readFile(filePath)
const renderThemes = themeIds.map(themeId => Connector.render(state, filePath, context, themeId, id))
try {
[raw, ...rendered] = await Promise.all([readTemplate, ...renderThemes])
} catch (err) {
const relativeFilePath = relativeToCwd(filePath)
const message = [
`Variant "${title}" could not be rendered!`,
`Component: ${componentId}\nFile: ${relativeFilePath}`,
err
]
if (state.config.debug) message.push(markSample(JSON.stringify(context, null, 2)))
throw new UiengineInputError(message, err)
}
const fixData = { id, componentId, title, file, extension, raw, context }
const themes = R.zipObj(themeIds, rendered)
const variant = R.mergeAll([data, fixData, { themes }])
debug3(state, `Variant.fetchObject(${id}):end`)
return variant
}
module.exports = {
fetchObjects,
fetchObject,
findVariants
}