From aa766021662250339edf01f37b0d7a047babc2e3 Mon Sep 17 00:00:00 2001
From: Jacob Parker <jacobparker1992@gmail.com>
Date: Sat, 16 Nov 2019 18:05:39 +0000
Subject: [PATCH 1/3] Add support for directional border shorthands

---
 src/__tests__/border.js      | 100 ++++++++++++++++++++++++++++-------
 src/__tests__/borderRight.js |  47 ++++++++++++++++
 src/__tests__/colors.js      |  10 +++-
 src/__tests__/units.js       |  27 +++++++---
 src/transforms/border.js     |  49 ++++++++++++++++-
 src/transforms/index.js      |  11 +++-
 6 files changed, 211 insertions(+), 33 deletions(-)
 create mode 100644 src/__tests__/borderRight.js

diff --git a/src/__tests__/border.js b/src/__tests__/border.js
index 31c9a08..2d39f85 100644
--- a/src/__tests__/border.js
+++ b/src/__tests__/border.js
@@ -2,80 +2,140 @@ import transformCss from '..'
 
 it('transforms border none', () => {
   expect(transformCss([['border', 'none']])).toEqual({
-    borderWidth: 0,
-    borderColor: 'black',
+    borderTopWidth: 0,
+    borderRightWidth: 0,
+    borderBottomWidth: 0,
+    borderLeftWidth: 0,
+    borderTopColor: 'black',
+    borderRightColor: 'black',
+    borderBottomColor: 'black',
+    borderLeftColor: 'black',
     borderStyle: 'solid',
   })
 })
 
 it('transforms border shorthand', () => {
   expect(transformCss([['border', '2px dashed #f00']])).toEqual({
-    borderWidth: 2,
-    borderColor: '#f00',
+    borderTopWidth: 2,
+    borderRightWidth: 2,
+    borderBottomWidth: 2,
+    borderLeftWidth: 2,
+    borderTopColor: '#f00',
+    borderRightColor: '#f00',
+    borderBottomColor: '#f00',
+    borderLeftColor: '#f00',
     borderStyle: 'dashed',
   })
 })
 
 it('transforms border shorthand in other order', () => {
   expect(transformCss([['border', '#f00 2px dashed']])).toEqual({
-    borderWidth: 2,
-    borderColor: '#f00',
+    borderTopWidth: 2,
+    borderRightWidth: 2,
+    borderBottomWidth: 2,
+    borderLeftWidth: 2,
+    borderTopColor: '#f00',
+    borderRightColor: '#f00',
+    borderBottomColor: '#f00',
+    borderLeftColor: '#f00',
     borderStyle: 'dashed',
   })
 })
 
 it('transforms border shorthand missing color', () => {
   expect(transformCss([['border', '2px dashed']])).toEqual({
-    borderWidth: 2,
-    borderColor: 'black',
+    borderTopWidth: 2,
+    borderRightWidth: 2,
+    borderBottomWidth: 2,
+    borderLeftWidth: 2,
+    borderTopColor: 'black',
+    borderRightColor: 'black',
+    borderBottomColor: 'black',
+    borderLeftColor: 'black',
     borderStyle: 'dashed',
   })
 })
 
 it('transforms border shorthand missing style', () => {
   expect(transformCss([['border', '2px #f00']])).toEqual({
-    borderWidth: 2,
-    borderColor: '#f00',
+    borderTopWidth: 2,
+    borderRightWidth: 2,
+    borderBottomWidth: 2,
+    borderLeftWidth: 2,
+    borderTopColor: '#f00',
+    borderRightColor: '#f00',
+    borderBottomColor: '#f00',
+    borderLeftColor: '#f00',
     borderStyle: 'solid',
   })
 })
 
 it('transforms border shorthand missing width', () => {
   expect(transformCss([['border', '#f00 dashed']])).toEqual({
-    borderWidth: 1,
-    borderColor: '#f00',
+    borderTopWidth: 1,
+    borderRightWidth: 1,
+    borderBottomWidth: 1,
+    borderLeftWidth: 1,
+    borderTopColor: '#f00',
+    borderRightColor: '#f00',
+    borderBottomColor: '#f00',
+    borderLeftColor: '#f00',
     borderStyle: 'dashed',
   })
 })
 
 it('transforms border shorthand missing color & width', () => {
   expect(transformCss([['border', 'dashed']])).toEqual({
-    borderWidth: 1,
-    borderColor: 'black',
+    borderTopWidth: 1,
+    borderRightWidth: 1,
+    borderBottomWidth: 1,
+    borderLeftWidth: 1,
+    borderTopColor: 'black',
+    borderRightColor: 'black',
+    borderBottomColor: 'black',
+    borderLeftColor: 'black',
     borderStyle: 'dashed',
   })
 })
 
 it('transforms border shorthand missing style & width', () => {
   expect(transformCss([['border', '#f00']])).toEqual({
-    borderWidth: 1,
-    borderColor: '#f00',
+    borderTopWidth: 1,
+    borderRightWidth: 1,
+    borderBottomWidth: 1,
+    borderLeftWidth: 1,
+    borderTopColor: '#f00',
+    borderRightColor: '#f00',
+    borderBottomColor: '#f00',
+    borderLeftColor: '#f00',
     borderStyle: 'solid',
   })
 })
 
 it('transforms border shorthand missing color & style', () => {
   expect(transformCss([['border', '2px']])).toEqual({
-    borderWidth: 2,
-    borderColor: 'black',
+    borderTopWidth: 2,
+    borderRightWidth: 2,
+    borderBottomWidth: 2,
+    borderLeftWidth: 2,
+    borderTopColor: 'black',
+    borderRightColor: 'black',
+    borderBottomColor: 'black',
+    borderLeftColor: 'black',
     borderStyle: 'solid',
   })
 })
 
 it('transforms border for unsupported units', () => {
   expect(transformCss([['border', '3em solid black']])).toEqual({
-    borderWidth: '3em',
-    borderColor: 'black',
+    borderTopWidth: '3em',
+    borderRightWidth: '3em',
+    borderBottomWidth: '3em',
+    borderLeftWidth: '3em',
+    borderTopColor: 'black',
+    borderRightColor: 'black',
+    borderBottomColor: 'black',
+    borderLeftColor: 'black',
     borderStyle: 'solid',
   })
 })
