/* @flow */
import toCssValue from './toCssValue'
import type {ToCssOptions, JssStyle} from '../types'
/**
* Indent a string.
* http://jsperf.com/array-join-vs-for
*/
function indentStr(str: string, indent: number): string {
let result = ''
for (let index = 0; index < indent; index++) result += ' '
return result + str
}
/**
* Converts a Rule to CSS string.
*/
export default function toCss(
selector?: string,
style: JssStyle,
options: ToCssOptions = {}
): string {
let result = ''
if (!style) return result
let {indent = 0} = options
const {fallbacks} = style
if (selector) indent++
// Apply fallbacks first.
if (fallbacks) {
// Array syntax {fallbacks: [{prop: value}]}
if (Array.isArray(fallbacks)) {
for (let index = 0; index < fallbacks.length; index++) {
const fallback = fallbacks[index]
for (const prop in fallback) {
const value = fallback[prop]
if (value != null) {
if (result) result += '\n'
result += `${indentStr(`${prop}: ${toCssValue(value)};`, indent)}`
}
}
}
} else {
// Object syntax {fallbacks: {prop: value}}
for (const prop in fallbacks) {
const value = fallbacks[prop]
if (value != null) {
if (result) result += '\n'
result += `${indentStr(`${prop}: ${toCssValue(value)};`, indent)}`
}
}
}
}
for (const prop in style) {
const value = style[prop]
if (value != null && prop !== 'fallbacks') {
if (result) result += '\n'
result += `${indentStr(`${prop}: ${toCssValue(value)};`, indent)}`
}
}
// Allow empty style in this case, because properties will be added dynamically.
if (!result && !options.allowEmpty) return result
// When rule is being stringified before selector was defined.
if (!selector) return result
indent--
if (result) result = `\n${result}\n`
return indentStr(`${selector} {${result}`, indent) + indentStr('}', indent)
}