ts.setSyntheticLeadingComments не удаляет существующие комментарии - PullRequest
1 голос
/ 15 марта 2019

Описание

Привет,

Я пытаюсь создать что-то, что добавит комментарии поверх функции.К сожалению, похоже, что ts.setSyntheticLeadingComments не позволяет мне заменить существующие комментарии.

Я пытался:

  • ts.setSyntheticLeadingComments(node, [])
  • ts.setSyntheticLeadingComments(node, undefined)
  • node = ts.setSyntheticLeadingComments(node, [])

Но ни одна из этих работ.В конечном счете, моя цель состояла в том, чтобы иметь возможность заменить существующие комментарии, которые я сгенерировал бы новыми.

Есть идеи?Спасибо 10

Воспроизведение

const transformFactory = (context: ts.TransformationContext) => (
  rootNode: ts.SourceFile
): ts.SourceFile => {
  const visit = (node: ts.Node) => {
    node = ts.visitEachChild(node, visit, context);

    ts.setSyntheticLeadingComments(node, []);

    return node;
  };

  return ts.visitNode(rootNode, visit);
};

const sourceFile = ts.createSourceFile(
  path,
  source,
  ts.ScriptTarget.ESNext,
  true,
  ts.ScriptKind.TS
);
const result = ts.transform(sourceFile, [transformFactory]);
const resultPrinter = ts.createPrinter({ removeComments: false });

console.log(resultPrinter.printFile(result.transformed[0]));

Попробуйте следующий преобразователь и посмотрите, как вообще не удаляются комментарии

Использование ts.createPrinter(..., { substituteNode(hint, node) { ... } }) тоже не помогает

Примечание:

Кажется, что ts.getSyntheticLeadingComments() не работает так, как я ожидаю.Он всегда возвращает undefined, что заставляет меня использовать следующие утилиты, хотя я не уверен, что полностью понимаю цель этого (заимствовано из https://github.com/angular/tsickle/blob/6f5835a644f3c628a61e3dcd558bb9c59c73dc2f/src/transformer_util.ts#L257-L266)

/**
 * A replacement for ts.getLeadingCommentRanges that returns the union of synthetic and
 * non-synthetic comments on the given node, with their text included. The returned comments must
 * not be mutated, as their content might or might not be reflected back into the AST.
 */
export function getAllLeadingComments(node: ts.Node):
    ReadonlyArray<Readonly<ts.CommentRange&{text: string}>> {
  const allRanges: Array<Readonly<ts.CommentRange&{text: string}>> = [];
  const nodeText = node.getFullText();
  const cr = ts.getLeadingCommentRanges(nodeText, 0);
  if (cr) allRanges.push(...cr.map(c => ({...c, text: nodeText.substring(c.pos, c.end)})));
  const synthetic = ts.getSyntheticLeadingComments(node);
  if (synthetic) allRanges.push(...synthetic);
  return allRanges;
}

1 Ответ

0 голосов
/ 15 марта 2019

Проблема в том, что функции *SyntheticLeadingComments влияют на исходные комментарии. Они не будут. Они будут влиять только на комментарии, которые были ранее синтезированы (т.е. добавлены вами в коде).

Фактические комментарии не сохраняются как узлы в AST. Вы можете получить реальные исходные комментарии, используя getLeadingCommentRanges и getTrailingCommentRanges.

Узел имеет позицию start и end, которые не содержат никаких комментариев. Существует также полный старт для узла, который является позицией, включая любые ведущие комментарии. Когда выводится узел, именно так машинопись знает, как копировать комментарии в вывод.

Если мы используем setTextRange, чтобы установить диапазон узла, чтобы исключить эти существующие комментарии, то в результате мы эффективно удаляем их из вывода и можем добавлять новые комментарии, используя setSyntheticLeadingComments:

import * as ts from 'typescript'

const transformFactory = (context: ts.TransformationContext) => (
    rootNode: ts.SourceFile
): ts.SourceFile => {
    const visit = (node: ts.Node) => {
        node = ts.visitEachChild(node, visit, context);
            if(ts.isFunctionDeclaration(node)) {
            let sourceFileText = node.getSourceFile().text;
            const existingComments = ts.getLeadingCommentRanges(sourceFileText, node.pos);
            if (existingComments) {
                // Log existing comments just for fun 
                for (const comment of existingComments) {
                    console.log(sourceFileText.substring(comment.pos, comment.end))
                }
                // Comment also attaches to the first child, we must remove it recursively.
                let removeComments =  (c: ts.Node) => {
                    if (c.getFullStart() === node.getFullStart()) {
                        ts.setTextRange(c, { pos: c.getStart(), end: c.getEnd() });
                    }
                    c = ts.visitEachChild(c, removeComments, context);
                    return c;
                }
                ts.visitEachChild(node, removeComments, context);
                ts.setTextRange(node, { pos: node.getStart(), end: node.getEnd() })
                ts.setSyntheticLeadingComments(node, [{
                    pos: -1,
                    end: -1,
                    hasTrailingNewLine: false,
                    text: "Improved comment",
                    kind: ts.SyntaxKind.SingleLineCommentTrivia
                }]);

            }
        }
        return node;
    };

    return ts.visitNode(rootNode, visit);
};

const sourceFile = ts.createSourceFile(
    "path.ts",
    `
// Original comment
function test () {

}
`,
    ts.ScriptTarget.ESNext,
    true,
    ts.ScriptKind.TS
);
const result = ts.transform(sourceFile, [transformFactory]);
const resultPrinter = ts.createPrinter({ removeComments: false });

console.log("!");
console.log(resultPrinter.printFile(result.transformed[0]));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...