diff --git a/src/__tests__/borderRight.js b/src/__tests__/borderRight.js
new file mode 100644
index 0000000..4aab147
--- /dev/null
+++ b/src/__tests__/borderRight.js
@@ -0,0 +1,47 @@
+import transformCss from '..'
+
+it('transforms border none', () => {
+  expect(transformCss([['border-right', 'none']])).toEqual({
+    borderRightWidth: 0,
+    borderRightColor: 'black',
+  })
+})
+
+it('transforms border shorthand in other order', () => {
+  expect(transformCss([['border-right', '#f00 2px']])).toEqual({
+    borderRightWidth: 2,
+    borderRightColor: '#f00',
+  })
+})
+
+it('transforms border shorthand missing width', () => {
+  expect(transformCss([['border-right', '#f00']])).toEqual({
+    borderRightWidth: 1,
+    borderRightColor: '#f00',
+  })
+})
+
+it('transforms border shorthand missing color', () => {
+  expect(transformCss([['border-right', '2px']])).toEqual({
+    borderRightWidth: 2,
+    borderRightColor: 'black',
+  })
+})
+
+it('transforms border for unsupported units', () => {
+  expect(transformCss([['border-right', '3em black']])).toEqual({
+    borderRightWidth: '3em',
+    borderRightColor: 'black',
+  })
+})
+
+it('does not transform border with percentage width', () => {
+  expect(() => transformCss([['border-right', '3% black']])).toThrow()
+})
+
+it('does not transform style', () => {
+  expect(() => transformCss([['border-right', '2px dashed #f00']])).toThrow()
+  expect(() => transformCss([['border-right', 'dashed #f00']])).toThrow()
+  expect(() => transformCss([['border-right', '2px dashed']])).toThrow()
+  expect(() => transformCss([['border-right', 'dashed']])).toThrow()
+})
diff --git a/src/__tests__/colors.js b/src/__tests__/colors.js
index 9a0fe62..f919ac3 100644
--- a/src/__tests__/colors.js
+++ b/src/__tests__/colors.js
@@ -18,9 +18,15 @@ it('transforms transparent color', () => {
 
 it('transforms border shorthand with transparent color', () => {
   expect(transformCss([['border', '2px dashed transparent']])).toEqual({
-    borderColor: 'transparent',
+    borderTopWidth: 2,
+    borderRightWidth: 2,
+    borderBottomWidth: 2,
+    borderLeftWidth: 2,
+    borderTopColor: 'transparent',
+    borderRightColor: 'transparent',
+    borderBottomColor: 'transparent',
+    borderLeftColor: 'transparent',
     borderStyle: 'dashed',
-    borderWidth: 2,
   })
 })
 
diff --git a/src/__tests__/units.js b/src/__tests__/units.js
index d1a13f8..1ce1f60 100644
--- a/src/__tests__/units.js
+++ b/src/__tests__/units.js
@@ -2,7 +2,8 @@ import transformCss from '..'
 
 // List of units from:
 // https://developer.mozilla.org/en-US/docs/Web/CSS/length
-const lengthUnits = [
+
+describe.each([
   'ch',
   'em',
   'ex',
@@ -16,9 +17,7 @@ const lengthUnits = [
   'in',
   'pc',
   'pt',
-]
-
-lengthUnits.forEach(unit => {
+])('Handles unit: %s', unit => {
   const value = `2${unit}`
 
   it('allows CSS length units in transformed values', () => {
@@ -56,14 +55,26 @@ lengthUnits.forEach(unit => {
 
   it('allows units to be used with border shorthand property', () => {
     expect(transformCss([['border', `#f00 ${value} dashed`]])).toEqual({
-      borderWidth: value,
-      borderColor: '#f00',
+      borderTopWidth: value,
+      borderRightWidth: value,
+      borderBottomWidth: value,
+      borderLeftWidth: value,
+      borderTopColor: '#f00',
+      borderRightColor: '#f00',
+      borderBottomColor: '#f00',
+      borderLeftColor: '#f00',
       borderStyle: 'dashed',
     })
 
     expect(transformCss([['border', value]])).toEqual({
-      borderWidth: value,
-      borderColor: 'black',
+      borderTopWidth: value,
+      borderRightWidth: value,
+      borderBottomWidth: value,
+      borderLeftWidth: value,
+      borderTopColor: 'black',
+      borderRightColor: 'black',
+      borderBottomColor: 'black',
+      borderLeftColor: 'black',
       borderStyle: 'solid',
     })
   })
diff --git a/src/transforms/border.js b/src/transforms/border.js
index d4c77b4..64956af 100644
--- a/src/transforms/border.js
+++ b/src/transforms/border.js
@@ -13,7 +13,7 @@ const defaultBorderWidth = 1
 const defaultBorderColor = 'black'
 const defaultBorderStyle = 'solid'
 
-export default tokenStream => {
+const baseParse = (tokenStream, allowBorderStyle) => {
   let borderWidth
   let borderColor
   let borderStyle
@@ -47,7 +47,52 @@ export default tokenStream => {
 
   if (borderWidth === undefined) borderWidth = defaultBorderWidth
   if (borderColor === undefined) borderColor = defaultBorderColor
-  if (borderStyle === undefined) borderStyle = defaultBorderStyle
+  if (borderStyle === undefined) {
+    borderStyle = defaultBorderStyle
+  } else if (!allowBorderStyle) {
+    throw new Error(
+      'Setting a border style on a single border side is not supported'
+    )
+  }
 
   return { borderWidth, borderColor, borderStyle }
 }
+
+export default tokenStream => {
+  // eslint-disable-next-line prefer-const
+  let { borderWidth, borderColor, borderStyle } = baseParse(tokenStream, true)
+
+  if (borderStyle === undefined) borderStyle = defaultBorderStyle
+
+  return {
+    borderTopWidth: borderWidth,
+    borderRightWidth: borderWidth,
+    borderBottomWidth: borderWidth,
+    borderLeftWidth: borderWidth,
+    borderTopColor: borderColor,
+    borderRightColor: borderColor,
+    borderBottomColor: borderColor,
+    borderLeftColor: borderColor,
+    borderStyle,
+  }
+}
+
+export const borderTop = tokenStream => {
+  const { borderWidth, borderColor } = baseParse(tokenStream, false)
+  return { borderTopWidth: borderWidth, borderTopColor: borderColor }
+}
+
+export const borderRight = tokenStream => {
+  const { borderWidth, borderColor } = baseParse(tokenStream, false)
+  return { borderRightWidth: borderWidth, borderRightColor: borderColor }
+}
+
+export const borderBottom = tokenStream => {
+  const { borderWidth, borderColor } = baseParse(tokenStream, false)
+  return { borderBottomWidth: borderWidth, borderBottomColor: borderColor }
+}
+
+export const borderLeft = tokenStream => {
+  const { borderWidth, borderColor } = baseParse(tokenStream, false)
+  return { borderLeftWidth: borderWidth, borderLeftColor: borderColor }
+}
diff --git a/src/transforms/index.js b/src/transforms/index.js
index 66320ae..0a50d86 100644
--- a/src/transforms/index.js
+++ b/src/transforms/index.js
@@ -7,7 +7,12 @@ import {
   PERCENT,
   AUTO,
 } from '../tokenTypes'
-import border from './border'
+import border, {
+  borderTop,
+  borderRight,
+  borderBottom,
+  borderLeft,
+} from './border'
 import boxShadow from './boxShadow'
 import flex from './flex'
 import flexFlow from './flexFlow'
@@ -55,8 +60,12 @@ const textShadowOffset = tokenStream => ({
 export default {
   background,
   border,
+  borderBottom,
   borderColor,
+  borderLeft,
   borderRadius,
+  borderRight,
+  borderTop,
   borderWidth,
   boxShadow,
   flex,

From 4fe5f869ec05df2bee6b0211eb476b19ad130092 Mon Sep 17 00:00:00 2001
From: Jacob Parker <jacobparker1992@gmail.com>
Date: Sat, 16 Nov 2019 18:22:17 +0000
Subject: [PATCH 2/3] Improve border consistency

---
 src/__tests__/border.js      | 54 ++++++++----------------------------
 src/__tests__/borderRight.js | 47 -------------------------------
 src/__tests__/units.js       |  2 +-
 src/transforms/border.js     | 48 +++++++++-----------------------
 4 files changed, 26 insertions(+), 125 deletions(-)
 delete mode 100644 src/__tests__/borderRight.js

diff --git a/src/__tests__/border.js b/src/__tests__/border.js
index 2d39f85..3007b1c 100644
--- a/src/__tests__/border.js
+++ b/src/__tests__/border.js
@@ -56,20 +56,6 @@ it('transforms border shorthand missing color', () => {
   })
 })
 
-it('transforms border shorthand missing style', () => {
-  expect(transformCss([['border', '2px #f00']])).toEqual({
-    borderTopWidth: 2,
-    borderRightWidth: 2,
-    borderBottomWidth: 2,
-    borderLeftWidth: 2,
-    borderTopColor: '#f00',
-    borderRightColor: '#f00',
-    borderBottomColor: '#f00',
-    borderLeftColor: '#f00',
-    borderStyle: 'solid',
-  })
-})
-
 it('transforms border shorthand missing width', () => {
   expect(transformCss([['border', '#f00 dashed']])).toEqual({
     borderTopWidth: 1,
@@ -98,34 +84,6 @@ it('transforms border shorthand missing color & width', () => {
   })
 })
 
-it('transforms border shorthand missing style & width', () => {
-  expect(transformCss([['border', '#f00']])).toEqual({
-    borderTopWidth: 1,
-    borderRightWidth: 1,
-    borderBottomWidth: 1,
-    borderLeftWidth: 1,
-    borderTopColor: '#f00',
-    borderRightColor: '#f00',
-    borderBottomColor: '#f00',
-    borderLeftColor: '#f00',
-    borderStyle: 'solid',
-  })
-})
-
-it('transforms border shorthand missing color & style', () => {
-  expect(transformCss([['border', '2px']])).toEqual({
-    borderTopWidth: 2,
-    borderRightWidth: 2,
-    borderBottomWidth: 2,
-    borderLeftWidth: 2,
-    borderTopColor: 'black',
-    borderRightColor: 'black',
-    borderBottomColor: 'black',
-    borderLeftColor: 'black',
-    borderStyle: 'solid',
-  })
-})
-
 it('transforms border for unsupported units', () => {
   expect(transformCss([['border', '3em solid black']])).toEqual({
     borderTopWidth: '3em',
@@ -140,6 +98,18 @@ it('transforms border for unsupported units', () => {
   })
 })
 
+it('does not transform border shorthand missing style', () => {
+  expect(() => transformCss([['border', '2px #f00']])).toThrow()
+})
+
+it('does not transform border shorthand missing style & width', () => {
+  expect(() => transformCss([['border', '#f00']])).toThrow()
+})
+
+it('does not transforms border shorthand missing color & style', () => {
+  expect(() => transformCss([['border', '2px']])).toThrow()
+})
+
 it('does not transform border with percentage width', () => {
   expect(() => transformCss([['border', '3% solid black']])).toThrow()
 })
diff --git a/src/__tests__/borderRight.js b/src/__tests__/borderRight.js
deleted file mode 100644
index 4aab147..0000000
--- a/src/__tests__/borderRight.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import transformCss from '..'
-
-it('transforms border none', () => {
-  expect(transformCss([['border-right', 'none']])).toEqual({
-    borderRightWidth: 0,
-    borderRightColor: 'black',
-  })
-})
-
-it('transforms border shorthand in other order', () => {
-  expect(transformCss([['border-right', '#f00 2px']])).toEqual({
-    borderRightWidth: 2,
-    borderRightColor: '#f00',
-  })
-})
-
-it('transforms border shorthand missing width', () => {
-  expect(transformCss([['border-right', '#f00']])).toEqual({
-    borderRightWidth: 1,
-    borderRightColor: '#f00',
-  })
-})
-
-it('transforms border shorthand missing color', () => {
-  expect(transformCss([['border-right', '2px']])).toEqual({
-    borderRightWidth: 2,
-    borderRightColor: 'black',
-  })
-})
-
-it('transforms border for unsupported units', () => {
-  expect(transformCss([['border-right', '3em black']])).toEqual({
-    borderRightWidth: '3em',
-    borderRightColor: 'black',
-  })
-})
-
-it('does not transform border with percentage width', () => {
-  expect(() => transformCss([['border-right', '3% black']])).toThrow()
-})
-
-it('does not transform style', () => {
-  expect(() => transformCss([['border-right', '2px dashed #f00']])).toThrow()
-  expect(() => transformCss([['border-right', 'dashed #f00']])).toThrow()
-  expect(() => transformCss([['border-right', '2px dashed']])).toThrow()
-  expect(() => transformCss([['border-right', 'dashed']])).toThrow()
-})
diff --git a/src/__tests__/units.js b/src/__tests__/units.js
index 1ce1f60..2370c53 100644
--- a/src/__tests__/units.js
+++ b/src/__tests__/units.js
@@ -66,7 +66,7 @@ describe.each([
       borderStyle: 'dashed',
     })
 
-    expect(transformCss([['border', value]])).toEqual({
+    expect(transformCss([['border', `${value} solid`]])).toEqual({
       borderTopWidth: value,
       borderRightWidth: value,
       borderBottomWidth: value,
diff --git a/src/transforms/border.js b/src/transforms/border.js
index 64956af..b6a3168 100644
--- a/src/transforms/border.js
+++ b/src/transforms/border.js
@@ -11,16 +11,25 @@ const BORDER_STYLE = regExpToken(/^(solid|dashed|dotted)$/)
 
 const defaultBorderWidth = 1
 const defaultBorderColor = 'black'
-const defaultBorderStyle = 'solid'
 
-const baseParse = (tokenStream, allowBorderStyle) => {
+export default tokenStream => {
   let borderWidth
   let borderColor
   let borderStyle
 
   if (tokenStream.matches(NONE)) {
     tokenStream.expectEmpty()
-    return { borderWidth: 0, borderColor: 'black', borderStyle: 'solid' }
+    return {
+      borderTopWidth: 0,
+      borderRightWidth: 0,
+      borderBottomWidth: 0,
+      borderLeftWidth: 0,
+      borderTopColor: 'black',
+      borderRightColor: 'black',
+      borderBottomColor: 'black',
+      borderLeftColor: 'black',
+      borderStyle: 'solid',
+    }
   }
 
   let partsParsed = 0
@@ -48,22 +57,11 @@ const baseParse = (tokenStream, allowBorderStyle) => {
   if (borderWidth === undefined) borderWidth = defaultBorderWidth
   if (borderColor === undefined) borderColor = defaultBorderColor
   if (borderStyle === undefined) {
-    borderStyle = defaultBorderStyle
-  } else if (!allowBorderStyle) {
     throw new Error(
-      'Setting a border style on a single border side is not supported'
+      'You must define a border style in the border shorthand (e.g. solid)'
     )
   }
 
-  return { borderWidth, borderColor, borderStyle }
-}
-
-export default tokenStream => {
-  // eslint-disable-next-line prefer-const
-  let { borderWidth, borderColor, borderStyle } = baseParse(tokenStream, true)
-
-  if (borderStyle === undefined) borderStyle = defaultBorderStyle
-
   return {
     borderTopWidth: borderWidth,
     borderRightWidth: borderWidth,
@@ -76,23 +74,3 @@ export default tokenStream => {
     borderStyle,
   }
 }
-
-export const borderTop = tokenStream => {
-  const { borderWidth, borderColor } = baseParse(tokenStream, false)
-  return { borderTopWidth: borderWidth, borderTopColor: borderColor }
-}
-
-export const borderRight = tokenStream => {
-  const { borderWidth, borderColor } = baseParse(tokenStream, false)
-  return { borderRightWidth: borderWidth, borderRightColor: borderColor }
-}
-
-export const borderBottom = tokenStream => {
-  const { borderWidth, borderColor } = baseParse(tokenStream, false)
-  return { borderBottomWidth: borderWidth, borderBottomColor: borderColor }
-}
-
-export const borderLeft = tokenStream => {
-  const { borderWidth, borderColor } = baseParse(tokenStream, false)
-  return { borderLeftWidth: borderWidth, borderLeftColor: borderColor }
-}

From e5e0e168e3fefd12cc9de146cf6a6a2b61879a40 Mon Sep 17 00:00:00 2001
From: Jacob Parker <jacobparker1992@gmail.com>
Date: Sat, 16 Nov 2019 18:24:34 +0000
Subject: [PATCH 3/3] fix build

---
 src/transforms/index.js | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/src/transforms/index.js b/src/transforms/index.js
index 0a50d86..66320ae 100644
--- a/src/transforms/index.js
+++ b/src/transforms/index.js
@@ -7,12 +7,7 @@ import {
   PERCENT,
   AUTO,
 } from '../tokenTypes'
-import border, {
-  borderTop,
-  borderRight,
-  borderBottom,
-  borderLeft,
-} from './border'
+import border from './border'
 import boxShadow from './boxShadow'
 import flex from './flex'
 import flexFlow from './flexFlow'
@@ -60,12 +55,8 @@ const textShadowOffset = tokenStream => ({
 export default {
   background,
   border,
-  borderBottom,
   borderColor,
-  borderLeft,
   borderRadius,
-  borderRight,
-  borderTop,
   borderWidth,
   boxShadow,
   flex,