From 6bc123d76bb9c17f247c4e64704fb50c4a99fd88 Mon Sep 17 00:00:00 2001 From: Maddy <12754347+MaddyDev@users.noreply.github.com> Date: Tue, 7 Apr 2020 15:55:53 -0700 Subject: [PATCH] Fix/open book spcl characters (#9888) * upgrade fast-glob that escapes them. * added tests * added test with brackets in bookPath --- extensions/notebook/package.json | 4 +- extensions/notebook/src/book/bookModel.ts | 2 +- .../notebook/src/test/book/book.test.ts | 66 ++++++++++++++++++ extensions/notebook/yarn.lock | 67 ++++++++++--------- 4 files changed, 105 insertions(+), 34 deletions(-) diff --git a/extensions/notebook/package.json b/extensions/notebook/package.json index 65d992242a..453d3a4045 100644 --- a/extensions/notebook/package.json +++ b/extensions/notebook/package.json @@ -42,7 +42,7 @@ "default": 5000, "description": "%notebook.maxTableRows.description%" }, - "notebook.trustedBooks":{ + "notebook.trustedBooks": { "type": "array", "default": [], "description": "%notebook.trustedBooks.description%", @@ -510,7 +510,7 @@ "@types/tar": "^4.0.3", "adm-zip": "^0.4.14", "error-ex": "^1.3.1", - "fast-glob": "^3.0.4", + "fast-glob": "^3.1.0", "figures": "^2.0.0", "fs-extra": "^5.0.0", "glob": "^7.1.1", diff --git a/extensions/notebook/src/book/bookModel.ts b/extensions/notebook/src/book/bookModel.ts index 55051766de..edd0009971 100644 --- a/extensions/notebook/src/book/bookModel.ts +++ b/extensions/notebook/src/book/bookModel.ts @@ -61,7 +61,7 @@ export class BookModel implements azdata.nb.NavigationProvider { maxDepth = undefined; } - let p: string = path.join(folderPath, '**', '_data', 'toc.yml').replace(/\\/g, '/'); + let p: string = path.posix.join(glob.escapePath(folderPath.replace(/\\/g, '/')), '**', '_data', 'toc.yml'); let tableOfContentPaths: string[] = await glob(p, { deep: maxDepth }); if (tableOfContentPaths.length > 0) { this._tableOfContentPaths = this._tableOfContentPaths.concat(tableOfContentPaths); diff --git a/extensions/notebook/src/test/book/book.test.ts b/extensions/notebook/src/test/book/book.test.ts index 5178aefa59..ba0a70929f 100644 --- a/extensions/notebook/src/test/book/book.test.ts +++ b/extensions/notebook/src/test/book/book.test.ts @@ -352,4 +352,70 @@ describe('BookTreeViewProviderTests', function () { } }); }); + + describe('BookTreeViewProvider.Commands', function (): void { + let rootFolderPath: string; + let tableOfContentsFile: string; + let bookTreeViewProvider: BookTreeViewProvider; + let appContext: AppContext; + + this.beforeAll(async () => { + rootFolderPath = path.join(os.tmpdir(), `BookTestData_${uuid.v4()}`); + let dataFolderPath = path.join(rootFolderPath, '_data'); + let contentFolderPath = path.join(rootFolderPath, 'content'); + let configFile = path.join(rootFolderPath, '_config.yml'); + tableOfContentsFile = path.join(dataFolderPath, 'toc.yml'); + let notebook2File = path.join(contentFolderPath, 'notebook2.ipynb'); + await fs.mkdir(rootFolderPath); + await fs.mkdir(dataFolderPath); + await fs.mkdir(contentFolderPath); + await fs.writeFile(configFile, 'title: Test Book'); + await fs.writeFile(tableOfContentsFile, '- title: Notebook1\n url: /notebook1\n- title: Notebook2\n url: /notebook2'); + await fs.writeFile(notebook2File, ''); + + const mockExtensionContext = new MockExtensionContext(); + appContext = new AppContext(mockExtensionContext, new ApiWrapper()); + bookTreeViewProvider = new BookTreeViewProvider(appContext.apiWrapper, [], mockExtensionContext, false, 'bookTreeView'); + let errorCase = new Promise((resolve, reject) => setTimeout(() => resolve(), 5000)); + await Promise.race([bookTreeViewProvider.initialized, errorCase.then(() => { throw new Error('BookTreeViewProvider did not initialize in time'); })]); + appContext = new AppContext(undefined, new ApiWrapper()); + }); + + it('should add book and initialize book on openBook', async () => { + should(bookTreeViewProvider.books.length).equal(0, 'Invalid books on initialize.'); + await bookTreeViewProvider.openBook(rootFolderPath); + should(bookTreeViewProvider.books.length).equal(1, 'Failed to initialize the book on open'); + }); + + it('should remove book on closeBook', async () => { + await bookTreeViewProvider.openBook(rootFolderPath); + should(bookTreeViewProvider.books.length).equal(1, 'Failed to initialize the book on open'); + await bookTreeViewProvider.closeBook(bookTreeViewProvider.books[0].bookItems[0]); + should(bookTreeViewProvider.books.length).equal(0, 'Failed to remove the book on close'); + }); + + it('should add book when bookPath contains special characters on openBook', async () => { + let rootFolderPath2 = path.join(os.tmpdir(), `BookTestData(1)_${uuid.v4()}`); + let dataFolderPath2 = path.join(rootFolderPath2, '_data'); + let contentFolderPath2 = path.join(rootFolderPath2, 'content'); + let configFile2 = path.join(rootFolderPath2, '_config.yml'); + let tableOfContentsFile2 = path.join(dataFolderPath2, 'toc.yml'); + let notebook2File2 = path.join(contentFolderPath2, 'notebook2.ipynb'); + await fs.mkdir(rootFolderPath2); + await fs.mkdir(dataFolderPath2); + await fs.mkdir(contentFolderPath2); + await fs.writeFile(configFile2, 'title: Test Book'); + await fs.writeFile(tableOfContentsFile2, '- title: Notebook1\n url: /notebook1\n- title: Notebook2\n url: /notebook2'); + await fs.writeFile(notebook2File2, ''); + + await bookTreeViewProvider.openBook(rootFolderPath2); + should(bookTreeViewProvider.books.length).equal(1, 'Failed to initialize the book on open'); + }); + + this.afterAll(async function (): Promise { + if (await exists(rootFolderPath)) { + await promisify(rimraf)(rootFolderPath); + } + }); + }); }); diff --git a/extensions/notebook/yarn.lock b/extensions/notebook/yarn.lock index 97b898627c..5f0489e4f1 100644 --- a/extensions/notebook/yarn.lock +++ b/extensions/notebook/yarn.lock @@ -41,25 +41,25 @@ "@phosphor/disposable" "^1.1.2" "@phosphor/signaling" "^1.2.2" -"@nodelib/fs.scandir@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz#7fa8fed654939e1a39753d286b48b4836d00e0eb" - integrity sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg== +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== dependencies: - "@nodelib/fs.stat" "2.0.1" + "@nodelib/fs.stat" "2.0.3" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.1", "@nodelib/fs.stat@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz#814f71b1167390cfcb6a6b3d9cdeb0951a192c14" - integrity sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw== +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== -"@nodelib/fs.walk@^1.2.1": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz#6a6450c5e17012abd81450eb74949a4d970d2807" - integrity sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ== +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== dependencies: - "@nodelib/fs.scandir" "2.1.1" + "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" "@phosphor/algorithm@^1.1.2": @@ -585,17 +585,17 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= -fast-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" - integrity sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg== +fast-glob@^3.1.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" + integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A== dependencies: - "@nodelib/fs.stat" "^2.0.1" - "@nodelib/fs.walk" "^1.2.1" - glob-parent "^5.0.0" - is-glob "^4.0.1" - merge2 "^1.2.3" + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" micromatch "^4.0.2" + picomatch "^2.2.1" fast-json-stable-stringify@^2.0.0: version "2.0.0" @@ -670,10 +670,10 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-parent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" - integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== +glob-parent@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== dependencies: is-glob "^4.0.1" @@ -975,10 +975,10 @@ md5@^2.1.0: crypt "~0.0.1" is-buffer "~1.1.1" -merge2@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.4.tgz#c9269589e6885a60cf80605d9522d4b67ca646e3" - integrity sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A== +merge2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" + integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== micromatch@^4.0.2: version "4.0.2" @@ -1169,6 +1169,11 @@ picomatch@^2.0.5: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== +picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"