UNPKG

@taiga-ui/cdk

Version:

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

156 lines 7.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.migrateTokens = migrateTokens; const ng_morph_1 = require("ng-morph"); const constants_1 = require("../../../../constants"); const colored_log_1 = require("../../../../utils/colored-log"); const get_named_import_references_1 = require("../../../../utils/get-named-import-references"); const import_manipulations_1 = require("../../../../utils/import-manipulations"); const insert_todo_1 = require("../../../../utils/insert-todo"); const project_root_1 = require("../../../../utils/project-root"); const TOKEN_FUNCTIONS = ['tuiCreateToken', 'tuiCreateTokenFromFactory']; const ANGULAR_CORE = '@angular/core'; const INJECTION_TOKEN = 'InjectionToken'; /** * Migrates Taiga UI token functions to Angular's InjectionToken * * This schematic: * 1. Finds all references to `tuiCreateToken` and `tuiCreateTokenFromFactory` * 2. Replaces them with equivalent `InjectionToken` implementations * 3. Handles proper import management for `InjectionToken` * 4. Preserves type parameters and factory functions * 5. Adds descriptive error handling and logging */ function migrateTokens(tree, options) { if (!options['skip-logs']) { (0, colored_log_1.infoLog)('Starting token migration to InjectionToken...'); } const project = (0, ng_morph_1.createProject)(tree, (0, project_root_1.projectRoot)(), constants_1.ALL_TS_FILES); (0, ng_morph_1.setActiveProject)(project); const allFiles = (0, ng_morph_1.getSourceFiles)(); if (!options['skip-logs']) { (0, colored_log_1.infoLog)(`Found ${allFiles.length} source files`); } TOKEN_FUNCTIONS.forEach((tokenFunction) => { const references = (0, get_named_import_references_1.getNamedImportReferences)(tokenFunction, '@taiga-ui/cdk'); if (!options['skip-logs']) { (0, colored_log_1.infoLog)(`Found ${references.length} references for ${tokenFunction}`); } references.forEach((ref) => { if (ref.wasForgotten()) { return; } try { const parent = ref.getParent(); const sourceFile = ref.getSourceFile(); if (ng_morph_1.Node.isImportSpecifier(parent)) { (0, import_manipulations_1.removeImport)(parent); return; } if (ng_morph_1.Node.isCallExpression(parent)) { const declaration = parent.getFirstAncestorByKind(ng_morph_1.SyntaxKind.VariableDeclaration); if (!declaration) { if (!ref.wasForgotten()) { (0, insert_todo_1.insertTodo)(ref, 'Could not find variable declaration'); } return; } const constName = declaration.getName(); if (!constName) { if (!ref.wasForgotten()) { (0, insert_todo_1.insertTodo)(ref, 'Variable declaration has no name'); } return; } const newExpression = createInjectionTokenExpression(parent, constName, tokenFunction); parent.replaceWithText(newExpression); // handle InjectionToken imports let hasValueImport = false; const coreImports = []; sourceFile.getImportDeclarations().forEach((decl) => { if (decl.getModuleSpecifierValue() !== ANGULAR_CORE) { return; } coreImports.push(decl); const namedImports = decl.getNamedImports(); const tokenImport = namedImports.find((i) => i.getName() === INJECTION_TOKEN); if (!tokenImport) { return; } // remove InjectionToken from type-only imports if (tokenImport.isTypeOnly() || decl.isTypeOnly()) { tokenImport.remove(); // remove the import declaration if it becomes empty if (decl.getNamedImports().length === 0) { decl.remove(); } } else { hasValueImport = true; } }); // add InjectionToken as regular import if needed if (!hasValueImport) { sourceFile.addImportDeclaration({ moduleSpecifier: ANGULAR_CORE, namedImports: [INJECTION_TOKEN], isTypeOnly: false, }); } } } catch (error) { const message = error instanceof Error ? error.message : String(error); if (!options['skip-logs']) { (0, colored_log_1.infoLog)(`Error migrating token: ${message}`); } if (!ref.wasForgotten()) { (0, insert_todo_1.insertTodo)(ref, `Migration failed: ${message}`); } } }); }); (0, ng_morph_1.saveActiveProject)(); if (!options['skip-logs']) { (0, colored_log_1.titleLog)('Token migration completed!'); } } /** * Creates InjectionToken expression to replace token functions * * This function: * - Preserves type parameters (<T> syntax) * - Converts token values to factory functions when needed * - Adds ngDevMode checks for token descriptions * - Handles different cases for tuiCreateToken vs tuiCreateTokenFromFactory * * Example conversions: * tuiCreateToken('default') → new InjectionToken(..., { factory: () => 'default' }) * tuiCreateTokenFromFactory(() => value) → new InjectionToken(..., { factory: () => value }) */ function createInjectionTokenExpression(callExpression, constName, tokenFunction) { const typeArgs = callExpression.getTypeArguments(); const typeArgsText = typeArgs.length ? `<${typeArgs.map((t) => t.getText()).join(', ')}>` : ''; const args = callExpression.getArguments(); const isFactory = tokenFunction === 'tuiCreateTokenFromFactory'; const tokenDescription = `ngDevMode ? '${constName}' : ''`; if (args.length > 0 && args[0]) { const argText = args[0].getText(); const isObjectOrArray = argText.startsWith('{') || argText.startsWith('['); if (isFactory) { return `new ${INJECTION_TOKEN}${typeArgsText}(${tokenDescription}, { factory: ${argText} })`; } const factoryContent = isObjectOrArray ? `() => (${argText})` : `() => ${argText}`; return `new ${INJECTION_TOKEN}${typeArgsText}(${tokenDescription}, { factory: ${factoryContent} })`; } return `new ${INJECTION_TOKEN}${typeArgsText}(${tokenDescription})`; } //# sourceMappingURL=migrate-tokens.js.map