maitxn/version-bump-tar
@reggi/path-to-regexp
dependabot/npm_and_yarn/main/copy-to-clipboard-4.0.2
dependabot/npm_and_yarn/main/eslint-10.4.0
dependabot/npm_and_yarn/main/npmcli/eslint-config-7.0.0
dependabot/npm_and_yarn/main/proc-log-7.0.0
dependabot/npm_and_yarn/npm_and_yarn-826852524d
dependabot/npm_and_yarn/npm_and_yarn-ab9a7f4bc2
deprecate-totp-2fa
dhei/classic-tokens
gat-bypass-2fa-docs
jpg619/fix-accessibility-content-flow
jpg619/version-bump-tar-2
kartykp/gat-bypass-2fa-docs
kartykp/upgrade-path-to-regex
main
maitxn/version-bump-tar
patch-1
reggi/cache-based-on-version
reggi/dev-engines
reggi/fix-transform-prettier
reggi/overrides
update-search-sensitivity
| 1 | const {posix} = require('path') |
| 2 | const fs = require('fs').promises |
| 3 | const yaml = require('yaml') |
| 4 | const semver = require('semver') |
| 5 | const pacote = require('pacote') |
| 6 | const extractRelease = require('./extract') |
| 7 | const log = require('./log') |
| 8 | |
| 9 | const DOCS_PATH = 'cli' |
| 10 | |
| 11 | const updateNav = async (updates, {nav, path}) => { |
| 12 | const variants = updates.map(release => ({ |
| 13 | title: release.title, |
| 14 | shortName: release.id, |
| 15 | url: release.url, |
| 16 | default: release.default, |
| 17 | type: release.type, |
| 18 | children: release.nav, |
| 19 | })) |
| 20 | |
| 21 | const index = nav.contents.items.findIndex(n => posix.basename(n.get('url')) === DOCS_PATH) |
| 22 | const key = [index, 'variants'] |
| 23 | const current = nav.getIn(key) |
| 24 | |
| 25 | if (!current) { |
| 26 | nav.setIn(key, nav.createNode(variants)) |
| 27 | } else { |
| 28 | for (const variant of variants) { |
| 29 | const vIndex = current.items.findIndex(n => n.get('url') === variant.url) |
| 30 | if (vIndex === -1) { |
| 31 | nav.addIn(key, nav.createNode(variant)) |
| 32 | } else { |
| 33 | nav.setIn([...key, vIndex], nav.createNode(variant)) |
| 34 | } |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | return fs.writeFile(path, nav.toString(), 'utf-8') |
| 39 | } |
| 40 | |
| 41 | const getCurrentVersions = nav => { |
| 42 | // the only place the current versions are stored is in the nav |
| 43 | const currentSections = nav.find(s => s.url === `/${DOCS_PATH}`).variants |
| 44 | |
| 45 | const currentVersions = currentSections |
| 46 | .map(v => { |
| 47 | const version = v.title?.match(/^Version\s(.*?)$/)[1] |
| 48 | return version |
| 49 | }) |
| 50 | .sort(semver.compare) |
| 51 | |
| 52 | return { |
| 53 | versions: currentVersions, |
| 54 | latest: currentVersions[currentVersions.length - 1], |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | const main = async ({loglevel, releases: rawReleases, useCurrent, navPath, contentPath, prerelease, cache}) => { |
| 59 | /* istanbul ignore next */ |
| 60 | if (loglevel) { |
| 61 | log.on(loglevel) |
| 62 | } |
| 63 | |
| 64 | const baseNav = await fs.readFile(navPath, 'utf-8') |
| 65 | const navData = yaml.parse(baseNav) |
| 66 | const navDoc = yaml.parseDocument(baseNav) |
| 67 | |
| 68 | const pack = useCurrent |
| 69 | ? getCurrentVersions(navData) |
| 70 | : await pacote.packument('npm', {preferOnline: true}).then(p => ({ |
| 71 | versions: Object.keys(p.versions), |
| 72 | latest: p['dist-tags'].latest, |
| 73 | })) |
| 74 | |
| 75 | const releaseVersions = rawReleases |
| 76 | .map(release => { |
| 77 | const major = Number(release.id.replace(/^v/, '')) |
| 78 | const range = `>=${major}.0.0-a <${major + 1}.0.0` // include all prereleases |
| 79 | const version = semver.parse(semver.maxSatisfying(pack.versions, range)) |
| 80 | |
| 81 | return ( |
| 82 | version && { |
| 83 | ...release, |
| 84 | version: version.toString(), |
| 85 | // the default release is always controlled by the latest dist-tag |
| 86 | default: semver.eq(version, pack.latest), |
| 87 | prerelease: version.prerelease.length > 0, |
| 88 | } |
| 89 | ) |
| 90 | }) |
| 91 | .filter(Boolean) |
| 92 | |
| 93 | const latestRelease = |
| 94 | releaseVersions.find(r => r.default) ?? |
| 95 | releaseVersions.slice(0).sort((a, b) => semver.compare(b.version, a.version))[0] |
| 96 | |
| 97 | const releases = releaseVersions.map(release => { |
| 98 | const type = release.default |
| 99 | ? 'latest' |
| 100 | : release.prerelease |
| 101 | ? 'prerelease' |
| 102 | : semver.gt(release.version, latestRelease.version) |
| 103 | ? 'current' |
| 104 | : 'legacy' |
| 105 | |
| 106 | return { |
| 107 | ...release, |
| 108 | type, |
| 109 | title: `Version ${release.version}`, |
| 110 | url: `/${DOCS_PATH}/${release.id}`, |
| 111 | urlPrefix: DOCS_PATH, |
| 112 | urlPrefixes: [DOCS_PATH, `${DOCS_PATH}-documentation`], |
| 113 | } |
| 114 | }) |
| 115 | |
| 116 | /** |
| 117 | * this voids the cache when a new version is added to release.json / not in the cli-cache.json |
| 118 | * this is done so that the previous major versions nav can be reset to legacy and pages can be droped from its variant |
| 119 | */ |
| 120 | cache?.voidOnNewKey(releases.map(v => v.id)) |
| 121 | |
| 122 | const updates = await Promise.all( |
| 123 | releases.map(r => extractRelease(r, {cache, contentPath, baseNav: navData, prerelease})), |
| 124 | ).then(r => r.filter(Boolean)) |
| 125 | |
| 126 | await cache?.save() |
| 127 | |
| 128 | await updateNav(updates, {nav: navDoc, path: navPath}) |
| 129 | } |
| 130 | |
| 131 | module.exports = main |