Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
package.schematics.bundles.signal-queries-migration.js Maven / Gradle / Ivy
'use strict' ;
'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 = _interopDefaultLegacy(ts);
var assert__default = _interopDefaultLegacy(assert);
function migrateHostBindings (host, references, info ) {
const seenReferences = new WeakMap ();
for (const reference of references) {
if (!combine_units.isHostBindingReference(reference)) {
continue ;
}
if (!host.shouldMigrateReferencesToField(reference.target)) {
continue ;
}
const bindingField = reference.from.hostPropertyNode;
const expressionOffset = bindingField.getStart() + 1 ;
const readEndPos = expressionOffset + reference.from.read.sourceSpan.end;
if (seenReferences.get(bindingField)?.has(readEndPos)) {
continue ;
}
if (seenReferences.has(bindingField)) {
seenReferences.get(bindingField).add(readEndPos);
}
else {
seenReferences.set(bindingField, new Set ([readEndPos]));
}
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 })));
}
}
function migrateTemplateReferences (host, references ) {
const seenFileReferences = new Set ();
for (const reference of references) {
if (!combine_units.isTemplateReference(reference)) {
continue ;
}
if (!host.shouldMigrateReferencesToField(reference.target)) {
continue ;
}
const fileReferenceId = `${reference.from .templateFile.id} :${reference.from .read.sourceSpan.end} ` ;
if (seenFileReferences.has(fileReferenceId)) {
continue ;
}
seenFileReferences.add(fileReferenceId);
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,
})));
}
}
function extractQueryListType (node ) {
if (ts__default["default" ].isNewExpression(node) &&
ts__default["default" ].isIdentifier(node.expression) &&
node.expression.text === 'QueryList' ) {
return node.typeArguments?.[0 ];
}
if (ts__default["default" ].isTypeReferenceNode(node) &&
ts__default["default" ].isIdentifier(node.typeName) &&
node.typeName.text === 'QueryList' ) {
return node.typeArguments?.[0 ];
}
return undefined ;
}
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,
});
const defaultDescendants = metadata.kind !== 'contentChildren' ;
const optionProperties = [];
const args = [
metadata.args[0 ],
];
let type = node.type;
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 (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) {
newQueryFn = ts__default["default" ].factory.createPropertyAccessExpression(newQueryFn, 'required' );
}
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;
(Button )`.
if (type !== undefined &&
resolvedReadType instanceof checker.WrappedNodeExpr &&
ts__default["default" ].isIdentifier(resolvedReadType.node) &&
ts__default["default" ].isTypeReferenceNode(type ) &&
ts__default["default" ].isIdentifier(type .typeName ) &&
type .typeName .text === resolvedReadType .node .text ) {
locatorType = null ;
}
const call = ts__default["default" ].factory.createCallExpression(newQueryFn,
resolvedReadType === null && type !== undefined ? [type] : undefined, args);
const updated = ts__default["default" ].factory.createPropertyDeclaration([ts__default["default" ].factory.createModifier(ts__default["default" ].SyntaxKind .ReadonlyKeyword )], node.name, undefined, undefined, call);
return [
new combine_units.Replacement (combine_units.projectFile(node.getSourceFile(), info), new combine_units.TextUpdate ({
position: node.getStart(),
end: node.getEnd(),
toInsert: printer.printNode(ts__default["default" ].EmitHint .Unspecified , updated, sf),
})),
];
}
function getClassFieldDescriptorForSymbol(symbol, info) {
if (symbol?.valueDeclaration === undefined ||
!ts__default["default" ].isPropertyDeclaration(symbol.valueDeclaration)) {
return null ;
}
const key = getUniqueIDForClassProperty(symbol.valueDeclaration, info);
if (key === null ) {
return null ;
}
return {
key,
node: symbol.valueDeclaration,
};
}
function getUniqueIDForClassProperty(property, info) {
if (!ts__default["default" ].isClassDeclaration(property.parent) || property.parent.name === undefined) {
return null ;
}
if (property.name === undefined) {
return null ;
}
const id = combine_units.projectFile(property.getSourceFile(), info).id.replace(/\.d\.ts$/, '.ts');
return `${id}-${property.parent.name.text}-${property.name.getText()}`;
}
function extractSourceQueryDefinition(node, reflector, evaluator, info) {
if ((!ts__default["default" ].isPropertyDeclaration(node) && !ts__default["default" ].isAccessor(node)) ||
!ts__default["default" ].isClassDeclaration(node.parent) ||
node.parent.name === undefined ||
!ts__default["default" ].isIdentifier(node.name)) {
return null ;
}
const decorators = reflector.getDecoratorsOfDeclaration(node) ?? [];
const ngDecorators = checker.getAngularDecorators(decorators, program.queryDecoratorNames, false );
if (ngDecorators.length === 0 ) {
return null ;
}
const decorator = ngDecorators[0 ];
const id = getUniqueIDForClassProperty(node, info);
if (id === null ) {
return null ;
}
let kind;
if (decorator.name === 'ViewChil d') {
kind = 'viewChil d';
}
else if (decorator.name === 'ViewChildre n') {
kind = 'viewChildre n';
}
else if (decorator.name === 'ContentChil d') {
kind = 'contentChil d';
}
else if (decorator.name === 'ContentChildre n') {
kind = 'contentChildre n';
}
else {
throw new Error ('Unexpected query decorator detected.');
}
let queryInfo = null ;
try {
queryInfo = program.extractDecoratorQueryMetadata(node, decorator.name, decorator.args ?? [], node.name.text, reflector, evaluator);
}
catch (e) {
if (!(e instanceof checker.FatalDiagnosticError )) {
throw e;
}
console.error(`Skipping query: ${e.node.getSourceFile().fileName}: ${e.toString()}`);
return null ;
}
return {
id,
kind,
args: decorator.args ?? [],
queryInfo,
node: node,
fieldDecorators: decorators,
};
}
function markFieldIncompatibleInMetadata(data, id, reason) {
const existing = data[id];
if (existing === undefined) {
data[id] = {
fieldReason: reason,
classReason: null ,
};
}
else if (existing.fieldReason === null ) {
existing.fieldReason = reason;
}
else {
existing.fieldReason = migrate_ts_type_references.pickFieldIncompatibility({ reason, context: null }, { reason: existing.fieldReason, context: null }).reason;
}
}
function filterBestEffortIncompatibilities(knownQueries) {
for (const query of Object .values(knownQueries.globalMetadata.problematicQueries)) {
if (query.fieldReason !== null &&
!migrate_ts_type_references.nonIgnorableFieldIncompatibilities.includes(query.fieldReason)) {
query.fieldReason = null ;
}
}
}
class KnownQueries {
info;
config;
globalMetadata;
classToQueryFields = new Map ();
knownQueryIDs = new Map ();
constructor(info, config, globalMetadata) {
this .info = info;
this .config = config;
this .globalMetadata = globalMetadata;
}
isFieldIncompatible(descriptor) {
return this .getIncompatibilityForField(descriptor) !== null ;
}
markFieldIncompatible(field, incompatibility) {
markFieldIncompatibleInMetadata(this .globalMetadata.problematicQueries, field.key, incompatibility.reason);
}
markClassIncompatible(node, reason) {
this .classToQueryFields.get(node)?.forEach((f) => {
this .globalMetadata.problematicQueries[f.key] ??= { classReason: null , fieldReason: null };
this .globalMetadata.problematicQueries[f.key].classReason = reason;
});
}
registerQueryField(queryField, id) {
if (!this .classToQueryFields.has(queryField.parent)) {
this .classToQueryFields.set(queryField.parent, []);
}
this .classToQueryFields.get(queryField.parent).push({
key: id,
node: queryField,
});
this .knownQueryIDs.set(id, { key: id, node: queryField });
const descriptor = { key: id, node: queryField };
const file = combine_units.projectFile(queryField.getSourceFile(), this .info);
if (this .config.shouldMigrateQuery !== undefined &&
!this .config.shouldMigrateQuery(descriptor, file)) {
this .markFieldIncompatible(descriptor, {
context: null ,
reason: migrate_ts_type_references.FieldIncompatibilityReason .SkippedViaConfigFilter ,
});
}
}
attemptRetrieveDescriptorFromSymbol(symbol) {
const descriptor = getClassFieldDescriptorForSymbol(symbol, this .info);
if (descriptor !== null && this .knownQueryIDs.has(descriptor.key)) {
return descriptor;
}
return null ;
}
shouldTrackClassReference(clazz) {
return this .classToQueryFields.has(clazz);
}
getQueryFieldsOfClass(clazz) {
return this .classToQueryFields.get(clazz);
}
getAllClassesWithQueries() {
return Array .from(this .classToQueryFields.keys()).filter((c) => ts__default["default" ].isClassDeclaration(c));
}
captureKnownFieldInheritanceRelationship(derived, parent) {
if (this .isFieldIncompatible(parent) && !this .isFieldIncompatible(derived)) {
this .markFieldIncompatible(derived, {
context: null ,
reason: migrate_ts_type_references.FieldIncompatibilityReason .ParentIsIncompatible ,
});
return ;
}
if (this .isFieldIncompatible(derived) && !this .isFieldIncompatible(parent)) {
this .markFieldIncompatible(parent, {
context: null ,
reason: migrate_ts_type_references.FieldIncompatibilityReason .DerivedIsIncompatible ,
});
}
}
captureUnknownDerivedField(field) {
this .markFieldIncompatible(field, {
context: null ,
reason: migrate_ts_type_references.FieldIncompatibilityReason .OverriddenByDerivedClass ,
});
}
captureUnknownParentField(field) {
this .markFieldIncompatible(field, {
context: null ,
reason: migrate_ts_type_references.FieldIncompatibilityReason .TypeConflictWithBaseClass ,
});
}
getIncompatibilityForField(descriptor) {
const problematicInfo = this .globalMetadata.problematicQueries[descriptor.key];
if (problematicInfo === undefined) {
return null ;
}
if (problematicInfo.fieldReason !== null ) {
return { context: null , reason: problematicInfo.fieldReason };
}
if (problematicInfo.classReason !== null ) {
return problematicInfo.classReason;
}
return null ;
}
getIncompatibilityTextForField(field) {
const incompatibilityInfo = this .globalMetadata.problematicQueries[field.key];
if (incompatibilityInfo.fieldReason !== null ) {
return migrate_ts_type_references.getMessageForFieldIncompatibility(incompatibilityInfo.fieldReason, {
single: 'quer y',
plural: 'querie s',
});
}
if (incompatibilityInfo.classReason !== null ) {
return migrate_ts_type_references.getMessageForClassIncompatibility(incompatibilityInfo.classReason, {
single: 'quer y',
plural: 'querie s',
});
}
return null ;
}
}
function queryFunctionNameToDecorator(name) {
if (name === 'viewChil d') {
return 'ViewChil d';
}
else if (name === 'viewChildre n') {
return 'ViewChildre n';
}
else if (name === 'contentChil d') {
return 'ContentChil d';
}
else if (name === 'contentChildre n') {
return 'ContentChildre n';
}
throw new Error (`Unexpected query function name: ${name}`);
}
function checkTsReferenceAccessesField(ref, fieldName) {
const accessNode = combine_units.traverseAccess(ref.from.node);
if (!ts__default["default" ].isPropertyAccessExpression(accessNode.parent) ||
!ts__default["default" ].isIdentifier(accessNode.parent.name)) {
return null ;
}
if (accessNode.parent.name.text !== fieldName) {
return null ;
}
return accessNode.parent;
}
function checkNonTsReferenceAccessesField(ref, fieldName) {
const readFromPath = ref.from.readAstPath.at(-1 );
const parentRead = ref.from.readAstPath.at(-2 );
if (ref.from.read !== readFromPath) {
return null ;
}
if (!(parentRead instanceof checker.PropertyRead ) || parentRead.name !== fieldName) {
return null ;
}
return parentRead;
}
function checkTsReferenceCallsField(ref, fieldName) {
const propertyAccess = checkTsReferenceAccessesField(ref, fieldName);
if (propertyAccess === null ) {
return null ;
}
if (ts__default["default" ].isCallExpression(propertyAccess.parent) &&
propertyAccess.parent.expression === propertyAccess) {
return propertyAccess.parent;
}
return null ;
}
function checkNonTsReferenceCallsField(ref, fieldName) {
const propertyAccess = checkNonTsReferenceAccessesField(ref, fieldName);
if (propertyAccess === null ) {
return null ;
}
const accessIdx = ref.from.readAstPath.indexOf(propertyAccess);
if (accessIdx === -1 ) {
return null ;
}
const potentialCall = ref.from.readAstPath[accessIdx - 1 ];
if (potentialCall === undefined || !(potentialCall instanceof checker.Call )) {
return null ;
}
return potentialCall;
}
function removeQueryListToArrayCall(ref, info, globalMetadata, knownQueries, replacements) {
if (!combine_units.isHostBindingReference(ref) && !combine_units.isTemplateReference(ref) && !combine_units.isTsReference(ref)) {
return ;
}
if (knownQueries.isFieldIncompatible(ref.target)) {
return ;
}
if (!globalMetadata.knownQueryFields[ref.target.key]?.isMulti) {
return ;
}
if (combine_units.isTsReference(ref)) {
const toArrayCallExpr = checkTsReferenceCallsField(ref, 'toArra y');
if (toArrayCallExpr === null ) {
return ;
}
const toArrayExpr = toArrayCallExpr.expression;
replacements.push(new combine_units.Replacement (combine_units.projectFile(toArrayExpr.getSourceFile(), info), new combine_units.TextUpdate ({
position: toArrayExpr.expression.getEnd(),
end: toArrayCallExpr.getEnd(),
toInsert: '',
})));
return ;
}
const callExpr = checkNonTsReferenceCallsField(ref, 'toArra y');
if (callExpr === null ) {
return ;
}
const file = combine_units.isHostBindingReference(ref) ? ref.from.file : ref.from.templateFile;
const offset = combine_units.isHostBindingReference(ref) ? ref.from.hostPropertyNode.getStart() + 1 : 0 ;
replacements.push(new combine_units.Replacement (file, new combine_units.TextUpdate ({
position: offset + callExpr.receiver.receiver.sourceSpan.end,
end: offset + callExpr.sourceSpan.end,
toInsert: '',
})));
}
function replaceQueryListGetCall(ref, info, globalMetadata, knownQueries, replacements) {
if (!combine_units.isHostBindingReference(ref) && !combine_units.isTemplateReference(ref) && !combine_units.isTsReference(ref)) {
return ;
}
if (knownQueries.isFieldIncompatible(ref.target)) {
return ;
}
if (!globalMetadata.knownQueryFields[ref.target.key]?.isMulti) {
return ;
}
if (combine_units.isTsReference(ref)) {
const getCallExpr = checkTsReferenceCallsField(ref, 'ge t');
if (getCallExpr === null ) {
return ;
}
const getExpr = getCallExpr.expression;
replacements.push(new combine_units.Replacement (combine_units.projectFile(getExpr.getSourceFile(), info), new combine_units.TextUpdate ({
position: getExpr.name.getStart(),
end: getExpr.name.getEnd(),
toInsert: 'a t',
})));
return ;
}
const callExpr = checkNonTsReferenceCallsField(ref, 'ge t');
if (callExpr === null ) {
return ;
}
const file = combine_units.isHostBindingReference(ref) ? ref.from.file : ref.from.templateFile;
const offset = combine_units.isHostBindingReference(ref) ? ref.from.hostPropertyNode.getStart() + 1 : 0 ;
replacements.push(new combine_units.Replacement (file, new combine_units.TextUpdate ({
position: offset + callExpr.receiver.nameSpan.start,
end: offset + callExpr.receiver.nameSpan.end,
toInsert: 'a t',
})));
}
const problematicQueryListMethods = [
'dirt y',
'change s',
'setDirt y',
'rese t',
'notifyOnChange s',
'destro y',
];
function checkForIncompatibleQueryListAccesses(ref, result) {
if (combine_units.isTsReference(ref)) {
for (const problematicFn of problematicQueryListMethods) {
const access = checkTsReferenceAccessesField(ref, problematicFn);
if (access !== null ) {
result.potentialProblematicReferenceForMultiQueries[ref.target.key] = true ;
return ;
}
}
}
if (combine_units.isHostBindingReference(ref) || combine_units.isTemplateReference(ref)) {
for (const problematicFn of problematicQueryListMethods) {
const access = checkNonTsReferenceAccessesField(ref, problematicFn);
if (access !== null ) {
result.potentialProblematicReferenceForMultiQueries[ref.target.key] = true ;
return ;
}
}
}
}
const mapping = new Map ([
['firs t', 'at (0 )!'],
['las t', 'at (-1 )!'],
]);
function replaceQueryListFirstAndLastReferences(ref, info, globalMetadata, knownQueries, replacements) {
if (!combine_units.isHostBindingReference(ref) && !combine_units.isTemplateReference(ref) && !combine_units.isTsReference(ref)) {
return ;
}
if (knownQueries.isFieldIncompatible(ref.target)) {
return ;
}
if (!globalMetadata.knownQueryFields[ref.target.key]?.isMulti) {
return ;
}
if (combine_units.isTsReference(ref)) {
const expr = checkTsReferenceAccessesField(ref, 'firs t') ?? checkTsReferenceAccessesField(ref, 'las t');
if (expr === null ) {
return ;
}
replacements.push(new combine_units.Replacement (combine_units.projectFile(expr.getSourceFile(), info), new combine_units.TextUpdate ({
position: expr.name.getStart(),
end: expr.name.getEnd(),
toInsert: mapping.get(expr.name.text),
})));
return ;
}
const expr = checkNonTsReferenceAccessesField(ref, 'firs t') ?? checkNonTsReferenceAccessesField(ref, 'las t');
if (expr === null ) {
return ;
}
const file = combine_units.isHostBindingReference(ref) ? ref.from.file : ref.from.templateFile;
const offset = combine_units.isHostBindingReference(ref) ? ref.from.hostPropertyNode.getStart() + 1 : 0 ;
replacements.push(new combine_units.Replacement (file, new combine_units.TextUpdate ({
position: offset + expr.nameSpan.start,
end: offset + expr.nameSpan.end,
toInsert: mapping.get(expr.name),
})));
}
class SignalQueriesMigration extends combine_units .TsurgeComplexMigration {
config;
constructor(config = {}) {
super ();
this .config = config;
}
async analyze(info) {
const { templateTypeChecker } = info.ngCompiler?.['ensureAnalyze d']() ?? {
templateTypeChecker: null ,
};
const resourceLoader = info.ngCompiler?.['resourceManage r'] ?? null ;
if (templateTypeChecker !== null ) {
templateTypeChecker.generateAllTypeCheckBlocks();
}
const { sourceFiles, program: program$1 } = info;
const checker$1 = program$1. getTypeChecker();
const reflector = new checker.TypeScriptReflectionHost (checker$1 );
const evaluator = new program.PartialEvaluator (reflector, checker$1 , null );
const res = {
knownQueryFields: {},
potentialProblematicQueries: {},
potentialProblematicReferenceForMultiQueries: {},
reusableAnalysisReferences: null ,
};
const groupedAstVisitor = new migrate_ts_type_references.GroupedTsAstVisitor (sourceFiles);
const referenceResult = { references: [] };
const classesWithFilteredQueries = new Set ();
const filteredQueriesForCompilationUnit = new Map ();
const findQueryDefinitionsVisitor = (node) => {
const extractedQuery = extractSourceQueryDefinition(node, reflector, evaluator, info);
if (extractedQuery !== null ) {
const queryNode = extractedQuery.node;
const descriptor = {
key: extractedQuery.id,
node: queryNode,
};
const containingFile = combine_units.projectFile(queryNode.getSourceFile(), info);
if (this .config.shouldMigrateQuery === undefined ||
this .config.shouldMigrateQuery(descriptor, containingFile)) {
classesWithFilteredQueries.add(queryNode.parent);
filteredQueriesForCompilationUnit.set(extractedQuery.id, {
fieldName: extractedQuery.queryInfo.propertyName,
});
}
res.knownQueryFields[extractedQuery.id] = {
fieldName: extractedQuery.queryInfo.propertyName,
isMulti: extractedQuery.queryInfo.first === false ,
};
if (ts__default["default" ].isAccessor(queryNode)) {
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id, migrate_ts_type_references.FieldIncompatibilityReason .Accessor );
}
if (queryNode.type !== undefined &&
ts__default["default" ].isUnionTypeNode(queryNode.type ) &&
(queryNode.type .types.length > 2 ||
!queryNode.type .types.some((t) => t.kind === ts__default["default" ].SyntaxKind .UndefinedKeyword ))) {
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id, migrate_ts_type_references.FieldIncompatibilityReason .SignalQueries__IncompatibleMultiUnionType );
}
const hostBindingDecorators = checker.getAngularDecorators(extractedQuery.fieldDecorators, ['HostBindin g'],
false );
if (hostBindingDecorators.length > 0 ) {
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id, migrate_ts_type_references.FieldIncompatibilityReason .SignalIncompatibleWithHostBinding );
}
}
};
this .config.reportProgressFn?.(20 , 'Scanning for queries..');
groupedAstVisitor.register(findQueryDefinitionsVisitor);
groupedAstVisitor.execute();
const allFieldsOrKnownQueries = {
shouldTrackClassReference: (node) => classesWithFilteredQueries.has(node),
attemptRetrieveDescriptorFromSymbol: (s) => {
const descriptor = getClassFieldDescriptorForSymbol(s, info);
if (this .config.assumeNonBatch &&
(descriptor === null || !filteredQueriesForCompilationUnit.has(descriptor.key))) {
return null ;
}
return descriptor;
},
};
groupedAstVisitor.register(combine_units.createFindAllSourceFileReferencesVisitor(info, checker$1 , reflector, resourceLoader, evaluator, templateTypeChecker, allFieldsOrKnownQueries,
this .config.assumeNonBatch
? new Set (Array .from(filteredQueriesForCompilationUnit.values()).map((f) => f.fieldName))
: null , referenceResult).visitor);
const inheritanceGraph = new migrate_ts_type_references.InheritanceGraph (checker$1 ).expensivePopulate(info.sourceFiles);
migrate_ts_type_references.checkIncompatiblePatterns(inheritanceGraph, checker$1 , groupedAstVisitor, {
...allFieldsOrKnownQueries,
isFieldIncompatible: (f) => res.potentialProblematicQueries[f.key]?.fieldReason !== null ||
res.potentialProblematicQueries[f.key]?.classReason !== null ,
markClassIncompatible: (clazz, reason) => {
for (const field of clazz.members) {
const key = getUniqueIDForClassProperty(field, info);
if (key !== null ) {
res.potentialProblematicQueries[key] ??= { classReason: null , fieldReason: null };
res.potentialProblematicQueries[key].classReason = reason;
}
}
},
markFieldIncompatible: (f, incompatibility) => markFieldIncompatibleInMetadata(res.potentialProblematicQueries, f.key, incompatibility.reason),
}, () => Array .from(classesWithFilteredQueries));
this .config.reportProgressFn?.(60 , 'Scanning for references and problematic patterns..');
groupedAstVisitor.execute();
for (const ref of referenceResult.references) {
if (combine_units.isTsReference(ref) && ref.from.isWrite) {
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key, migrate_ts_type_references.FieldIncompatibilityReason .WriteAssignment );
}
if ((combine_units.isTemplateReference(ref) || combine_units.isHostBindingReference(ref)) && ref.from.isWrite) {
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key, migrate_ts_type_references.FieldIncompatibilityReason .WriteAssignment );
}
if (combine_units.isTemplateReference(ref) && ref.from.isLikelyPartOfNarrowing) {
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key, migrate_ts_type_references.FieldIncompatibilityReason .PotentiallyNarrowedInTemplateButNoSupportYet );
}
checkForIncompatibleQueryListAccesses(ref, res);
}
if (this .config.assumeNonBatch) {
res.reusableAnalysisReferences = referenceResult.references;
}
return combine_units.confirmAsSerializable(res);
}
async combine(unitA, unitB) {
const combined = {
knownQueryFields: {},
potentialProblematicQueries: {},
potentialProblematicReferenceForMultiQueries: {},
reusableAnalysisReferences: null ,
};
for (const unit of [unitA, unitB]) {
for (const [id, value] of Object .entries(unit.knownQueryFields)) {
combined.knownQueryFields[id] = value;
}
for (const [id, info] of Object .entries(unit.potentialProblematicQueries)) {
if (info.fieldReason !== null ) {
markFieldIncompatibleInMetadata(combined.potentialProblematicQueries, id, info.fieldReason);
}
if (info.classReason !== null ) {
combined.potentialProblematicQueries[id] ??= {
classReason: null ,
fieldReason: null ,
};
combined.potentialProblematicQueries[id].classReason =
info.classReason;
}
}
for (const id of Object .keys(unit.potentialProblematicReferenceForMultiQueries)) {
combined.potentialProblematicReferenceForMultiQueries[id] = true ;
}
if (unit.reusableAnalysisReferences !== null ) {
combined.reusableAnalysisReferences = unit.reusableAnalysisReferences;
}
}
for (const unit of [unitA, unitB]) {
for (const id of Object .keys(unit.potentialProblematicReferenceForMultiQueries)) {
if (combined.knownQueryFields[id]?.isMulti) {
markFieldIncompatibleInMetadata(combined.potentialProblematicQueries, id, migrate_ts_type_references.FieldIncompatibilityReason .SignalQueries__QueryListProblematicFieldAccessed );
}
}
}
return combine_units.confirmAsSerializable(combined);
}
async globalMeta(combinedData) {
const globalUnitData = {
knownQueryFields: combinedData.knownQueryFields,
problematicQueries: combinedData.potentialProblematicQueries,
reusableAnalysisReferences: combinedData.reusableAnalysisReferences,
};
for (const id of Object .keys(combinedData.potentialProblematicReferenceForMultiQueries)) {
if (combinedData.knownQueryFields[id]?.isMulti) {
markFieldIncompatibleInMetadata(globalUnitData.problematicQueries, id, migrate_ts_type_references.FieldIncompatibilityReason .SignalQueries__QueryListProblematicFieldAccessed );
}
}
return combine_units.confirmAsSerializable(globalUnitData);
}
async migrate(globalMetadata, info) {
const { templateTypeChecker, metaReader } = info.ngCompiler?.['ensureAnalyze d']() ?? {
templateTypeChecker: null ,
metaReader: null ,
};
const resourceLoader = info.ngCompiler?.['resourceManage r'] ?? null ;
const { program: program$1 , sourceFiles } = info;
const checker$1 = program$1. getTypeChecker();
const reflector = new checker.TypeScriptReflectionHost (checker$1 );
const evaluator = new program.PartialEvaluator (reflector, checker$1 , null );
const replacements = [];
const importManager = new checker.ImportManager ();
const printer = ts__default["default" ].createPrinter();
const filesWithSourceQueries = new Map ();
const filesWithIncompleteMigration = new Map ();
const filesWithQueryListOutsideOfDeclarations = new WeakSet ();
const knownQueries = new KnownQueries (info, this .config, globalMetadata);
const referenceResult = { references: [] };
const sourceQueries = [];
const queryWholeProgramVisitor = (node) => {
const extractedQuery = extractSourceQueryDefinition(node, reflector, evaluator, info);
if (extractedQuery !== null ) {
knownQueries.registerQueryField(extractedQuery.node, extractedQuery.id);
sourceQueries.push(extractedQuery);
return ;
}
if (ts__default["default" ].isPropertyDeclaration(node) ||
(ts__default["default" ].isAccessor(node) && ts__default["default" ].isClassDeclaration(node.parent))) {
const classFieldID = getUniqueIDForClassProperty(node, info);
if (classFieldID !== null && globalMetadata.knownQueryFields[classFieldID] !== undefined) {
knownQueries.registerQueryField(node, classFieldID);
return ;
}
}
if (ts__default["default" ].isIdentifier(node) &&
node.text === 'QueryLis t' &&
ts__default["default" ].findAncestor(node, ts__default["default" ].isImportDeclaration) === undefined) {
filesWithQueryListOutsideOfDeclarations.add(node.getSourceFile());
}
ts__default["default" ].forEachChild(node, queryWholeProgramVisitor);
};
for (const sf of info.fullProgramSourceFiles) {
ts__default["default" ].forEachChild(sf, queryWholeProgramVisitor);
}
const fieldNamesToConsiderForReferenceLookup = new Set (Object .values(globalMetadata.knownQueryFields).map((f) => f.fieldName));
const groupedAstVisitor = new migrate_ts_type_references.GroupedTsAstVisitor (sourceFiles);
if (globalMetadata.reusableAnalysisReferences !== null ) {
referenceResult.references = globalMetadata.reusableAnalysisReferences;
}
else {
groupedAstVisitor.register(combine_units.createFindAllSourceFileReferencesVisitor(info, checker$1 , reflector, resourceLoader, evaluator, templateTypeChecker, knownQueries, fieldNamesToConsiderForReferenceLookup, referenceResult).visitor);
}
const inheritanceGraph = new migrate_ts_type_references.InheritanceGraph (checker$1 ).expensivePopulate(info.sourceFiles);
migrate_ts_type_references.checkInheritanceOfKnownFields(inheritanceGraph, metaReader, knownQueries, {
getFieldsForClass: (n) => knownQueries.getQueryFieldsOfClass(n) ?? [],
isClassWithKnownFields: (clazz) => knownQueries.getQueryFieldsOfClass(clazz) !== undefined,
});
this .config.reportProgressFn?.(80 , 'Checking inheritance..');
groupedAstVisitor.execute();
if (this .config.bestEffortMode) {
filterBestEffortIncompatibilities(knownQueries);
}
this .config.reportProgressFn?.(90 , 'Migrating queries..');
for (const extractedQuery of sourceQueries) {
const node = extractedQuery.node;
const sf = node.getSourceFile();
const descriptor = { key: extractedQuery.id, node: extractedQuery.node };
const incompatibility = knownQueries.getIncompatibilityForField(descriptor);
updateFileState(filesWithSourceQueries, sf, extractedQuery.kind);
if (incompatibility !== null ) {
if (this .config.insertTodosForSkippedFields) {
replacements.push(...migrate_ts_type_references.insertTodoForIncompatibility(node, info, incompatibility, {
single: 'quer y',
plural: 'querie s',
}));
}
updateFileState(filesWithIncompleteMigration, sf, extractedQuery.kind);
continue ;
}
replacements.push(...computeReplacementsToMigrateQuery(node, extractedQuery, importManager, info, printer, info.userOptions, checker$1 ));
}
const referenceMigrationHost = {
printer,
replacements,
shouldMigrateReferencesToField: (field) => !knownQueries.isFieldIncompatible(field),
shouldMigrateReferencesToClass: (clazz) => !!knownQueries
.getQueryFieldsOfClass(clazz)
?.some((q) => !knownQueries.isFieldIncompatible(q)),
};
migrate_ts_type_references.migrateTypeScriptReferences(referenceMigrationHost, referenceResult.references, checker$1 , info);
migrateTemplateReferences(referenceMigrationHost, referenceResult.references);
migrateHostBindings(referenceMigrationHost, referenceResult.references, info);
migrate_ts_type_references.migrateTypeScriptTypeReferences(referenceMigrationHost, referenceResult.references, importManager, info);
for (const ref of referenceResult.references) {
removeQueryListToArrayCall(ref, info, globalMetadata, knownQueries, replacements);
replaceQueryListGetCall(ref, info, globalMetadata, knownQueries, replacements);
replaceQueryListFirstAndLastReferences(ref, info, globalMetadata, knownQueries, replacements);
}
for (const [file, types] of filesWithSourceQueries) {
let seenIncompatibleMultiQuery = false ;
for (const type of types ) {
const incompatibleQueryTypesForFile = filesWithIncompleteMigration.get(file);
if (!incompatibleQueryTypesForFile?.has(type )) {
importManager.removeImport(file, queryFunctionNameToDecorator(type ), '@angular/core ') ;
}
else if (type === 'viewChildren ' || type === 'contentChildren ') {
seenIncompatibleMultiQuery = true ;
}
}
if (!seenIncompatibleMultiQuery && !filesWithQueryListOutsideOfDeclarations.has(file)) {
importManager.removeImport(file, 'QueryLis t', '@angular /core');
}
}
combine_units.applyImportManagerChanges(importManager, replacements, sourceFiles, info);
return { replacements, knownQueries };
}
async stats(globalMetadata) {
let queriesCount = 0 ;
let multiQueries = 0 ;
let incompatibleQueries = 0 ;
const fieldIncompatibleCounts = {};
const classIncompatibleCounts = {};
for (const query of Object .values(globalMetadata.knownQueryFields)) {
queriesCount++;
if (query.isMulti) {
multiQueries++;
}
}
for (const [id, info] of Object .entries(globalMetadata.problematicQueries)) {
if (globalMetadata.knownQueryFields[id] === undefined) {
continue ;
}
incompatibleQueries++;
if (info.classReason !== null ) {
const reasonName = migrate_ts_type_references.ClassIncompatibilityReason [info.classReason];
const key = `incompat-class -$ {reasonName}`;
classIncompatibleCounts[key] ??= 0 ;
classIncompatibleCounts[key]++;
}
if (info.fieldReason !== null ) {
const reasonName = migrate_ts_type_references.FieldIncompatibilityReason [info.fieldReason];
const key = `incompat-field-${reasonName}`;
fieldIncompatibleCounts[key] ??= 0 ;
fieldIncompatibleCounts[key]++;
}
}
return {
counters: {
queriesCount,
multiQueries,
incompatibleQueries,
...fieldIncompatibleCounts,
...classIncompatibleCounts,
},
};
}
}
function updateFileState(stateMap, node, queryType) {
const file = node.getSourceFile();
if (!stateMap.has(file)) {
stateMap.set(file, new Set ());
}
stateMap.get(file).add(queryType);
}
function migrate(options) {
return async (tree, context) => {
const { buildPaths, testPaths } = await project_tsconfig_paths.getProjectTsConfigPaths(tree);
if (!buildPaths.length && !testPaths.length) {
throw new schematics.SchematicsException ('Could not find any tsconfig file. Cannot run signal queries migration.');
}
const fs = new combine_units.DevkitMigrationFilesystem (tree);
checker.setFileSystem(fs);
const migration = new SignalQueriesMigration ({
bestEffortMode: options.bestEffortMode,
insertTodosForSkippedFields: options.insertTodos,
shouldMigrateQuery: (_query, file) => {
return (file.rootRelativePath.startsWith(fs.normalize(options.path)) &&
!/(^|\/)node_modules\
},
});
const analysisPath = fs.resolve(options.analysisDir);
const unitResults = [];
const programInfos = [...buildPaths, ...testPaths].map((tsconfigPath) => {
context.logger.info(`Preparing analysis for : ${tsconfigPath}..`);
const baseInfo = migration.createProgram(tsconfigPath, fs);
const info = migration.prepareProgram(baseInfo);
if (analysisPath !== '/') {
info.sourceFiles = info.sourceFiles.filter((sf) => sf.fileName.startsWith(analysisPath));
info.fullProgramSourceFiles = info.fullProgramSourceFiles.filter((sf) => sf.fileName.startsWith(analysisPath));
}
return { info, tsconfigPath };
});
for (const { info, tsconfigPath } of programInfos) {
context.logger.info(`Scanning for queries: ${tsconfigPath}..`);
unitResults.push(await migration.analyze(info));
}
context.logger.info(``);
context.logger.info(`Processing analysis data between targets..`);
context.logger.info(``);
const combined = await combine_units.synchronouslyCombineUnitData(migration, unitResults);
if (combined === null ) {
context.logger.error('Migration failed unexpectedly with no analysis data');
return ;
}
const globalMeta = await migration.globalMeta(combined);
const replacementsPerFile = new Map ();
for (const { info, tsconfigPath } of programInfos) {
context.logger.info(`Migrating : ${tsconfigPath}..`);
const { replacements } = await migration.migrate(globalMeta, info);
const changesPerFile = combine_units.groupReplacementsByFile(replacements);
for (const [file, changes] of changesPerFile) {
if (!replacementsPerFile.has(file)) {
replacementsPerFile.set(file, changes);
}
}
}
context.logger.info(`Applying changes..`);
for (const [file, changes] of replacementsPerFile) {
const recorder = tree.beginUpdate(file);
for (const c of changes) {
recorder
.remove(c.data.position, c.data.end - c.data.position)
.insertLeft(c.data.position, c.data.toInsert);
}
tree.commitUpdate(recorder);
}
context.logger.info('');
context.logger.info(`Successfully migrated to signal queries 🎉`);
const { counters: { queriesCount, incompatibleQueries, multiQueries }, } = await migration.stats(globalMeta);
const migratedQueries = queriesCount - incompatibleQueries;
context.logger.info('');
context.logger.info(`Successfully migrated to signal queries 🎉`);
context.logger.info(` -> Migrated ${migratedQueries}/${queriesCount} queries.`);
if (incompatibleQueries > 0 && !options.insertTodos) {
context.logger.warn(`To see why ${incompatibleQueries} queries couldn't be migrated`);
context.logger.warn(`consider re-running with "--insert-todos" or "--best-effort-mode" .`);
}
if (options.bestEffortMode) {
context.logger.warn(`You ran with best effort mode. Manually verify all code ` +
`works as intended, and fix where necessary.`);
}
};
}
exports.migrate = migrate;