UNPKG

igniteui-angular-sovn

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

138 lines (115 loc) 6.04 kB
import { Element } from '@angular/compiler'; import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; import { UpdateChanges } from '../common/UpdateChanges'; import { FileChange, findElementNodes, getAttribute, getSourceOffset, hasAttribute, parseFile, serializeNodes } from '../common/util'; import { nativeImport } from '../common/import-helper.js'; const version = '11.0.0'; export default (): Rule => async (host: Tree, context: SchematicContext) => { context.logger.info( `Applying migration for Ignite UI for Angular to version ${version}` ); const { HtmlParser, getHtmlTagDefinition } = await nativeImport('@angular/compiler') as typeof import('@angular/compiler'); const update = new UpdateChanges(__dirname, host, context); const TAGS = ['igx-grid', 'igx-tree-grid', 'igx-hierarchical-grid']; const prop = ['[showToolbar]', 'showToolbar']; const warnMsg = `\n<!-- Auto migrated template content. Please, check your bindings! -->\n`; const changes = new Map<string, FileChange[]>(); const applyChanges = () => { for (const [path, change] of changes.entries()) { let buffer = host.read(path).toString(); change.sort((c, c1) => c.position - c1.position) .reverse() .forEach(c => buffer = c.apply(buffer)); host.overwrite(path, buffer); } }; const addChange = (path: string, change: FileChange) => { if (changes.has(path)) { changes.get(path).push(change); } else { changes.set(path, [change]); } }; const makeNgIf = (name: string, value: string) => name.startsWith('[') && value !== 'true'; // Try to preserve the template context variable binding const getTemplateBinding = (node: Element) => { const template = findElementNodes([node], ['ng-template']) .filter(tmpl => hasAttribute(tmpl as Element, 'igxToolbarCustomContent'))[0]; if (template) { return (template as Element).attrs.find(attr => attr.name.startsWith('let') && attr.value.startsWith('grid')) .name.split('-')[1]; } return 'childGrid'; }; const moveTemplateIfAny = (grid: Element) => { const ngTemplates = findElementNodes([grid], ['ng-template']); const toolbarTemplate = ngTemplates.filter(template => hasAttribute(template as Element, 'igxToolbarCustomContent'))[0]; if (toolbarTemplate) { return `${warnMsg}\n${serializeNodes((toolbarTemplate as Element).children, getHtmlTagDefinition).join('')}\n`; } return ''; }; // Row island migration for (const path of update.templateFiles) { findElementNodes(parseFile(new HtmlParser(), host, path), 'igx-row-island') .filter(island => hasAttribute(island as Element, prop)) .map(island => getSourceOffset(island as Element)) .forEach(offset => { const { startTag, file, node } = offset; const binding = getTemplateBinding(node); const { name, value } = getAttribute(node, prop)[0]; // eslint-disable-next-line max-len const text = `\n<igx-grid-toolbar [grid]="${binding}" *igxGridToolbar="let ${binding}"${makeNgIf(name, value) ? ` *ngIf="${value}"` : ''}>${moveTemplateIfAny(node)}</igx-grid-toolbar>\n`; addChange(file.url, new FileChange(startTag.end, text)); }); } applyChanges(); changes.clear(); // Clear row island templates for (const path of update.templateFiles) { findElementNodes(parseFile(new HtmlParser(), host, path), 'igx-row-island') .filter(grid => hasAttribute(grid as Element, prop)) .map(grid => findElementNodes([grid], ['ng-template'])) .reduce((prev, curr) => prev.concat(curr), []) .filter(template => hasAttribute(template as Element, 'igxToolbarCustomContent')) .forEach(node => { const { startTag, endTag, file } = getSourceOffset(node as Element); const replaceText = file.content.substring(startTag.start, endTag.end); addChange(file.url, new FileChange(startTag.start, '', replaceText, 'replace')); }); } applyChanges(); changes.clear(); // General migration // Prepare the file changes for (const path of update.templateFiles) { findElementNodes(parseFile(new HtmlParser(), host, path), TAGS) .filter(grid => hasAttribute(grid as Element, prop)) .map(node => getSourceOffset(node as Element)) .forEach(offset => { const { startTag, file, node } = offset; const { name, value } = getAttribute(node, prop)[0]; // eslint-disable-next-line max-len const text = `\n<igx-grid-toolbar${makeNgIf(name, value) ? ` *ngIf="${value}"` : ''}>${moveTemplateIfAny(node)}</igx-grid-toolbar>\n`; addChange(file.url, new FileChange(startTag.end, text)); }); } applyChanges(); changes.clear(); // Remove toolbar templates after migration for (const path of update.templateFiles) { findElementNodes(parseFile(new HtmlParser(), host, path), TAGS) .filter(grid => hasAttribute(grid as Element, prop)) .map(grid => findElementNodes([grid], ['ng-template'])) .reduce((prev, curr) => prev.concat(curr), []) .filter(template => hasAttribute(template as Element, 'igxToolbarCustomContent')) .forEach(node => { const { startTag, endTag, file } = getSourceOffset(node as Element); const replaceText = file.content.substring(startTag.start, endTag.end); addChange(file.url, new FileChange(startTag.start, '', replaceText, 'replace')); }); } applyChanges(); // Remove the input properties update.applyChanges(); };