From 8954327aa96d06b77f8d53efa08bee0958c79137 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Mon, 7 Jan 2019 23:40:36 +0800 Subject: [PATCH] refactor: migrate utils to TS --- package.json | 2 + packages/pjax/index.d.ts | 7 +- src/utils/{DOMHelper.js => DOMHelper.ts} | 67 ++++++++++++------- .../{GitHubHelper.js => GitHubHelper.ts} | 60 ++++++++++++++--- src/utils/{URLHelper.js => URLHelper.ts} | 9 +-- .../{configHelper.js => configHelper.ts} | 18 +++-- src/utils/{cx.js => cx.ts} | 4 +- src/utils/general.js | 17 ----- src/utils/general.ts | 12 ++++ src/utils/{keyHelper.js => keyHelper.ts} | 14 ++-- .../{storageHelper.js => storageHelper.ts} | 4 +- src/utils/{treeParser.js => treeParser.ts} | 45 +++++++++---- tsconfig.json | 6 +- yarn.lock | 24 +++++++ 14 files changed, 197 insertions(+), 92 deletions(-) rename src/utils/{DOMHelper.js => DOMHelper.ts} (83%) rename src/utils/{GitHubHelper.js => GitHubHelper.ts} (60%) rename src/utils/{URLHelper.js => URLHelper.ts} (89%) rename src/utils/{configHelper.js => configHelper.ts} (58%) rename src/utils/{cx.js => cx.ts} (79%) delete mode 100644 src/utils/general.js create mode 100644 src/utils/general.ts rename src/utils/{keyHelper.js => keyHelper.ts} (81%) rename src/utils/{storageHelper.js => storageHelper.ts} (73%) rename src/utils/{treeParser.js => treeParser.ts} (65%) diff --git a/package.json b/package.json index 8a89f14..1520f2e 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "react-dom": "^16.4.0" }, "devDependencies": { + "@types/chrome": "^0.0.77", + "@types/nprogress": "^0.0.29", "@types/react": "^16.7.18", "@types/react-dom": "^16.0.11", "awesome-typescript-loader": "^5.2.1", diff --git a/packages/pjax/index.d.ts b/packages/pjax/index.d.ts index 1e78099..c02dac4 100644 --- a/packages/pjax/index.d.ts +++ b/packages/pjax/index.d.ts @@ -76,7 +76,7 @@ declare class Pjax { * @param {string} href * @param {Pjax.IOptions} options */ - loadUrl(href: string, options?: Pjax.IOptions): void; + loadUrl(href: string, options?: Partial): void; /** * Called after all switches complete (even async). @@ -179,6 +179,11 @@ declare namespace Pjax { requestParams?: IRequestParams[]; formData?: FormData; } + + /** + * Cache accessed pages + */ + forceCache?: boolean } export type Switch = (oldEl: Element, newEl: Element, options?: IOptions, switchesOptions?: StringKeyedObject) => void; diff --git a/src/utils/DOMHelper.js b/src/utils/DOMHelper.ts similarity index 83% rename from src/utils/DOMHelper.js rename to src/utils/DOMHelper.ts index 28b2167..73d7517 100644 --- a/src/utils/DOMHelper.js +++ b/src/utils/DOMHelper.ts @@ -2,8 +2,8 @@ * this helper helps manipulating DOM */ -import PJAX from 'pjax' -import NProgress from 'nprogress' +import * as PJAX from 'pjax' +import * as NProgress from 'nprogress' NProgress.configure({ showSpinner: false }) @@ -11,7 +11,7 @@ NProgress.configure({ showSpinner: false }) * if should show gitako, then move body right to make space for showing gitako * otherwise, hide the space */ -function setBodyIndent(shouldShowGitako) { +function setBodyIndent(shouldShowGitako: boolean) { const spacingClassName = 'with-gitako-spacing' if (shouldShowGitako) { document.body.classList.add(spacingClassName) @@ -20,7 +20,7 @@ function setBodyIndent(shouldShowGitako) { } } -function $(selector, existCallback, otherwise) { +function $(selector: string, existCallback?: (element: Element) => any, otherwise?: () => any) { const element = document.querySelector(selector) if (element) { return existCallback ? existCallback(element) : element @@ -40,12 +40,19 @@ function getBranches() { } function getCurrentBranch() { - const selectedBranchButtonSelector = '.repository-content > .file-navigation > .branch-select-menu > button' - const branchNameFromButtonElement = $(selectedBranchButtonSelector, element => element.title.trim()) + const selectedBranchButtonSelector = + '.repository-content > .file-navigation > .branch-select-menu > button' + const branchNameFromButtonElement = $( + selectedBranchButtonSelector, + (element: HTMLButtonElement) => element.title.trim() + ) if (branchNameFromButtonElement) return branchNameFromButtonElement - const selectedBranchSelector = '.select-menu.branch-select-menu .select-menu-modal .select-menu-list .select-menu-item.selected svg.select-menu-item-icon + span' - const branchNameFromSelectElement = $(selectedBranchSelector, element => element.textContent.trim()) + const selectedBranchSelector = + '.select-menu.branch-select-menu .select-menu-modal .select-menu-list .select-menu-item.selected svg.select-menu-item-icon + span' + const branchNameFromSelectElement = $(selectedBranchSelector, element => + element.textContent.trim() + ) if (branchNameFromSelectElement) return branchNameFromSelectElement } @@ -78,9 +85,8 @@ function scrollToRepoContent() { /** * scroll to index-th element in the list - * @param {number} index index of node item in the list */ -function scrollToNodeElement(index) { +function scrollToNodeElement(index: number) { const nodeElementSelector = '.node-item' const nodeElements = document.querySelectorAll(nodeElementSelector) const targetElement = nodeElements[index] @@ -98,10 +104,10 @@ const pjax = new PJAX({ scrollTo: false, analytics: false, cacheBust: false, - forceCache: true, -}) + forceCache: true, // TODO: merge namespace, add forceCache +} as any) -function loadWithPJAX(URL) { +function loadWithPJAX(URL: string) { NProgress.start() pjax.loadUrl(URL, { scrollTo: 0 }) } @@ -130,9 +136,11 @@ const PAGE_TYPES = { function getCurrentPageType() { const blobWrapperSelector = '.repository-content .file .blob-wrapper table' const readmeSelector = '.repository-content .readme' - return $(blobWrapperSelector, () => PAGE_TYPES.RAW_TEXT) - || $(readmeSelector, () => PAGE_TYPES.RENDERED) - || PAGE_TYPES.OTHERS + return ( + $(blobWrapperSelector, () => PAGE_TYPES.RAW_TEXT) || + $(readmeSelector, () => PAGE_TYPES.RENDERED) || + PAGE_TYPES.OTHERS + ) } export const REPO_TYPE_PRIVATE = 'private' @@ -169,7 +177,7 @@ function attachCopyFileBtn() { * @param {element} copyFileBtn * @param {string} text */ - function setTempCopyFileBtnText(copyFileBtn, text) { + function setTempCopyFileBtnText(copyFileBtn: HTMLButtonElement, text: string) { copyFileBtn.innerText = text window.setTimeout(() => (copyFileBtn.innerText = 'Copy file'), 1000) } @@ -195,7 +203,7 @@ function attachCopyFileBtn() { setTempCopyFileBtnText(copyFileBtn, 'Copy failed!') } }) - btnGroup.insertBefore(copyFileBtn, btnGroups.lastChild) + btnGroup.insertBefore(copyFileBtn, btnGroup.lastChild) }) } } @@ -205,7 +213,7 @@ function attachCopyFileBtn() { * @param {element} element * @returns {boolean} whether copy is successful */ -function copyElementContent(element) { +function copyElementContent(element: Element) { window.getSelection().removeAllRanges() const range = document.createRange() range.selectNode(element) @@ -223,7 +231,7 @@ function copyElementContent(element) { * TODO: 'reactify' it */ function createClippy() { - function setTempClippyIconFeedback(clippy, type) { + function setTempClippyIconFeedback(clippy: Element, type: 'success' | 'fail') { const tempIconClassName = type === 'success' ? 'success' : 'fail' clippy.classList.add(tempIconClassName) window.setTimeout(() => { @@ -262,12 +270,13 @@ function createClippy() { const clippy = createClippy() -let currentCodeSnippetElement +let currentCodeSnippetElement: Element function attachCopySnippet() { const readmeSelector = '.repository-content #readme article' return $(readmeSelector, readmeElement => - readmeElement.addEventListener('mouseover', ({ target }) => { + readmeElement.addEventListener('mouseover', e => { // only move clippy when mouse is over a new snippet(
)
+      const target = e.target as Element
       if (target.nodeName === 'PRE') {
         if (currentCodeSnippetElement !== target) {
           currentCodeSnippetElement = target
@@ -291,12 +300,12 @@ function attachCopySnippet() {
  */
 function focusFileExplorer() {
   const sideBarContentSelector = '.gitako-side-bar .file-explorer'
-  $(sideBarContentSelector, sideBarElement => sideBarElement.focus())
+  $(sideBarContentSelector, (sideBarElement: HTMLElement) => sideBarElement.focus())
 }
 
 function focusSearchInput() {
   const searchInputSelector = '.search-input'
-  $(searchInputSelector, searchInputElement => {
+  $(searchInputSelector, (searchInputElement: HTMLElement) => {
     if (document.activeElement !== searchInputElement) {
       searchInputElement.focus()
     }
@@ -309,14 +318,20 @@ function focusSearchInput() {
  */
 function clickOnNodeElement(index = 0) {
   const nodeElementSelector = '.node-item'
-  const nodeElements = document.querySelectorAll(nodeElementSelector)
+  const nodeElements: NodeListOf = document.querySelectorAll(nodeElementSelector)
   nodeElements[index].click()
 }
 
 /**
  * a combination of few above functions
  */
-function decorateGitHubPageContent({ copyFileButton, copySnippetButton }) {
+function decorateGitHubPageContent({
+  copyFileButton,
+  copySnippetButton,
+}: {
+  copyFileButton: boolean
+  copySnippetButton: boolean
+}) {
   if (copyFileButton) attachCopyFileBtn()
   if (copySnippetButton) attachCopySnippet()
 }
diff --git a/src/utils/GitHubHelper.js b/src/utils/GitHubHelper.ts
similarity index 60%
rename from src/utils/GitHubHelper.js
rename to src/utils/GitHubHelper.ts
index 61698d9..8c92102 100644
--- a/src/utils/GitHubHelper.js
+++ b/src/utils/GitHubHelper.ts
@@ -4,16 +4,24 @@ export const BAD_CREDENTIALS = 'Bad credentials'
 export const API_RATE_LIMIT = `API rate limit`
 export const EMPTY_PROJECT = `Empty project`
 
-function apiRateLimitExceeded(content) {
-  return content && content['documentation_url'] === 'https://developer.github.com/v3/#rate-limiting'
+function apiRateLimitExceeded(content: any) {
+  return (
+    content && content['documentation_url'] === 'https://developer.github.com/v3/#rate-limiting'
+  )
 }
 
-function isEmptyProject(content) {
+function isEmptyProject(content: any) {
   return content && content['message'] === 'Git Repository is empty.'
 }
 
-async function request(url, { accessToken } = {}) {
-  const headers = {}
+type Options = {
+  accessToken?: string
+}
+
+async function request(url: string, { accessToken }: Options = {}) {
+  const headers = {} as {
+    Authorization?: string
+  }
   if (accessToken) {
     headers.Authorization = `token ${accessToken}`
   }
@@ -30,22 +38,56 @@ async function request(url, { accessToken } = {}) {
   }
 }
 
-async function getRepoMeta({ userName, repoName, accessToken }) {
+export type MetaData = {
+  userName?: string
+  repoName?: string
+  branchName?: string
+  accessToken?: string
+}
+
+async function getRepoMeta({ userName, repoName, accessToken }: MetaData) {
   const url = `https://api.github.com/repos/${userName}/${repoName}`
   return await request(url, { accessToken })
 }
 
-async function getTreeData({ userName, repoName, branchName, accessToken }) {
+export type TreeItem = {
+  path: string
+}
+
+export type TreeData = {
+  userName: string
+  repoName: string
+  branchName: string
+  accessToken: string
+  tree: TreeItem[]
+}
+
+async function getTreeData({ userName, repoName, branchName, accessToken }: TreeData) {
   const url = `https://api.github.com/repos/${userName}/${repoName}/git/trees/${branchName}?recursive=1`
   return await request(url, { accessToken })
 }
 
-async function getBlobData({ userName, repoName, accessToken, fileSHA }) {
+export type ItemData = {
+  userName: string
+  repoName: string
+  branchName: string
+  accessToken: string
+}
+
+export type BlobData = {
+  fileSHA: string
+} & ItemData
+
+async function getBlobData({ userName, repoName, accessToken, fileSHA }: BlobData) {
   const url = `https://api.github.com/repos/${userName}/${repoName}/git/blobs/${fileSHA}`
   return await request(url, { accessToken })
 }
 
-function getUrlForRedirect({ userName, repoName, branchName }, type = 'blob', path) {
+function getUrlForRedirect(
+  { userName, repoName, branchName }: MetaData,
+  type = 'blob',
+  path?: string
+) {
   return `https://github.com/${userName}/${repoName}/${type}/${branchName}/${path}`
 }
 
diff --git a/src/utils/URLHelper.js b/src/utils/URLHelper.ts
similarity index 89%
rename from src/utils/URLHelper.js
rename to src/utils/URLHelper.ts
index ca00ffa..32cf4c7 100644
--- a/src/utils/URLHelper.js
+++ b/src/utils/URLHelper.ts
@@ -1,4 +1,5 @@
 import { raiseError } from 'analytics'
+import { MetaData } from './GitHubHelper'
 
 function parse() {
   const { pathname } = window.location
@@ -20,7 +21,7 @@ function parse() {
 
 function parseSHA() {
   const { type, path } = parse()
-  return (type === 'blob' || type === 'tree') ? path[0] : false
+  return type === 'blob' || type === 'tree' ? path[0] : false
 }
 
 function isInRepoPage() {
@@ -37,18 +38,18 @@ const TYPES = {
   // TODO: record more types
 }
 
-function isInCodePage(metaData = {}) {
+function isInCodePage(metaData: MetaData = {}) {
   const mergedRepo = { ...parse(), ...metaData }
   const { type, branchName } = mergedRepo
   return Boolean(
-    isInRepoPage(mergedRepo) &&
+    isInRepoPage() &&
       (!type || type === TYPES.TREE || type === TYPES.BLOB) &&
       type !== TYPES.COMMIT &&
       (branchName || (!type && !branchName))
   )
 }
 
-function isCommitPath(path) {
+function isCommitPath(path: string[]) {
   return /^[a-z0-9]{40}$/.test(path[0])
 }
 
diff --git a/src/utils/configHelper.js b/src/utils/configHelper.ts
similarity index 58%
rename from src/utils/configHelper.js
rename to src/utils/configHelper.ts
index 160f629..70f2a7c 100644
--- a/src/utils/configHelper.js
+++ b/src/utils/configHelper.ts
@@ -1,6 +1,14 @@
 import storageHelper from 'utils/storageHelper'
 import { pick } from 'utils/general'
 
+type Config = {
+  shortcut: string
+  accessToken: string | null
+  compressSingletonFolder: boolean
+  copyFileButton: boolean
+  copySnippetButton: boolean
+}
+
 export const config = {
   shortcut: 'shortcut',
   accessToken: 'access_token',
@@ -11,19 +19,19 @@ export const config = {
 
 const configKeys = Object.values(config)
 
-function get() {
-  return storageHelper.get(configKeys)
+function get(): any {
+  return storageHelper.get(configKeys) || {}
 }
 
-function getOne(key) {
+function getOne(key: keyof Config) {
   return get()[key]
 }
 
-function set(partialConfig) {
+function set(partialConfig: Partial) {
   return storageHelper.set(pick(partialConfig, configKeys))
 }
 
-function setOne(key, value) {
+function setOne(key: K, value: Config[K]) {
   return set({
     [key]: value,
   })
diff --git a/src/utils/cx.js b/src/utils/cx.ts
similarity index 79%
rename from src/utils/cx.js
rename to src/utils/cx.ts
index 994a954..27adb15 100644
--- a/src/utils/cx.js
+++ b/src/utils/cx.ts
@@ -1,9 +1,7 @@
 /**
  * cx('class1', { class2: true, class3: false }) --> 'class1 class2'
- * @param {string} baseClassNames
- * @param {object} optionalClassNames
  */
-export default function cx(...classNames) {
+export default function cx(...classNames: (string | object)[]): string {
   return classNames
     .filter(Boolean)
     .map(className => {
diff --git a/src/utils/general.js b/src/utils/general.js
deleted file mode 100644
index 5deebbc..0000000
--- a/src/utils/general.js
+++ /dev/null
@@ -1,17 +0,0 @@
-
-/**
- * @param {Object} source
- * @param {Object|Array} keys
- * @returns
- */
-export function pick(source, keys) {
-  if (keys && typeof keys === 'object') {
-    return (
-      Array.isArray(keys) ? keys : Object.keys(keys)
-    ).reduce((copy, key) => {
-      copy[key] = source[key]
-      return copy
-    }, {})
-  }
-  return {}
-}
diff --git a/src/utils/general.ts b/src/utils/general.ts
new file mode 100644
index 0000000..d5448d7
--- /dev/null
+++ b/src/utils/general.ts
@@ -0,0 +1,12 @@
+export function pick(source: T, keys: string[]): T {
+  if (keys && typeof keys === 'object') {
+    return (Array.isArray(keys) ? keys : Object.keys(keys)).reduce(
+      (copy, key) => {
+        copy[key] = source[key]
+        return copy
+      },
+      {} as T
+    )
+  }
+  return {} as T
+}
diff --git a/src/utils/keyHelper.js b/src/utils/keyHelper.ts
similarity index 81%
rename from src/utils/keyHelper.js
rename to src/utils/keyHelper.ts
index 292a0e2..d305a91 100644
--- a/src/utils/keyHelper.js
+++ b/src/utils/keyHelper.ts
@@ -1,6 +1,6 @@
 const keyCodeArray = [
   ...'1234567890abcdefghijklmnopqrstuvwxyz'.split(''),
-  ...'`[]\\;\',./'.split(''),
+  ..."`[]\\;',./".split(''),
   'alt',
   'shift',
   'ctrl',
@@ -8,7 +8,7 @@ const keyCodeArray = [
 ]
 const validKeyCodes = new Set(keyCodeArray)
 
-function isValidKey(key) {
+function isValidKey(key: string) {
   return validKeyCodes.has(key)
 }
 
@@ -18,7 +18,7 @@ function isValidKey(key) {
  * @param {string} keysString
  * @returns {string}
  */
-function parse(keysString) {
+function parse(keysString: string) {
   return (
     keysString
       .split('+')
@@ -32,13 +32,11 @@ function parse(keysString) {
   )
 }
 
-function parseKeyCode(code) {
-  return code
-    .toLowerCase()
-    .replace(/^control$/, 'ctrl')
+function parseKeyCode(code: string) {
+  return code.toLowerCase().replace(/^control$/, 'ctrl')
 }
 
-function parseEvent(e) {
+function parseEvent(e: KeyboardEvent) {
   const { altKey: alt, shiftKey: shift, metaKey: meta, ctrlKey: ctrl } = e
   const code = parseKeyCode(e.key)
   const keys = { meta, ctrl, shift, alt, [code]: true }
diff --git a/src/utils/storageHelper.js b/src/utils/storageHelper.ts
similarity index 73%
rename from src/utils/storageHelper.js
rename to src/utils/storageHelper.ts
index 8f06782..767345a 100644
--- a/src/utils/storageHelper.js
+++ b/src/utils/storageHelper.ts
@@ -1,10 +1,10 @@
 const localStorage = chrome.storage.local
 
-function get(mapping) {
+function get(mapping: string | string[] | object) {
   return new Promise(resolve => localStorage.get(mapping, resolve))
 }
 
-function set(value) {
+function set(value: any) {
   return new Promise(resolve => localStorage.set(value, resolve))
 }
 
diff --git a/src/utils/treeParser.js b/src/utils/treeParser.ts
similarity index 65%
rename from src/utils/treeParser.js
rename to src/utils/treeParser.ts
index 69ec360..ef2b542 100644
--- a/src/utils/treeParser.js
+++ b/src/utils/treeParser.ts
@@ -1,6 +1,25 @@
-import GitHubHelper from 'utils/GitHubHelper'
+import GitHubHelper, { TreeData, MetaData } from 'utils/GitHubHelper'
 
-const nodeTemplate = {
+interface BasicItem {
+  name: string | null
+  path: string | null
+  parent?: BasicItem | null
+  mode: null
+  type: string | null
+  url: string | null
+}
+
+interface Folder extends BasicItem {
+  contents?: Item[]
+}
+
+interface Blob extends BasicItem {
+  sha: string | null
+}
+
+type Item = Folder & Blob
+
+const nodeTemplate: Blob = {
   name: null,
   path: null,
   mode: null,
@@ -9,10 +28,10 @@ const nodeTemplate = {
   url: null,
 }
 
-function sortFoldersToFront(root) {
-  const isFolder = node => node.type === 'tree'
-  const isNotFolder = node => !isFolder(node)
-  function depthFirstSearch(root) {
+const isFolder = (node: BasicItem) => node.type === 'tree'
+const isNotFolder = (node: BasicItem) => !isFolder(node)
+function sortFoldersToFront(root: Item) {
+  function depthFirstSearch(root: Item) {
     const nodes = root.contents
     if (nodes) {
       nodes.splice(0, Infinity, ...nodes.filter(isFolder), ...nodes.filter(isNotFolder))
@@ -23,14 +42,14 @@ function sortFoldersToFront(root) {
   return depthFirstSearch(root)
 }
 
-function setParentNode(root, parent = null) {
+function setParentNode(root: Item, parent: Item | null = null) {
   root.parent = parent
   if (root.contents) {
     root.contents.forEach(node => setParentNode(node, root))
   }
 }
 
-function findGitModules(root) {
+function findGitModules(root: Item) {
   if (root.contents) {
     const modulesFile = root.contents.find(content => content.name === '.gitmodules')
     if (modulesFile) {
@@ -40,14 +59,14 @@ function findGitModules(root) {
   return null
 }
 
-function parse(treeData, metaData) {
+function parse(treeData: TreeData, metaData: MetaData) {
   const { tree } = treeData
 
   // nodes are created from items and put onto tree
   const pathToNode = new Map()
   const pathToItem = new Map()
 
-  const root = { ...nodeTemplate, name: '', path: '', contents: [] }
+  const root: Item = { ...nodeTemplate, name: '', path: '', contents: [] }
   pathToNode.set('', root)
 
   tree.forEach(item => pathToItem.set(item.path, item))
@@ -69,9 +88,7 @@ function parse(treeData, metaData) {
         ...nodeTemplate,
         ...item,
         name: item.path.replace(/^.*\//, ''),
-        url: item.url
-          ? GitHubHelper.getUrlForRedirect(metaData, item.type, item.path)
-          : null,
+        url: item.url ? GitHubHelper.getUrlForRedirect(metaData, item.type, item.path) : null,
         contents: item.type === 'tree' ? [] : null,
       }
       pathToNode.get(path).contents.push(node)
@@ -81,7 +98,7 @@ function parse(treeData, metaData) {
   })
 
   setParentNode(root)
-  
+
   return {
     gitModules: findGitModules(root),
     root: sortFoldersToFront(root),
diff --git a/tsconfig.json b/tsconfig.json
index d6fd1cf..450d0fc 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,18 +1,18 @@
 {
   "files": ["src/content.jsx"],
   "compilerOptions": {
-    "target": "es2015",
+    "target": "es2016",
     "outDir": "dist",
     "jsx": "react",
     "allowJs": true,
     "module": "commonjs",
     "noImplicitAny": true,
     "resolveJsonModule": true,
-    "lib": ["dom", "es2015"],
+    "lib": ["dom", "es2017.object", "es2016"],
     "baseUrl": ".",
     "experimentalDecorators": true,
     "paths": {
-      "*": ["src/*"]
+      "*": ["src/*", "packages/*"]
     }
   },
   "include": ["src"]
diff --git a/yarn.lock b/yarn.lock
index ba878c0..e2fbe46 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -87,11 +87,35 @@
     lodash "^4.2.0"
     to-fast-properties "^2.0.0"
 
+"@types/chrome@^0.0.77":
+  version "0.0.77"
+  resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.77.tgz#afab7a45da9ebf67d5d50c0ee0a347582128d47e"
+  integrity sha512-VPjm9KeAbwNM0gY8wFGCqO45N382xxiUhgGaiqQPai/NmLNOHBl6w6m71seq566Na0v/+skcWozzyalmX/FMIg==
+  dependencies:
+    "@types/filesystem" "*"
+
+"@types/filesystem@*":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.29.tgz#ee3748eb5be140dcf980c3bd35f11aec5f7a3748"
+  integrity sha512-85/1KfRedmfPGsbK8YzeaQUyV1FQAvMPMTuWFQ5EkLd2w7szhNO96bk3Rh/SKmOfd9co2rCLf0Voy4o7ECBOvw==
+  dependencies:
+    "@types/filewriter" "*"
+
+"@types/filewriter@*":
+  version "0.0.28"
+  resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
+  integrity sha1-wFTor02d11205jq8dviFFocU1LM=
+
 "@types/node@*":
   version "9.3.0"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-9.3.0.tgz#3a129cda7c4e5df2409702626892cb4b96546dd5"
   integrity sha512-wNBfvNjzsJl4tswIZKXCFQY0lss9nKUyJnG6T94X/eqjRgI2jHZ4evdjhQYBSan/vGtF6XVXPApOmNH2rf0KKw==
 
+"@types/nprogress@^0.0.29":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.0.29.tgz#060bd510022a005f1840234030d3132fb9195471"
+  integrity sha1-BgvVEAIqAF8YQCNAMNMTL7kZVHE=
+
 "@types/prop-types@*":
   version "15.5.8"
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce"