@ 261105.4
current
import semver from 'semver';

export function getEOLDate(ltsStartDate) {
  // Maintenance LTS lasts for 18 months.
  const result = getLTSMaintenanceStartDate(ltsStartDate);
  result.setMonth(result.getMonth() + 18);
  return result;
}

export function getLTSMaintenanceStartDate(ltsStartDate) {
  // Active LTS lasts for one year.
  const result = new Date(ltsStartDate);
  result.setMonth(result.getMonth() + 12);
  return result;
}

export function getStartLTSBlurb({ date, ltsCodename, versionComponents }) {
  const dateFormat = { month: 'long', year: 'numeric' };
  // TODO pull these from the schedule.json in the Release repo?
  const eolDate = getEOLDate(date);
  const eol = eolDate.toLocaleString('en-US', dateFormat);
  const { major } = versionComponents;
  return [
    `This release marks the transition of Node.js ${major}.x into Long Term Support (LTS)`,
    `with the codename '${ltsCodename}'. It will continue to receive updates through to`,
    `the end of ${eol}.`,
    '',
    'Other than updating metadata, such as the `process.release` object, to reflect',
    'that the release is LTS, no further changes since the previous release are',
    'included.'
  ].join('\n');
}

export function updateTestProcessRelease(test, options) {
  const { versionComponents, ltsCodename } = options;
  if (test.includes(ltsCodename)) {
    return test;
  }
  const inLines = test.split('\n');
  const outLines = [];
  const { major, minor } = versionComponents;
  for (const line of inLines) {
    if (line === '} else {') {
      outLines.push(`} else if (versionParts[0] === '${major}' ` +
                    `&& versionParts[1] >= ${minor}) {`
      );
      outLines.push(
        `  assert.strictEqual(process.release.lts, '${ltsCodename}');`
      );
    }
    outLines.push(line);
  }
  return outLines.join('\n');
}

export function getAlphaVersionComponents(version) {
  const [tag, ...components] = version.prerelease;
  if (tag !== 'alpha' || components.length !== 3 ||
      !components.every(Number.isInteger) ||
      version.minor !== 0 || version.patch !== 0) {
    return null;
  }
  const [major, minor, patch] = components;
  return { major, minor, patch };
}

export function isAlphaReleaseLine(nodeVersionH) {
  return /^#define NODE_ALPHA_MAJOR_VERSION \d+$/m.test(nodeVersionH);
}

export function formatVersion({ major, minor, patch }, alphaVersionComponents) {
  const version = `${major}.${minor}.${patch}`;
  if (!alphaVersionComponents) return version;
  return `${version}-alpha.${formatVersion(alphaVersionComponents)}`;
}

export function updateNodeVersionForNextRelease(
  nodeVersionH, { versionComponents, alphaVersionComponents }) {
  const macro = alphaVersionComponents ? 'NODE_ALPHA_PATCH_VERSION' : 'NODE_PATCH_VERSION';
  const { patch } = alphaVersionComponents ?? versionComponents;
  return nodeVersionH
    .replace(new RegExp(`^#define ${macro} ${patch}$`, 'm'), `#define ${macro} ${patch + 1}`)
    .replace(/^#define NODE_VERSION_IS_RELEASE 1$/m, '#define NODE_VERSION_IS_RELEASE 0');
}

export function updateNodeVersionForNextMajor(nodeVersionH, major) {
  return nodeVersionH
    .replace(/^#define NODE_MAJOR_VERSION \d+$/m, `#define NODE_MAJOR_VERSION ${major}`)
    .replace(/^#define NODE_MINOR_VERSION \d+$/m, '#define NODE_MINOR_VERSION 0')
    .replace(/^#define NODE_PATCH_VERSION \d+$/m, '#define NODE_PATCH_VERSION 0');
}

export function incrementVersion(version, release) {
  const parsed = semver.parse(version);
  const alpha = parsed && getAlphaVersionComponents(parsed);
  if (!alpha) return semver.inc(version, release);
  return formatVersion(parsed, release === 'minor'
    ? { major: alpha.major, minor: alpha.minor + 1, patch: 0 }
    : { ...alpha, patch: alpha.patch + 1 });
}