9
\$\begingroup\$

Solved, question with improved code

I've created a simple npm module and CLI program to get the latest GitHub and Bitbucket release from their APIs using Node.js. Please tell me if there's anything to improve!

Module code:

#!/usr/bin/env node
const fetch = require("node-fetch");
/**
 * @param {string} string
 * @return {string}
 */
const normalize = (string) => {
 try {
 return string.toUpperCase().trim()
 } catch (e) {
 return string
 }
}
/**
 * @param {string} provider
 * @param {string} user
 * @param {string} repo
 * @param {string} part
 */
module.exports.getRelease = async ({provider, user, repo, part = ""}) => {
 if (normalize(provider) === normalize("github")) {
 let json = (await (await fetch(`https://api.github.com/repos/${user}/${repo}/releases/latest`)).json())
 if (json.message === "Not Found") throw "Invalid repository"
 if (!("assets" in json)) throw "Rate limit exceeded"
 let browser_download_urls = json.assets.map(asset => asset.browser_download_url)
 return browser_download_urls.filter(url => url.includes(part))
 } else if (normalize(provider) === normalize("bitbucket")) {
 let json = (await (await fetch(`https://api.bitbucket.org/2.0/repositories/${user}/${repo}/downloads/`)).json())
 if (json.type === "error") throw "Invalid repository"
 let links = json.values.map(value => value.links.self.href)
 return links.filter(url => url.includes(part))
 } else {
 throw "Invalid provider"
 }
}
const usage = _ => {
 console.log(
 `Usage: get-release (github|bitbucket) user repo [partofreleasefile]
 Ex: get-release github phhusson treble_experimentations
 get-release github phhusson treble_experimentations arm64-ab-gapps
 get-release bitbucket JesusFreke smali
 get-release bitbucket JesusFreke smali baksmali`
 )
 process.exit(1)
}
// If via CLI
if (require.main === module) {
 let args = process.argv.slice(2)
 if (args.length !== 3 && args.length !== 4) {
 usage()
 }
 module.exports.getRelease({
 provider: args[0],
 user: args[1],
 repo: args[2],
 part: args[3]
 }).then(result => {
 if (result.length !== 1) {
 console.log(result)
 } else {
 console.log(result[0])
 }
 }).catch(error => {
 console.log(error)
 usage()
 process.exit(1)
 })
}

Called using:

const { getRelease } = require("get-release")
;(async _ => {
 let url = await getRelease(
 {
 provider: "github",
 user: "phhusson",
 repo: "treble_experimentations",
 part: "arm64-ab-gapps"
 }
 )
 console.log(url[0])
})()
asked Jul 19, 2020 at 17:50
\$\endgroup\$
2
  • \$\begingroup\$ Why the double await in (await (await fetch(, does it not work with a single await? \$\endgroup\$ Commented Jul 22, 2020 at 6:49
  • \$\begingroup\$ @konijn Nope, it doesn't work without the double \$\endgroup\$ Commented Jul 22, 2020 at 12:54

1 Answer 1

1
\$\begingroup\$

Consider using a hashmap of provider -> process. This will enable you to register new providers with relative ease.

async function githubRelease({user, repo, part = ""}) {
 let json = (await (await fetch(`https://api.github.com/repos/${user}/${repo}/releases/latest`)).json())
 if (json.message === "Not Found") throw "Invalid repository"
 if (!("assets" in json)) throw "Rate limit exceeded"
 let browser_download_urls = json.assets.map(asset => asset.browser_download_url)
 return browser_download_urls.filter(url => url.includes(part))
}

It will then be mapped inside the getRelease function as follows:

module.exports.getRelease = async ({provider, user, repo, part = ""}) => {
 if !(providerMethods[normalise(provider)]) {
 throw "Invalid provider"
 }
 return providerMethods[normalise(provider)](user, repo, part)
}

where providerMethods would be:

let providerMethods = {
 normalise("github"): githubReleases
}

This will enable users of your module to register new (or private) registry providers. They can add a new provider to the providerMethods object (gitlab etc) and don't have to wait for you to update the library first for supporting any extra providers (you can add providers if popular).

The await (await fetch()).json() can be extracted to another function. Although, I'd prefer using the promise.then(r => r.json()).catch() chain over multiple awaits, it is entirely dependent on your comfort with the language.

answered Jul 22, 2020 at 4:32
\$\endgroup\$
1
  • \$\begingroup\$ Hi, I've made changes: Improved code. Thanks for answering! \$\endgroup\$ Commented Jul 22, 2020 at 15:25

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.