UNPKG

@taiga-ui/cdk

Version:

Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance

190 lines • 7.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.migrateRepeatTimes = migrateRepeatTimes; const elements_1 = require("../../../../utils/templates/elements"); const template_resource_1 = require("../../../../utils/templates/template-resource"); const NGFOR_SEARCH_ATTR = '*ngFor'; const NGFOR_ATTR = '*ngFor'.toLowerCase(); const TUI_REPEAT_TIMES_DIRECTIVE_ATTR = '*tuiRepeatTimes'.toLowerCase(); const TUI_REPEAT_TIMES_DIRECTIVE_PATTERN = /^(?:let\s+(\w+)\s+)?of\s+(\S[\s\S]*)$/; const FOR_BLOCK_PATTERN = /@for\s*\(/g; const NGFOR_REPEAT_TIMES_PIPE_PATTERN = /let\s+(\w+)\s+of\s+([^\s|]+)\s*\|\s*tuiRepeatTimes\s*/; function migrateRepeatTimes({ resource, recorder, fileSystem, }) { const template = (0, template_resource_1.getTemplateFromTemplateResource)(resource, fileSystem); const templateOffset = (0, template_resource_1.getTemplateOffset)(resource); for (const element of (0, elements_1.findElementsWithAttribute)(template, NGFOR_SEARCH_ATTR)) { migrateNgForRepeatTimesPipe(element, template, recorder, templateOffset); } for (const element of (0, elements_1.findElementsWithAttribute)(template, TUI_REPEAT_TIMES_DIRECTIVE_ATTR)) { migrateTuiRepeatTimesDirective(element, template, recorder, templateOffset); } migrateAtForRepeatTimes(template, recorder, templateOffset); } function migrateNgForRepeatTimesPipe(element, template, recorder, offset) { const attr = element.attrs.find((a) => a.name === NGFOR_ATTR && a.value.includes('tuiRepeatTimes')); if (!attr) { return; } const parsed = NGFOR_REPEAT_TIMES_PIPE_PATTERN.exec(attr.value); if (!parsed) { return; } const [, variable = '', expression = ''] = parsed; const wrapped = replaceStructuralDirectiveWithForBlock({ element, template, recorder, offset, attrName: NGFOR_ATTR, header: buildRepeatTimesForHeader({ expression }), }); if (wrapped && variable && variable !== '_' && variable !== '$index') { replaceVariableInElement(element, template, recorder, offset, variable); } } function migrateTuiRepeatTimesDirective(element, template, recorder, offset) { const attr = element.attrs.find((a) => a.name === TUI_REPEAT_TIMES_DIRECTIVE_ATTR); if (!attr) { return; } const parsed = TUI_REPEAT_TIMES_DIRECTIVE_PATTERN.exec(attr.value.trim()); if (!parsed) { return; } const [, variable = '', expression = ''] = parsed; replaceStructuralDirectiveWithForBlock({ element, template, recorder, offset, attrName: TUI_REPEAT_TIMES_DIRECTIVE_ATTR, header: buildRepeatTimesForHeader({ expression, indexAliasName: variable }), }); } function buildRepeatTimesForHeader({ expression, indexAliasName = '', }) { const alias = indexAliasName && indexAliasName !== '_' && indexAliasName !== '$index' ? `; let ${indexAliasName} = $index` : ''; return `@for (_ of '-'.repeat(${expression.trim().replace(/;+$/, '')}); track $index${alias})`; } function replaceStructuralDirectiveWithForBlock({ element, template, recorder, offset, attrName, header, }) { var _a; const loc = element.sourceCodeLocation; const attrLoc = (_a = loc === null || loc === void 0 ? void 0 : loc.attrs) === null || _a === void 0 ? void 0 : _a[attrName]; if (!loc || !attrLoc) { return false; } const indentStr = ' '.repeat(computeIndent(template, loc.startOffset)); const isPureNgContainer = element.tagName === 'ng-container' && element.attrs.length === 1; if (isPureNgContainer) { const startTag = loc.startTag; if (!startTag) { return false; } const endTag = loc.endTag; recorder.remove(offset + loc.startOffset, startTag.endOffset - loc.startOffset); recorder.insertRight(offset + loc.startOffset, `${header} {`); if (endTag) { recorder.remove(offset + endTag.startOffset, endTag.endOffset - endTag.startOffset); recorder.insertRight(offset + endTag.startOffset, `${indentStr}}`); } return true; } recorder.remove(offset + attrLoc.startOffset - 1, attrLoc.endOffset - attrLoc.startOffset + 1); recorder.insertLeft(offset + loc.startOffset, `${header} {\n${indentStr}`); recorder.insertRight(offset + loc.endOffset, `\n${indentStr}}`); return true; } function replaceVariableInElement(element, template, recorder, offset, variable) { var _a; const loc = element.sourceCodeLocation; if (!loc) { return; } const ngForLoc = (_a = loc.attrs) === null || _a === void 0 ? void 0 : _a[NGFOR_ATTR]; const searchStart = loc.startOffset; const searchEnd = loc.endOffset; const content = template.slice(searchStart, searchEnd); const pattern = new RegExp(String.raw `\b${variable}\b`, 'g'); let match; while ((match = pattern.exec(content)) !== null) { const absolutePos = searchStart + match.index; if (ngForLoc && absolutePos >= ngForLoc.startOffset && absolutePos < ngForLoc.endOffset) { continue; } recorder.remove(offset + absolutePos, variable.length); recorder.insertRight(offset + absolutePos, '$index'); } } function computeIndent(template, pos) { const lastNewLine = template.lastIndexOf('\n', pos); return pos - (lastNewLine + 1); } function migrateAtForRepeatTimes(template, recorder, offset) { var _a, _b; const replacements = []; for (const match of template.matchAll(FOR_BLOCK_PATTERN)) { const start = match.index; if (start === undefined) { continue; } const openParen = start + ((_b = (_a = match[0]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1; const closeParen = findMatchingParen(template, openParen); if (closeParen === -1) { continue; } const header = template.slice(openParen + 1, closeParen); const replacementHeader = replaceRepeatTimesInForHeader(header); if (!replacementHeader) { continue; } replacements.push({ start: openParen + 1, end: closeParen, replacement: replacementHeader, }); } replacements .sort((a, b) => b.start - a.start) .forEach(({ start, end, replacement }) => { recorder.remove(offset + start, end - start); recorder.insertRight(offset + start, replacement); }); } function replaceRepeatTimesInForHeader(header) { const pipeMatch = /\|\s*tuiRepeatTimes\b/.exec(header); if ((pipeMatch === null || pipeMatch === void 0 ? void 0 : pipeMatch.index) === undefined) { return null; } const beforePipe = header.slice(0, pipeMatch.index); const ofIndex = beforePipe.lastIndexOf(' of '); if (ofIndex === -1) { return null; } const expression = beforePipe.slice(ofIndex + ' of '.length).trim(); if (!expression) { return null; } const beforeExpression = beforePipe.slice(0, ofIndex + ' of '.length); const afterPipe = header.slice(pipeMatch.index + pipeMatch[0].length); return `${beforeExpression}'-'.repeat(${expression})${afterPipe}`; } function findMatchingParen(template, openParen) { let depth = 0; for (let i = openParen; i < template.length; i++) { const char = template[i]; if (char === '(') { depth++; } else if (char === ')') { depth--; if (depth === 0) { return i; } } } return -1; } //# sourceMappingURL=migrate-repeat-times.js.map