function addCommentToText()

in packages/flow-dev-tools/src/comment/commentMutator.js [189:317]


function addCommentToText(
  contents: Buffer,
  loc: FlowLoc,
  inside: Context,
  comments: Array<string>,
  ast: any,
  startOfLine?: number,
): Buffer {
  let startOffset;
  let start;
  if (startOfLine == null) {
    startOffset = loc.start.offset;
    start = findStartOfLine(contents, startOffset);
  } else {
    start = startOfLine;
    startOffset = startOfLine;
  }

  const endOfLine = findEndOfLine(contents, startOffset);
  let line = contents.toString('utf8', start, endOfLine);
  const inJSX = inside === JSX_FRAGMENT || inside === JSX;
  if (inside === NORMAL) {
    return insertCommentToText(
      contents,
      start,
      formatComment(comments, line, {jsx: false}).join('\n') + '\n',
    );
  } else if (inJSX && ast.type === 'JSXElement') {
    return insertCommentToText(
      contents,
      start,
      formatComment(comments, line, {jsx: true}).join('\n') + '\n',
    );
  } else if (
    inside === TEMPLATE ||
    (inJSX && ast.type === 'JSXExpressionContainer')
  ) {
    /* Ok, so we have something like
     *
     * <jsx>
     *   {10 * 'hello'}
     * <jsx>
     *
     * We need to stick the comment inside the expression container.
     * So the above example turns into
     *
     * <jsx>
     *   {
     *     // Comment
     *     10 * 'hello'}
     * <jsx>
     *
     * Same thing if we have something like
     *
     * var str = `hello
     *   ${10 * 'hello'}
     * `;
     *
     * We need to stick the comment inside of the template element. So the
     * above example turns into
     *
     * var str = `hello
     *   ${
     *     // Comment
     *     10 * 'hello'}
     * `;
     */
    const start_col = inJSX ? ast.loc.start.column + 1 : ast.loc.start.column;
    const part1 = line.substr(0, start_col);
    const match = part1.match(/^ */);
    const padding = match ? match[0] + '  ' : '  ';
    const part2 = padding + line.substr(start_col);
    const newCode = []
      // $FlowFixMe unsealed object but should just be {||}
      .concat([part1], formatComment(comments, part2, {}), [part2])
      .join('\n');
    return Buffer.concat([
      contents.slice(0, start),
      Buffer.from(newCode),
      contents.slice(endOfLine),
    ]);
  } else if (inJSX && ast.type === 'JSXText') {
    /* Ignore the case where the error's loc starts after the last non-whitespace
     * character of the line. This can occur when an error's loc spans the
     * children of a JSX element. We cannot safely add a comment to the line
     * before the error's loc, as it may be contained within a JSXOpeningElement.
     *
     *     Loc
     *      |
     *      v
     * <jsx>
     *   JSXElement, JSXExpressionContainer, or JSXText here...
     * <jsx>
     */
    let firstNonWhitespaceCharacter = startOffset;
    let atEndOfLine = true;
    while (firstNonWhitespaceCharacter < contents.length) {
      if (
        bufferCharAt(contents, firstNonWhitespaceCharacter).match(newlineRegex)
      ) {
        break;
      } else if (
        bufferCharAt(contents, firstNonWhitespaceCharacter).match(edible)
      ) {
        firstNonWhitespaceCharacter++;
      } else {
        atEndOfLine = false;
        break;
      }
    }
    if (atEndOfLine) {
      return contents;
    }
    /*
     * Otherwise add an expression container above the text with our comment.
     *
     * <jsx>
     *   {// Comment}
     *   JSX Text Here
     * <jsx>
     */
    return insertCommentToText(
      contents,
      start,
      formatComment(comments, line, {jsx: true}).join('\n') + '\n',
    );
  }
  return contents;
}