From f3f86a79eafef9c67a2fcf6d1879330c367ba957 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 31 Jan 2021 23:58:07 +0800 Subject: [PATCH] refactor: simplify init logics --- src/driver/core/SideBar.ts | 136 +++++++++++++----------------- src/platforms/GitHub/URLHelper.ts | 4 +- src/platforms/GitHub/index.ts | 25 ++++-- src/platforms/Gitea/index.ts | 18 ++-- src/platforms/Gitee/index.ts | 17 ++-- src/utils/general.ts | 16 ++++ 6 files changed, 120 insertions(+), 96 deletions(-) diff --git a/src/driver/core/SideBar.ts b/src/driver/core/SideBar.ts index aec4513..b3fbb98 100644 --- a/src/driver/core/SideBar.ts +++ b/src/driver/core/SideBar.ts @@ -2,6 +2,7 @@ import { ConfigsContextShape } from 'containers/ConfigsContext' import { GetCreatedMethod, MethodCreator } from 'driver/connect' import { errors, platform, platformName } from 'platforms' import * as DOMHelper from 'utils/DOMHelper' +import { createPromiseQueue } from 'utils/general' export type Props = { configContext: ConfigsContextShape @@ -26,7 +27,6 @@ export type ConnectorState = { initializingPromise: Promise | null } & { init: GetCreatedMethod - setMetaData: GetCreatedMethod setShouldShow: GetCreatedMethod toggleShowSideBar: GetCreatedMethod toggleShowSettings: GetCreatedMethod @@ -34,18 +34,10 @@ export type ConnectorState = { type BoundMethodCreator = MethodCreator -export const init: BoundMethodCreator = dispatch => async () => { - const { - state: { initializingPromise }, - } = dispatch.get() - if (initializingPromise) await initializingPromise +const promiseQueue = createPromiseQueue() - let done: any = null // cannot use type `(() => void) | null` here - dispatch.set({ - initializingPromise: new Promise(resolve => { - done = () => resolve() - }), - }) +export const init: BoundMethodCreator = dispatch => async () => { + const leave = await promiseQueue.enter() try { const metaData = platform.resolveMeta() @@ -53,90 +45,85 @@ export const init: BoundMethodCreator = dispatch => async () => { dispatch.set({ disabled: true }) return } + const { userName, repoName, branchName } = metaData + DOMHelper.markGitakoReadyState(true) dispatch.set({ errorDueToAuth: false, showSettings: false, logoContainerElement: DOMHelper.insertLogoMountPoint(), }) - dispatch.call(setMetaData, metaData) const { props: { configContext }, } = dispatch.get() const { accessToken } = configContext.val - if (!metaData.userName || !metaData.repoName) return - const guessDefaultBranch = 'master' - const getTreeDataAggressively = platform.getTreeData( + const guessDefaultBranch = 'master' // when to switch to 'main'? + let getTreeData = platform.getTreeData( { - branchName: metaData.branchName || guessDefaultBranch, - userName: metaData.userName, - repoName: metaData.repoName, + branchName: branchName || guessDefaultBranch, + userName, + repoName, }, '/', true, accessToken, ) - const caughtAggressiveError = getTreeDataAggressively?.catch(error => { - // 1. the repo has no master branch - // 2. detect branch name from DOM failed - // 3. not very possible... - // not handle this error immediately - return error - }) - let getTreeData = getTreeDataAggressively - const metaDataFromAPI = await platform.getMetaData( - { - userName: metaData.userName, - repoName: metaData.repoName, - }, - accessToken, - ) - const projectDefaultBranchName = metaDataFromAPI?.defaultBranchName - const detectedBranchName = metaData.branchName - if ( - !detectedBranchName && - projectDefaultBranchName && - projectDefaultBranchName !== metaData.branchName && - metaData.type !== 'pull' - ) { - // Accessing repository's non-homepage(no branch name in URL, nor in DOM) - // We predicted its default branch to be 'master' and sent aggressive request - // Throw that request due to the repo do not use {defaultBranchName} as default branch - metaData.branchName = projectDefaultBranchName - getTreeData = platform.getTreeData( - { - branchName: metaData.branchName, - userName: metaData.userName, - repoName: metaData.repoName, - }, - '/', - true, - accessToken, - ) + getTreeData.catch(error => error) // catch it early to prevent the error being raised higher + + const metaDataFromAPI = await platform.getMetaData({ userName, repoName }, accessToken) + + if (branchName) { + const safeMetaData = { + ...metaDataFromAPI, + userName, + repoName, + branchName, + } + dispatch.set({ metaData: safeMetaData }) + getTreeData.catch(error => { + dispatch.call(handleError, error) + }) } else { - caughtAggressiveError.then(error => { - // aggressive requested correct branch but ends in failure (e.g. project is empty) - if (error instanceof Error) { - dispatch.call(handleError, error) - } - }) + const { defaultBranchName } = metaDataFromAPI + + if (!defaultBranchName) { + throw new Error(`Failed resolving default branch name`) + } + + const safeMetaData = { + ...metaDataFromAPI, + userName, + repoName, + branchName: defaultBranchName, + } + dispatch.set({ metaData: safeMetaData }) + + if (defaultBranchName !== guessDefaultBranch && metaData.type !== 'pull') { + // Accessing repository's non-homepage(no branch name in URL, nor in DOM) + // We predicted its default branch to be 'master' and sent aggressive request + // Throw that request due to the repo do not use {defaultBranchName} as default branch + getTreeData = platform.getTreeData( + { + branchName: defaultBranchName, + userName, + repoName, + }, + '/', + true, + accessToken, + ) + } } - getTreeData - .then(async ({ root: treeData, defer }) => { - if (treeData) { - dispatch.set({ treeData, defer }) - } - }) - .catch(err => dispatch.call(handleError, err)) - Object.assign(metaData, metaDataFromAPI) - dispatch.call(setMetaData, metaData) + + const { root: treeData, defer } = await getTreeData + dispatch.set({ treeData, defer }) } catch (err) { dispatch.call(handleError, err) - } finally { - if (done) done() } + + leave() } export const handleError: BoundMethodCreator<[Error]> = dispatch => async err => { @@ -197,6 +184,3 @@ export const toggleShowSettings: BoundMethodCreator = dispatch => () => dispatch.set(({ showSettings }) => ({ showSettings: !showSettings, })) - -export const setMetaData: BoundMethodCreator<[ConnectorState['metaData']]> = dispatch => metaData => - dispatch.set({ metaData }) diff --git a/src/platforms/GitHub/URLHelper.ts b/src/platforms/GitHub/URLHelper.ts index f8093cd..e388fd0 100644 --- a/src/platforms/GitHub/URLHelper.ts +++ b/src/platforms/GitHub/URLHelper.ts @@ -1,6 +1,8 @@ import { raiseError } from 'analytics' -export function parse(): Pick & { path: string[] } { +export function parse(): Partial> & { + path: string[] +} { const { pathname } = window.location let [ , diff --git a/src/platforms/GitHub/index.ts b/src/platforms/GitHub/index.ts index d17ade2..7562c0d 100644 --- a/src/platforms/GitHub/index.ts +++ b/src/platforms/GitHub/index.ts @@ -101,10 +101,17 @@ export const GitHub: Platform = { branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA() } + const { userName, repoName, type } = URLHelper.parse() + if (!userName || !repoName) { + return null + } + const metaData = { - ...URLHelper.parse(), + userName, + repoName, + type, branchName, - } as MetaData + } return metaData }, async getMetaData({ userName, repoName }, accessToken) { @@ -202,14 +209,14 @@ export const GitHub: Platform = { })), ) - const gitModules = root.contents?.find(item => item.name === '.gitmodules') - if (gitModules) { - if (userName && repoName && gitModules.sha) { - const blobData = await API.getBlobData(userName, repoName, gitModules.sha, accessToken) + const gitModules = root.contents?.find( + item => item.type === 'blob' && item.name === '.gitmodules', + ) + if (gitModules?.sha) { + const blobData = await API.getBlobData(userName, repoName, gitModules.sha, accessToken) - if (blobData && blobData.encoding === 'base64' && blobData.content) { - await resolveGitModules(root, Base64.decode(blobData.content)) - } + if (blobData && blobData.encoding === 'base64' && blobData.content) { + await resolveGitModules(root, Base64.decode(blobData.content)) } } diff --git a/src/platforms/Gitea/index.ts b/src/platforms/Gitea/index.ts index e5bf1dd..f89681d 100644 --- a/src/platforms/Gitea/index.ts +++ b/src/platforms/Gitea/index.ts @@ -82,15 +82,23 @@ export const Gitea: Platform = { return null } - let detectedBranchName + let branchName if (DOMHelper.isInCodePage()) { - detectedBranchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA() + branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA() + } + + const { userName, repoName, type } = URLHelper.parse() + if (!userName || !repoName) { + return null } const metaData = { - ...URLHelper.parse(), - branchName: detectedBranchName, - } as MetaData + userName, + repoName, + type, + branchName, + } + return metaData }, async getMetaData(partialMetaData, accessToken) { diff --git a/src/platforms/Gitee/index.ts b/src/platforms/Gitee/index.ts index 14c8da1..3e93575 100644 --- a/src/platforms/Gitee/index.ts +++ b/src/platforms/Gitee/index.ts @@ -78,17 +78,24 @@ export const Gitee: Platform = { return null } - let detectedBranchName + let branchName if (DOMHelper.isInCodePage()) { // not working well with non-branch blob // cannot handle '/' split branch name, should not use when possibly on branch page - detectedBranchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA() + branchName = DOMHelper.getCurrentBranch() || URLHelper.parseSHA() + } + + const { userName, repoName, type } = URLHelper.parse() + if (!userName || !repoName) { + return null } const metaData = { - ...URLHelper.parse(), - branchName: detectedBranchName, - } as MetaData + userName, + repoName, + type, + branchName, + } return metaData }, async getMetaData(partialMetaData, accessToken) { diff --git a/src/utils/general.ts b/src/utils/general.ts index 8b6d1a6..4a78db9 100644 --- a/src/utils/general.ts +++ b/src/utils/general.ts @@ -187,3 +187,19 @@ export function withEffect any>( export function run(fn: () => T) { return fn() } + +export function createPromiseQueue() { + let promise: Promise + return { + async enter() { + let leave: () => void + const current = new Promise(resolve => (leave = () => resolve())) + + const lastPromise = promise + promise = current! + if (lastPromise) await lastPromise + + return leave! + }, + } +}