How to query specific line(s) from a file using GitHub APIs |

IT-блоги How to query specific line(s) from a file using GitHub APIs 10 мая 2021 г.


One of the neat features about GitHub is the generation of permalinks urls that highlights a range of line numbers. This is particularly useful when you want to highlight a chunk of code or a line to show it to someone else.

To do so, just navigate to the file you want on github and click on one line, hit the Shift key and click on the end line for the code block. This generates a URL with the highlighted block content that you can then use for sharing.

Tip: You can just add #L{start_line}-L{end_line} to the URL as follows{org_name}/{repo_name}/{path_to_file}#L{start_line}-L{end_line}

Note: You can perhaps do the same thing with other version control platforms like bitbucket or gitlabs but I have not checked.

Show me the API!

I was recently working on a project that dynamically generates code snippet from files hosted on github. Naturally, I referred to GitHub's APIs to query file content. Simple right? Well let's dig deeper into it.

Navigating through Github's APIs, I was disappointed to find out there is no API that query a specific line number(s) from a file. The Search API only allows to query the full content of the file. No problem, let's dig into coding logic for post processing.

Show me the code!

To bypass this limitation, I was able to fetch the content of the file using the SearchAPI as follows

async function fetchContent(orgName, repoName, file, ref) {
  const baseURL = `${orgName}/${repoName}/contents/${file}?ref=${ref}`
  let res = await fetch(baseURL).catch(err => {
    throw new Error(`Error fetching content from ${baseURL}. ${err}`)

  if (!res.ok){
    throw new Error(`Response status from ${baseURL}: ${res.status}`)

  let body = await res.text()
  // Content body from github is base64 encoded
  return Base64.decode(JSON.parse(body).content)

let content = await fetchContent(orgName, repoName, file, ref)

This brings in the whole file as text with new line delimiters presented as \n. You see where I'm going with this 👀

From here, you can split() the text content using \n as the separator and store it in an array

content = content.split('\n')

And then simply generate the snippet using a getSlice(content,range) method

let snippet = getSlice(content,range)

Where getSlice is defined as follows

// Splits the content given the range a-b or just line number a
const getSlice = (content, range) => {
  if (range.includes('-')){
    var a = range.split("-")[0] - 1
    var b = range.split("-")[1]
    return content.slice(a,b).join('\r\n')
  } else if (parseInt(range)) {
    return content[parseInt(range)-1]

Note: range is passed as a string with a - delimiter between the start_line and end_line

And thats it!

What about you?

Did you find this useful? I am curious to know if anyone has another approach for this since GitHub does not have an API to do so (yet!)


Наш сайт является информационным посредником. Сообщить о нарушении авторских прав.

node github tutorial javascript