Skip to content
This repository was archived by the owner on Jan 22, 2019. It is now read-only.

Code intel inject#186

Merged
ijsnow merged 20 commits intomasterfrom
code-intel-inject
Sep 19, 2018
Merged

Code intel inject#186
ijsnow merged 20 commits intomasterfrom
code-intel-inject

Conversation

@ijsnow
Copy link

@ijsnow ijsnow commented Sep 18, 2018

This PR changes GitHub to use the new generic way of injecting code intelligence.

A couple TODOs:

  • Add single file view, snippets and search results back, won't take long
  • Talk with @chrismwendt about what I blew away in terms of Extensions and how to get it added back
  • Put behind a feature flag for GitHub until we get extensions support back in

Testing plan:

Go through the regular flows of using

I have tested on:

  • Chrome
  • Firefox
  • Safari
  • Phabricator Bundle


for (const codeHost of codeHosts) {
const check = codeHost.check()
const checking = check instanceof Promise ? check : Promise.resolve(check)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can call Promise.resolve() on maybe-Promises (it's made for that use case), and directly await the return

return subscriptions
}

async function injectCodeIntelligenceToCodeHosts(codeHosts: CodeHost[]): Promise<Subscription> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An async function that returns Subscriptions on first sight seems like a weird mix of patterns to me

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I not make this an async function?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be (it looks like it does only side effects)
I just thought the returned Subscription was weird because if it is to cancel the operation, the operation already happened when the Promise resolves. But I see that it actually represents the subscription for hoverify etc? In that case this makes sense. Just some documentation would help explain what the return value actually is

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I'll add some docs

* Cast a Node to an HTMLElement if it has a classList. This should not be used
* if you need 100% confidence the Node is an HTMLElement.
*/
function naiveCheckIsHTMLElement(node: Node): node is HTMLElement {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the problem with instanceof HTMLElement?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, tbh didn't really think about it. I get why Node, Element, and HTMLElement all exists as separate types but they do confuse me sometimes.

// as a prop, but TS complains that it does not
// exist.
if ((entry as any).isIntersecting) {
intersectingElements.next(entry.target as HTMLElement)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of Subjects, prefer the Observable constructor

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably related to your comment below but I found it quite hard to implement this in another way. I only ever want to create on IntersectionObserver so I put it above the function that gets called for everything that's piped through but it needs to be used there so I created a Subject so data could be piped into it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried using the observable constructor but ended up here

return (codeViews: Observable<ResolvedCodeView>) =>
new Observable<ResolvedCodeView>(observer => {
codeViews.subscribe(({ codeView, ...rest }) => {
intersectionObserver.observe(codeView)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems wrong to have the intersectionObserver be shared between all Observable subscriptions at this layer - if the intend is to share, the share() operator should accomplish that

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I'm not sure how to use that in place of this subscription here. That sounds reasonable. Could you give me some guidance?

toolbarButtonProps,
}

const resolveCodeView = (elem: HTMLElement) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add return type

import { resolveDiffFileInfo } from './file_info'
import { createCodeViewToolbarMount, parseURL } from './util'

const toolbarButtonProps = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add type declaration

map(({ codeView, ...rest }) => {
const { headFilePath, baseFilePath } = getDeltaFileName(codeView)
if (!headFilePath) {
throw new Error('cannot determine file path')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the type this never happens, in what case does it happen?

map(({ codeView, ...rest }) => {
const diffResolvedRev = getDiffResolvedRev()
if (!diffResolvedRev) {
throw new Error('cannot determine delta info')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what case does this happen? This error message is rather unhelpful, should getDiffResolvedRev maybe throw the error instead?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't an error as far as I know. This piece was just ported over from existing logic. Would probably be worth looking into at some point.

},
]

function checkIsPhabricator(): Promise<boolean> | boolean {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this just always return a Promise for simplicity? You could just make it an async function

@ijsnow
Copy link
Author

ijsnow commented Sep 19, 2018

@chrismwendt last TODO is to get extensions stuff in here.

We could merge this in behind a feature flag defaulted to off and then follow up with that

@ijsnow
Copy link
Author

ijsnow commented Sep 19, 2018

This is now behind a feature flag. We don't need to worry about blowing away extensions stuff before merging this in. cc @chrismwendt

@ijsnow ijsnow merged commit becfba3 into master Sep 19, 2018
@ijsnow ijsnow deleted the code-intel-inject branch September 19, 2018 17:13
@sourcegraph-bot
Copy link

🎉 This PR is included in version 1.15.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants