mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
Merge branch 'fix/load-meta-data' into develop
This commit is contained in:
commit
5664ea1de8
6 changed files with 139 additions and 17 deletions
|
|
@ -45,6 +45,7 @@
|
|||
"react-use": "^17.3.2",
|
||||
"react-window": "^1.8.7",
|
||||
"styled-components": "^5.3.5",
|
||||
"superstruct": "^1.0.3",
|
||||
"webext-domain-permission-toggle": "^3.0.0",
|
||||
"webext-dynamic-content-scripts": "^8.1.1",
|
||||
"webextension-polyfill": "^0.10.0"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
import { raiseError } from 'analytics'
|
||||
import { Clippy, ClippyClassName } from 'components/Clippy'
|
||||
import * as React from 'react'
|
||||
import * as s from 'superstruct'
|
||||
import { $ } from 'utils/$'
|
||||
import { formatClass, parseIntFromElement } from 'utils/DOMHelper'
|
||||
import { renderReact } from 'utils/general'
|
||||
import { embeddedDataStruct } from './embeddedDataStructures'
|
||||
|
||||
const selectors = {
|
||||
normal: {
|
||||
reactApp: `react-app[app-name="react-code-view"] [data-target="react-app.reactRoot"]`,
|
||||
codeTab: '#code-tab',
|
||||
branchSwitcher: [`summary[title="Switch branches or tags"]`, `#branch-select-menu`].join(),
|
||||
fileNavigation: `.file-navigation`,
|
||||
breadcrumbs: `[data-testid="breadcrumbs"]`,
|
||||
|
|
@ -27,28 +30,28 @@ const selectors = {
|
|||
pathContext: '[data-testid="breadcrumbs"]',
|
||||
pathContextFileName: '[data-testid="breadcrumbs-filename"]',
|
||||
pathContextScreenReaderHeading: '[data-testid="screen-reader-heading"]',
|
||||
embeddedData: {
|
||||
app: 'script[type="application/json"][data-target="react-app.embeddedData"]',
|
||||
reposOverview:
|
||||
'[partial-name="repos-overview"] script[type="application/json"][data-target="react-partial.embeddedData"]',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export function resolveMetaFromDOMJSON(): { defaultBranch: string; metaData: MetaData } | void {
|
||||
// in code page, there is a JSON script tag in DOM with meta data
|
||||
const json = $('script[type="application/json"][data-target="react-app.embeddedData"]', e => {
|
||||
const getDOMJSON = (selector: string) =>
|
||||
$(selector, e => {
|
||||
try {
|
||||
return JSON.parse(e.textContent || '')
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
})
|
||||
if (!json) return
|
||||
|
||||
const { payload } = json
|
||||
if (!payload) return
|
||||
|
||||
function getMetaFromPayload(payload: s.Infer<typeof embeddedDataStruct.repoPayload>) {
|
||||
const { repo, refInfo } = payload
|
||||
if (!repo || !refInfo) return
|
||||
|
||||
const { defaultBranch, name: repoName, ownerLogin: userName } = repo
|
||||
const { name: branchName } = refInfo
|
||||
|
||||
return {
|
||||
defaultBranch,
|
||||
metaData: {
|
||||
|
|
@ -59,8 +62,27 @@ export function resolveMetaFromDOMJSON(): { defaultBranch: string; metaData: Met
|
|||
}
|
||||
}
|
||||
|
||||
// in code page, there is a JSON script tag in DOM with meta data
|
||||
function resolveEmbeddedAppData() {
|
||||
const data = getDOMJSON(selectors.globalNavigation.embeddedData.app)
|
||||
if (s.is(data, embeddedDataStruct.app)) return getMetaFromPayload(data.payload)
|
||||
}
|
||||
|
||||
function resolveEmbeddedReposOverviewData() {
|
||||
const data = getDOMJSON(selectors.globalNavigation.embeddedData.reposOverview)
|
||||
if (s.is(data, embeddedDataStruct.reposOverview))
|
||||
return getMetaFromPayload(data.props.initialPayload)
|
||||
}
|
||||
|
||||
export function resolveEmbeddedData(): {
|
||||
defaultBranch: string
|
||||
metaData: MetaData
|
||||
} | void {
|
||||
return resolveEmbeddedAppData() || resolveEmbeddedReposOverviewData()
|
||||
}
|
||||
|
||||
export function resolveMeta(): Partial<MetaData> {
|
||||
const dataFromJSON = resolveMetaFromDOMJSON()
|
||||
const dataFromJSON = resolveEmbeddedData()
|
||||
if (dataFromJSON) return dataFromJSON.metaData
|
||||
|
||||
const metaData = {
|
||||
|
|
@ -129,7 +151,9 @@ export function getCurrentBranch(passive = false) {
|
|||
].join()
|
||||
const branchButtonElement = $(selectedBranchButtonSelector)
|
||||
if (branchButtonElement) {
|
||||
const branchNameSpanElement = branchButtonElement.querySelector('span')
|
||||
const branchNameSpanElement = branchButtonElement.querySelector(
|
||||
['.ref-selector-button-text-container', 'span'].join(),
|
||||
)
|
||||
if (branchNameSpanElement) {
|
||||
const partialBranchNameFromInnerText = branchNameSpanElement.textContent?.trim() || ''
|
||||
if (partialBranchNameFromInnerText && !partialBranchNameFromInnerText.includes('…'))
|
||||
|
|
@ -137,7 +161,7 @@ export function getCurrentBranch(passive = false) {
|
|||
}
|
||||
const defaultTitle = 'Switch branches or tags'
|
||||
const title = branchButtonElement.title.trim()
|
||||
if (title !== defaultTitle && !title.includes(' ')) return title
|
||||
if (title && title !== defaultTitle && !title.includes(' ')) return title
|
||||
}
|
||||
|
||||
const findFileButtonSelector = 'main .file-navigation a[data-hotkey="t"]'
|
||||
|
|
@ -154,6 +178,17 @@ export function getCurrentBranch(passive = false) {
|
|||
}
|
||||
}
|
||||
|
||||
const branchNameFromCodeTab = $(selectors.normal.codeTab, e => {
|
||||
if (e instanceof HTMLAnchorElement) {
|
||||
const chunks = e.href.split('/')
|
||||
const indexOfTree = chunks.indexOf('tree')
|
||||
if (indexOfTree === -1) return
|
||||
const branchName = chunks.slice(indexOfTree + 1).join('/')
|
||||
return branchName
|
||||
}
|
||||
})
|
||||
if (branchNameFromCodeTab) return branchNameFromCodeTab
|
||||
|
||||
if (!passive) raiseError(new Error('cannot get current branch'))
|
||||
}
|
||||
|
||||
|
|
|
|||
81
src/platforms/GitHub/embeddedDataStructures.ts
Normal file
81
src/platforms/GitHub/embeddedDataStructures.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import * as s from 'superstruct'
|
||||
|
||||
const repo = s.object({
|
||||
id: s.number(),
|
||||
defaultBranch: s.string(),
|
||||
name: s.string(),
|
||||
ownerLogin: s.string(),
|
||||
currentUserCanPush: s.boolean(),
|
||||
isFork: s.boolean(),
|
||||
isEmpty: s.boolean(),
|
||||
createdAt: s.string(),
|
||||
ownerAvatar: s.string(),
|
||||
public: s.boolean(),
|
||||
private: s.boolean(),
|
||||
isOrgOwned: s.boolean(),
|
||||
})
|
||||
|
||||
const user = s.object({
|
||||
id: s.number(),
|
||||
login: s.string(),
|
||||
userEmail: s.string(),
|
||||
})
|
||||
|
||||
const rel = s.object({
|
||||
name: s.string(),
|
||||
listCacheKey: s.string(),
|
||||
canEdit: s.boolean(),
|
||||
refType: s.string(),
|
||||
currentOid: s.string(),
|
||||
})
|
||||
|
||||
const treeItem = s.object({
|
||||
name: s.string(),
|
||||
path: s.string(),
|
||||
contentType: s.string(),
|
||||
})
|
||||
|
||||
const tree = s.object({
|
||||
items: s.array(treeItem),
|
||||
templateDirectorySuggestionUrl: s.nullable(s.never()),
|
||||
readme: s.nullable(s.never()),
|
||||
totalCount: s.number(),
|
||||
showBranchInfobar: s.boolean(),
|
||||
})
|
||||
|
||||
const repoPayload = s.object({
|
||||
allShortcutsEnabled: s.boolean(),
|
||||
path: s.string(),
|
||||
repo: repo,
|
||||
currentUser: user,
|
||||
refInfo: rel,
|
||||
tree: tree,
|
||||
fileTree: s.nullable(s.never()),
|
||||
fileTreeProcessingTime: s.nullable(s.never()),
|
||||
foldersToFetch: s.array(s.unknown()),
|
||||
treeExpanded: s.boolean(),
|
||||
symbolsExpanded: s.boolean(),
|
||||
isOverview: s.boolean(),
|
||||
overview: s.unknown(),
|
||||
})
|
||||
|
||||
const reposOverview = s.object({
|
||||
props: s.object({
|
||||
initialPayload: repoPayload,
|
||||
appPayload: s.unknown(),
|
||||
}),
|
||||
})
|
||||
const app = s.object({
|
||||
payload: repoPayload,
|
||||
})
|
||||
|
||||
export const embeddedDataStruct = {
|
||||
repo,
|
||||
user,
|
||||
rel,
|
||||
treeItem,
|
||||
tree,
|
||||
repoPayload,
|
||||
reposOverview,
|
||||
app,
|
||||
}
|
||||
|
|
@ -7,12 +7,12 @@ import { resolveGitModules } from 'utils/gitSubmodule'
|
|||
import { sortFoldersToFront } from 'utils/treeParser'
|
||||
import * as API from './API'
|
||||
import * as DOMHelper from './DOMHelper'
|
||||
import * as URLHelper from './URLHelper'
|
||||
import { getCommitTreeData } from './getCommitTreeData'
|
||||
import { getPullRequestTreeData } from './getPullRequestTreeData'
|
||||
import { useEnterpriseStatBarStyleFix } from './hooks/useEnterpriseStatBarStyleFix'
|
||||
import { useGitHubAttachCopySnippetButton } from './hooks/useGitHubAttachCopySnippetButton'
|
||||
import { useGitHubCodeFold } from './hooks/useGitHubCodeFold'
|
||||
import * as URLHelper from './URLHelper'
|
||||
|
||||
export function processTree(tree: TreeNode[]): TreeNode {
|
||||
// nodes are created from items and put onto tree
|
||||
|
|
@ -109,7 +109,7 @@ export const GitHub: Platform = {
|
|||
}
|
||||
|
||||
const { type } = metaFromURL
|
||||
let branchName
|
||||
let branchName = metaFromDOM.branchName
|
||||
if (URLHelper.isInPullPage()) {
|
||||
branchName = DOMHelper.getIssueTitle()
|
||||
} else if (URLHelper.isInCommitPage()) {
|
||||
|
|
@ -130,7 +130,7 @@ export const GitHub: Platform = {
|
|||
return metaData
|
||||
},
|
||||
async getDefaultBranchName({ userName, repoName }, accessToken) {
|
||||
const dataFromJSON = DOMHelper.resolveMetaFromDOMJSON()
|
||||
const dataFromJSON = DOMHelper.resolveEmbeddedData()
|
||||
if (dataFromJSON?.defaultBranch) return dataFromJSON.defaultBranch
|
||||
|
||||
return (await API.getRepoMeta(userName, repoName, accessToken)).default_branch
|
||||
|
|
|
|||
|
|
@ -113,10 +113,10 @@ module.exports = {
|
|||
sideEffects: false,
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
test: /\.m?js$/,
|
||||
loader: 'babel-loader',
|
||||
// Transpile as least files under node_modules
|
||||
include: /node_modules\/(webext-content-scripts|webext-detect-page)\/.*\.js$/,
|
||||
include: /node_modules\/(webext-content-scripts|webext-detect-page|superstruct)\/.*\.m?js$/,
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11325,6 +11325,11 @@ stylis@^4.0.6:
|
|||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.1.tgz#e46c6a9bbf7c58db1e65bb730be157311ae1fe12"
|
||||
integrity sha512-lVrM/bNdhVX2OgBFNa2YJ9Lxj7kPzylieHd3TNjuGE0Re9JB7joL5VUKOVH1kdNNJTgGPpT8hmwIAPLaSyEVFQ==
|
||||
|
||||
superstruct@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmmirror.com/superstruct/-/superstruct-1.0.3.tgz#de626a5b49c6641ff4d37da3c7598e7a87697046"
|
||||
integrity sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg==
|
||||
|
||||
supports-color@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
|
||||
|
|
|
|||
Loading…
Reference in a new issue