@awesome-fe/translate
Version:
Translation utils
129 lines • 5.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsdocTranslator = void 0;
const abstract_translator_1 = require("./abstract-translator");
const ts_morph_1 = require("ts-morph");
const util_1 = require("util");
const markdown_translator_1 = require("./markdown-translator");
const lodash_1 = require("lodash");
const delay_1 = require("../dom/delay");
function getTagsWithAncestors(node) {
if (!node) {
return [];
}
// 如果不是,就跳过这一层,直接返回父级的结果
if (!ts_morph_1.Node.isJSDocable(node)) {
return getTagsWithAncestors(node.getParent());
}
// 取当前节点的所有标记
const tags = node.getJsDocs().map(it => it.getTags()).flat();
// 合并当前节点的标记和父级节点的标记
return [...tags, ...getTagsWithAncestors(node.getParent())];
}
function shouldTranslate(node, options) {
if (!ts_morph_1.Node.isJSDocable(node)) {
return false;
}
if (ts_morph_1.Node.isModifierable(node)) {
if (node.hasModifier(ts_morph_1.SyntaxKind.PrivateKeyword)) {
return false;
}
}
const tags = getTagsWithAncestors(node).map(it => it.getTagName());
return (!options.mustIncludesTags || (0, lodash_1.intersection)(tags, options.mustIncludesTags).length > 0) &&
(!options.mustExcludesTags || (0, lodash_1.intersection)(tags, options.mustExcludesTags).length === 0);
}
function preprocess(text) {
return text.replace(/(```\w*\n)(.*?)(```\n)/gs, (_, leading, body, tailing) => {
return `${leading}${body.replace(/@/g, '@')}${tailing}`;
});
}
function postprocess(text) {
return text.replace(/@/g, '@');
}
class JsdocTranslator extends abstract_translator_1.AbstractTranslator {
markdownTranslator = new markdown_translator_1.MarkdownTranslator(this.engine);
parse(text) {
const project = new ts_morph_1.Project({ manipulationSettings: { indentationText: ts_morph_1.IndentationText.TwoSpaces } });
return project.createSourceFile('placeholder.ts', preprocess(text));
}
serialize(doc) {
return postprocess(doc.getFullText());
}
async flush() {
return super.flush()
// 需要等待一小段时间才能确保已经写回,目前原因不详
.then(() => (0, delay_1.delay)(500));
}
translateMarkdown(sentence, options) {
return this.markdownTranslator.translateContentAndFlush(sentence, options).then((result) => result);
}
translateDoc(doc, options) {
this.translateNode(doc, options).then(it => it);
return doc;
}
async translateNode(node, options) {
if (ts_morph_1.Node.isJSDocable(node) && shouldTranslate(node, options)) {
const docs = node.getJsDocs();
for (const doc of docs) {
const structure = doc.getStructure();
const tagTasks = structure.tags.map(tag => this.translateTag(tag, options));
const origin = structure.description.trim();
const descriptionTask = this.translateMarkdown(origin, options).then(translation => {
if (translation.trim() !== origin.trim()) {
structure.description = removeExtraBlankLines(translation);
}
});
Promise.all([...tagTasks, descriptionTask].filter(it => !!it)).then(() => {
if (!(0, util_1.isDeepStrictEqual)(structure, doc.getStructure())) {
doc.set(structure);
}
});
}
}
const children = Array.from(node.getChildren());
children.forEach((subNode) => {
this.translateNode(subNode, options);
});
return node;
}
translateTag(tag, options) {
const text = tag.text;
if (isBinaryTag(tag)) {
const [, name, description] = (text ?? '').match(/^((?:{.*?}\s*)?(?:[\w.\[\]]+|\[.*?])\s+)([\s\S]*)$/) ?? [];
if (description?.trim()) {
return this.translateMarkdown(description, options).then(translation => {
if (translation.trim() !== description.trim()) {
tag.text = (name ?? '') + removeExtraBlankLines(translation);
}
});
}
}
else if (isUnaryTag(tag)) {
const [, prefix, description] = (text ?? '').match(/^({.*?}\s*)?([\s\S]*)$/);
if (description?.trim()) {
return this.translateMarkdown(description, options).then(translation => {
if (translation.trim() !== description.trim()) {
const leadingLines = ['publicApi', 'returns', 'codeGenApi', 'ngModule'].includes(tag.tagName) ? '\n\n' : '';
const tailingLines = ['usageNotes', 'description', 'deprecated'].includes(tag.tagName) ? '\n\n' : '';
tag.text = leadingLines + (prefix ?? '') + tailingLines + removeExtraBlankLines(translation);
}
});
}
}
}
}
exports.JsdocTranslator = JsdocTranslator;
// 有两个参数且需要翻译的标记,如 @param a Some value
function isBinaryTag(tag) {
return ['param', 'arg', 'argument', 'property', 'prop', 'yields', 'yield', 'template', 'breaking-change'].includes(tag.tagName);
}
// 有一个参数且需要翻译的标记,如 @returns Some value
function isUnaryTag(tag) {
return ['returns', 'return', 'classdesc', 'description', 'desc', 'summary', 'throws',
'deprecated', 'usageNotes', 'see'].includes(tag.tagName);
}
function removeExtraBlankLines(translation) {
return translation.replace(/\n$/s, '') + '\n';
}
//# sourceMappingURL=jsdoc-translator.js.map