From ac78af2aa00e4cd86ad71798036ab84f4def0db5 Mon Sep 17 00:00:00 2001
From: Blake Dietz <blakedietz@gmail.com>
Date: Thu, 14 Feb 2019 16:22:56 -0700
Subject: [PATCH] fix(File tree): Only allow markdown files in the tree (#27)

* perf(tag-tree-data-provider.ts): Scan files asynchronously (#24)
* Scan files asynchronously
* Only include markdown files
* docs(CHANGELOG.md): Automatically publish changes to CHANGELOG.md (#25)

Automatically publish changes to CHANGELOG.md
---
 .circleci/CHANGELOG.md        |  0
 package-lock.json             | 21 ++++++++
 package.json                  | 33 ++++++-------
 src/tag-tree-data-provider.ts | 93 ++++++++++++++---------------------
 4 files changed, 74 insertions(+), 73 deletions(-)
 create mode 100644 .circleci/CHANGELOG.md

diff --git a/.circleci/CHANGELOG.md b/.circleci/CHANGELOG.md
new file mode 100644
index 0000000..e69de29
diff --git a/package-lock.json b/package-lock.json
index d8e4e80..18cdfcc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -165,6 +165,18 @@
 				"any-observable": "^0.3.0"
 			}
 		},
+		"@semantic-release/changelog": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@semantic-release/changelog/-/changelog-3.0.2.tgz",
+			"integrity": "sha1-sJqODQcu9U0rx6XIL2ES3DyK6F0=",
+			"dev": true,
+			"requires": {
+				"@semantic-release/error": "^2.1.0",
+				"aggregate-error": "^2.0.0",
+				"fs-extra": "^7.0.0",
+				"lodash": "^4.17.4"
+			}
+		},
 		"@semantic-release/commit-analyzer": {
 			"version": "6.1.0",
 			"resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-6.1.0.tgz",
@@ -450,6 +462,15 @@
 			"integrity": "sha512-9spv6SklidqxevvZyOUGjZVz4QRXGu2dNaLyXIFzFYZW0AGDykzPRIUFJXTlQXyfzAucddwTcGtJNim8zqSOPA==",
 			"dev": true
 		},
+		"@types/recursive-readdir": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz",
+			"integrity": "sha1-s5zVR0/Vjqcn/kNNXGi3ogupEhw=",
+			"dev": true,
+			"requires": {
+				"@types/node": "*"
+			}
+		},
 		"@types/shelljs": {
 			"version": "0.8.2",
 			"resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.2.tgz",
diff --git a/package.json b/package.json
index d211b8b..a848c69 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
     "watch": "tsc -watch -p ./"
   },
   "devDependencies": {
+    "@semantic-release/changelog": "^3.0.2",
     "@semantic-release/commit-analyzer": "^6.1.0",
     "@semantic-release/exec": "^3.3.2",
     "@semantic-release/git": "^7.0.8",
@@ -34,6 +35,7 @@
     "@types/debounce": "^1.2.0",
     "@types/jest": "^23.3.12",
     "@types/node": "^10.12.18",
+    "@types/recursive-readdir": "2.2.0",
     "commitizen": "^3.0.5",
     "cz-conventional-changelog": "^2.1.0",
     "husky": "^1.3.1",
@@ -67,10 +69,10 @@
     }
   },
   "icon": "images/icon.png",
-	"galleryBanner": {
-		"color": "#073642",
-		"theme": "dark"
-	},
+  "galleryBanner": {
+    "color": "#073642",
+    "theme": "dark"
+  },
   "publisher": "vscode-nested-tags",
   "config": {
     "loglevel": "verbose",
@@ -91,20 +93,15 @@
     ]
   },
   "release": {
-    "verifyConditions": [
-      "semantic-release-vsce",
-      "@semantic-release/github"
-    ],
-    "prepare": {
-      "path": "semantic-release-vsce",
-      "packageVsix": "vscode-nested-tags.vsix"
-    },
-    "publish": [
-      "semantic-release-vsce",
-      {
-        "path": "@semantic-release/github",
-        "assets": "vscode-nested-tags.vsix"
-      }
+    "plugins": [
+      ["semantic-release-vsce", {
+          "path": "@semantic-release/github",
+          "assets": "vscode-nested-tags.vsix"
+      }],
+      "@semantic-release/github",
+      ["@semantic-release/changelog", {
+        "changelogFile": "./CHANGELOG.md"
+      }]
     ]
   }
 }
diff --git a/src/tag-tree-data-provider.ts b/src/tag-tree-data-provider.ts
index fdab08c..6b2dc02 100644
--- a/src/tag-tree-data-provider.ts
+++ b/src/tag-tree-data-provider.ts
@@ -1,6 +1,6 @@
 import { debounce } from "debounce";
 import * as fs from "fs";
-import * as path from "path";
+import * as recursiveReadDir from "recursive-readdir";
 import * as vscode from "vscode";
 import { setsAreEqual } from "./sets";
 import { FileNode, fileNodeSort } from "./tag-tree/file-node";
