Files
standardnotes-app-web/packages/mobile/src/Style/CssParser.ts
2022-06-09 09:45:15 -05:00

104 lines
3.1 KiB
TypeScript

const PREFIX_GENERIC = '--'
const PREFIX_STANDARD_NOTES = '--sn-stylekit'
const PREFIX_STANDARD_NOTES_BURN = '--sn-'
function camelCaseToDashed(camel: string) {
return camel.replace(/[A-Z]/g, m => '-' + m.toLowerCase())
}
export function objectToCss(object: any) {
let result = ''
for (const key of Object.keys(object)) {
const dashed = `sn-${camelCaseToDashed(key).toLowerCase()}`
const line = `--${dashed}: ${object[key]};\n`
result += line
}
return `
:root {
${result}
}
`
}
export default class CSSParser {
/**
* @param css: CSS file contents in string format
*/
static cssToObject(css: string) {
const object: Record<string, string> = {}
const lines = css.split('\n')
for (let line of lines) {
line = line.trim()
if (line.startsWith(PREFIX_GENERIC)) {
// Remove initial '--'
if (line.startsWith(PREFIX_STANDARD_NOTES)) {
line = line.slice(PREFIX_STANDARD_NOTES_BURN.length, line.length)
} else {
// Not all vars start with --sn-stylekit. e.g --background-color
line = line.slice(PREFIX_GENERIC.length, line.length)
}
const parts = line.split(':')
let key = parts[0].trim()
let value = parts[1].trim()
key = this.hyphenatedStringToCamelCase(key)
value = value.replace(';', '').trim()
object[key] = value
}
}
this.resolveVariablesThatReferenceOtherVariables(object)
return object
}
static resolveVariablesThatReferenceOtherVariables(object: Record<string, any>, round = 0) {
for (const key of Object.keys(object)) {
const value = object[key]
const stripValue = 'var('
if (typeof value === 'string' && value.startsWith(stripValue)) {
const from = stripValue.length
const to = value.indexOf(')')
let varName = value.slice(from, to)
if (varName.startsWith(PREFIX_STANDARD_NOTES)) {
varName = varName.slice(PREFIX_STANDARD_NOTES_BURN.length, varName.length)
} else {
// Not all vars start with --sn-stylekit. e.g --background-color
varName = varName.slice(PREFIX_GENERIC.length, varName.length)
}
varName = this.hyphenatedStringToCamelCase(varName)
object[key] = object[varName]
}
}
// Two rounds are required. The first will replace all right hand side variables with
// the left hand counterparts. In the first round, variables on rhs mentioned before
// its value has been gotten to in the loop will be missed. The second round takes care of this
// and makes sure that all values will resolve.
if (round === 0) {
this.resolveVariablesThatReferenceOtherVariables(object, ++round)
}
}
static hyphenatedStringToCamelCase(string: string) {
const comps = string.split('-')
let result = ''
for (let i = 0; i < comps.length; i++) {
const part = comps[i]
if (i === 0) {
result += part
} else {
result += this.capitalizeFirstLetter(part)
}
}
return result
}
static capitalizeFirstLetter(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
}