Repository navigation
Expand file tree
/
Copy pathparse.ts
More file actions
152 lines (124 loc) · 4.24 KB
/
Copy pathparse.ts
File metadata and controls
152 lines (124 loc) · 4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
* MIT License
* Copyright (c) 2019 Elijah Mooring
*
* @license MIT
* @author Elijah Mooring
* @file https://github.com/Vehmloewff/shineup/blob/master/lib/parsejs.js
*/
import flatten from 'flat'
export const isLayered = obj => {
let layerFound = false
for (let possibleLayer in obj) {
if (
!/^\$/.test(possibleLayer) &&
typeof obj[possibleLayer] === 'object'
) {
layerFound = true
break
}
}
return layerFound
}
export const addDotToClassName = className => {
if (!/^(\.|\$)/.test(className)) return '.' + className
else return className
}
export const getParent = (obj, delimiter) => {
const returnObj = {}
Object.keys(obj).forEach(key => {
const roots = key.split(delimiter)
const root = roots[roots.length - 1]
returnObj[root] = obj[key]
})
return returnObj
}
export const flattenObjectChildren = (obj, id) => {
const delimiter = `|`
const savedObject = obj
const callAllFunctions = obj => {
let funcsExist = true
const callVisibileFunctions = obj => {
funcsExist = false
for (let key in obj) {
if (typeof obj[key] === 'function') {
const rootKeys = key.split(delimiter)
const lastKey = rootKeys.pop()
const className = rootKeys[0].replace(/^\./, '')
const res = obj[key]({
obj: savedObject,
parent: getParent(obj, delimiter),
key: lastKey,
id,
className,
querySelector: `.${id}.${className}`,
})
// If last key starts with '&'...
if (lastKey && /^&/.test(lastKey)) {
// Spread it over the parent
delete obj[key]
if (typeof res !== 'object')
throw new Error(
`The value of all keys starting with an '&' symbol of type 'function' must return an object.`
)
const rootKey = rootKeys.join(delimiter)
Object.keys(res).forEach(newKey => {
obj[`${rootKey}|${newKey}`] = res[newKey]
})
}
// Otherwise
else {
// Carry on
obj[key] = res
}
funcsExist = true
}
}
return obj
}
while (funcsExist)
obj = callVisibileFunctions(flatten(obj, { delimiter }))
return obj
}
const changeKey = (key: string) => {
const levels = key.split('|')
const highestLevel = levels.pop()
return `${levels.join('').replace(/\$/g, ' ')}|${highestLevel}`
}
const flatObj = callAllFunctions(obj)
const newObj = {}
for (let key in flatObj) {
const value = flatObj[key]
key = changeKey(key)
newObj[key] = value
}
return flatten.unflatten(newObj, { delimiter })
}
export const parse = (obj = {}, id: string = 'svelte') => {
// Check the types
if (typeof obj !== 'object')
throw new Error(
`The first paramater must be of type 'object'. Recieved type '${typeof obj}';`
)
if (typeof id !== 'string')
throw new Error(
`The second paramater must be of type 'string'. Recieved type '${typeof id}';`
)
if (JSON.stringify(obj) === `{}`) return { css: {}, classes: {} }
// All the types are valid. Carry on.
if (!isLayered(obj)) {
const defaultName = 'default'
const defaultCSS = { [defaultName]: {} }
defaultCSS[defaultName] = obj
obj = defaultCSS
}
const classes: any = {}
for (let className in obj) {
const dottedClassname = addDotToClassName(className)
obj[dottedClassname] = obj[className]
classes[className] = `${id} ${className}`
delete obj[className]
}
const css = flattenObjectChildren(obj, id)
return { css, classes }
}