UNPKG

4.64 kBJavaScriptView Raw
1import cssProperties from 'css-properties'
2import isExpression from 'is-expression'
3import toCamelCase from 'to-camel-case'
4
5const BASIC = /^(CaptureEmail|CaptureFile|CaptureNumber|CapturePhone|CaptureSecure|CaptureText|CaptureTextArea|G|Horizontal|Image|List|Svg|SvgCircle|SvgEllipse|SvgDefs|SvgGroup|SvgLinearGradient|SvgRadialGradient|SvgLine|SvgPath|SvgPolygon|SvgPolyline|SvgRect|SvgSymbol|SvgText|SvgUse|SvgStop|Text|Vertical|FakeProps)$/i
6const BLOCK = /^([A-Z][a-zA-Z0-9]*)(\s+([A-Z][a-zA-Z0-9]*))?$/
7const BOOL = /^(false|true)$/i
8const CAPTURE = /^(CaptureEmail|CaptureFile|CaptureNumber|CapturePhone|CaptureSecure|CaptureText|CaptureTextArea)$/i
9const CODE_EXPLICIT = /^{.+}$/
10const CODE_IMPLICIT = /props\./
11const CODE_DEFAULT = /^props$/
12const COMMENT = /^#(.+)$/
13const INTERPOLATED_EXPRESSION = /\${.+}/
14const FLOAT = /^[0-9]+\.[0-9]+$/
15const FONTABLE = /^(CaptureEmail|CaptureNumber|CapturePhone|CaptureSecure|CaptureText|CaptureTextArea|Text)$/
16const INT = /^[0-9]+$/
17const NOT_GROUP = /^(Image|FakeProps|Text|Proxy|SvgCircle|SvgEllipse|SvgLine|SvgPath|SvgPolygon|SvgPolyline|SvgRect|SvgText|SvgStop)$/i
18const PROP = /^([a-z][a-zA-Z0-9]*)(\s+(.+))?$/
19const STYLE = new RegExp(
20 `^(${cssProperties
21 .map(toCamelCase)
22 .join(
23 '|'
24 )}|pointerEvents|clipPath|appRegion|userSelect|hyphens|overflowWrap)$`
25)
26const TEMPLATE_LITERAL = /^`.+`$/
27const TRUE = /^true$/i
28const USER_COMMENT = /^##(.*)$/
29
30export const is = (thing, line) => thing.test(line)
31export const isBasic = line => is(BASIC, line)
32export const isBlock = line => is(BLOCK, line)
33export const isBool = line => is(BOOL, line)
34export const isCapture = line => is(CAPTURE, line)
35export const isCode = line =>
36 is(CODE_EXPLICIT, line) || is(CODE_IMPLICIT, line) || isCodeDefault(line)
37export const isCodeDefault = line => is(CODE_DEFAULT, line)
38export const isValidCode = rcode => {
39 try {
40 let code = rcode
41 if (isInterpolatedExpression(code) && !isTemplateLiteral(code)) {
42 code = `\`${code}\``
43 }
44 // eslint-disable-next-line
45 new Function('props', 'state', 'event', code)({}, {}, {})
46 return isExpression(code, { strict: true })
47 } catch (error) {
48 return false
49 }
50}
51export const isComment = line => is(COMMENT, line)
52export const isEmptyList = line => line === 'is empty list'
53export const isEmptyText = line => line === ''
54export const isEnd = line => line === ''
55export const isInterpolatedExpression = line =>
56 is(INTERPOLATED_EXPRESSION, line)
57export const isFloat = line => is(FLOAT, line)
58export const isFontable = line => is(FONTABLE, line)
59export const isGroup = line => !is(NOT_GROUP, line) && !isCapture(line)
60export const isList = line => line === 'List'
61export const isInt = line => is(INT, line)
62export const isProp = line => is(PROP, line)
63export const isTemplateLiteral = line => is(TEMPLATE_LITERAL, line)
64export const isStyle = line => is(STYLE, line)
65export const isTrue = line => is(TRUE, line)
66export const isUserComment = line => is(USER_COMMENT, line)
67
68const get = (regex, line) => line.match(regex)
69
70export const getBlock = line => {
71 // eslint-disable-next-line
72 const [_, is, _1, block] = get(BLOCK, line)
73 return {
74 block: block || is,
75 is: block ? is : null,
76 }
77}
78export const getCodeData = line =>
79 line
80 .replace(/^{/, '')
81 .replace(/}$/, '')
82 .split(' ')
83 .filter(l => /[.[]/.test(l))
84export const getComment = line => {
85 try {
86 return get(COMMENT, line).slice(1)
87 } catch (err) {
88 return ''
89 }
90}
91export const getMainFont = line =>
92 line ? line.split(',')[0].replace(/['"]/g, '') : ''
93export const getProp = line => {
94 // eslint-disable-next-line
95 let [_, prop, _1, value = ''] = get(PROP, line)
96 if (isCodeDefault(value)) {
97 value = `props.${prop}`
98 }
99 return [prop, value]
100}
101export const getValue = value => {
102 if (isFloat(value)) {
103 return parseFloat(value, 10)
104 } else if (isInt(value)) {
105 return parseInt(value, 10)
106 } else if (isEmptyText(value)) {
107 return ''
108 } else if (isBool(value)) {
109 return isTrue(value)
110 } else if (isInterpolatedExpression(value)) {
111 return fixBackticks(value)
112 } else {
113 return value
114 }
115}
116
117export const fixBackticks = value =>
118 isTemplateLiteral(value) ? value : `\`${value}\``
119
120export const warn = (message, block) => {
121 if (!Array.isArray(block.warnings)) {
122 block.warnings = []
123 }
124 block.warnings.push(message)
125}
126
127const SYSTEM_SCOPES = [
128 'active',
129 // TODO disabled should be a prop instead I think
130 'disabled',
131 'focus',
132 'hover',
133 'placeholder',
134 'print',
135 // TODO do we want to do media queries here?
136]
137export const isSystemScope = name => SYSTEM_SCOPES.includes(name)