@@ -25,13 +25,9 @@ class TagTreeDataProvider
   readonly onDidChangeTreeData: vscode.Event< TagNode | FileNode | null> = this._onDidChangeTreeData.event;
 
   constructor() {
-    // vscode.window.onDidChangeActiveTextEditor(() => this.onActiveEditorChanged());
-    // vscode.workspace.onDidSaveTextDocument((e) => {
-    //   console.log(e);
-    // });
-
-    // Register the extension to events of interest
-    // Debounce to improve performance. Otherwise a file read would occur during each of the user's change to the document.
+    /* Register the extension to events of interest
+     * Debounce to improve performance. Otherwise a file read would occur during each of the user's change to the document.
+     */
     vscode.workspace.onDidChangeTextDocument(debounce((e: vscode.TextDocumentChangeEvent) => this.onDocumentChanged(e), 500));
     vscode.workspace.onWillSaveTextDocument((e) => {
       this.onWillSaveTextDocument(e);
@@ -39,21 +35,23 @@ class TagTreeDataProvider
 
     this.tagTree = new TagTree();
 
-    // Add all files in the current workspace folder to the tag tree
-    // @ts-ignore
-    const workspaceFolder = vscode.workspace.workspaceFolders[0].uri.fsPath;
-    const files = [];
-
-    // TODO: (bdietz) - this is probably going to be pretty slow
-    for(const filePath of this.walkFileSystemSync(workspaceFolder)) {
-    const fileInfo = this.getTagsFromFileOnFileSystem(filePath);
-      if (fileInfo.tags.size > 0) {
-        files.push(fileInfo);
-      }
-    }
-
-    for (const fileInfo of files) {
-      this.tagTree.addFile(fileInfo.filePath, [...fileInfo.tags], fileInfo.filePath);
+    /* Add all files in the current workspace folder to the tag tree
+     * @ts-ignore
+     */
+    if (vscode.workspace.workspaceFolders!.length > 0) {
+      vscode.workspace.workspaceFolders!.forEach(workspaceFolder => {
+        const { fsPath } = workspaceFolder.uri;
+        recursiveReadDir(fsPath, ["!*.md"], (error: any, files: any) => {
+            for (const filePath of files) {
+                const fileInfo = this.getTagsFromFileOnFileSystem(filePath);
+                if (fileInfo.tags.size > 0) {
+                  this.tagTree.addFile(fileInfo.filePath, [...fileInfo.tags], fileInfo.filePath);
+                }
+            }
+
+            this._onDidChangeTreeData.fire();
+          });
+      });
     }
   }
 
@@ -114,7 +112,7 @@ class TagTreeDataProvider
    * @param changeEvent
    */
   private onWillSaveTextDocument(changeEvent: vscode.TextDocumentWillSaveEvent) {
-    if (changeEvent.document.isDirty) {
+    if (changeEvent.document.isDirty && changeEvent.document.languageId === "markdown") {
       const filePath = changeEvent.document.fileName;
       const fileInfo = this.getTagsFromFileOnFileSystem(filePath);
       const tagsInTreeForFile = this.tagTree.getTagsForFile(filePath);
@@ -132,37 +130,21 @@ class TagTreeDataProvider
    */
   private onDocumentChanged(changeEvent: vscode.TextDocumentChangeEvent): void {
     const filePath = changeEvent.document.fileName;
-    const fileInfo = this.getTagsFromFileText(changeEvent.document.getText(), filePath);
-    const tagsInTreeForFile = this.tagTree.getTagsForFile(filePath);
-    const isUpdateNeeded = !setsAreEqual(fileInfo.tags, tagsInTreeForFile);
-    /*
-     * This could be potentially performance intensive due to the number of changes that could
-     * be made to a document and how large the document is. There will definitely need to be some
-     * work done around TagTree to make sure that the code
-     */
-    if (isUpdateNeeded) {
-      this.tagTree.deleteFile(filePath);
-      this.tagTree.addFile(filePath, [...fileInfo.tags.values()], filePath);
-      // TODO: (bdietz) - this._onDidChangeTreeData.fire(specificNode?)
-      this._onDidChangeTreeData.fire();
-    }
-  }
-
- /**
-  * NOTE: Stole this from https://gist.github.com/luciopaiva/4ba78a124704007c702d0293e7ff58dd.
-  *
-  * Recursively walk through the file system synchronously.
-  */
-  private *walkFileSystemSync(dir: string): IterableIterator<string> {
-    const files = fs.readdirSync(dir);
-
-    for (const file of files) {
-      const pathToFile = path.join(dir, file);
-      const isDirectory = fs.statSync(pathToFile).isDirectory();
-      if (isDirectory) {
-        yield* this.walkFileSystemSync(pathToFile);
-      } else {
-        yield pathToFile;
+    // If the file has been saved and the file is a markdown file allow for making changes to the tag tree
+    if (filePath !== undefined && changeEvent.document.languageId === "markdown") {
+      const fileInfo = this.getTagsFromFileText(changeEvent.document.getText(), filePath);
+      const tagsInTreeForFile = this.tagTree.getTagsForFile(filePath);
+      const isUpdateNeeded = !setsAreEqual(fileInfo.tags, tagsInTreeForFile);
+      /*
+      * This could be potentially performance intensive due to the number of changes that could
+      * be made to a document and how large the document is. There will definitely need to be some
+      * work done around TagTree to make sure that the code
+      */
+      if (isUpdateNeeded) {
+        this.tagTree.deleteFile(filePath);
+        this.tagTree.addFile(filePath, [...fileInfo.tags.values()], filePath);
+        // TODO: (bdietz) - this._onDidChangeTreeData.fire(specificNode?)
+        this._onDidChangeTreeData.fire();
       }
     }
   }
@@ -210,6 +192,7 @@ class TagTreeDataProvider
             .split(',');
             return {...accumulator, tags: new Set([...accumulator.tags,...tagsToAdd])};
           }
+
           return accumulator;
         }, { tags: new Set(), filePath });
   }