'use strict'; /** * @license Angular v19.2.13 * (c) 2010-2025 Google LLC. https://angular.io/ * License: MIT */ 'use strict'; var checker = require('./checker-5pyJrZ9G.cjs'); var ts = require('typescript'); require('os'); var index$1 = require('./index-BIvVb6in.cjs'); require('path'); var project_paths = require('./project_paths-CyWVEsbT.cjs'); var apply_import_manager = require('./apply_import_manager-QQDfWa1Z.cjs'); var migrate_ts_type_references = require('./migrate_ts_type_references-Czrg1gcB.cjs'); var assert = require('assert'); var index = require('./index-BPhQoCcF.cjs'); require('@angular-devkit/core'); require('node:path/posix'); require('fs'); require('module'); require('url'); require('@angular-devkit/schematics'); require('./project_tsconfig_paths-CDVxT6Ov.cjs'); require('./leading_space-D9nQ8UQC.cjs'); /** * Phase that migrates Angular host binding references to * unwrap signals. */ function migrateHostBindings(host, references, info) { const seenReferences = new WeakMap(); for (const reference of references) { // This pass only deals with host binding references. if (!index.isHostBindingReference(reference)) { continue; } // Skip references to incompatible inputs. if (!host.shouldMigrateReferencesToField(reference.target)) { continue; } const bindingField = reference.from.hostPropertyNode; const expressionOffset = bindingField.getStart() + 1; // account for quotes. const readEndPos = expressionOffset + reference.from.read.sourceSpan.end; // Skip duplicate references. Can happen if the host object is shared. if (seenReferences.get(bindingField)?.has(readEndPos)) { continue; } if (seenReferences.has(bindingField)) { seenReferences.get(bindingField).add(readEndPos); } else { seenReferences.set(bindingField, new Set([readEndPos])); } // Expand shorthands like `{bla}` to `{bla: bla()}`. const appendText = reference.from.isObjectShorthandExpression ? `: ${reference.from.read.name}()` : `()`; host.replacements.push(new project_paths.Replacement(project_paths.projectFile(bindingField.getSourceFile(), info), new project_paths.TextUpdate({ position: readEndPos, end: readEndPos, toInsert: appendText }))); } } /** * Phase that migrates Angular template references to * unwrap signals. */ function migrateTemplateReferences(host, references) { const seenFileReferences = new Set(); for (const reference of references) { // This pass only deals with HTML template references. if (!index.isTemplateReference(reference)) { continue; } // Skip references to incompatible inputs. if (!host.shouldMigrateReferencesToField(reference.target)) { continue; } // Skip duplicate references. E.g. if a template is shared. const fileReferenceId = `${reference.from.templateFile.id}:${reference.from.read.sourceSpan.end}`; if (seenFileReferences.has(fileReferenceId)) { continue; } seenFileReferences.add(fileReferenceId); // Expand shorthands like `{bla}` to `{bla: bla()}`. const appendText = reference.from.isObjectShorthandExpression ? `: ${reference.from.read.name}()` : `()`; host.replacements.push(new project_paths.Replacement(reference.from.templateFile, new project_paths.TextUpdate({ position: reference.from.read.sourceSpan.end, end: reference.from.read.sourceSpan.end, toInsert: appendText, }))); } } /** * Extracts the type `T` of expressions referencing `QueryList`. */ function extractQueryListType(node) { // Initializer variant of `new QueryList()`. if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'QueryList') { return node.typeArguments?.[0]; } // Type variant of `: QueryList`. if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.text === 'QueryList') { return node.typeArguments?.[0]; } return undefined; } /** * A few notes on changes: * * @ViewChild() * --> static is gone! * --> read stays * * @ViewChildren() * --> emitDistinctChangesOnly is gone! * --> read stays * * @ContentChild() * --> descendants stays * --> read stays * --> static is gone! * * @ContentChildren() * --> descendants stays * --> read stays * --> emitDistinctChangesOnly is gone! */ function computeReplacementsToMigrateQuery(node, metadata, importManager, info, printer, options, checker$1) { const sf = node.getSourceFile(); let newQueryFn = importManager.addImport({ requestedFile: sf, exportModuleSpecifier: '@angular/core', exportSymbolName: metadata.kind, }); // The default value for descendants is `true`, except for `ContentChildren`. const defaultDescendants = metadata.kind !== 'contentChildren'; const optionProperties = []; const args = [ metadata.args[0], // Locator. ]; let type = node.type; // For multi queries, attempt to unwrap `QueryList` types, or infer the // type from the initializer, if possible. if (!metadata.queryInfo.first) { if (type === undefined && node.initializer !== undefined) { type = extractQueryListType(node.initializer); } else if (type !== undefined) { type = extractQueryListType(type); } } if (metadata.queryInfo.read !== null) { assert(metadata.queryInfo.read instanceof checker.WrappedNodeExpr); optionProperties.push(ts.factory.createPropertyAssignment('read', metadata.queryInfo.read.node)); } if (metadata.queryInfo.descendants !== defaultDescendants) { optionProperties.push(ts.factory.createPropertyAssignment('descendants', metadata.queryInfo.descendants ? ts.factory.createTrue() : ts.factory.createFalse())); } if (optionProperties.length > 0) { args.push(ts.factory.createObjectLiteralExpression(optionProperties)); } const strictNullChecksEnabled = options.strict === true || options.strictNullChecks === true; const strictPropertyInitialization = options.strict === true || options.strictPropertyInitialization === true; let isRequired = node.exclamationToken !== undefined; // If we come across an application with strict null checks enabled, but strict // property initialization is disabled, there are two options: // - Either the query is already typed to include `undefined` explicitly, // in which case an option query makes sense. // - OR, the query is not typed to include `undefined`. In which case, the query // should be marked as required to not break the app. The user-code throughout // the application (given strict null checks) already assumes non-nullable! if (strictNullChecksEnabled && !strictPropertyInitialization && node.initializer === undefined && node.questionToken === undefined && type !== undefined && !checker$1.isTypeAssignableTo(checker$1.getUndefinedType(), checker$1.getTypeFromTypeNode(type))) { isRequired = true; } if (isRequired && metadata.queryInfo.first) { // If the query is required already via some indicators, and this is a "single" // query, use the available `.required` method. newQueryFn = ts.factory.createPropertyAccessExpression(newQueryFn, 'required'); } // If this query is still nullable (i.e. not required), attempt to remove // explicit `undefined` types if possible. if (!isRequired && type !== undefined && ts.isUnionTypeNode(type)) { type = migrate_ts_type_references.removeFromUnionIfPossible(type, (v) => v.kind !== ts.SyntaxKind.UndefinedKeyword); } let locatorType = Array.isArray(metadata.queryInfo.predicate) ? null : metadata.queryInfo.predicate.expression; let resolvedReadType = metadata.queryInfo.read ?? locatorType; // If the original property type and the read type are matching, we can rely // on the TS inference, instead of repeating types, like in `viewChild