UNPKG

@jsverse/transloco-keys-manager

Version:

Extract translatable keys from projects that uses Transloco

102 lines 4.14 kB
import * as cheerio from 'cheerio'; import { getConfig } from '../../config.js'; import { TEMPLATE_TYPE } from '../../types.js'; import { readFile } from '../../utils/file.utils.js'; import { regexFactoryMap } from '../../utils/regexs.utils.js'; import { addCommentSectionKeys } from '../add-comment-section-keys.js'; /** * We can't use AST here since the comments markings support the read property, and the AST extracts them without context * */ export function templateCommentsExtractor({ file, scopes, defaultValue, scopeToKeys, }) { const { hasComments, content } = keepMarkingCommentsOnly(readFile(file)); if (!hasComments) return scopeToKeys; const templateContainers = []; const baseParams = { defaultValue, scopes, scopeToKeys }; const { containers, hasStructural } = getNgTemplateContainers(content); if (containers.length > 0) { const fileTemplate = hasStructural ? content.replace(/\*transloco/g, '__transloco') : content; const $ = loadCheerio(fileTemplate); for (const query of containers) { $(query).each((_, element) => { const containerType = !!element.attribs.__transloco ? TEMPLATE_TYPE.STRUCTURAL : TEMPLATE_TYPE.NG_TEMPLATE; templateContainers.push({ containerContent: $(element).html(), read: extractReadValue(element, containerType), }); }); } } /** Add the global content to the containers array */ templateContainers.push({ containerContent: loadCheerio(content).html() }); templateContainers.forEach(({ containerContent, read }, _, arr) => { addCommentSectionKeys({ read, regexFactory: regexFactoryMap.template.comments, content: removeInnerContainers(containerContent, arr), ...baseParams, }); }); return scopeToKeys; } function getNgTemplateContainers(content) { const hasNgTemplate = content.match(/<ng-template[^>]*transloco[^>]*>/); const hasStructural = content.includes('*transloco'); const containers = []; if (hasNgTemplate) containers.push('ng-template[transloco]'); if (hasStructural) containers.push('[__transloco]'); return { containers, hasStructural, }; } function keepMarkingCommentsOnly(content) { const { marker } = getConfig(); const validMarking = regexFactoryMap.template.validateComment(marker); let hasComments = false; return { /* Search all comments, if they include anything but the markings remove them */ content: content.replace(regexFactoryMap.template.comments(), (comment) => { if (validMarking.test(comment)) { hasComments = true; return comment; } return ''; }), hasComments, }; } function removeInnerContainers(content, allContainers) { return allContainers .filter(({ containerContent }) => content !== containerContent && content.includes(containerContent)) .reduce((acc, { containerContent }) => acc.replace(containerContent, ''), content); } function loadCheerio(content) { return cheerio.load(content, { xml: { decodeEntities: false } }); } /** Get the read value from an ngTemplate/ngContainer element */ function extractReadValue(element, templateType) { let read; if (templateType === TEMPLATE_TYPE.STRUCTURAL) { const data = element.attribs.__transloco; const readSearch = data.match(/(?:read|prefix):\s*(['"])(?<read>[^"']*)\1/); read = readSearch?.groups?.read; } if (templateType === TEMPLATE_TYPE.NG_TEMPLATE) { const attrs = Object.keys(element.attribs); const readSearch = attrs.find((attr) => ['translocoread', '[translocoread]', 'translocoprefix', '[translocoprefix]'].includes(attr)); read = readSearch && element.attribs[readSearch].replace(/['"]/g, ''); } return read; } //# sourceMappingURL=comments.extractor.js.map