Repository: gcanti/fp-ts
Pull request #679 (2018-12-23 16:04:34)

Bug Fix: fix `Tree.drawTree`


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2feece9..f7034017 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,11 @@
 **Note**: Gaps between patch versions are faulty/broken releases. **Note**: A feature tagged as Experimental is in a
 high state of flux, you're at risk of it changing without notice.
 
+# 1.12.2
+
+- **Bug Fix**
+  - fix `Tree.drawTree` (@gcanti)
+
 # 1.12.1
 
 - **Bug Fix**
diff --git a/README.md b/README.md
index 177bc554..9f85d02c 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,8 @@ The stable version is tested against TypeScript 3.2.2, but should run with TypeS
 
 You can use [unknown-ts](https://github.com/gcanti/unknown-ts) as a polyfill.
 
+**Note**. Make sure to always have a single version of `fp-ts` installed in your project. Multiple versions are known to cause `tsc` to hang during compilation. You can check the versions currently installed using `npm ls fp-ts` (make sure there's a single version and all the others are marked as `deduped`).
+
 # Ecosystem
 
 - [io-ts](https://github.com/gcanti/io-ts) - TypeScript compatible runtime type system for IO validation
diff --git a/docs/Tree.md b/docs/Tree.md
index 8909dc0d..f77882bd 100644
--- a/docs/Tree.md
+++ b/docs/Tree.md
@@ -126,9 +126,9 @@ Neat 2-dimensional drawing of a tree
 _Example_
 
 ```ts
-import { Tree, drawTree } from 'fp-ts/lib/Tree'
+import { Tree, drawTree, tree } from 'fp-ts/lib/Tree'
 
-const fa = new Tree('a', [new Tree('b', []), new Tree('c', []), new Tree('d', [new Tree('e', []), new Tree('f', [])])])
+const fa = new Tree('a', [tree.of('b'), tree.of('c'), new Tree('d', [tree.of('e'), tree.of('f')])])
 
 assert.strictEqual(
   drawTree(fa),
diff --git a/package.json b/package.json
index 3beea79c..00d1021f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "fp-ts",
-  "version": "1.12.1",
+  "version": "1.12.2",
   "description": "Functional programming in TypeScript",
   "files": [
     "lib"
diff --git a/src/Tree.ts b/src/Tree.ts
index 3b68891a..754384fb 100644
--- a/src/Tree.ts
+++ b/src/Tree.ts
@@ -1,5 +1,5 @@
 import { Applicative } from './Applicative'
-import { getSetoid as getArraySetoid, traverse as arrayTraverse } from './Array'
+import { getSetoid as getArraySetoid, traverse as arrayTraverse, empty } from './Array'
 import { Comonad1 } from './Comonad'
 import { Foldable2v1 } from './Foldable2v'
 import { concat, identity, toString } from './function'
@@ -80,7 +80,7 @@ const map = <A, B>(fa: Tree<A>, f: (a: A) => B): Tree<B> => {
 }
 
 const of = <A>(a: A): Tree<A> => {
-  return new Tree(a, [])
+  return new Tree(a, empty)
 }
 
 const ap = <A, B>(fab: Tree<(a: A) => B>, fa: Tree<A>): Tree<B> => {
@@ -163,58 +163,38 @@ export const tree: Monad1<URI> & Foldable2v1<URI> & Traversable2v1<URI> & Comona
   extend
 }
 
-type Line<A> = {
-  value: A
-  indentation: number
-  isLast: boolean
-}
-
-const asIndentedLines = <A>(indentation: number, forest: Forest<A>): Array<Line<A>> => {
-  const r: Array<Line<A>> = []
+const draw = (indentation: string, forest: Forest<string>): string => {
+  let r: string = ''
   const len = forest.length
-  let tree: Tree<A>
+  let tree: Tree<string>
   for (let i = 0; i < len; i++) {
     tree = forest[i]
-    r.push({ value: tree.value, indentation, isLast: i === len - 1 })
-    r.push(...asIndentedLines(indentation + 1, tree.forest))
-  }
-  return r
-}
-
-const indentation = '   '
-const getIndentation = (n: number): string => {
-  let r = ''
-  for (let i = 0; i < n; i++) {
-    r += indentation
+    const isLast = i === len - 1
+    r += indentation + (isLast ? '└' : '├') + '─ ' + tree.value
+    r += draw(indentation + (len > 1 && !isLast ? '│  ' : '   '), tree.forest)
   }
   return r
 }
 
-const drawLine = (line: Line<string>): string => {
-  return getIndentation(line.indentation) + (line.isLast ? '└' : '├') + '─ ' + line.value
-}
-
 /**
  * Neat 2-dimensional drawing of a forest
  * @function
  * @since 1.6.0
  */
 export const drawForest = (forest: Forest<string>): string => {
-  return asIndentedLines(0, forest)
-    .map(drawLine)
-    .join('\n')
+  return draw('\n', forest)
 }
 
 /**
  * Neat 2-dimensional drawing of a tree
  *
  * @example
- * import { Tree, drawTree } from 'fp-ts/lib/Tree'
+ * import { Tree, drawTree, tree } from 'fp-ts/lib/Tree'
  *
  * const fa = new Tree('a', [
- *   new Tree('b', []),
- *   new Tree('c', []),
- *   new Tree('d', [new Tree('e', []), new Tree('f', [])])
+ *   tree.of('b'),
+ *   tree.of('c'),
+ *   new Tree('d', [tree.of('e'), tree.of('f')])
  * ])
  *
  * assert.strictEqual(drawTree(fa), `a
@@ -228,7 +208,7 @@ export const drawForest = (forest: Forest<string>): string => {
  * @since 1.6.0
  */
 export const drawTree = (tree: Tree<string>): string => {
-  return tree.value + '\n' + drawForest(tree.forest)
+  return tree.value + drawForest(tree.forest)
 }
 
 /**


Test patch:
diff --git a/test/Tree.ts b/test/Tree.ts
index 4fc03a80..39bb243d 100644
--- a/test/Tree.ts
+++ b/test/Tree.ts
@@ -86,19 +86,57 @@ describe('Tree', () => {
   })
 
   it('drawTree', () => {
-    const fa = new Tree('a', [
+    const tree = new Tree('a', [])
+    assert.strictEqual(drawTree(tree), 'a')
+
+    const tree1 = new Tree('a', [
       new Tree('b', []),
       new Tree('c', []),
-      new Tree('d', [new Tree('e', []), new Tree('f', [])])
+      new Tree('d', [new Tree('e', []), new Tree('f', [])]),
+      new Tree('g', [])
     ])
     assert.strictEqual(
-      drawTree(fa),
+      drawTree(tree1),
       `a
 ├─ b
 ├─ c
+├─ d
+│  ├─ e
+│  └─ f
+└─ g`
+    )
+
+    const tree2 = new Tree('a', [new Tree('b', [new Tree('c', [])])])
+    assert.strictEqual(
+      drawTree(tree2),
+      `a
+└─ b
+   └─ c`
+    )
+
+    const tree3 = new Tree('a', [new Tree('b', [new Tree('c', [])]), new Tree('d', [new Tree('e', [])])])
+    assert.strictEqual(
+      drawTree(tree3),
+      `a
+├─ b
+│  └─ c
 └─ d
-   ├─ e
-   └─ f`
+   └─ e`
+    )
+
+    const tree4 = new Tree('a', [
+      new Tree('b', [new Tree('c', [new Tree('d', [])]), new Tree('e', [new Tree('f', [])])]),
+      new Tree('e', [])
+    ])
+    assert.strictEqual(
+      drawTree(tree4),
+      `a
+├─ b
+│  ├─ c
+│  │  └─ d
+│  └─ e
+│     └─ f
+└─ e`
     )
   })