All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.schematics.bundles.signal-queries-migration.js Maven / Gradle / Ivy

'use strict';
/**
 * @license Angular v19.0.5
 * (c) 2010-2024 Google LLC. https://angular.io/
 * License: MIT
 */
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var schematics = require('@angular-devkit/schematics');
var project_tsconfig_paths = require('./project_tsconfig_paths-e9ccccbf.js');
var combine_units = require('./combine_units-438d7a79.js');
require('os');
var ts = require('typescript');
var checker = require('./checker-eced36c5.js');
var program = require('./program-c49e652e.js');
require('path');
var migrate_ts_type_references = require('./migrate_ts_type_references-7e102890.js');
var assert = require('assert');
require('@angular-devkit/core');
require('node:path/posix');
require('fs');
require('module');
require('url');
require('./leading_space-d190b83b.js');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);

/**
 * 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 (!combine_units.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 combine_units.Replacement(combine_units.projectFile(bindingField.getSourceFile(), info), new combine_units.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 (!combine_units.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 combine_units.Replacement(reference.from.templateFile, new combine_units.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__default["default"].isNewExpression(node) &&
        ts__default["default"].isIdentifier(node.expression) &&
        node.expression.text === 'QueryList') {
        return node.typeArguments?.[0];
    }
    // Type variant of `: QueryList`.
    if (ts__default["default"].isTypeReferenceNode(node) &&
        ts__default["default"].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__default["default"](metadata.queryInfo.read instanceof checker.WrappedNodeExpr);
        optionProperties.push(ts__default["default"].factory.createPropertyAssignment('read', metadata.queryInfo.read.node));
    }
    if (metadata.queryInfo.descendants !== defaultDescendants) {
        optionProperties.push(ts__default["default"].factory.createPropertyAssignment('descendants', metadata.queryInfo.descendants ? ts__default["default"].factory.createTrue() : ts__default["default"].factory.createFalse()));
    }
    if (optionProperties.length > 0) {
        args.push(ts__default["default"].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__default["default"].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__default["default"].isUnionTypeNode(type)) {
        type = migrate_ts_type_references.removeFromUnionIfPossible(type, (v) => v.kind !== ts__default["default"].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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy