|
/** |
|
* Run these commands: |
|
* `npm install node-fetch@2` |
|
* `node main` |
|
* |
|
* Then enjoy README.md! |
|
*/ |
|
|
|
const fs = require("fs") |
|
const fetch = require("node-fetch") |
|
|
|
/** |
|
* @type {number} |
|
*/ |
|
let totalDownloads = 0 |
|
|
|
/** |
|
* @type {string} |
|
*/ |
|
let text = "" |
|
|
|
/** |
|
* @param {string} str |
|
* @returns {void} |
|
*/ |
|
const write = (str = "") => { |
|
text += str + "\n" |
|
} |
|
|
|
/** |
|
* @returns {Promise<{package: string; downloads: Record<string,number>}>} |
|
*/ |
|
const get = async () => { |
|
const res = await fetch("https://api.npmjs.org/versions/react/last-week") |
|
|
|
return await res.json() |
|
} |
|
|
|
/** |
|
* @param {{package: string; downloads: Record<string,number>}} data |
|
* @returns {Record<string, number>} |
|
*/ |
|
const getDownloads = (data) => data.downloads |
|
|
|
/** |
|
* @param {Record<string,number>} data |
|
* @returns {{ tag: string; downloads: number }[]} |
|
*/ |
|
const formatResponse = (data) => { |
|
return Object.entries(data).map(([tag, downloads]) => ({ |
|
tag, |
|
downloads, |
|
})) |
|
} |
|
|
|
/** |
|
* @param {{ tag: string; downloads: number }[]} versions |
|
* @param {RegExp} regex |
|
* @returns {{ tag: string; downloads: number }[]} |
|
*/ |
|
const segmentByVersion = (versions, regex) => { |
|
/** @type {Record<string,number>} */ |
|
const versionsMap = {} |
|
|
|
for (const version of versions) { |
|
const tag = regex.exec(version.tag)?.[0] ?? "" |
|
|
|
versionsMap[tag] ??= 0 |
|
versionsMap[tag] += version.downloads |
|
totalDownloads += version.downloads |
|
} |
|
|
|
return formatResponse(versionsMap) |
|
} |
|
|
|
/** |
|
* @param {{ tag: string; downloads: number }[]} versions |
|
* @returns {{ tag: string; downloads: number }[]} |
|
*/ |
|
const sortByDownloads = (versions) => { |
|
return versions.sort((a, b) => { |
|
return a.downloads < b.downloads ? 1 : -1 |
|
}) |
|
} |
|
|
|
/** |
|
* @param {{ tag: string; downloads: number }[]} versions |
|
* @returns {{ tag: string; downloads: number; downloadsPercentage: string }[]} |
|
*/ |
|
const addDownloadsPercentage = (versions) => { |
|
const versionsWithPercentage = versions.map((version) => ({ |
|
...version, |
|
downloadsPercentage: `${Math.floor( |
|
(100 * version.downloads) / totalDownloads |
|
)}%`, |
|
})) |
|
|
|
totalDownloads = 0 |
|
|
|
return versionsWithPercentage |
|
} |
|
|
|
/** |
|
* @param {{ tag: string; downloads: number; downloadsPercentage: string }[]} versions |
|
* @param {string} heading |
|
* @returns {void} |
|
*/ |
|
const printResults = (versions, heading) => { |
|
write("```mermaid") |
|
write(`pie showData title ${heading}`) |
|
|
|
/** |
|
* @type {number} |
|
*/ |
|
let otherDownloads = 0 |
|
|
|
for (const version of versions) { |
|
if (version.downloadsPercentage === "0%") { |
|
otherDownloads += version.downloads |
|
} else { |
|
write(`"${version.tag}":${version.downloads}`) |
|
} |
|
} |
|
|
|
write(`"Other":${otherDownloads}`) |
|
write("```") |
|
write() |
|
} |
|
|
|
/** |
|
* @param {string} heading |
|
* @param {RegExp} regex |
|
* @returns {Promise<void>} |
|
*/ |
|
const printTable = (heading, regex) => { |
|
return get() |
|
.then(getDownloads) |
|
.then(formatResponse) |
|
.then((v) => segmentByVersion(v, regex)) |
|
.then(sortByDownloads) |
|
.then(addDownloadsPercentage) |
|
.then((v) => printResults(v, heading)) |
|
} |
|
|
|
/** |
|
* @returns {Promise<void>} |
|
*/ |
|
const main = async () => { |
|
write("# React Weekly Downloads segmented by version") |
|
write() |
|
|
|
await printTable("By Major Release", /^(\d+)/) |
|
await printTable("By Minor Release", /^(\d+\.\d+)/) |
|
await printTable("By Patch Release", /^(\d+\.\d+\.\d+)/) |
|
|
|
fs.writeFileSync("README.md", text) |
|
} |
|
|
|
main() |