 ' ' ? '\n' : ''));
}

function getArgDescription(type) {
  switch (typeLookup[type]) {
    case 'kNoOp':
    case 'kV8Option':
    case 'kBoolean':
    case undefined:
      break;
    case 'kHostPort':
      return '[host:]port';
    case 'kInteger':
    case 'kUInteger':
    case 'kString':
    case 'kStringList':
      return '...';
    default:
      require('assert').fail(`unknown option type ${type}`);
  }
}

function format(
  { options, aliases = new SafeMap(), firstColumn, secondColumn }
) {
  let text = '';
  let maxFirstColumnUsed = 0;

  const sortedOptions = ArrayPrototypeSort(
    [...options.entries()],
    ({ 0: name1, 1: option1 }, { 0: name2, 1: option2 }) => {
      if (option1.defaultIsTrue) {
        name1 = `--no-${StringPrototypeSlice(name1, 2)}`;
      }
      if (option2.defaultIsTrue) {
        name2 = `--no-${StringPrototypeSlice(name2, 2)}`;
      }
      return StringPrototypeLocaleCompare(name1, name2);
    },
  );

  for (const {
    0: name, 1: { helpText, type, value, defaultIsTrue }
  } of sortedOptions) {
    if (!helpText) continue;

    let displayName = name;

    if (defaultIsTrue) {
      displayName = `--no-${StringPrototypeSlice(displayName, 2)}`;
    }

    const argDescription = getArgDescription(type);
    if (argDescription)
      displayName += `=${argDescription}`;

    for (const { 0: from, 1: to } of aliases) {
      // For cases like e.g. `-e, --eval`.
      if (to[0] === name && to.length === 1) {
        displayName = `${from}, ${displayName}`;
      }

      // For cases like `--inspect-brk[=[host:]port]`.
      const targetInfo = options.get(to[0]);
      const targetArgDescription =
        targetInfo ? getArgDescription(targetInfo.type) : '...';
      if (from === `${name}=`) {
        displayName += `[=${targetArgDescription}]`;
      } else if (from === `${name} <arg>`) {
        displayName += ` [${targetArgDescription}]`;
      }
    }

    let displayHelpText = helpText;
    if (value === !defaultIsTrue) {
      // Mark boolean options we currently have enabled.
      // In particular, it indicates whether --use-openssl-ca
      // or --use-bundled-ca is the (current) default.
      displayHelpText += ' (currently set)';
    }

    text += displayName;
    maxFirstColumnUsed = MathMax(maxFirstColumnUsed, displayName.length);
    if (displayName.length >= firstColumn)
      text += '\n' + StringPrototypeRepeat(' ', firstColumn);
    else
      text += StringPrototypeRepeat(' ', firstColumn - displayName.length);

    text += StringPrototypeTrimLeft(
      indent(fold(displayHelpText, secondColumn), firstColumn)) + '\n';
  }

  if (maxFirstColumnUsed < firstColumn - 4) {
    // If we have more than 4 blank gap spaces, reduce first column width.
    return format({
      options,
      aliases,
      firstColumn: maxFirstColumnUsed + 2,
      secondColumn
    });
  }

  return text;
}

function print(stream) {
  const { options, aliases } = require('internal/options');

  // Use 75 % of the available width, and at least 70 characters.
  const width = MathMax(70, (stream.columns || 0) * 0.75);
  const firstColumn = MathFloor(width * 0.4);
  const secondColumn = MathFloor(width * 0.57);

  options.set('-', { helpText: 'script read from stdin ' +
                               '(default if no file name is provided, ' +
                               'interactive mode if a tty)' });
  options.set('--', { helpText: 'indicate the end of node options' });
  stream.write(
    'Usage: node [options] [ script.js ] [arguments]\n' +
    '       node inspect [options] [ script.js | host:port ] [arguments]\n\n' +
    'Options:\n');
  stream.write(indent(format({
    options, aliases, firstColumn, secondColumn
  }), 2));

  stream.write('\nEnvironment variables:\n');

  stream.write(format({
    options: envVars, firstColumn, secondColumn
  }));

  stream.write('\nDocumentation can be found at https://nodejs.org/\n');
}

prepareMainThreadExecution();

markBootstrapComplete();

print(process.stdout);
