@npmcli/template-oss 4.18.0 → 4.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/config.js +49 -51
- package/lib/content/_job-release-integration.yml +1 -1
- package/lib/content/_step-node.yml +38 -12
- package/lib/content/ci-release.yml +1 -1
- package/lib/content/index.js +4 -4
- package/lib/content/pkg.json +0 -5
- package/lib/util/ci-versions.js +80 -0
- package/lib/util/git.js +0 -9
- package/lib/util/merge.js +0 -1
- package/package.json +1 -1
- package/lib/util/parse-ci-versions.js +0 -78
package/lib/config.js
CHANGED
|
@@ -1,41 +1,63 @@
|
|
|
1
1
|
const { relative, dirname, join, extname, posix, win32 } = require('path')
|
|
2
|
-
const { defaults, pick, omit, uniq } = require('lodash')
|
|
3
|
-
const
|
|
4
|
-
const parseCIVersions = require('./util/parse-ci-versions.js')
|
|
2
|
+
const { defaults, pick, omit, uniq, isPlainObject } = require('lodash')
|
|
3
|
+
const ciVersions = require('./util/ci-versions.js')
|
|
5
4
|
const parseDependabot = require('./util/dependabot.js')
|
|
6
5
|
const git = require('./util/git.js')
|
|
7
6
|
const gitignore = require('./util/gitignore.js')
|
|
8
|
-
const {
|
|
7
|
+
const { mergeWithCustomizers, customizers } = require('./util/merge.js')
|
|
9
8
|
const { FILE_KEYS, parseConfig: parseFiles, getAddedFiles, mergeFiles } = require('./util/files.js')
|
|
10
9
|
|
|
11
10
|
const CONFIG_KEY = 'templateOSS'
|
|
12
11
|
const getPkgConfig = (pkg) => pkg[CONFIG_KEY] || {}
|
|
13
12
|
|
|
14
13
|
const { name: NAME, version: LATEST_VERSION } = require('../package.json')
|
|
15
|
-
const { minimatch } = require('minimatch')
|
|
16
14
|
const MERGE_KEYS = [...FILE_KEYS, 'defaultContent', 'content']
|
|
17
15
|
const DEFAULT_CONTENT = require.resolve(NAME)
|
|
18
16
|
|
|
19
|
-
const merge =
|
|
17
|
+
const merge = mergeWithCustomizers(
|
|
18
|
+
customizers.mergeArrays('branches', 'distPaths', 'allowPaths', 'ignorePaths'),
|
|
19
|
+
(value, srcValue, key) => {
|
|
20
|
+
if (key === 'ciVersions' && (Array.isArray(srcValue) || isPlainObject(srcValue))) {
|
|
21
|
+
return { ...ciVersions.parse(value), ...ciVersions.parse(srcValue) }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
)
|
|
20
25
|
|
|
21
26
|
const makePosix = (v) => v.split(win32.sep).join(posix.sep)
|
|
22
27
|
const deglob = (v) => makePosix(v).replace(/[/*]+$/, '')
|
|
23
28
|
const posixDir = (v) => `${v === '.' ? '' : deglob(v).replace(/\/$/, '')}${posix.sep}`
|
|
24
29
|
const posixGlob = (str) => `${posixDir(str)}**`
|
|
25
30
|
|
|
26
|
-
const getCmdPath = (key, {
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
const getCmdPath = (key, { pkgConfig, rootConfig, isRoot, pkg, rootPkg }) => {
|
|
32
|
+
const result = (local, isRelative) => {
|
|
33
|
+
let root = local
|
|
34
|
+
const isLocal = local.startsWith('.') || local.startsWith('/')
|
|
35
|
+
|
|
36
|
+
if (isLocal) {
|
|
37
|
+
if (isRelative) {
|
|
38
|
+
// Make a path relative from a workspace to the root if we are in a workspace
|
|
39
|
+
local = makePosix(join(relative(pkg.path, rootPkg.path), local))
|
|
40
|
+
}
|
|
41
|
+
local = `node ${local}`
|
|
42
|
+
root = `node ${root}`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
isLocal,
|
|
47
|
+
local,
|
|
48
|
+
root,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
29
51
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
52
|
+
if (pkgConfig[key]) {
|
|
53
|
+
return result(pkgConfig[key])
|
|
54
|
+
}
|
|
33
55
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
root: !isLocal ? defaultPath : `node ${rootPath}`,
|
|
37
|
-
local: !isLocal ? defaultPath : `node ${wsToRoot(rootPath)}`,
|
|
56
|
+
if (rootConfig[key]) {
|
|
57
|
+
return result(rootConfig[key], !isRoot)
|
|
38
58
|
}
|
|
59
|
+
|
|
60
|
+
return result(key)
|
|
39
61
|
}
|
|
40
62
|
|
|
41
63
|
const mergeConfigs = (...configs) => {
|
|
@@ -139,9 +161,8 @@ const getFullConfig = async ({
|
|
|
139
161
|
] : [],
|
|
140
162
|
]
|
|
141
163
|
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
const npxPath = getCmdPath('npx', { rootConfig, defaultConfig, isRoot, pkg, rootPkg })
|
|
164
|
+
const npmPath = getCmdPath('npm', { pkgConfig, rootConfig, isRoot, pkg, rootPkg })
|
|
165
|
+
const npxPath = getCmdPath('npx', { pkgConfig, rootConfig, isRoot, pkg, rootPkg })
|
|
145
166
|
|
|
146
167
|
// these are written to ci yml files so it needs to always use posix
|
|
147
168
|
const pkgPath = makePosix(relative(rootPkg.path, pkg.path)) || '.'
|
|
@@ -157,9 +178,12 @@ const getFullConfig = async ({
|
|
|
157
178
|
|
|
158
179
|
const branches = uniq([...pkgConfig.branches ?? [], pkgConfig.releaseBranch]).filter(Boolean)
|
|
159
180
|
const gitBranches = await git.getBranches(rootPkg.path, branches)
|
|
160
|
-
const currentBranch = await git.currentBranch(rootPkg.path)
|
|
161
|
-
const isReleaseBranch = currentBranch ? minimatch(currentBranch, pkgConfig.releaseBranch) : false
|
|
162
181
|
const defaultBranch = await git.defaultBranch(rootPkg.path) ?? 'main'
|
|
182
|
+
const isReleaseBranch = !!pkgConfig.backport
|
|
183
|
+
const publishTag = isReleaseBranch ? `next-${pkgConfig.backport}` : 'latest'
|
|
184
|
+
const releaseBranch = isReleaseBranch
|
|
185
|
+
? pkgConfig.releaseBranch.replace(/\*/g, pkgConfig.backport)
|
|
186
|
+
: defaultBranch
|
|
163
187
|
|
|
164
188
|
// all derived keys
|
|
165
189
|
const derived = {
|
|
@@ -179,12 +203,11 @@ const getFullConfig = async ({
|
|
|
179
203
|
// controls whether we are in a monorepo with any public workspaces
|
|
180
204
|
isMonoPublic: isMono && !!publicPkgs.filter(p => p.path !== rootPkg.path).length,
|
|
181
205
|
// git
|
|
182
|
-
defaultBranch,
|
|
183
|
-
baseBranch: isReleaseBranch ? currentBranch : defaultBranch,
|
|
184
206
|
branches: gitBranches.branches,
|
|
185
207
|
branchPatterns: gitBranches.patterns,
|
|
186
208
|
isReleaseBranch,
|
|
187
|
-
|
|
209
|
+
releaseBranch,
|
|
210
|
+
publishTag,
|
|
188
211
|
dependabot: parseDependabot(pkgConfig, defaultConfig, gitBranches.branches),
|
|
189
212
|
// repo
|
|
190
213
|
repoDir: rootPkg.path,
|
|
@@ -218,6 +241,8 @@ const getFullConfig = async ({
|
|
|
218
241
|
// lockfiles are only present at the root, so this only should be set for
|
|
219
242
|
// all workspaces based on the root
|
|
220
243
|
lockfile: rootPkgConfig.lockfile,
|
|
244
|
+
// ci versions / engines
|
|
245
|
+
ciVersions: ciVersions.get(pkg.pkgJson.engines?.node, pkgConfig),
|
|
221
246
|
// gitignore
|
|
222
247
|
ignorePaths: [
|
|
223
248
|
...gitignore.sort([
|
|
@@ -242,33 +267,6 @@ const getFullConfig = async ({
|
|
|
242
267
|
__PARTIAL_DIRS__: fileDirs,
|
|
243
268
|
}
|
|
244
269
|
|
|
245
|
-
if (pkgConfig.ciVersions) {
|
|
246
|
-
let versions = pkgConfig.ciVersions
|
|
247
|
-
if (versions === 'latest' || (Array.isArray(versions) && versions.includes('latest'))) {
|
|
248
|
-
const { ciVersions } = [isWorkspace ? rootPkgConfig : {}, defaultConfig]
|
|
249
|
-
.find(c => Array.isArray(c.ciVersions))
|
|
250
|
-
const defaultLatest = ciVersions[ciVersions.length - 1]
|
|
251
|
-
versions = [].concat(versions).map(v => v === 'latest' ? defaultLatest : v)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const { targets, engines } = parseCIVersions(versions)
|
|
255
|
-
|
|
256
|
-
// get just a list of the target versions (not ranges)
|
|
257
|
-
// these are used for the node version when doing engines checks
|
|
258
|
-
// since we want to test in the lowest version of each major
|
|
259
|
-
let targetVersions = targets.filter(t => semver.valid(t))
|
|
260
|
-
// if the versions are all ranges then convert them to the lower bound of each range
|
|
261
|
-
if (!targetVersions.length) {
|
|
262
|
-
targetVersions = targets.filter(t => semver.validRange(t)).map(t => {
|
|
263
|
-
return new semver.Range(t).set[0][0].semver.version
|
|
264
|
-
})
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
derived.ciVersions = targets
|
|
268
|
-
derived.baseCiVersions = targetVersions
|
|
269
|
-
derived.engines = pkgConfig.engines || engines
|
|
270
|
-
}
|
|
271
|
-
|
|
272
270
|
if (!pkgConfig.eslint) {
|
|
273
271
|
derived.ignorePaths = derived.ignorePaths.filter(p => !p.includes('eslint'))
|
|
274
272
|
if (Array.isArray(pkgConfig.requiredPackages?.devDependencies)) {
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
- name: Setup Node
|
|
2
2
|
uses: actions/setup-node@v3
|
|
3
|
+
id: node
|
|
3
4
|
with:
|
|
4
5
|
node-version: {{#if jobIsMatrix}}$\{{ matrix.node-version }}{{else}}{{ last ciVersions }}{{/if}}
|
|
6
|
+
check-latest: contains({{#if jobIsMatrix}}matrix.node-version{{else}}'{{ last ciVersions }}'{{/if}}, '.x')
|
|
5
7
|
{{#if lockfile}}
|
|
6
8
|
cache: npm
|
|
7
9
|
{{/if}}
|
|
10
|
+
|
|
8
11
|
{{#if updateNpm}}
|
|
9
|
-
|
|
12
|
+
# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
|
|
10
13
|
- name: Update Windows npm
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
if: |
|
|
15
|
+
matrix.platform.os == 'windows-latest' && (
|
|
16
|
+
startsWith(steps.node.outputs.node-version, 'v10.') || startsWith(steps.node.outputs.node-version, 'v12.') || startsWith(steps.node.outputs.node-version, 'v14.')
|
|
17
|
+
)
|
|
13
18
|
run: |
|
|
14
19
|
curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz
|
|
15
20
|
tar xf npm-7.5.4.tgz
|
|
@@ -17,15 +22,36 @@
|
|
|
17
22
|
node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz
|
|
18
23
|
cd ..
|
|
19
24
|
rmdir /s /q package
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
|
|
26
|
+
# Start on Node 10 because we dont test on anything lower
|
|
27
|
+
- name: Install npm@7 on Node 10
|
|
28
|
+
shell: bash
|
|
29
|
+
if: startsWith(steps.node.outputs.node-version, 'v10.')
|
|
30
|
+
id: npm-7
|
|
31
|
+
run: |
|
|
32
|
+
npm i --prefer-online --no-fund --no-audit -g npm@7
|
|
33
|
+
echo "updated=true" >> "$GITHUB_OUTPUT"
|
|
34
|
+
|
|
35
|
+
- name: Install npm@8 on Node 12
|
|
36
|
+
shell: bash
|
|
37
|
+
if: startsWith(steps.node.outputs.node-version, 'v12.')
|
|
38
|
+
id: npm-8
|
|
39
|
+
run: |
|
|
40
|
+
npm i --prefer-online --no-fund --no-audit -g npm@8
|
|
41
|
+
echo "updated=true" >> "$GITHUB_OUTPUT"
|
|
42
|
+
|
|
43
|
+
- name: Install npm@9 on Node 14/16/18.0
|
|
44
|
+
shell: bash
|
|
45
|
+
if: startsWith(steps.node.outputs.node-version, 'v14.') || startsWith(steps.node.outputs.node-version, 'v16.') || startsWith(steps.node.outputs.node-version, 'v18.0.')
|
|
46
|
+
id: npm-9
|
|
47
|
+
run: |
|
|
48
|
+
npm i --prefer-online --no-fund --no-audit -g npm@9
|
|
49
|
+
echo "updated=true" >> "$GITHUB_OUTPUT"
|
|
50
|
+
|
|
51
|
+
- name: Install npm@latest on Node
|
|
52
|
+
if: $\{{ !(steps.npm-7.outputs.updated || steps.npm-8.outputs.updated || steps.npm-9.outputs.updated) }}
|
|
53
|
+
run: npm i --prefer-online --no-fund --no-audit -g npm@latest
|
|
54
|
+
|
|
29
55
|
- name: npm Version
|
|
30
56
|
run: npm -v
|
|
31
57
|
{{/if}}
|
package/lib/content/index.js
CHANGED
|
@@ -136,6 +136,8 @@ module.exports = {
|
|
|
136
136
|
windowsCI: true,
|
|
137
137
|
macCI: true,
|
|
138
138
|
branches: ['main', 'latest'],
|
|
139
|
+
// set this to the major version to backport
|
|
140
|
+
backport: null,
|
|
139
141
|
releaseBranch: 'release/v*',
|
|
140
142
|
distPaths: [
|
|
141
143
|
'bin/',
|
|
@@ -156,14 +158,12 @@ module.exports = {
|
|
|
156
158
|
'/CHANGELOG*',
|
|
157
159
|
],
|
|
158
160
|
ignorePaths: [],
|
|
159
|
-
ciVersions:
|
|
161
|
+
ciVersions: {},
|
|
162
|
+
latestCiVersion: 20,
|
|
160
163
|
lockfile: false,
|
|
161
164
|
codeowner: '@npm/cli-team',
|
|
162
165
|
eslint: true,
|
|
163
166
|
publish: false,
|
|
164
|
-
npm: 'npm',
|
|
165
|
-
npx: 'npx',
|
|
166
|
-
npmSpec: 'latest',
|
|
167
167
|
updateNpm: true,
|
|
168
168
|
dependabot: 'increase-if-necessary',
|
|
169
169
|
unwantedPackages: [
|
package/lib/content/pkg.json
CHANGED
|
@@ -21,11 +21,6 @@
|
|
|
21
21
|
"postpublish": {{{ del }}}
|
|
22
22
|
},
|
|
23
23
|
"repository": {{#if repository}}{{{ json repository }}}{{else}}{{{ del }}}{{/if}},
|
|
24
|
-
"engines": {
|
|
25
|
-
{{#if engines}}
|
|
26
|
-
"node": {{{ json engines }}}
|
|
27
|
-
{{/if}}
|
|
28
|
-
},
|
|
29
24
|
{{{ json __CONFIG_KEY__ }}}: {
|
|
30
25
|
"version": {{#if isDogFood}}{{{ del }}}{{else}}{{{ json __VERSION__ }}}{{/if}}
|
|
31
26
|
},
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const { uniq, range, isPlainObject } = require('lodash')
|
|
2
|
+
const semver = require('semver')
|
|
3
|
+
|
|
4
|
+
const parseCiVersions = (ciVersions) => {
|
|
5
|
+
if (Array.isArray(ciVersions)) {
|
|
6
|
+
return Object.fromEntries(ciVersions.map((v) => [v, true]))
|
|
7
|
+
}
|
|
8
|
+
if (isPlainObject(ciVersions)) {
|
|
9
|
+
return ciVersions
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const getLowerBounds = (sRange) => {
|
|
14
|
+
return new semver.Range(sRange).set.map(c => c[0])
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const getCiVersions = (nodeEngines, pkgConfig) => {
|
|
18
|
+
let allCiVersions = {}
|
|
19
|
+
|
|
20
|
+
// get ci versions
|
|
21
|
+
const { latestCiVersion, ciVersions } = pkgConfig
|
|
22
|
+
|
|
23
|
+
if (latestCiVersion) {
|
|
24
|
+
allCiVersions[`${latestCiVersion}.x`] = true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// determine the ci versions from the node engines set
|
|
28
|
+
if (nodeEngines) {
|
|
29
|
+
const lowerBounds = getLowerBounds(nodeEngines)
|
|
30
|
+
.map(v => v.semver)
|
|
31
|
+
.filter(v => v.version)
|
|
32
|
+
|
|
33
|
+
for (const version of lowerBounds) {
|
|
34
|
+
allCiVersions[version.version] = true
|
|
35
|
+
allCiVersions[`${version.major}.x`] = true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const lowestCiVersion = semver.sort(lowerBounds)[0]?.major
|
|
39
|
+
if (lowestCiVersion && latestCiVersion) {
|
|
40
|
+
for (const major of range(lowestCiVersion, latestCiVersion, 2)) {
|
|
41
|
+
allCiVersions[`${major}.x`] = true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (ciVersions === 'latest' && latestCiVersion) {
|
|
47
|
+
// the plain string 'latest' means latest only and everything else is removed
|
|
48
|
+
allCiVersions = { [`${latestCiVersion}.x`]: true }
|
|
49
|
+
} else {
|
|
50
|
+
// this allows ciVersions to turn off default versions by setting them to a falsy value
|
|
51
|
+
Object.assign(allCiVersions, parseCiVersions(ciVersions))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (allCiVersions.latest && latestCiVersion) {
|
|
55
|
+
delete allCiVersions.latest
|
|
56
|
+
allCiVersions[`${latestCiVersion}.x`] = true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const filteredCiVersions = Object.entries(allCiVersions)
|
|
60
|
+
.filter(([, v]) => v)
|
|
61
|
+
.map(([k]) => k)
|
|
62
|
+
|
|
63
|
+
return uniq(filteredCiVersions).sort((a, b) => {
|
|
64
|
+
const aComp = getLowerBounds(a)[0]
|
|
65
|
+
const bComp = getLowerBounds(b)[0]
|
|
66
|
+
|
|
67
|
+
if (aComp.semver.major > bComp.semver.major) {
|
|
68
|
+
return 1
|
|
69
|
+
} else if (aComp.semver.major < bComp.semver.major) {
|
|
70
|
+
return -1
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return aComp.operator ? 1 : -1
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = {
|
|
78
|
+
parse: parseCiVersions,
|
|
79
|
+
get: getCiVersions,
|
|
80
|
+
}
|
package/lib/util/git.js
CHANGED
|
@@ -66,17 +66,8 @@ const defaultBranch = async (path) => {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
const currentBranch = async (path) => {
|
|
70
|
-
try {
|
|
71
|
-
return await tryGit(path, 'rev-parse', '--abbrev-ref', 'HEAD')
|
|
72
|
-
} catch {
|
|
73
|
-
// ignore errors
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
69
|
module.exports = {
|
|
78
70
|
getUrl,
|
|
79
71
|
getBranches,
|
|
80
72
|
defaultBranch,
|
|
81
|
-
currentBranch,
|
|
82
73
|
}
|
package/lib/util/merge.js
CHANGED
|
@@ -65,7 +65,6 @@ const customizers = {
|
|
|
65
65
|
module.exports = {
|
|
66
66
|
// default merge is to overwrite arrays
|
|
67
67
|
merge: mergeWithCustomizers(customizers.overwriteArrays),
|
|
68
|
-
mergeWithArrays: (...keys) => mergeWithCustomizers(customizers.mergeArrays(...keys)),
|
|
69
68
|
mergeWithCustomizers,
|
|
70
69
|
mergeWith,
|
|
71
70
|
customizers,
|
package/package.json
CHANGED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
const semver = require('semver')
|
|
2
|
-
const { partition, uniq, groupBy } = require('lodash')
|
|
3
|
-
|
|
4
|
-
// try to parse a version. if its invalid then
|
|
5
|
-
// try to parse it as a range instead
|
|
6
|
-
const versionOrRange = (v) => semver.parse(v) || new semver.Range(v)
|
|
7
|
-
|
|
8
|
-
// get the version or the upper bound of the range
|
|
9
|
-
// used for sorting to give the latest ci target
|
|
10
|
-
const getMaxVersion = (v) => v.version || v.set[0][1].semver.version
|
|
11
|
-
|
|
12
|
-
// given an array of versions, returns an object where
|
|
13
|
-
// each key is a major and each value is a sorted list of versions
|
|
14
|
-
const versionsByMajor = (versions) => {
|
|
15
|
-
const majors = groupBy(versions, (v) => semver.major(v))
|
|
16
|
-
for (const [k, vs] of Object.entries(majors)) {
|
|
17
|
-
majors[k] = semver.sort(vs)[0]
|
|
18
|
-
}
|
|
19
|
-
return majors
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// given a list of semver ci targets like:
|
|
23
|
-
// ['12.13.0', '12.x', '14.15.0', '14.x', '16.0.0', '16.x']
|
|
24
|
-
// this will parse into a uniq list of lowest "supported"
|
|
25
|
-
// versions. In our cases so that will return
|
|
26
|
-
// '^12.13.0 || ^14.15.0 || >=16'. This is not super generic but fits
|
|
27
|
-
// our use case for now where we want to test on a bunch of
|
|
28
|
-
// specific versions/ranges and map them to somewhat loose
|
|
29
|
-
// semver range for package.json#engines.node. This only supports
|
|
30
|
-
// returning ^ ranges and makes the last version >= currently.
|
|
31
|
-
//
|
|
32
|
-
// Assumptions:
|
|
33
|
-
// - ranges span a single major version
|
|
34
|
-
// - specific versions are lower then the upper bound of
|
|
35
|
-
// ranges within the same major version
|
|
36
|
-
const parseCITargets = (targets = []) => {
|
|
37
|
-
const [versions, ranges] = partition(
|
|
38
|
-
targets.map((t) => versionOrRange(t)),
|
|
39
|
-
(t) => t.version
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
const sorted = [...versions, ...ranges]
|
|
43
|
-
.sort((a, b) => semver.compareBuild(getMaxVersion(a), getMaxVersion(b)))
|
|
44
|
-
.map((v) => v.version || v.raw)
|
|
45
|
-
|
|
46
|
-
// object of {major: lowestVersion } for all passed in versions
|
|
47
|
-
const minVersions = versionsByMajor(versions)
|
|
48
|
-
|
|
49
|
-
// object of {major: lowestVersionInRange } for all passed in ranges
|
|
50
|
-
const minRanges = versionsByMajor(ranges.map((r) => semver.minVersion(r)))
|
|
51
|
-
|
|
52
|
-
// Given all the uniq major versions in targets...
|
|
53
|
-
const parsedRanges = uniq([...Object.keys(minVersions), ...Object.keys(minRanges)])
|
|
54
|
-
// first sort by major to make it display nicer
|
|
55
|
-
.sort((a, b) => Number(a) - Number(b))
|
|
56
|
-
.map((major) => {
|
|
57
|
-
const minVersion = minVersions[major]
|
|
58
|
-
const minRange = minRanges[major]
|
|
59
|
-
// if we only have one then return that
|
|
60
|
-
if (!minVersion || !minRange) {
|
|
61
|
-
return minVersion || minRange
|
|
62
|
-
}
|
|
63
|
-
// otherwise return min version
|
|
64
|
-
// XXX: this assumes the versions are lower than the upper
|
|
65
|
-
// bound for any range for the same major. This is ok for
|
|
66
|
-
// now but will break with more complex/specific semver ranges
|
|
67
|
-
return minVersion
|
|
68
|
-
})
|
|
69
|
-
// make the last version allow all greater than
|
|
70
|
-
.map((v, index, list) => (index === list.length - 1 ? '>=' : '^') + v)
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
targets: sorted,
|
|
74
|
-
engines: parsedRanges.join(' || '),
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
module.exports = parseCITargets
|