From 5a1c0f4962a1377b4c18e0bf2376748203cdb63d Mon Sep 17 00:00:00 2001 From: Benjamin Lupton Date: Thu, 16 Nov 2023 00:30:15 +0800 Subject: [PATCH] v1.83.0 - better mass support for old node versions - use `node:` prefix on builtins as our min supported node version supports it - consistently order imports - base: - for fetching, instead of `master` use `HEAD` (evolutes to the default branch) - if a bevry organisation: - output `SECURITY.md` - add tidelift to `FUNDING.yml` if publishing to npm - ci: - remove macos and windows ci tests for now, was causing too much overload with dependabot - update `bevry-actions/npm` version - include automerge into `bevry.yml` as per github recommendation, rather than as its own third party workflow - have dependabot also update github action packages - have dependabot only update on sunday on midnight in perth time (so it doesn't overload @balupton's work schedule) - only allow security dependabot requests, as boundation handles the dep updates, and the dep updates overwhelm github - fs: - instead of exec'ing `rm -rf`, use builtin recursive remove now that our min supported node supports it - better handling of poor internet connection and invalid caching - git: - correctly name `getGitActiveDefaultBranch` to `getGitActiveBranch` - questions/runtime: - **introduced target versions, instead of using supported/test versions, to ensure that `expandNodeVersions`` works correctly** - runtime: - update legacy version compat table (needs to be adjusted for semver as coerce isn't available on older semver versions, or rather needs to be dep and node version specific rather than clumped together) - have npm scripts use `rm -rf` instead of `rm -Rf` for greater compat - **if targeting old node versions, have prettier enforce es5 comma mode, otherwise native javascript editions and the editions autoload will break compat** --- .github/workflows/bevry.yml | 2 +- HISTORY.md | 28 ++++++++++++ package-lock.json | 5 +-- package.json | 3 +- source/base.js | 85 +++++++++++++++++++++++++---------- source/bin.js | 2 +- source/ci.js | 75 +++++++++++++++++++------------ source/data.js | 2 +- source/editions.js | 2 +- source/fs.js | 39 +++++++++------- source/get-git.js | 4 +- source/index.js | 4 +- source/package.js | 4 +- source/questions.js | 90 ++++++++++++++++++++++++++++++------- source/runtime.js | 36 +++++++++------ source/util.js | 2 +- source/versions.js | 7 ++- source/website.js | 2 +- 18 files changed, 275 insertions(+), 117 deletions(-) diff --git a/.github/workflows/bevry.yml b/.github/workflows/bevry.yml index a8a06bc..e9770b3 100644 --- a/.github/workflows/bevry.yml +++ b/.github/workflows/bevry.yml @@ -45,7 +45,7 @@ jobs: - run: npm run our:compile - run: npm run our:meta - name: publish to npm - uses: bevry-actions/npm@v1.1.0 + uses: bevry-actions/npm@v1.1.1 with: npmAuthToken: ${{ secrets.NPM_AUTH_TOKEN }} npmBranchTag: ':next' diff --git a/HISTORY.md b/HISTORY.md index 04ca7ff..660dce7 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,33 @@ # History +## v1.83.0 2023 November 16 + +- use `node:` prefix on builtins as our min supported node version supports it +- consistently order imports +- base: + - for fetching, instead of `master` use `HEAD` (evolutes to the default branch) + - if a bevry organisation: + - output `SECURITY.md` + - add tidelift to `FUNDING.yml` if publishing to npm +- ci: + - remove macos and windows ci tests for now, was causing too much overload with dependabot + - update `bevry-actions/npm` version + - include automerge into `bevry.yml` as per github recommendation, rather than as its own third party workflow + - have dependabot also update github action packages + - have dependabot only update on sunday on midnight in perth time (so it doesn't overload @balupton's work schedule) + - only allow security dependabot requests, as boundation handles the dep updates, and the dep updates overwhelm github +- fs: + - instead of exec'ing `rm -rf`, use builtin recursive remove now that our min supported node supports it + - better handling of poor internet connection and invalid caching +- git: + - correctly name `getGitActiveDefaultBranch` to `getGitActiveBranch` +- questions/runtime: + - **introduced target versions, instead of using supported/test versions, to ensure that `expandNodeVersions`` works correctly** +- runtime: + - update legacy version compat table (needs to be adjusted for semver as coerce isn't available on older semver versions, or rather needs to be dep and node version specific rather than clumped together) + - have npm scripts use `rm -rf` instead of `rm -Rf` for greater compat + - **if targeting old node versions, have prettier enforce es5 comma mode, otherwise native javascript editions and the editions autoload will break compat** + ## v1.82.1 2023 November 4 - Better error message when all ESM editions fail diff --git a/package-lock.json b/package-lock.json index 25c1734..2635c4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "boundation", - "version": "1.82.0", + "version": "1.83.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "boundation", - "version": "1.82.0", + "version": "1.83.0", "license": "Artistic-2.0", "dependencies": { "@bevry/ansi": "^3.5.0", @@ -24,7 +24,6 @@ "inquirer": "^9.2.11", "js-yaml": "^4.1.0", "safeps": "^10.18.0", - "semver": "^7.5.4", "typechecker": "^7.18.0", "version-compare": "^1.5.0", "version-range": "^1.5.0" diff --git a/package.json b/package.json index c109644..2e913d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boundation", - "version": "1.82.1", + "version": "1.83.0", "description": "Automatic scaffolding and upgrading of your JavaScript ecosystem projects using Bevry's best practices", "homepage": "https://github.com/bevry/boundation", "license": "Artistic-2.0", @@ -110,7 +110,6 @@ "inquirer": "^9.2.11", "js-yaml": "^4.1.0", "safeps": "^10.18.0", - "semver": "^7.5.4", "typechecker": "^7.18.0", "version-compare": "^1.5.0", "version-range": "^1.5.0" diff --git a/source/base.js b/source/base.js index 674735b..2e1d549 100644 --- a/source/base.js +++ b/source/base.js @@ -1,8 +1,8 @@ /* eslint-disable camelcase */ // builtin -import * as pathUtil from 'path' -import * as urlUtil from 'url' +import * as pathUtil from 'node:path' +import * as urlUtil from 'node:url' // external import Errlop from 'errlop' @@ -19,7 +19,7 @@ import { unlink, spawn, writeYAML, - rmrf, + remove, } from './fs.js' export async function download(opts) { @@ -87,7 +87,7 @@ export async function updateBaseFiles({ answers, packageData }) { ].filter((i) => i) if (answers.packageManager !== 'yarn') purgeList.push('./.yarnrc', './.yarnrc.yml', './.yarn/') - await rmrf(purgeList.filter((i) => `./${i}`)) + await remove(purgeList.filter((i) => `./${i}`)) status('...removed old files') // rename old files @@ -137,27 +137,27 @@ export async function updateBaseFiles({ answers, packageData }) { status('downloading files...') /** @type {Array} */ const downloads = [ - 'https://raw.githubusercontent.com/bevry/base/master/.editorconfig', + 'https://raw.githubusercontent.com/bevry/base/HEAD/.editorconfig', { - url: 'https://raw.githubusercontent.com/bevry/base/master/.gitignore', + url: 'https://raw.githubusercontent.com/bevry/base/HEAD/.gitignore', custom: true, }, { - url: 'https://raw.githubusercontent.com/bevry/base/master/.prettierignore', + url: 'https://raw.githubusercontent.com/bevry/base/HEAD/.prettierignore', custom: true, }, - 'https://raw.githubusercontent.com/bevry/base/master/LICENSE.md', - 'https://raw.githubusercontent.com/bevry/base/master/CONTRIBUTING.md', + 'https://raw.githubusercontent.com/bevry/base/HEAD/LICENSE.md', + 'https://raw.githubusercontent.com/bevry/base/HEAD/CONTRIBUTING.md', ] if (answers.type === 'package') { downloads.push({ - url: 'https://raw.githubusercontent.com/bevry/base/master/HISTORY.md', + url: 'https://raw.githubusercontent.com/bevry/base/HEAD/HISTORY.md', overwrite: false, }) } if (answers.npm) { downloads.push({ - url: 'https://raw.githubusercontent.com/bevry/base/master/.npmignore', + url: 'https://raw.githubusercontent.com/bevry/base/HEAD/.npmignore', custom: true, }) } else { @@ -165,7 +165,7 @@ export async function updateBaseFiles({ answers, packageData }) { } if (answers.flowtype) { downloads.push( - 'https://raw.githubusercontent.com/bevry/base/master/.flowconfig', + 'https://raw.githubusercontent.com/bevry/base/HEAD/.flowconfig', ) } else { await unlink('.flowconfig') @@ -203,16 +203,16 @@ export async function updateBaseFiles({ answers, packageData }) { await write( 'README.md', [ - '', - '', - '', + '', + '', + '', '## Usage', answers.docs && newDocumentationLink, - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', ] .filter((i) => i) .join('\n\n'), @@ -238,7 +238,7 @@ export async function updateBaseFiles({ answers, packageData }) { /\[(Tutorials & Guides|Documentation)\.?\]/g, '[Tutorials & Guides.]', ) - // insert new documentaiton under usage + // insert new documentation under usage if (newDocumentationLink) { content = content.replace('## Usage', function (found) { return found + '\n\n' + newDocumentationLink @@ -277,8 +277,44 @@ export async function updateBaseFiles({ answers, packageData }) { status('...updated history file') } - // write the funding file + // write bevry specific files if (isBevryOrganisation(answers.organisation)) { + // security + if (answers.npm) { + status('writing security file...') + await write( + 'SECURITY.md', + [ + '# Security Policy', + '', + '## Security Practices', + '', + `This project meets standardized secure software development practices, including 2FA for all members, password managers with monitoring, secure secret retrieval instead of storage. [Learn about our practices.](https://tidelift.com/funding/github/npm/${answers.name})`, + '', + '## Supported Versions', + '', + `This project uses [Bevry's automated tooling](https://github.com/bevry/boundation) to deliver the latest updates, fixes, and improvements inside the latest release while still maintaining widespread ecosystem compatibility.`, + '', + `[Refer to supported ecosystem versions: \`Editions\` section in \`README.md\`](https://github.com/${answers.githubSlug}/blob/${answers.defaultBranch}/README.md#Editions)`, + '', + `[Refer to automated support of ecosystem versions: \`boundation\` entries in \`HISTORY.md\`](https://github.com/${answers.githubSlug}/blob/${answers.defaultBranch}/HISTORY.md)`, + '', + `Besides testing and verification, out CI also [auto-merges](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions) [Dependabot security updates](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates) and [auto-publishes](https://github.com/bevry-actions/npm) successful builds of the [\`${answers.defaultBranch}\` branch](https://github.com/bevry/wait/actions?query=branch%3A${answers.defaultBranch}) to the [\`next\` version tag](https://www.npmjs.com/package/${answers.name}?activeTab=versions), offering immediate resolutions before scheduled maintenance releases.`, + '', + '## Reporting a Vulnerability', + '', + `[Report the vulnerability to the project owners.](https://github.com/${answers.githubSlug}/security/advisories)`, + '', + '[Report the vulnerability to Tidelift.](https://tidelift.com/security)', + ] + .filter((i) => i) + .join('\n\n'), + ) + status('...wrote security file') + } + + // fuunding + // https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository await spawn(['mkdir', '-p', '.github']) await write( '.github/FUNDING.yml', @@ -288,8 +324,11 @@ export async function updateBaseFiles({ answers, packageData }) { 'open_collective: bevry', 'ko_fi: balupton', 'liberapay: bevry', + answers.npm ? `tidelift: npm/${answers.name}` : '', "custom: ['https://bevry.me/fund']", - ].join('\n'), + ] + .filter(Boolean) + .join('\n'), ) } } diff --git a/source/bin.js b/source/bin.js index 113a00c..c9c90fd 100755 --- a/source/bin.js +++ b/source/bin.js @@ -1,7 +1,7 @@ #!/usr/bin/env node // builtin -import { resolve, join } from 'path' +import { resolve, join } from 'node:path' // get root with imports import filedirname from 'filedirname' diff --git a/source/ci.js b/source/ci.js index 6fc5935..73b72ce 100644 --- a/source/ci.js +++ b/source/ci.js @@ -1,10 +1,12 @@ +// external +import { intersect } from '@bevry/list' +import { filterNodeVersions } from '@bevry/nodejs-versions' + // local import { status, warn } from './log.js' import { readYAML, unlink, exists, writeYAML, spawn } from './fs.js' import { trimEmpty } from './util.js' -import { intersect } from '@bevry/list' import { allLanguages } from './data.js' -import { filterNodeVersions } from '@bevry/nodejs-versions' // github actions no longer supports node versions prior to 16 // https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/ @@ -19,7 +21,7 @@ function generateGitHubActionsJSON(state) { // prepare vars const actionsOperatingSystems = answers.npm - ? ['ubuntu-latest', 'macos-latest', 'windows-latest'] + ? ['ubuntu-latest'] // , 'macos-latest', 'windows-latest'] : ['ubuntu-latest'] const actionsOperatingSystemsExperimental = intersect( actionsOperatingSystems, @@ -94,7 +96,7 @@ function generateGitHubActionsJSON(state) { const npmPublishSteps = [ { name: 'publish to npm', - uses: 'bevry-actions/npm@v1.1.0', + uses: 'bevry-actions/npm@v1.1.1', with: { npmAuthToken: '${{ secrets.NPM_AUTH_TOKEN }}', npmBranchTag: answers.npm ? ':next' : null, @@ -206,6 +208,24 @@ function generateGitHubActionsJSON(state) { ], } : null, + automerge: { + permissions: { + contents: 'write', + 'pull-requests': 'write', + }, + 'runs-on': 'ubuntu-latest', + if: "github.actor == 'dependabot[bot]'", + steps: [ + { + name: 'Enable auto-merge for Dependabot PRs', + run: 'gh pr merge --auto --merge "$PR_URL"', + env: { + PR_URL: '${{github.event.pull_request.html_url}}', + GITHUB_TOKEN: '${{secrets.GITHUB_TOKEN}}', + }, + }, + ], + }, }, }) } @@ -219,19 +239,38 @@ export async function updateCI(state) { unlink('.travis.yml'), unlink('.mergify.yml'), unlink('.dependabot/config.yml'), + unlink('.github/workflows/automerge.yml'), spawn(['mkdir', '-p', '.github/workflows']), ]) // dependabot v2 file - // https://docs.github.com/en/github/administering-a-repository/enabling-and-disabling-version-updates#enabling-github-dependabot-version-updates - // https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#ignore + // https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file await writeYAML('.github/dependabot.yml', { version: 2, updates: [ + { + 'package-ecosystem': 'github-actions', + directory: '/', + schedule: { + interval: 'weekly', + day: 'sunday', + time: '00:00', + timezone: 'Australia/Perth', + }, + }, { 'package-ecosystem': 'npm', directory: '/', - schedule: { interval: 'weekly', day: 'sunday' }, + schedule: { + interval: 'weekly', + day: 'sunday', + time: '00:00', + timezone: 'Australia/Perth', + }, + // only allow security updates + // this is because of the lag it causes on the bevry org + // as well as that github only supports the maintained node.js versions so dependabot could merge a dependency that breaks unmaintained node.js versions that are still supported by our package + 'open-pull-requests-limit': 0, }, ], }) @@ -247,28 +286,6 @@ export async function updateCI(state) { ) } - // dependabot automerge - // https://github.com/ahmadnassri/action-dependabot-auto-merge - await writeYAML('.github/workflows/automerge.yml', { - name: 'automerge', - on: ['pull_request'], - jobs: { - automerge: { - 'runs-on': 'ubuntu-latest', - steps: [ - { uses: 'actions/checkout@v4' }, - { - uses: 'ahmadnassri/action-dependabot-auto-merge@v2', - with: { - 'github-token': - '${{ secrets.DEPENDABOT_AUTOMERGE_GITHUB_TOKEN }}', - }, - }, - ], - }, - }, - }) - // log status('...customised ci') } diff --git a/source/data.js b/source/data.js index d97a856..c06b606 100644 --- a/source/data.js +++ b/source/data.js @@ -1,5 +1,5 @@ // builtin -import { cwd } from 'process' +import { cwd } from 'node:process' // external import { diff --git a/source/editions.js b/source/editions.js index 605c162..1147cd0 100644 --- a/source/editions.js +++ b/source/editions.js @@ -1,5 +1,5 @@ // builtin -import * as pathUtil from 'path' +import * as pathUtil from 'node:path' // external import { add, has } from '@bevry/list' diff --git a/source/fs.js b/source/fs.js index ddf52a5..376ac5b 100644 --- a/source/fs.js +++ b/source/fs.js @@ -1,6 +1,6 @@ // builtin -import * as pathUtil from 'path' -import * as fsUtil from 'fs' +import * as pathUtil from 'node:path' +import * as fsUtil from 'node:fs' // external import yaml from 'js-yaml' @@ -39,7 +39,7 @@ export function unlink(file) { return new Promise(function (resolve, reject) { fsUtil.unlink(path, function (error) { if (error) { - if (error.message && error.message.includes('ENOENT')) return resolve() + if (error.code === 'ENOENT') return resolve() return reject(error) } console.log(path, 'has been removed') @@ -67,20 +67,23 @@ export async function unlinkIfContains(file, what) { } } -export function rmrf(files) { - return exec(`rm -Rf ${files.join(' ')}`) -} - -export function rmdir(file) { +export function remove(file) { + if (Array.isArray(file)) { + return Promise.all(file.map((i) => remove(i))) + } const path = pathUtil.resolve(pwd, file) return new Promise(function (resolve, reject) { - fsUtil.rmdir(path, { recursive: true }, function (error) { - if (error) { - if (error.message && error.message.includes('ENOENT')) return resolve() - return reject(error) - } - return resolve() - }) + fsUtil.rm( + path, + { recursive: true, force: true, maxRetries: 10 }, + function (error) { + if (error) { + if (error.code === 'ENOENT') return resolve() + return reject(error) + } + return resolve() + }, + ) }) } @@ -147,10 +150,14 @@ export function spawn(command, opts = {}) { if (stderr) { const errorMessage = stderr.toLowerCase() if ( + errorMessage.includes('enoent') || + errorMessage.includes('etarget') || errorMessage.includes('timeout') || errorMessage.includes('econn') ) { - console.log('trying again due to poor internet connection') + console.log( + 'trying again due to poor internet connection or caching', + ) return spawn(command, opts).then(resolve).catch(reject) } } diff --git a/source/get-git.js b/source/get-git.js index 73c16e0..100ab0e 100644 --- a/source/get-git.js +++ b/source/get-git.js @@ -72,7 +72,7 @@ async function getGitLocalConfigDefaultBranch(cwd = pwd) { } } -async function getGitActiveDefaultBranch(cwd = pwd) { +async function getGitActiveBranch(cwd = pwd) { try { const stdout = await exec('git rev-parse --abbrev-ref HEAD', { cwd, @@ -90,7 +90,7 @@ export async function getGitDefaultBranch(cwd = pwd) { if (detail.branch) return detail.branch try { const result = - (await getGitActiveDefaultBranch()) || + (await getGitActiveBranch()) || (await getGitLocalConfigDefaultBranch()) || (await getGitGlobalConfigDefaultBranch()) || 'main' diff --git a/source/index.js b/source/index.js index ee9caef..9651a62 100755 --- a/source/index.js +++ b/source/index.js @@ -1,3 +1,6 @@ +// external +import { preloadNodeVersions } from '@bevry/nodejs-versions' + // local import { status, success } from './log.js' import { spawn } from './fs.js' @@ -8,7 +11,6 @@ import { updateBaseFiles } from './base.js' import { generateEditions } from './editions.js' import { readWebsite, updateWebsite } from './website.js' import { updateRuntime } from './runtime.js' -import { preloadNodeVersions } from '@bevry/nodejs-versions' export default async function init(state) { await preloadNodeVersions() diff --git a/source/package.js b/source/package.js index 63036dc..dd18d8b 100644 --- a/source/package.js +++ b/source/package.js @@ -1,12 +1,10 @@ // builtin -import * as pathUtil from 'path' +import * as pathUtil from 'node:path' // external import * as typeChecker from 'typechecker' import { is as isBevryOrganisation } from '@bevry/github-orgs' import { complement, has } from '@bevry/list' - -// esm workarounds import arrangekeys from 'arrangekeys' import arrangePackageProperties from 'arrange-package-json' diff --git a/source/questions.js b/source/questions.js index b0438ea..299c7f1 100644 --- a/source/questions.js +++ b/source/questions.js @@ -1,7 +1,8 @@ // builtin -import * as pathUtil from 'path' +import * as pathUtil from 'node:path' // external +import versionCompare from 'version-compare' import { unique, last, first, intersect } from '@bevry/list' import { filterNodeVersions, @@ -60,7 +61,6 @@ import { isSourceModule, } from './package.js' import { getVercelAliases, getVercelName } from './website.js' -import versionCompare from 'version-compare' // ==================================== // Questions @@ -636,6 +636,7 @@ export async function getQuestions(state) { return filterSignificantNodeVersions({ released: true, maintainedOrLTS: true, + gte: '4', // minimum supported editions and assert-helpers version }) }, async default(opts) { @@ -782,15 +783,23 @@ export async function getQuestions(state) { message: 'Which Node.js versions must your package test against?', type: 'checkbox', validate: isSpecified, - choices({ nodeVersions, desiredNodeOnly, desiredNodeVersion }) { + choices({ + nodeVersions, + desiredNodeOnly, + desiredNodeVersion, + expandNodeVersions, + }) { if (desiredNodeOnly) { return [desiredNodeVersion] + } else if (expandNodeVersions) { + return nodeVersions } else if ( !nodeEngineVersion || isNodeVersionActiveOrCurrent(nodeEngineVersion) ) { return filterNodeVersions(nodeVersions, { maintained: true, + gte: nodeEngineVersion, }) } else { return filterNodeVersions(nodeVersions, { @@ -835,6 +844,60 @@ export async function getQuestions(state) { }, skip: true, }, + { + name: 'nodeVersionsTargeted', + message: + 'Which Node.js versions must your package target compilation against?', + type: 'checkbox', + validate: isSpecified, + choices({ + language, + desiredNodeVersion, + nodeVersionsSupported, + nodeVersionsTested, + }) { + if (language === 'json') return [desiredNodeVersion] + return unique(nodeVersionsTested.concat(nodeVersionsSupported)).sort( + versionCompare, + ) + }, + default(opts) { + return this.choices(opts) + }, + skip({ desiredNodeOnly }) { + return Boolean(desiredNodeOnly) + }, + }, + { + name: 'nodeVersionTargetMinimum', + message: + 'Automated property for constraining the minimum Node.js version for targeting', + type: 'list', + validate: isNumber, + choices({ language, desiredNodeVersion, nodeVersionsTargeted }) { + if (language === 'json') return [desiredNodeVersion] + return nodeVersionsTargeted + }, + default(opts) { + return first(this.choices(opts)) + }, + skip: true, + }, + { + name: 'nodeVersionTargetMaximum', + message: + 'Automated property for constraining the maximum Node.js version for targeting', + type: 'list', + validate: isNumber, + choices({ language, desiredNodeVersion, nodeVersionsTargeted }) { + if (language === 'json') return [desiredNodeVersion] + return nodeVersionsTargeted + }, + default(opts) { + return last(this.choices(opts)) + }, + skip: true, + }, { name: 'targets', type: 'checkbox', @@ -842,25 +905,22 @@ export async function getQuestions(state) { validate: isSpecified, async choices({ compilerNode, - desiredNodeVersion, - nodeVersionSupportedMinimum, - nodeVersionSupportedMaximum, - nodeVersionsSupported, + nodeVersions, + nodeVersionTargetMinimum, + nodeVersionTargetMaximum, }) { // ensure versions are in order of most preferred to least preferred // otherwise edition trimming will not work as expected + const nodeVersionsTargeted = filterNodeVersions(nodeVersions, { + gte: nodeVersionTargetMinimum, + lte: nodeVersionTargetMaximum, + }).reverse() return compilerNode === 'babel' - ? unique([ - desiredNodeVersion, - nodeVersionSupportedMinimum, - nodeVersionSupportedMaximum, - ]) - .sort(versionCompare) - .reverse() + ? nodeVersionsTargeted : compilerNode === 'typescript' ? intersect(allTypescriptTargets, [ ...(await fetchExclusiveCompatibleESVersionsForNodeVersions( - nodeVersionsSupported, + nodeVersionsTargeted, )), ]) // don't add ESNext as it is ephemeral : [] diff --git a/source/runtime.js b/source/runtime.js index d001c02..283826c 100644 --- a/source/runtime.js +++ b/source/runtime.js @@ -1,5 +1,5 @@ // builtin -import * as pathUtil from 'path' +import * as pathUtil from 'node:path' // external import versionCompare from 'version-compare' @@ -336,23 +336,29 @@ export async function updateRuntime(state) { // dependency compatibility for legacy node versions const dependencyCompat = { - cson: 5, - rimraf: 2, - safefs: 4, - safeps: 7, - taskgroup: 5, 'cli-spinners': 1, - 'lazy-require': 2, + 'lazy-require': 2, // 4 is node 10, 3 is node 8, 2 is node 0.10, extract-opts, safeps dep ... only docpad uses it + // safefs: 4, // 8 is node 4, 5 is node 8, 4 is 0.12, graceful-fs as only dep + // safeps: 7, // 11 is node 4, 9 is 8, 8 is 0.12, 7 is 0.8, extract-opts dep, safefs dep + // taskgroup: 5, // 6 is node 8, 5 is 0.8 + cson: 5, // 6 is node 8, 5 is 0.14, has many deps + rimraf: 2, + semver: 4, // 5 is node 10, 4 is 4 -- should use version-range or version-compare instead } + // editions v4 was last to support node <4 + // https://github.com/bevry/editions/blob/master/HISTORY.md#v500-2020-october-27 const devDependencyCompat = { - kava: 3, + // kava: 3, // 7 is node 4, 4 is 8, 3 is 0.12 + // '@bevry/ansi': 2, // 6 is node 4 + // errlop: 4, // 7 is node 4 + // assert-helpers needs 'process' module, which is node 4 and up } - if (versionCompare(answers.nodeVersionSupportedMinimum, 8) === -1) { + if (versionCompare(answers.nodeVersionSupportedMinimum, 10) === -1) { for (const [key, value] of Object.entries(dependencyCompat)) { versions[key] = value } } - if (versionCompare(answers.nodeVersionTestedMinimum, 8) === -1) { + if (versionCompare(answers.nodeVersionTestedMinimum, 10) === -1) { for (const [key, value] of Object.entries(devDependencyCompat)) { versions[key] = value } @@ -376,7 +382,7 @@ export async function updateRuntime(state) { // add our default scripts state.scripts = { 'our:setup:install': commands[answers.packageManager].install.join(' '), - 'our:clean': 'rm -Rf ./docs ./edition* ./es2015 ./es5 ./out ./.next', + 'our:clean': 'rm -rf ./docs ./edition* ./es2015 ./es5 ./out ./.next', 'our:meta:projectz': packageData.name === 'projectz' ? 'npm run our:bin -- compile' @@ -501,6 +507,10 @@ export async function updateRuntime(state) { packageData.prettier = { semi: false, singleQuote: true, + trailingComma: + versionCompare(answers.nodeVersionTargetMinimum, '8') < 0 + ? 'es5' + : 'all', } state.scripts['our:verify:eslint'] = [ 'eslint', @@ -619,7 +629,7 @@ export async function updateRuntime(state) { tools.forEach(function (tool) { const out = tools.length === 1 ? './docs' : `./docs/${tool}` packages[tool] = 'dev' - const parts = [`rm -Rf ${out}`, '&&'] + const parts = [`rm -rf ${out}`, '&&'] switch (tool) { case 'typedoc': packages.typedoc = 'dev' @@ -645,7 +655,7 @@ export async function updateRuntime(state) { '&&', `mv ${out}/$npm_package_name/$npm_package_version/* ${out}/`, '&&', - `rm -Rf ${out}/$npm_package_name/$npm_package_version`, + `rm -rf ${out}/$npm_package_name/$npm_package_version`, ) break case 'yuidoc': diff --git a/source/util.js b/source/util.js index 9fc5dea..5997b53 100644 --- a/source/util.js +++ b/source/util.js @@ -156,7 +156,7 @@ export function fixTsc(editionDirectory, sourceDirectory) { '||', '(', // begin move `mv ${editionDirectory}/${sourceDirectory} edition-temp`, - `&& rm -Rf ${editionDirectory}`, + `&& rm -rf ${editionDirectory}`, `&& mv edition-temp ${editionDirectory}`, `)`, // end move ')', // end fix diff --git a/source/versions.js b/source/versions.js index f366e96..a544299 100644 --- a/source/versions.js +++ b/source/versions.js @@ -1,13 +1,13 @@ // builtin -import { join } from 'path' +import { join } from 'node:path' // external -import testen from '@bevry/testen' +import testen, { Versions } from '@bevry/testen' import { complement, intersect } from '@bevry/list' import { filterNodeVersions } from '@bevry/nodejs-versions' +import versionCompare from 'version-compare' // local -const { Versions } = testen import { status } from './log.js' import { writePackage, @@ -15,7 +15,6 @@ import { setPackageNodeEngine, } from './package.js' import { updateRuntime } from './runtime.js' -import versionCompare from 'version-compare' import { nodeMajorVersion, nodeMajorVersions } from './util.js' // Update engines diff --git a/source/website.js b/source/website.js index 073d574..6d89d7e 100644 --- a/source/website.js +++ b/source/website.js @@ -1,5 +1,5 @@ // builtin -import * as pathUtil from 'path' +import * as pathUtil from 'node:path' // local import { pwd } from './data.js'