# File Tree

<style>
  pre:not(#LOG) {
    background-color:  rgba(240,240,250,1);
    padding: 6px;
    width: 800px;
  }
  
  #LOG {
    display: inline-block; 
    overflow:auto; 
    width: 800px; 
    height: 300px; 
    margin: 0px; 
    vertical-align: top; 
    padding: 5px; 
    background:rgba(240,240,240,0.8);
    border: 1px dashed gray;
  }
  
</style>


<script>
import {hideHiddenElements, toggleLayer, showVariable, runExampleButton} from "src/client/essay.js"
""
import "src/client/ContextJS/src/async.js"

</script>


```javascript {.Log .Hidden}
var logComonent  = lively.query(this, "#LOG")

function log(s) {
   logComonent.textContent += s +"\n" 
}
function clearLog() {
  logComonent.textContent = ""
}
clearLog()
```

<div id="examplespace" style="position:sticky; top: 10px;
width: 840px; height: 1px; left: 850px; z-index: 1000">
  <pre id="LOG"></pre>
</div>


Traverse directories ansync with promises:

```javascript {.TreeDef .NoResult}
import * as Layers from 'src/client/ContextJS/src/Layers.js'

    


class FileTree {
  constructor(base) {
    this.base = base
  }
  async walk(relative) {
    log("tree " + relative )
    log("" + " Layers: " + Layers.currentLayers().map(ea => ea.name).join(" "))
    var url = this.base + relative
    debugger
    var result = await fetch(url, { 
      method: "OPTIONS"
    }).then(r => r.json())  
    if (result.contents) {
      for(var ea of result.contents) {
        if (ea.type == "directory") {
          this.walk(relative + "/" + ea.name).then(resp => {
            ea.contents = resp.contents
          })
        }
      }
    }
    return result
  }
}
```

```javascript {.TreeRun}
new FileTree(lively4url).walk("/doc")
```

<script>runExampleButton("Run", this, ["Log", "TreeDef", "TreeRun"])</script>

The result is created asynchronously modified as the tree is walked.  

The `walk` method does not wait for its recursive child calls to finish.

Traverse directories ansync with waiting on promises, forcing it to the domain structure....:

```javascript  {.TreeDef2 .NoResult}
class FileTree {
  constructor(base) {
    this.base = base
  }
  async walk(relative) {
    log("tree " + relative)
    var url = this.base + relative
    var result = await fetch(url, { 
      method: "OPTIONS"
    }).then(r => r.json())  
    if (result.contents) {
      for(var ea of result.contents) {
        if (ea.type == "directory") {
          ea.contents = (await this.walk(relative + "/" + ea.name)).contents
        }
      }
    }
    return result
  }
}
```

```javascript {.TreeRun2}
new FileTree(lively4url).walk("/doc")
```

<script>runExampleButton("Run", this, ["Log", "TreeDef2", "TreeRun2"])</script>

The log of "await" keyword forces the tree walking algorithm to traverse the directory in depth-first order, resulting in a tree that resembles the domain structure.

But forcing the algorithm into sync behavior to better understand it is a different approach....

```javascript {.TimeWalkDef}

cop.layer(self, "LogPromise").refineClass(Promise, {
  constructorHook(...args) {
    log("new Promise Layers: " + Layers.currentLayers().map(ea => ea.name).join(" "))
    return cop.proceed(...args)  
  },

  then(...args) {
    log("then " +  Layers.currentLayers().map(ea => ea.name).join(" "))
    var result = cop.proceed(...args)
    return result
  }
})




cop.layer(self, "TimeWalkLayer").refineClass(FileTree, {
  walk(...args) {
    var start = performance.now()
    log("start " + start)
    var result = cop.proceed(...args)
    // result.then(() => {
    //   log("time " + (start - performance.now()) +"ms")
    // })
    return result
  }
})
```


```javascript {.TimeWalkRun}

cop.withLayers([LogPromise, TimeWalkLayer], () => {
  new FileTree(lively4url).walk("/doc")
})
```

<script>runExampleButton("Run", this, ["Log", "TreeDef", "TimeWalkDef", "TimeWalkRun"])</script>

## Walk Pure Promises


```javascript  {.TreeDefPromise .NoResult}
class FileTree {
  constructor(base) {
    this.base = base
  }
  walk(relative) {
    log("promise tree " + relative)
    var url = this.base + relative
    return fetch(url, { 
      method: "OPTIONS"
    }).then(r => r.json()).then( result => {
      if (result.contents) {
        for(var ea of result.contents) {
          if (ea.type == "directory") {
            this.walk(relative + "/" + ea.name).then( tree => {
              ea.contents = tree.contents
            })
          }
        }
      }
      return result
    })
  }
}
```


<script>runExampleButton("Run", this, ["Log", "TreeDefPromise", "TimeWalkDef", "TimeWalkRun"])</script>



<script>hideHiddenElements(this)</script>
