Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ranges/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const data = await ranges('alpha', { now: '2026-12-15' })

## Structure

This module will return a medium-sized object with the following structure, with each property being in the context of the range it's under:
This module will return a medium-sized object with the following structure, with each property being in the context of the range it's under. A field with nothing to point to, like `oldestSecurity` on a release line that hasn't had a security release yet, is `undefined` (and left out of JSON).

- all:
- versions (Array): An array of versions. Leaves out Alpha releases.
Expand Down
45 changes: 19 additions & 26 deletions ranges/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,12 @@ async function generateRanges(filter, options) {
if (data[line].support?.phases.current === 'start') {
ranges.current.versions.push(key); // add current iteration to the versions array if the phase is `start` which means it'll be current.

if (
ranges.current.oldestSecurity === undefined &&
ranges.current.newestSecurity === undefined
) {
ranges.current.oldestSecurity = `${data[line].security.oldest}`;
ranges.current.newestSecurity = `${data[line].security.newest}`;
// only the first Current line fills these in. checking the versions
// count rather than the fields, since a line without a security
// release leaves them undefined.
if (ranges.current.versions.length === 1) {
ranges.current.oldestSecurity = data[line].security.oldest;
ranges.current.newestSecurity = data[line].security.newest;
}
}
}
Expand All @@ -176,14 +176,12 @@ async function generateRanges(filter, options) {
// TODO: do we want to include all versions in the release line, even prior to it being minted LTS?
ranges['lts/latest'].versions.push(key);

if (ranges['lts/latest'].oldestSecurity === undefined) {
// only checking if this one is undefined, since everything else _should_ be undefined if this one is. saves some processing power.
ranges['lts/latest'].oldestSecurity =
`${data[line].security.oldest}`;
ranges['lts/latest'].newestSecurity =
`${data[line].security.newest}`;
ranges['lts/latest'].oldestLts = `${data[line].support.lts.oldest}`;
ranges['lts/latest'].newestLts = `${data[line].support.lts.newest}`;
if (ranges['lts/latest'].versions.length === 1) {
// only the first LTS line fills these in, same as 'current'
ranges['lts/latest'].oldestSecurity = data[line].security.oldest;
ranges['lts/latest'].newestSecurity = data[line].security.newest;
ranges['lts/latest'].oldestLts = data[line].support.lts.oldest;
ranges['lts/latest'].newestLts = data[line].support.lts.newest;
}
}
}
Expand All @@ -203,26 +201,21 @@ async function generateRanges(filter, options) {
) {
ranges['lts/maintenance'].versions.push(key);

if (
ranges['lts/maintenance'].newestSecurity === undefined &&
ranges['lts/maintenance'].newestLts === undefined
) {
if (ranges['lts/maintenance'].versions.length === 1) {
ranges['lts/maintenance'].newestSecurity =
`${data[line].security.newest}`;
ranges['lts/maintenance'].newestLts =
`${data[line].support.lts.newest}`;
data[line].security.newest;
ranges['lts/maintenance'].newestLts = data[line].support.lts.newest;
}

if (
ranges['lts/maintenance'].oldestSecurity !==
`${data[line].security.oldest}` ||
data[line].security.oldest ||
ranges['lts/maintenance'].oldestLts !==
`${data[line].support.lts.oldest}`
data[line].support.lts.oldest
) {
ranges['lts/maintenance'].oldestSecurity =
`${data[line].security.oldest}`;
ranges['lts/maintenance'].oldestLts =
`${data[line].support.lts.oldest}`;
data[line].security.oldest;
ranges['lts/maintenance'].oldestLts = data[line].support.lts.oldest;
}
}
}
Expand Down
126 changes: 126 additions & 0 deletions ranges/test/emptyFields.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
const { deepStrictEqual } = require('node:assert');
const ranges = require('../index');
const { at } = require('./fixtures');
const { describe, it } = require('node:test');

// core's snapshot time, when the Current line hasn't had a security release yet
const snapshotNow = JSON.parse(require('../../core/test/data/static/now.json'));

describe('fields without a value should be undefined, not "undefined"', async () => {
it('should leave out the security fields of a Current line without security releases', async () => {
const data = await ranges(undefined, at(snapshotNow));

deepStrictEqual(data.current.versions, ['v25.1.0', 'v25.0.0']);
deepStrictEqual(data.current.oldestSecurity, undefined);
deepStrictEqual(data.current.newestSecurity, undefined);
deepStrictEqual(JSON.parse(JSON.stringify(data.current)), {
versions: ['v25.1.0', 'v25.0.0'],
newest: 'v25.1.0',
oldest: 'v25.0.0',
});
});

it('should leave out the security fields of an LTS line without security releases', async () => {
// a date when the only Active LTS line hasn't had a security release
const data = await ranges(undefined, at('2016-06-01'));

deepStrictEqual(data['lts/latest'].oldestSecurity, undefined);
deepStrictEqual(data['lts/latest'].newestSecurity, undefined);
deepStrictEqual(data['lts/latest'].oldestLts, '4.2.0');
deepStrictEqual(data['lts/latest'].newestLts, '4.4.5');
deepStrictEqual(data['lts/active'].newestSecurity, undefined);
});

it('should only take the security fields from the first Current line', async () => {
// a date when the newest Current line has no security releases, but an
// older line also in "current" (one with no LTS or maintenance dates in
// schedule.json) has one
const data = await ranges('current', at('2016-06-23'));

deepStrictEqual(data.current.newest, 'v6.2.2');
deepStrictEqual(data.current.versions.includes('v0.12.15'), true);
deepStrictEqual(data.current.oldestSecurity, undefined);
deepStrictEqual(data.current.newestSecurity, undefined);
});

it('should leave out the LTS and security fields when the data has none', async () => {
// made-up data, since the real data always has these by the time a line
// is LTS: neither line has security releases, and the newest release of
// each line isn't marked as LTS, so core has no `support.lts.newest`
const release = (version, date, lts = false) => ({
version,
date,
lts,
files: ['linux-x64', 'src'],
});
const index = [
release('v99.1.0', '2099-11-01'),
release('v99.0.0', '2099-10-25', 'Placeholder'),
release('v98.1.0', '2098-11-01'),
release('v98.0.0', '2098-10-25', 'Placeholder'),
];
const schedule = {
v98: {
start: '2098-04-20',
lts: '2098-10-20',
maintenance: '2099-10-20',
end: '2101-04-30',
codename: '',
},
v99: {
start: '2099-04-20',
lts: '2099-10-20',
maintenance: '2100-10-20',
end: '2102-04-30',
codename: '',
},
};
// round-tripping through JSON to check what ends up in the output
const data = JSON.parse(
JSON.stringify(
await ranges(undefined, at('2099-12-01', { index, schedule })),
),
);

deepStrictEqual(data['lts/latest'], {
versions: ['v99.0.0'],
oldestLts: '99.0.0',
newest: 'v99.0.0',
oldest: 'v99.0.0',
});
deepStrictEqual(data['lts/maintenance'], {
versions: ['v98.0.0'],
oldestLts: '98.0.0',
newest: 'v98.0.0',
oldest: 'v98.0.0',
});
deepStrictEqual(data['lts/active'], {
versions: ['v99.0.0', 'v98.0.0'],
oldestLts: '98.0.0',
newest: 'v99.0.0',
oldest: 'v98.0.0',
});
});

it('should never have "undefined" as a value', async () => {
for (const now of [
'2016-06-01',
'2018-01-01',
'2020-01-01',
'2024-01-01',
'2025-09-01',
snapshotNow,
]) {
const data = await ranges(undefined, at(now));
for (const range in data) {
for (const field in data[range]) {
deepStrictEqual(
data[range][field] === 'undefined',
false,
`${now} ${range}.${field}`,
);
}
}
}
});
});
Loading