at last... it's complete
This commit is contained in:
parent
0c91c37645
commit
71a4781080
|
@ -34,8 +34,8 @@ export default {
|
||||||
directives: {
|
directives: {
|
||||||
'--defaultButtonHoverGlow': 'shadow | 0 0 4 --text',
|
'--defaultButtonHoverGlow': 'shadow | 0 0 4 --text',
|
||||||
'--defaultButtonShadow': 'shadow | 0 0 2 #000000',
|
'--defaultButtonShadow': 'shadow | 0 0 2 #000000',
|
||||||
'--defaultButtonBevel': 'shadow | $borderSide(#FFFFFF, top, 0.2) | $borderSide(#000000, bottom, 0.2)',
|
'--defaultButtonBevel': 'shadow | $borderSide(#FFFFFF, top, 0.2), $borderSide(#000000, bottom, 0.2)',
|
||||||
'--pressedButtonBevel': 'shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2)'
|
'--pressedButtonBevel': 'shadow | $borderSide(#FFFFFF, bottom, 0.2), $borderSide(#000000, top, 0.2)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,24 +1,51 @@
|
||||||
|
import { flattenDeep } from 'lodash'
|
||||||
|
|
||||||
|
const parseShadow = string => {
|
||||||
|
const modes = ['_full', 'inset', 'x', 'y', 'blur', 'spread', 'color', 'alpha']
|
||||||
|
const regexPrep = [
|
||||||
|
// inset keyword (optional)
|
||||||
|
'^(?:(inset)\\s+)?',
|
||||||
|
// x
|
||||||
|
'(?:([0-9]+(?:\\.[0-9]+)?)\\s+)',
|
||||||
|
// y
|
||||||
|
'(?:([0-9]+(?:\\.[0-9]+)?)\\s+)',
|
||||||
|
// blur (optional)
|
||||||
|
'(?:([0-9]+(?:\\.[0-9]+)?)\\s+)?',
|
||||||
|
// spread (optional)
|
||||||
|
'(?:([0-9]+(?:\\.[0-9]+)?)\\s+)?',
|
||||||
|
// either hex, variable or function
|
||||||
|
'(#[0-9a-f]{6}|--[a-z\\-_]+|\\$[a-z\\-()_]+)',
|
||||||
|
// opacity (optional)
|
||||||
|
'(?:\\s+\\/\\s+([0-9]+(?:\\.[0-9]+)?)\\s*)?$'
|
||||||
|
].join('')
|
||||||
|
const regex = new RegExp(regexPrep, 'gis') // global, (stable) indices, single-string
|
||||||
|
const result = regex.exec(string)
|
||||||
|
if (result == null) {
|
||||||
|
return string
|
||||||
|
} else {
|
||||||
|
return Object.fromEntries(modes.map((mode, i) => [mode, result[i]]))
|
||||||
|
}
|
||||||
|
}
|
||||||
// this works nearly the same as HTML tree converter
|
// this works nearly the same as HTML tree converter
|
||||||
export const deserialize = (input) => {
|
const parseIss = (input) => {
|
||||||
const buffer = []
|
const buffer = [{ selector: null, content: [] }]
|
||||||
let textBuffer = ''
|
let textBuffer = ''
|
||||||
|
|
||||||
const getCurrentBuffer = () => {
|
const getCurrentBuffer = () => {
|
||||||
let current = buffer[buffer.length - 1][1]
|
let current = buffer[buffer.length - 1]
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
current = { name: null, content: [] }
|
current = { selector: null, content: [] }
|
||||||
}
|
}
|
||||||
buffer.push(current)
|
|
||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes current line buffer, adds it to output buffer and clears line buffer
|
// Processes current line buffer, adds it to output buffer and clears line buffer
|
||||||
const flushText = (content) => {
|
const flushText = (kind) => {
|
||||||
if (textBuffer === '') return
|
if (textBuffer === '') return
|
||||||
if (content) {
|
if (kind === 'content') {
|
||||||
getCurrentBuffer().content.push(textBuffer)
|
getCurrentBuffer().content.push(textBuffer.trim())
|
||||||
} else {
|
} else {
|
||||||
getCurrentBuffer().name = textBuffer
|
getCurrentBuffer().selector = textBuffer.trim()
|
||||||
}
|
}
|
||||||
textBuffer = ''
|
textBuffer = ''
|
||||||
}
|
}
|
||||||
|
@ -27,17 +54,90 @@ export const deserialize = (input) => {
|
||||||
const char = input[i]
|
const char = input[i]
|
||||||
|
|
||||||
if (char === ';') {
|
if (char === ';') {
|
||||||
flushText(true)
|
flushText('content')
|
||||||
} else if (char === '{') {
|
} else if (char === '{') {
|
||||||
flushText(false)
|
flushText('header')
|
||||||
} else if (char === '}') {
|
} else if (char === '}') {
|
||||||
buffer.push({ name: null, content: [] })
|
flushText('content')
|
||||||
|
buffer.push({ selector: null, content: [] })
|
||||||
textBuffer = ''
|
textBuffer = ''
|
||||||
} else {
|
} else {
|
||||||
textBuffer += char
|
textBuffer += char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flushText()
|
|
||||||
return buffer
|
return buffer
|
||||||
}
|
}
|
||||||
|
export const deserialize = (input) => {
|
||||||
|
const ast = parseIss(input)
|
||||||
|
const finalResult = ast.filter(i => i.selector != null).map(item => {
|
||||||
|
const { selector, content } = item
|
||||||
|
let stateCount = 0
|
||||||
|
const selectors = selector.split(/,/g)
|
||||||
|
const result = selectors.map(selector => {
|
||||||
|
const output = { component: '' }
|
||||||
|
let currentDepth = null
|
||||||
|
|
||||||
|
selector.split(/ /g).reverse().forEach((fragment, index, arr) => {
|
||||||
|
const fragmentObject = { component: '' }
|
||||||
|
|
||||||
|
let mode = 'component'
|
||||||
|
for (let i = 0; i < fragment.length; i++) {
|
||||||
|
const char = fragment[i]
|
||||||
|
switch (char) {
|
||||||
|
case '.': {
|
||||||
|
mode = 'variant'
|
||||||
|
fragmentObject.variant = ''
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case ':': {
|
||||||
|
mode = 'state'
|
||||||
|
fragmentObject.state = fragmentObject.state || []
|
||||||
|
stateCount++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
if (mode === 'state') {
|
||||||
|
const currentState = fragmentObject.state[stateCount - 1]
|
||||||
|
if (currentState == null) {
|
||||||
|
fragmentObject.state.push('')
|
||||||
|
}
|
||||||
|
fragmentObject.state[stateCount - 1] += char
|
||||||
|
} else {
|
||||||
|
fragmentObject[mode] += char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentDepth !== null) {
|
||||||
|
currentDepth.parent = { ...fragmentObject }
|
||||||
|
currentDepth = currentDepth.parent
|
||||||
|
} else {
|
||||||
|
Object.keys(fragmentObject).forEach(key => {
|
||||||
|
output[key] = fragmentObject[key]
|
||||||
|
})
|
||||||
|
if (index !== (arr.length - 1)) {
|
||||||
|
output.parent = { component: '' }
|
||||||
|
}
|
||||||
|
currentDepth = output
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
output.directives = Object.fromEntries(content.map(d => {
|
||||||
|
const [property, value] = d.split(':')
|
||||||
|
console.log(property, value)
|
||||||
|
let realValue = value.trim()
|
||||||
|
if (property === 'shadow') {
|
||||||
|
realValue = parseShadow(value.split(',').map(v => v.trim()))
|
||||||
|
} if (!Number.isNaN(Number(value))) {
|
||||||
|
realValue = Number(value)
|
||||||
|
}
|
||||||
|
return [property, realValue]
|
||||||
|
}))
|
||||||
|
|
||||||
|
return output
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
return flattenDeep(finalResult)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import { unroll } from './iss_utils.js'
|
import { unroll } from './iss_utils.js'
|
||||||
|
|
||||||
const serializeShadow = s => `{${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}}`
|
const serializeShadow = s => {
|
||||||
|
if (typeof s === 'object') {
|
||||||
|
return `{${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}}`
|
||||||
|
} else {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const serialize = (ruleset) => {
|
export const serialize = (ruleset) => {
|
||||||
return ruleset.map((rule) => {
|
return ruleset.map((rule) => {
|
||||||
|
@ -8,8 +14,8 @@ export const serialize = (ruleset) => {
|
||||||
|
|
||||||
const header = unroll(rule).reverse().map(rule => {
|
const header = unroll(rule).reverse().map(rule => {
|
||||||
const { component } = rule
|
const { component } = rule
|
||||||
const newVariant = rule.variant === 'normal' ? '' : ('.' + rule.variant)
|
const newVariant = (rule.variant == null || rule.variant === 'normal') ? '' : ('.' + rule.variant)
|
||||||
const newState = rule.state.filter(st => st !== 'normal')
|
const newState = (rule.state || []).filter(st => st !== 'normal')
|
||||||
|
|
||||||
return `${component}${newVariant}${newState.map(st => ':' + st).join('')}`
|
return `${component}${newVariant}${newState.map(st => ':' + st).join('')}`
|
||||||
}).join(' ')
|
}).join(' ')
|
||||||
|
@ -19,9 +25,9 @@ export const serialize = (ruleset) => {
|
||||||
const [valType, newValue] = value.split('|') // only first one! intentional!
|
const [valType, newValue] = value.split('|') // only first one! intentional!
|
||||||
switch (valType) {
|
switch (valType) {
|
||||||
case 'shadow':
|
case 'shadow':
|
||||||
return ` ${directive}: ${newValue.map(serializeShadow).join(', ')}`
|
return ` ${directive}: ${valType.trim()} | ${newValue.map(serializeShadow).map(s => s.trim()).join(', ')}`
|
||||||
default:
|
default:
|
||||||
return ` ${directive}: ${newValue}`
|
return ` ${directive}: ${valType.trim()} | ${newValue.trim()}`
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (directive) {
|
switch (directive) {
|
||||||
|
|
|
@ -23,9 +23,6 @@ import {
|
||||||
findRules
|
findRules
|
||||||
} from './iss_utils.js'
|
} from './iss_utils.js'
|
||||||
import { parseCssShadow } from './css_utils.js'
|
import { parseCssShadow } from './css_utils.js'
|
||||||
import {
|
|
||||||
serialize
|
|
||||||
} from './iss_serializer.js'
|
|
||||||
|
|
||||||
// Ensuring the order of components
|
// Ensuring the order of components
|
||||||
const components = {
|
const components = {
|
||||||
|
|
|
@ -1,47 +1,16 @@
|
||||||
import { deserialize } from 'src/services/theme_data/iss_deserializer.js'
|
import { deserialize } from 'src/services/theme_data/iss_deserializer.js'
|
||||||
|
import { serialize } from 'src/services/theme_data/iss_serializer.js'
|
||||||
|
import Button from 'src/components/button.style.js'
|
||||||
|
|
||||||
/* eslint-disable quotes */
|
describe.only('ISS (de)serialization', () => {
|
||||||
const testData = ```
|
describe('ISS deserialization', () => {
|
||||||
Root {
|
it('Output should = input', () => {
|
||||||
--accent: color | #e2b188;
|
const normalized = Button.defaultRules.map(x => ({ component: 'Button', ...x }))
|
||||||
--badgeNotification: color | #e15932;
|
const serialized = serialize(normalized)
|
||||||
--bg: color | #0f161e;
|
const deserialized = deserialize(serialized)
|
||||||
--cBlue: color | #81beea;
|
// deserialized.toString()
|
||||||
--cGreen: color | #5dc94a;
|
|
||||||
--cOrange: color | #ffc459;
|
|
||||||
--cRed: color | #d31014;
|
|
||||||
--defaultButtonBevel: shadow | $borderSide(#FFFFFF, top, 0.2) | $borderSide(#000000, bottom, 0.2);
|
|
||||||
--defaultButtonHoverGlow: shadow | 0 0 4 --text;
|
|
||||||
--defaultButtonShadow: shadow | 0 0 2 #000000;
|
|
||||||
--defaultInputBevel: shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2);
|
|
||||||
--fg: color | #151e2b;
|
|
||||||
--font: generic | sans-serif;
|
|
||||||
--link: color | #e2b188;
|
|
||||||
--monoFont: generic | monospace;
|
|
||||||
--pressedButtonBevel: shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2);
|
|
||||||
--selectionBackground: color | --accent;
|
|
||||||
--selectionText: color | $textColor(--accent, --text, no-preserve);
|
|
||||||
--text: color | #b9b9ba;
|
|
||||||
--wallpaper: color | #0c1118;
|
|
||||||
background: transparent;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Root Underlay {
|
expect(JSON.stringify(deserialized)).to.equal(JSON.stringify(normalized))
|
||||||
background: #000000;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
Root Underlay, test {
|
|
||||||
background: #000000;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
describe.only('html_tree_converter', () => {
|
|
||||||
describe('convertHtmlToTree', () => {
|
|
||||||
it('should parse ISS correctly', () => {
|
|
||||||
console.log(deserialize(testData))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue