├── BUILD_INFO ├── schematics ├── ng-generate │ ├── cleanup-unused-imports │ │ └── schema.json │ ├── route-lazy-loading │ │ └── schema.json │ ├── self-closing-tags-migration │ │ └── schema.json │ ├── output-migration │ │ └── schema.json │ ├── signal-input-migration │ │ └── schema.json │ ├── signal-queries-migration │ │ └── schema.json │ ├── standalone-migration │ │ └── schema.json │ ├── inject-migration │ │ └── schema.json │ └── signals │ │ └── schema.json ├── migrations │ ├── common-to-standalone-migration │ │ └── schema.json │ ├── router-testing-module-migration │ │ └── schema.json │ ├── control-flow-migration │ │ └── schema.json │ ├── ngstyle-to-style-migration │ │ └── schema.json │ └── ngclass-to-class-migration │ │ └── schema.json ├── bundles │ ├── nodes-B16H9JUd.cjs │ ├── property_name-BBwFuqMe.cjs │ ├── leading_space-D9nQ8UQC.cjs │ ├── symbol-BObKoqes.cjs │ ├── ng_decorators-DSFlWYQY.cjs │ ├── signals.cjs │ ├── apply_import_manager-1Zs_gpB6.cjs │ ├── project_tsconfig_paths-CDVxT6Ov.cjs │ ├── application-config-core.cjs │ ├── router-current-navigation.cjs │ ├── router-last-successful-navigation.cjs │ ├── imports-DP72APSx.cjs │ ├── parse_html-8VLCL37B.cjs │ ├── add-bootstrap-context-to-server-main.cjs │ ├── ng_component_template-Dsuq1Lw7.cjs │ └── self-closing-tags-migration.cjs ├── migrations.json └── collection.json ├── types ├── _weak_ref-chunk.d.ts ├── _effect-chunk.d.ts ├── primitives-event-dispatch.d.ts ├── primitives-di.d.ts ├── primitives-signals.d.ts ├── rxjs-interop.d.ts ├── _formatter-chunk.d.ts ├── _api-chunk.d.ts └── _event_dispatcher-chunk.d.ts ├── README.md ├── fesm2022 ├── _attribute-chunk.mjs ├── _weak_ref-chunk.mjs ├── _weak_ref-chunk.mjs.map ├── primitives-di.mjs ├── _attribute-chunk.mjs.map ├── _not_found-chunk.mjs ├── _linked_signal-chunk.mjs ├── primitives-di.mjs.map ├── _not_found-chunk.mjs.map ├── primitives-signals.mjs ├── _linked_signal-chunk.mjs.map ├── rxjs-interop.mjs ├── _resource-chunk.mjs └── _effect-chunk.mjs ├── event-dispatch-contract.min.js ├── LICENSE ├── resources └── best-practices.md └── package.json /BUILD_INFO: -------------------------------------------------------------------------------- 1 | Wed Dec 17 01:41:40 UTC 2025 2 | 9fa77af1106578f4fe79e8091df0fab7ed66c096 3 | -------------------------------------------------------------------------------- /schematics/ng-generate/cleanup-unused-imports/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "AngularCleanupUnusedImportsMigration", 4 | "title": "Angular Cleanup Unused Imports Schema", 5 | "type": "object", 6 | "properties": {} 7 | } 8 | -------------------------------------------------------------------------------- /types/_weak_ref-chunk.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | declare function setAlternateWeakRefImpl(impl: unknown): void; 8 | 9 | export { setAlternateWeakRefImpl }; 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular 2 | 3 | The sources for this package are in the main [Angular](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. 4 | 5 | Usage information and reference details can be found in [Angular documentation](https://angular.dev/overview). 6 | 7 | License: MIT 8 | -------------------------------------------------------------------------------- /fesm2022/_attribute-chunk.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | const Attribute = { 8 | JSACTION: 'jsaction' 9 | }; 10 | 11 | export { Attribute }; 12 | //# sourceMappingURL=_attribute-chunk.mjs.map 13 | -------------------------------------------------------------------------------- /fesm2022/_weak_ref-chunk.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | function setAlternateWeakRefImpl(impl) {} 8 | 9 | export { setAlternateWeakRefImpl }; 10 | //# sourceMappingURL=_weak_ref-chunk.mjs.map 11 | -------------------------------------------------------------------------------- /event-dispatch-contract.min.js: -------------------------------------------------------------------------------- 1 | (()=>{function p(t,n,r,o,e,i,f,m){return{eventType:t,event:n,targetElement:r,eic:o,timeStamp:e,eia:i,eirp:f,eiack:m}}function u(t){let n=[],r=e=>{n.push(e)};return{c:t,q:n,et:[],etc:[],d:r,h:e=>{r(p(e.type,e,e.target,t,Date.now()))}}}function s(t,n,r){for(let o=0;o prop.name && ts.isIdentifier(prop.name) && prop.name.text === name); 24 | } 25 | 26 | exports.findLiteralProperty = findLiteralProperty; 27 | exports.getPropertyNameText = getPropertyNameText; 28 | -------------------------------------------------------------------------------- /schematics/bundles/leading_space-D9nQ8UQC.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | /** 10 | * Gets the leading line whitespace of a given node. 11 | * 12 | * Useful for inserting e.g. TODOs without breaking indentation. 13 | */ 14 | function getLeadingLineWhitespaceOfNode(node) { 15 | const fullText = node.getFullText().substring(0, node.getStart() - node.getFullStart()); 16 | let result = ''; 17 | for (let i = fullText.length - 1; i > -1; i--) { 18 | // Note: LF line endings are `\n` while CRLF are `\r\n`. This logic should cover both, because 19 | // we start from the beginning of the node and go backwards so will always hit `\n` first. 20 | if (fullText[i] !== '\n') { 21 | result = fullText[i] + result; 22 | } 23 | else { 24 | break; 25 | } 26 | } 27 | return result; 28 | } 29 | 30 | exports.getLeadingLineWhitespaceOfNode = getLeadingLineWhitespaceOfNode; 31 | -------------------------------------------------------------------------------- /fesm2022/_attribute-chunk.mjs.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"_attribute-chunk.mjs","sources":["../../../../../k8-fastbuild-ST-fdfa778d11ba/bin/packages/core/primitives/event-dispatch/src/attribute.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nexport const Attribute = {\n /**\n * The jsaction attribute defines a mapping of a DOM event to a\n * generic event (aka jsaction), to which the actual event handlers\n * that implement the behavior of the application are bound. The\n * value is a semicolon separated list of colon separated pairs of\n * an optional DOM event name and a jsaction name. If the optional\n * DOM event name is omitted, 'click' is assumed. The jsaction names\n * are dot separated pairs of a namespace and a simple jsaction\n * name.\n *\n * See grammar in README.md for expected syntax in the attribute value.\n */\n JSACTION: 'jsaction' as const,\n};\n"],"names":["Attribute","JSACTION"],"mappings":";;;;;;AAQO,MAAMA,SAAS,GAAG;AAavBC,EAAAA,QAAQ,EAAE;;;;;"} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2025 Google LLC. https://angular.dev/license 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /fesm2022/_not_found-chunk.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | let _currentInjector = undefined; 8 | function getCurrentInjector() { 9 | return _currentInjector; 10 | } 11 | function setCurrentInjector(injector) { 12 | const former = _currentInjector; 13 | _currentInjector = injector; 14 | return former; 15 | } 16 | function inject(token, options) { 17 | const currentInjector = getCurrentInjector(); 18 | if (!currentInjector) { 19 | throw new Error('Current injector is not set.'); 20 | } 21 | if (!token.ɵprov) { 22 | throw new Error('Token is not an injectable'); 23 | } 24 | return currentInjector.retrieve(token, options); 25 | } 26 | 27 | const NOT_FOUND = Symbol('NotFound'); 28 | class NotFoundError extends Error { 29 | name = 'ɵNotFound'; 30 | constructor(message) { 31 | super(message); 32 | } 33 | } 34 | function isNotFound(e) { 35 | return e === NOT_FOUND || e?.name === 'ɵNotFound'; 36 | } 37 | 38 | export { NOT_FOUND, NotFoundError, getCurrentInjector, inject, isNotFound, setCurrentInjector }; 39 | //# sourceMappingURL=_not_found-chunk.mjs.map 40 | -------------------------------------------------------------------------------- /schematics/bundles/symbol-BObKoqes.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | 11 | /** Checks whether a node is referring to a specific import specifier. */ 12 | function isReferenceToImport(typeChecker, node, importSpecifier) { 13 | // If this function is called on an identifier (should be most cases), we can quickly rule out 14 | // non-matches by comparing the identifier's string and the local name of the import specifier 15 | // which saves us some calls to the type checker. 16 | if (importSpecifier === null || 17 | (ts.isIdentifier(node) && node.text !== importSpecifier.name.text)) { 18 | return false; 19 | } 20 | const nodeSymbol = typeChecker.getTypeAtLocation(node).getSymbol(); 21 | const importSymbol = typeChecker.getTypeAtLocation(importSpecifier).getSymbol(); 22 | return (!!(nodeSymbol?.declarations?.[0] && importSymbol?.declarations?.[0]) && 23 | nodeSymbol.declarations[0] === importSymbol.declarations[0]); 24 | } 25 | 26 | exports.isReferenceToImport = isReferenceToImport; 27 | -------------------------------------------------------------------------------- /schematics/ng-generate/signal-input-migration/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "AngularSignalInputMigration", 4 | "title": "Angular Signal Input migration", 5 | "type": "object", 6 | "properties": { 7 | "path": { 8 | "type": "string", 9 | "description": "Path to the directory where all inputs should be migrated.", 10 | "x-prompt": "Which directory do you want to migrate?", 11 | "default": "./" 12 | }, 13 | "analysisDir": { 14 | "type": "string", 15 | "description": "Path to the directory that should be analyzed. References to migrated inputs are migrated based on this folder. Useful for larger projects if the analysis takes too long and the analysis scope can be narrowed.", 16 | "default": "./" 17 | }, 18 | "bestEffortMode": { 19 | "type": "boolean", 20 | "description": "Whether to eagerly migrate as much as possible, ignoring problematic patterns that would otherwise prevent migration.", 21 | "x-prompt": "Do you want to migrate as much as possible, even if it may break your build?", 22 | "default": false 23 | }, 24 | "insertTodos": { 25 | "type": "boolean", 26 | "description": "Whether the migration should add TODOs for inputs that could not be migrated", 27 | "default": false 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /schematics/ng-generate/signal-queries-migration/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "AngularSignalQueriesMigration", 4 | "title": "Angular Signal Queries migration", 5 | "type": "object", 6 | "properties": { 7 | "path": { 8 | "type": "string", 9 | "description": "Path to the directory where all queries should be migrated.", 10 | "x-prompt": "Which directory do you want to migrate?", 11 | "default": "./" 12 | }, 13 | "analysisDir": { 14 | "type": "string", 15 | "description": "Path to the directory that should be analyzed. References to migrated queries are migrated based on this folder. Useful for larger projects if the analysis takes too long and the analysis scope can be narrowed.", 16 | "default": "./" 17 | }, 18 | "bestEffortMode": { 19 | "type": "boolean", 20 | "description": "Whether to eagerly migrate as much as possible, ignoring problematic patterns that would otherwise prevent migration.", 21 | "x-prompt": "Do you want to migrate as much as possible, even if it may break your build?", 22 | "default": false 23 | }, 24 | "insertTodos": { 25 | "type": "boolean", 26 | "description": "Whether the migration should add TODOs for queries that could not be migrated", 27 | "default": false 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /schematics/ng-generate/standalone-migration/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "AngularStandaloneMigration", 4 | "title": "Angular Standalone Migration Schema", 5 | "type": "object", 6 | "properties": { 7 | "mode": { 8 | "description": "Operation that should be performed by the migrator", 9 | "type": "string", 10 | "enum": ["convert-to-standalone", "prune-ng-modules", "standalone-bootstrap"], 11 | "default": "convert-to-standalone", 12 | "x-prompt": { 13 | "message": "Choose the type of migration:", 14 | "type": "list", 15 | "items": [ 16 | { 17 | "value": "convert-to-standalone", 18 | "label": "Convert all components, directives and pipes to standalone" 19 | }, 20 | { 21 | "value": "prune-ng-modules", 22 | "label": "Remove unnecessary NgModule classes" 23 | }, 24 | { 25 | "value": "standalone-bootstrap", 26 | "label": "Bootstrap the application using standalone APIs" 27 | } 28 | ] 29 | } 30 | }, 31 | "path": { 32 | "type": "string", 33 | "description": "Path relative to the project root which should be migrated", 34 | "x-prompt": "Which path in your project should be migrated?", 35 | "default": "./" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /schematics/bundles/ng_decorators-DSFlWYQY.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | var imports = require('./imports-DP72APSx.cjs'); 11 | 12 | function getCallDecoratorImport(typeChecker, decorator) { 13 | // Note that this does not cover the edge case where decorators are called from 14 | // a namespace import: e.g. "@core.Component()". This is not handled by Ngtsc either. 15 | if (!ts.isCallExpression(decorator.expression) || 16 | !ts.isIdentifier(decorator.expression.expression)) { 17 | return null; 18 | } 19 | const identifier = decorator.expression.expression; 20 | return imports.getImportOfIdentifier(typeChecker, identifier); 21 | } 22 | 23 | /** 24 | * Gets all decorators which are imported from an Angular package (e.g. "@angular/core") 25 | * from a list of decorators. 26 | */ 27 | function getAngularDecorators(typeChecker, decorators) { 28 | return decorators 29 | .map((node) => ({ node, importData: getCallDecoratorImport(typeChecker, node) })) 30 | .filter(({ importData }) => importData && importData.importModule.startsWith('@angular/')) 31 | .map(({ node, importData }) => ({ 32 | node: node, 33 | name: importData.name, 34 | moduleName: importData.importModule, 35 | importNode: importData.node, 36 | })); 37 | } 38 | 39 | exports.getAngularDecorators = getAngularDecorators; 40 | -------------------------------------------------------------------------------- /schematics/migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "schematics": { 3 | "control-flow-migration": { 4 | "version": "21.0.0", 5 | "description": "Converts the entire application to block control flow syntax", 6 | "factory": "./bundles/control-flow-migration.cjs#migrate" 7 | }, 8 | "router-current-navigation": { 9 | "version": "21.0.0", 10 | "description": "Replaces usages of the deprecated Router.getCurrentNavigation method with the Router.currentNavigation signal", 11 | "factory": "./bundles/router-current-navigation.cjs#migrate", 12 | "optional": true 13 | }, 14 | "router-last-successful-navigation": { 15 | "version": "21.0.0", 16 | "description": "Ensures that the Router.lastSuccessfulNavigation signal is now invoked", 17 | "factory": "./bundles/router-last-successful-navigation.cjs#migrate" 18 | }, 19 | "application-config-core": { 20 | "version": "21.0.0", 21 | "description": "Moves imports of `ApplicationConfig` from `@angular/platform-browser` to `@angular/core`", 22 | "factory": "./bundles/application-config-core.cjs#migrate" 23 | }, 24 | "add-bootstrap-context-to-server-main": { 25 | "version": "21.0.0", 26 | "description": "Adds `BootstrapContext` to `bootstrapApplication` calls in `main.server.ts` to support server rendering.", 27 | "factory": "./bundles/add-bootstrap-context-to-server-main.cjs#migrate" 28 | }, 29 | "bootstrap-options-migration": { 30 | "version": "21.0.0", 31 | "description": "Migrates deprecated bootstrap options to providers.", 32 | "factory": "./bundles/bootstrap-options-migration.cjs#migrate" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /schematics/ng-generate/inject-migration/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "AngularInjectMigration", 4 | "title": "Angular Inject Migration Schema", 5 | "type": "object", 6 | "properties": { 7 | "path": { 8 | "type": "string", 9 | "description": "Path relative to the project root which should be migrated", 10 | "x-prompt": "Which path in your project should be migrated?", 11 | "default": "./" 12 | }, 13 | "migrateAbstractClasses": { 14 | "type": "boolean", 15 | "description": "Whether abstract classes should be migrated", 16 | "x-prompt": "Do you want to migrate abstract classes? Abstract classes are not migrated by default, because their parameters aren't guaranteed to be injectable", 17 | "default": false 18 | }, 19 | "backwardsCompatibleConstructors": { 20 | "type": "boolean", 21 | "description": "Whether to clean up constructors or keep their signatures backwards compatible", 22 | "x-prompt": "Do you want to clean up all constructors or keep them backwards compatible? Enabling this option will include an additional signature of `constructor(...args: unknown[]);` that will avoid errors for sub-classes, but will increase the amount of generated code by the migration", 23 | "default": false 24 | }, 25 | "nonNullableOptional": { 26 | "type": "boolean", 27 | "description": "Whether to cast the optional inject sites to be non-nullable", 28 | "x-prompt": "Do you want optional inject calls to be non-nullable? Enable this option if you want the return type to be identical to @Optional(), at the expense of worse type safety", 29 | "default": false 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /types/_effect-chunk.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { ReactiveNode, ValueEqualityFn, SIGNAL, ReactiveHookFn } from './_formatter-chunk.js'; 8 | 9 | interface SignalNode extends ReactiveNode { 10 | value: T; 11 | equal: ValueEqualityFn; 12 | } 13 | type SignalBaseGetter = (() => T) & { 14 | readonly [SIGNAL]: unknown; 15 | }; 16 | type SignalSetter = (newValue: T) => void; 17 | type SignalUpdater = (updateFn: (value: T) => T) => void; 18 | interface SignalGetter extends SignalBaseGetter { 19 | readonly [SIGNAL]: SignalNode; 20 | } 21 | /** 22 | * Creates a `Signal` getter, setter, and updater function. 23 | */ 24 | declare function createSignal(initialValue: T, equal?: ValueEqualityFn): [SignalGetter, SignalSetter, SignalUpdater]; 25 | declare function setPostSignalSetFn(fn: ReactiveHookFn | null): ReactiveHookFn | null; 26 | declare function signalGetFn(node: SignalNode): T; 27 | declare function signalSetFn(node: SignalNode, newValue: T): void; 28 | declare function signalUpdateFn(node: SignalNode, updater: (value: T) => T): void; 29 | declare function runPostSignalSetFn(node: SignalNode): void; 30 | declare const SIGNAL_NODE: SignalNode; 31 | 32 | interface BaseEffectNode extends ReactiveNode { 33 | fn: () => void; 34 | destroy(): void; 35 | cleanup(): void; 36 | run(): void; 37 | } 38 | declare const BASE_EFFECT_NODE: Omit; 39 | declare function runEffect(node: BaseEffectNode): void; 40 | 41 | export { BASE_EFFECT_NODE, SIGNAL_NODE, createSignal, runEffect, runPostSignalSetFn, setPostSignalSetFn, signalGetFn, signalSetFn, signalUpdateFn }; 42 | export type { BaseEffectNode, SignalGetter, SignalNode }; 43 | -------------------------------------------------------------------------------- /schematics/bundles/signals.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var schematics = require('@angular-devkit/schematics'); 10 | var signalQueriesMigration = require('./signal-queries-migration.cjs'); 11 | var signalInputMigration = require('./signal-input-migration.cjs'); 12 | var outputMigration = require('./output-migration.cjs'); 13 | require('@angular/compiler-cli/private/migrations'); 14 | require('typescript'); 15 | require('@angular/compiler-cli'); 16 | require('node:path'); 17 | require('./project_paths-DvD50ouC.cjs'); 18 | require('@angular-devkit/core'); 19 | require('node:path/posix'); 20 | require('./project_tsconfig_paths-CDVxT6Ov.cjs'); 21 | require('./apply_import_manager-1Zs_gpB6.cjs'); 22 | require('./migrate_ts_type_references-UGIUl7En.cjs'); 23 | require('assert'); 24 | require('./index-B7I9sIUx.cjs'); 25 | require('@angular/compiler'); 26 | require('./leading_space-D9nQ8UQC.cjs'); 27 | 28 | function migrate(options) { 29 | // The migrations are independent so we can run them in any order, but we sort them here 30 | // alphabetically so we get a consistent execution order in case of issue reports. 31 | const migrations = options.migrations.slice().sort(); 32 | const rules = []; 33 | for (const migration of migrations) { 34 | switch (migration) { 35 | case "inputs" /* SupportedMigrations.inputs */: 36 | rules.push(signalInputMigration.migrate(options)); 37 | break; 38 | case "outputs" /* SupportedMigrations.outputs */: 39 | rules.push(outputMigration.migrate(options)); 40 | break; 41 | case "queries" /* SupportedMigrations.queries */: 42 | rules.push(signalQueriesMigration.migrate(options)); 43 | break; 44 | default: 45 | throw new schematics.SchematicsException(`Unsupported migration "${migration}"`); 46 | } 47 | } 48 | return schematics.chain(rules); 49 | } 50 | 51 | exports.migrate = migrate; 52 | -------------------------------------------------------------------------------- /schematics/ng-generate/signals/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "$id": "AngularSignalMigration", 4 | "title": "Angular Signals migration", 5 | "type": "object", 6 | "properties": { 7 | "migrations": { 8 | "type": "array", 9 | "default": [ 10 | "inputs", 11 | "outputs", 12 | "queries" 13 | ], 14 | "items": { 15 | "type": "string", 16 | "enum": [ 17 | "inputs", 18 | "outputs", 19 | "queries" 20 | ] 21 | }, 22 | "description": "Signals-related migrations that should be run", 23 | "x-prompt": { 24 | "message": "Which migrations do you want to run?", 25 | "type": "list", 26 | "multiselect": true, 27 | "items": [ 28 | { 29 | "value": "inputs", 30 | "label": "Convert `@Input` to the signal-based `input`" 31 | }, 32 | { 33 | "value": "outputs", 34 | "label": "Convert `@Output` to the new `output` function" 35 | }, 36 | { 37 | "value": "queries", 38 | "label": "Convert `@ViewChild`/`@ViewChildren` and `@ContentChild`/`@ContentChildren` to the signal-based `viewChild`/`viewChildren` and `contentChild`/`contentChildren`" 39 | } 40 | ] 41 | } 42 | }, 43 | "path": { 44 | "type": "string", 45 | "description": "Path to the directory that should be migrated.", 46 | "x-prompt": "Which directory do you want to migrate?", 47 | "default": "./" 48 | }, 49 | "analysisDir": { 50 | "type": "string", 51 | "description": "Path to the directory that should be analyzed. Useful for larger projects if the analysis takes too long and the analysis scope can be narrowed.", 52 | "default": "./" 53 | }, 54 | "bestEffortMode": { 55 | "type": "boolean", 56 | "description": "Whether to eagerly migrate as much as possible, ignoring problematic patterns that would otherwise prevent migration.", 57 | "x-prompt": "Do you want to migrate as much as possible, even if it may break your build?", 58 | "default": false 59 | }, 60 | "insertTodos": { 61 | "type": "boolean", 62 | "description": "Whether the migration should add TODOs for code that could not be migrated", 63 | "default": false 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /resources/best-practices.md: -------------------------------------------------------------------------------- 1 | You are an expert in TypeScript, Angular, and scalable web application development. You write functional, maintainable, performant, and accessible code following Angular and TypeScript best practices. 2 | 3 | ## TypeScript Best Practices 4 | 5 | - Use strict type checking 6 | - Prefer type inference when the type is obvious 7 | - Avoid the `any` type; use `unknown` when type is uncertain 8 | 9 | ## Angular Best Practices 10 | 11 | - Always use standalone components over NgModules 12 | - Must NOT set `standalone: true` inside Angular decorators. It's the default in Angular v20+. 13 | - Use signals for state management 14 | - Implement lazy loading for feature routes 15 | - Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead 16 | - Use `NgOptimizedImage` for all static images. 17 | - `NgOptimizedImage` does not work for inline base64 images. 18 | 19 | ## Accessibility Requirements 20 | 21 | - It MUST pass all AXE checks. 22 | - It MUST follow all WCAG AA minimums, including focus management, color contrast, and ARIA attributes. 23 | 24 | ### Components 25 | 26 | - Keep components small and focused on a single responsibility 27 | - Use `input()` and `output()` functions instead of decorators 28 | - Use `computed()` for derived state 29 | - Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator 30 | - Prefer inline templates for small components 31 | - Prefer Reactive forms instead of Template-driven ones 32 | - Do NOT use `ngClass`, use `class` bindings instead 33 | - Do NOT use `ngStyle`, use `style` bindings instead 34 | - When using external templates/styles, use paths relative to the component TS file. 35 | 36 | ## State Management 37 | 38 | - Use signals for local component state 39 | - Use `computed()` for derived state 40 | - Keep state transformations pure and predictable 41 | - Do NOT use `mutate` on signals, use `update` or `set` instead 42 | 43 | ## Templates 44 | 45 | - Keep templates simple and avoid complex logic 46 | - Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch` 47 | - Use the async pipe to handle observables 48 | - Do not assume globals like (`new Date()`) are available. 49 | - Do not write arrow functions in templates (they are not supported). 50 | 51 | ## Services 52 | 53 | - Design services around a single responsibility 54 | - Use the `providedIn: 'root'` option for singleton services 55 | - Use the `inject()` function instead of constructor injection 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@angular/core", 3 | "version": "21.1.0-next.3+sha-9fa77af", 4 | "description": "Angular - the core framework", 5 | "author": "angular", 6 | "license": "MIT", 7 | "engines": { 8 | "node": "^20.19.0 || ^22.12.0 || >=24.0.0" 9 | }, 10 | "exports": { 11 | "./schematics/*": { 12 | "default": "./schematics/*.js" 13 | }, 14 | "./event-dispatch-contract.min.js": { 15 | "default": "./event-dispatch-contract.min.js" 16 | }, 17 | "./package.json": { 18 | "default": "./package.json" 19 | }, 20 | ".": { 21 | "types": "./types/core.d.ts", 22 | "default": "./fesm2022/core.mjs" 23 | }, 24 | "./primitives/di": { 25 | "types": "./types/primitives-di.d.ts", 26 | "default": "./fesm2022/primitives-di.mjs" 27 | }, 28 | "./primitives/event-dispatch": { 29 | "types": "./types/primitives-event-dispatch.d.ts", 30 | "default": "./fesm2022/primitives-event-dispatch.mjs" 31 | }, 32 | "./primitives/signals": { 33 | "types": "./types/primitives-signals.d.ts", 34 | "default": "./fesm2022/primitives-signals.mjs" 35 | }, 36 | "./rxjs-interop": { 37 | "types": "./types/rxjs-interop.d.ts", 38 | "default": "./fesm2022/rxjs-interop.mjs" 39 | }, 40 | "./testing": { 41 | "types": "./types/testing.d.ts", 42 | "default": "./fesm2022/testing.mjs" 43 | } 44 | }, 45 | "dependencies": { 46 | "tslib": "^2.3.0" 47 | }, 48 | "peerDependencies": { 49 | "@angular/compiler": "21.1.0-next.3+sha-9fa77af", 50 | "rxjs": "^6.5.3 || ^7.4.0", 51 | "zone.js": "~0.15.0 || ~0.16.0" 52 | }, 53 | "peerDependenciesMeta": { 54 | "@angular/compiler": { 55 | "optional": true 56 | }, 57 | "zone.js": { 58 | "optional": true 59 | } 60 | }, 61 | "repository": { 62 | "type": "git", 63 | "url": "https://github.com/angular/angular.git", 64 | "directory": "packages/core" 65 | }, 66 | "ng-update": { 67 | "migrations": "./schematics/migrations.json", 68 | "packageGroup": [ 69 | "@angular/core", 70 | "@angular/bazel", 71 | "@angular/common", 72 | "@angular/compiler", 73 | "@angular/compiler-cli", 74 | "@angular/animations", 75 | "@angular/elements", 76 | "@angular/platform-browser", 77 | "@angular/platform-browser-dynamic", 78 | "@angular/forms", 79 | "@angular/platform-server", 80 | "@angular/upgrade", 81 | "@angular/router", 82 | "@angular/language-service", 83 | "@angular/localize", 84 | "@angular/service-worker" 85 | ] 86 | }, 87 | "angular": { 88 | "bestPractices": { 89 | "format": "markdown", 90 | "path": "./resources/best-practices.md" 91 | } 92 | }, 93 | "schematics": "./schematics/collection.json", 94 | "sideEffects": false, 95 | "module": "./fesm2022/core.mjs", 96 | "typings": "./types/core.d.ts", 97 | "type": "module" 98 | } -------------------------------------------------------------------------------- /fesm2022/_linked_signal-chunk.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { SIGNAL, runPostProducerCreatedFn, producerUpdateValueVersion, signalSetFn, producerMarkClean, signalUpdateFn, REACTIVE_NODE, UNSET, defaultEquals, COMPUTING, consumerBeforeComputation, ERRORED, consumerAfterComputation, producerAccessed } from './_effect-chunk.mjs'; 8 | 9 | function createLinkedSignal(sourceFn, computationFn, equalityFn) { 10 | const node = Object.create(LINKED_SIGNAL_NODE); 11 | node.source = sourceFn; 12 | node.computation = computationFn; 13 | if (equalityFn != undefined) { 14 | node.equal = equalityFn; 15 | } 16 | const linkedSignalGetter = () => { 17 | producerUpdateValueVersion(node); 18 | producerAccessed(node); 19 | if (node.value === ERRORED) { 20 | throw node.error; 21 | } 22 | return node.value; 23 | }; 24 | const getter = linkedSignalGetter; 25 | getter[SIGNAL] = node; 26 | if (typeof ngDevMode !== 'undefined' && ngDevMode) { 27 | const debugName = node.debugName ? ' (' + node.debugName + ')' : ''; 28 | getter.toString = () => `[LinkedSignal${debugName}: ${node.value}]`; 29 | } 30 | runPostProducerCreatedFn(node); 31 | return getter; 32 | } 33 | function linkedSignalSetFn(node, newValue) { 34 | producerUpdateValueVersion(node); 35 | signalSetFn(node, newValue); 36 | producerMarkClean(node); 37 | } 38 | function linkedSignalUpdateFn(node, updater) { 39 | producerUpdateValueVersion(node); 40 | signalUpdateFn(node, updater); 41 | producerMarkClean(node); 42 | } 43 | const LINKED_SIGNAL_NODE = /* @__PURE__ */(() => { 44 | return { 45 | ...REACTIVE_NODE, 46 | value: UNSET, 47 | dirty: true, 48 | error: null, 49 | equal: defaultEquals, 50 | kind: 'linkedSignal', 51 | producerMustRecompute(node) { 52 | return node.value === UNSET || node.value === COMPUTING; 53 | }, 54 | producerRecomputeValue(node) { 55 | if (node.value === COMPUTING) { 56 | throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Detected cycle in computations.' : ''); 57 | } 58 | const oldValue = node.value; 59 | node.value = COMPUTING; 60 | const prevConsumer = consumerBeforeComputation(node); 61 | let newValue; 62 | try { 63 | const newSourceValue = node.source(); 64 | const prev = oldValue === UNSET || oldValue === ERRORED ? undefined : { 65 | source: node.sourceValue, 66 | value: oldValue 67 | }; 68 | newValue = node.computation(newSourceValue, prev); 69 | node.sourceValue = newSourceValue; 70 | } catch (err) { 71 | newValue = ERRORED; 72 | node.error = err; 73 | } finally { 74 | consumerAfterComputation(node, prevConsumer); 75 | } 76 | if (oldValue !== UNSET && newValue !== ERRORED && node.equal(oldValue, newValue)) { 77 | node.value = oldValue; 78 | return; 79 | } 80 | node.value = newValue; 81 | node.version++; 82 | } 83 | }; 84 | })(); 85 | 86 | export { createLinkedSignal, linkedSignalSetFn, linkedSignalUpdateFn }; 87 | //# sourceMappingURL=_linked_signal-chunk.mjs.map 88 | -------------------------------------------------------------------------------- /types/primitives-event-dispatch.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { EarlyJsactionDataContainer, EventInfo, Restriction } from './_event_dispatcher-chunk.js'; 8 | export { EventContract, EventContractContainer, EventDispatcher, EventInfoWrapper, EventPhase, registerDispatcher } from './_event_dispatcher-chunk.js'; 9 | 10 | declare const Attribute: { 11 | /** 12 | * The jsaction attribute defines a mapping of a DOM event to a 13 | * generic event (aka jsaction), to which the actual event handlers 14 | * that implement the behavior of the application are bound. The 15 | * value is a semicolon separated list of colon separated pairs of 16 | * an optional DOM event name and a jsaction name. If the optional 17 | * DOM event name is omitted, 'click' is assumed. The jsaction names 18 | * are dot separated pairs of a namespace and a simple jsaction 19 | * name. 20 | * 21 | * See grammar in README.md for expected syntax in the attribute value. 22 | */ 23 | JSACTION: "jsaction"; 24 | }; 25 | 26 | /** 27 | * Reads the jsaction parser cache for the given DOM element. If no cache is yet present, 28 | * creates an empty one. 29 | */ 30 | declare function getDefaulted(element: Element): { 31 | [key: string]: string | undefined; 32 | }; 33 | 34 | /** 35 | * Whether or not an event type should be registered in the capture phase. 36 | * @param eventType 37 | * @returns bool 38 | */ 39 | declare const isCaptureEventType: (eventType: string) => boolean; 40 | /** 41 | * Whether or not an event type is registered in the early contract. 42 | */ 43 | declare const isEarlyEventType: (eventType: string) => boolean; 44 | 45 | /** 46 | * Creates an `EarlyJsactionData`, adds events to it, and populates it on a nested object on 47 | * the window. 48 | */ 49 | declare function bootstrapAppScopedEarlyEventContract(container: HTMLElement, appId: string, bubbleEventTypes: string[], captureEventTypes: string[], dataContainer?: EarlyJsactionDataContainer): void; 50 | /** Get the queued `EventInfo` objects that were dispatched before a dispatcher was registered. */ 51 | declare function getAppScopedQueuedEventInfos(appId: string, dataContainer?: EarlyJsactionDataContainer): EventInfo[]; 52 | /** 53 | * Registers a dispatcher function on the `EarlyJsactionData` present on the nested object on the 54 | * window. 55 | */ 56 | declare function registerAppScopedDispatcher(restriction: Restriction, appId: string, dispatcher: (eventInfo: EventInfo) => void, dataContainer?: EarlyJsactionDataContainer): void; 57 | /** Removes all event listener handlers. */ 58 | declare function removeAllAppScopedEventListeners(appId: string, dataContainer?: EarlyJsactionDataContainer): void; 59 | /** Clear the early event contract. */ 60 | declare function clearAppScopedEarlyEventContract(appId: string, dataContainer?: EarlyJsactionDataContainer): void; 61 | 62 | export { Attribute, EarlyJsactionDataContainer, bootstrapAppScopedEarlyEventContract, clearAppScopedEarlyEventContract, getDefaulted as getActionCache, getAppScopedQueuedEventInfos, isCaptureEventType, isEarlyEventType, registerAppScopedDispatcher, removeAllAppScopedEventListeners }; 63 | -------------------------------------------------------------------------------- /schematics/bundles/apply_import_manager-1Zs_gpB6.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | var compilerCli = require('@angular/compiler-cli'); 11 | var project_paths = require('./project_paths-DvD50ouC.cjs'); 12 | 13 | /** 14 | * Applies import manager changes, and writes them as replacements the 15 | * given result array. 16 | */ 17 | function applyImportManagerChanges(importManager, replacements, sourceFiles, info) { 18 | const { newImports, updatedImports, deletedImports } = importManager.finalize(); 19 | const printer = ts.createPrinter({}); 20 | const pathToFile = new Map(sourceFiles.map((s) => [s.fileName, s])); 21 | // Capture new imports 22 | newImports.forEach((newImports, fileName) => { 23 | newImports.forEach((newImport) => { 24 | const printedImport = printer.printNode(ts.EmitHint.Unspecified, newImport, pathToFile.get(fileName)); 25 | replacements.push(new project_paths.Replacement(project_paths.projectFile(compilerCli.absoluteFrom(fileName), info), new project_paths.TextUpdate({ position: 0, end: 0, toInsert: `${printedImport}\n` }))); 26 | }); 27 | }); 28 | // Capture updated imports 29 | for (const [oldBindings, newBindings] of updatedImports.entries()) { 30 | // The import will be generated as multi-line if it already is multi-line, 31 | // or if the number of elements significantly increased and it previously 32 | // consisted of very few specifiers. 33 | const isMultiline = oldBindings.getText().includes('\n') || 34 | (newBindings.elements.length >= 6 && oldBindings.elements.length <= 3); 35 | const hasSpaceBetweenBraces = oldBindings.getText().startsWith('{ '); 36 | let formatFlags = ts.ListFormat.NamedImportsOrExportsElements | 37 | ts.ListFormat.Indented | 38 | ts.ListFormat.Braces | 39 | ts.ListFormat.PreserveLines | 40 | (isMultiline ? ts.ListFormat.MultiLine : ts.ListFormat.SingleLine); 41 | if (hasSpaceBetweenBraces) { 42 | formatFlags |= ts.ListFormat.SpaceBetweenBraces; 43 | } 44 | else { 45 | formatFlags &= ~ts.ListFormat.SpaceBetweenBraces; 46 | } 47 | const printedBindings = printer.printList(formatFlags, newBindings.elements, oldBindings.getSourceFile()); 48 | replacements.push(new project_paths.Replacement(project_paths.projectFile(oldBindings.getSourceFile(), info), new project_paths.TextUpdate({ 49 | position: oldBindings.getStart(), 50 | end: oldBindings.getEnd(), 51 | // TS uses four spaces as indent. We migrate to two spaces as we 52 | // assume this to be more common. 53 | toInsert: printedBindings.replace(/^ {4}/gm, ' '), 54 | }))); 55 | } 56 | // Update removed imports 57 | for (const removedImport of deletedImports) { 58 | replacements.push(new project_paths.Replacement(project_paths.projectFile(removedImport.getSourceFile(), info), new project_paths.TextUpdate({ 59 | position: removedImport.getStart(), 60 | end: removedImport.getEnd(), 61 | toInsert: '', 62 | }))); 63 | } 64 | } 65 | 66 | exports.applyImportManagerChanges = applyImportManagerChanges; 67 | -------------------------------------------------------------------------------- /schematics/bundles/project_tsconfig_paths-CDVxT6Ov.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var core = require('@angular-devkit/core'); 10 | 11 | /** 12 | * Gets all tsconfig paths from a CLI project by reading the workspace configuration 13 | * and looking for common tsconfig locations. 14 | */ 15 | async function getProjectTsConfigPaths(tree) { 16 | // Start with some tsconfig paths that are generally used within CLI projects. Note 17 | // that we are not interested in IDE-specific tsconfig files (e.g. /tsconfig.json) 18 | const buildPaths = new Set(); 19 | const testPaths = new Set(); 20 | const workspace = await getWorkspace(tree); 21 | for (const [, project] of workspace.projects) { 22 | for (const [name, target] of project.targets) { 23 | if (name !== 'build' && name !== 'test') { 24 | continue; 25 | } 26 | for (const [, options] of allTargetOptions(target)) { 27 | const tsConfig = options['tsConfig']; 28 | // Filter out tsconfig files that don't exist in the CLI project. 29 | if (typeof tsConfig !== 'string' || !tree.exists(tsConfig)) { 30 | continue; 31 | } 32 | if (name === 'build') { 33 | buildPaths.add(core.normalize(tsConfig)); 34 | } 35 | else { 36 | testPaths.add(core.normalize(tsConfig)); 37 | } 38 | } 39 | } 40 | } 41 | return { 42 | buildPaths: [...buildPaths], 43 | testPaths: [...testPaths], 44 | }; 45 | } 46 | /** Get options for all configurations for the passed builder target. */ 47 | function* allTargetOptions(target) { 48 | if (target.options) { 49 | yield [undefined, target.options]; 50 | } 51 | if (!target.configurations) { 52 | return; 53 | } 54 | for (const [name, options] of Object.entries(target.configurations)) { 55 | if (options) { 56 | yield [name, options]; 57 | } 58 | } 59 | } 60 | function createHost(tree) { 61 | return { 62 | async readFile(path) { 63 | const data = tree.read(path); 64 | if (!data) { 65 | throw new Error('File not found.'); 66 | } 67 | return core.virtualFs.fileBufferToString(data); 68 | }, 69 | async writeFile(path, data) { 70 | return tree.overwrite(path, data); 71 | }, 72 | async isDirectory(path) { 73 | // Approximate a directory check. 74 | // We don't need to consider empty directories and hence this is a good enough approach. 75 | // This is also per documentation, see: 76 | // https://angular.dev/tools/cli/schematics-for-libraries#get-the-project-configuration 77 | return !tree.exists(path) && tree.getDir(path).subfiles.length > 0; 78 | }, 79 | async isFile(path) { 80 | return tree.exists(path); 81 | }, 82 | }; 83 | } 84 | async function getWorkspace(tree) { 85 | const host = createHost(tree); 86 | const { workspace } = await core.workspaces.readWorkspace('/', host); 87 | return workspace; 88 | } 89 | 90 | exports.getProjectTsConfigPaths = getProjectTsConfigPaths; 91 | -------------------------------------------------------------------------------- /fesm2022/primitives-di.mjs.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"primitives-di.mjs","sources":["../../../../../k8-fastbuild-ST-fdfa778d11ba/bin/packages/core/primitives/di/src/injection_token.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Type} from './type';\n/**\n * Information about how a type or `InjectionToken` interfaces with the DI\n * system. This describes:\n *\n * 1. *How* the type is provided\n * The declaration must specify only one of the following:\n * - A `value` which is a predefined instance of the type.\n * - A `factory` which defines how to create the given type `T`, possibly\n * requesting injection of other types if necessary.\n * - Neither, in which case the type is expected to already be present in the\n * injector hierarchy. This is used for internal use cases.\n *\n * 2. *Where* the type is stored (if it is stored)\n * - The `providedIn` parameter specifies which injector the type belongs to.\n * - The `token` is used as the key to store the type in the injector.\n */\nexport interface ɵɵInjectableDeclaration {\n /**\n * Specifies that the given type belongs to a particular `Injector`,\n * `NgModule`, or a special scope (e.g. `'root'`).\n *\n * `any` is deprecated and will be removed soon.\n *\n * A value of `null` indicates that the injectable does not belong to any\n * scope, and won't be stored in any injector. For declarations with a\n * factory, this will create a new instance of the type each time it is\n * requested.\n */\n providedIn: Type | 'root' | 'platform' | 'any' | null;\n\n /**\n * The token to which this definition belongs.\n *\n * Note that this may not be the same as the type that the `factory` will create.\n */\n token: unknown;\n\n /**\n * Factory method to execute to create an instance of the injectable.\n */\n factory?: (t?: Type) => T;\n\n /**\n * In a case of no explicit injector, a location where the instance of the injectable is stored.\n */\n value?: T;\n}\n\n/**\n * A `Type` which has a `ɵprov: ɵɵInjectableDeclaration` static field.\n *\n * `InjectableType`s contain their own Dependency Injection metadata and are usable in an\n * `InjectorDef`-based `StaticInjector`.\n *\n * @publicApi\n */\nexport interface InjectionToken {\n ɵprov: ɵɵInjectableDeclaration;\n}\n\nexport function defineInjectable(opts: {\n token: unknown;\n providedIn?: Type | 'root' | 'platform' | 'any' | 'environment' | null;\n factory: () => T;\n}): ɵɵInjectableDeclaration {\n return {\n token: opts.token,\n providedIn: (opts.providedIn as any) || null,\n factory: opts.factory,\n value: undefined,\n } as ɵɵInjectableDeclaration;\n}\n\nexport type Constructor = Function & {prototype: T};\n\nexport function registerInjectable(\n ctor: unknown,\n declaration: ɵɵInjectableDeclaration,\n): InjectionToken {\n (ctor as unknown as InjectionToken).ɵprov = declaration;\n return ctor as Constructor & InjectionToken;\n}\n"],"names":["defineInjectable","opts","token","providedIn","factory","value","undefined","registerInjectable","ctor","declaration","ɵprov"],"mappings":";;;;;;;;AAqEM,SAAUA,gBAAgBA,CAAIC,IAInC,EAAA;EACC,OAAO;IACLC,KAAK,EAAED,IAAI,CAACC,KAAK;AACjBC,IAAAA,UAAU,EAAGF,IAAI,CAACE,UAAkB,IAAI,IAAI;IAC5CC,OAAO,EAAEH,IAAI,CAACG,OAAO;AACrBC,IAAAA,KAAK,EAAEC;GACsB;AACjC;AAIgB,SAAAC,kBAAkBA,CAChCC,IAAa,EACbC,WAAuC,EAAA;EAEtCD,IAAqC,CAACE,KAAK,GAAGD,WAAW;AAC1D,EAAA,OAAOD,IAA0C;AACnD;;;;"} -------------------------------------------------------------------------------- /schematics/bundles/application-config-core.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var migrations = require('@angular/compiler-cli/private/migrations'); 10 | var apply_import_manager = require('./apply_import_manager-1Zs_gpB6.cjs'); 11 | require('@angular/compiler-cli'); 12 | require('typescript'); 13 | require('node:path'); 14 | var project_paths = require('./project_paths-DvD50ouC.cjs'); 15 | var imports = require('./imports-DP72APSx.cjs'); 16 | require('@angular-devkit/core'); 17 | require('node:path/posix'); 18 | require('@angular-devkit/schematics'); 19 | require('./project_tsconfig_paths-CDVxT6Ov.cjs'); 20 | 21 | /** Migration that moves the import of `ApplicationConfig` from `platform-browser` to `core`. */ 22 | class ApplicationConfigCoreMigration extends project_paths.TsurgeFunnelMigration { 23 | async analyze(info) { 24 | const replacements = []; 25 | let importManager = null; 26 | for (const sourceFile of info.sourceFiles) { 27 | const specifier = imports.getImportSpecifier(sourceFile, '@angular/platform-browser', 'ApplicationConfig'); 28 | if (!specifier) { 29 | continue; 30 | } 31 | importManager ??= new migrations.ImportManager({ 32 | // Prevent the manager from trying to generate a non-conflicting import. 33 | generateUniqueIdentifier: () => null, 34 | shouldUseSingleQuotes: () => true, 35 | }); 36 | importManager.removeImport(sourceFile, 'ApplicationConfig', '@angular/platform-browser'); 37 | importManager.addImport({ 38 | exportSymbolName: 'ApplicationConfig', 39 | exportModuleSpecifier: '@angular/core', 40 | requestedFile: sourceFile, 41 | unsafeAliasOverride: specifier.propertyName ? specifier.name.text : undefined, 42 | }); 43 | } 44 | if (importManager !== null) { 45 | apply_import_manager.applyImportManagerChanges(importManager, replacements, info.sourceFiles, info); 46 | } 47 | return project_paths.confirmAsSerializable({ replacements }); 48 | } 49 | async migrate(globalData) { 50 | return project_paths.confirmAsSerializable(globalData); 51 | } 52 | async combine(unitA, unitB) { 53 | const seen = new Set(); 54 | const combined = []; 55 | [unitA.replacements, unitB.replacements].forEach((replacements) => { 56 | replacements.forEach((current) => { 57 | const { position, end, toInsert } = current.update.data; 58 | const key = current.projectFile.id + '/' + position + '/' + end + '/' + toInsert; 59 | if (!seen.has(key)) { 60 | seen.add(key); 61 | combined.push(current); 62 | } 63 | }); 64 | }); 65 | return project_paths.confirmAsSerializable({ replacements: combined }); 66 | } 67 | async globalMeta(combinedData) { 68 | return project_paths.confirmAsSerializable(combinedData); 69 | } 70 | async stats() { 71 | return project_paths.confirmAsSerializable({}); 72 | } 73 | } 74 | 75 | function migrate() { 76 | return async (tree) => { 77 | await project_paths.runMigrationInDevkit({ 78 | tree, 79 | getMigration: () => new ApplicationConfigCoreMigration(), 80 | }); 81 | }; 82 | } 83 | 84 | exports.migrate = migrate; 85 | -------------------------------------------------------------------------------- /fesm2022/_not_found-chunk.mjs.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"_not_found-chunk.mjs","sources":["../../../../../k8-fastbuild-ST-fdfa778d11ba/bin/packages/core/primitives/di/src/injector.ts","../../../../../k8-fastbuild-ST-fdfa778d11ba/bin/packages/core/primitives/di/src/not_found.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Constructor, InjectionToken} from './injection_token';\nimport {NotFound} from './not_found';\n\nexport interface Injector {\n retrieve(token: InjectionToken, options?: unknown): T | NotFound;\n}\n\n/**\n * Current injector value used by `inject`.\n * - `undefined`: it is an error to call `inject`\n * - `null`: `inject` can be called but there is no injector (limp-mode).\n * - Injector instance: Use the injector for resolution.\n */\nlet _currentInjector: Injector | undefined | null = undefined;\n\nexport function getCurrentInjector(): Injector | undefined | null {\n return _currentInjector;\n}\n\nexport function setCurrentInjector(\n injector: Injector | null | undefined,\n): Injector | undefined | null {\n const former = _currentInjector;\n _currentInjector = injector;\n return former;\n}\n\nexport function inject(token: InjectionToken | Constructor): T;\nexport function inject(\n token: InjectionToken | Constructor,\n options?: unknown,\n): T | NotFound {\n const currentInjector = getCurrentInjector();\n if (!currentInjector) {\n throw new Error('Current injector is not set.');\n }\n if (!(token as InjectionToken).ɵprov) {\n throw new Error('Token is not an injectable');\n }\n return currentInjector.retrieve(token as InjectionToken, options);\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n/**\n * Value returned if the key-value pair couldn't be found in the context\n * hierarchy.\n */\nexport const NOT_FOUND: unique symbol = Symbol('NotFound');\n\n/**\n * Error thrown when the key-value pair couldn't be found in the context\n * hierarchy. Context can be attached below.\n */\nexport class NotFoundError extends Error {\n override readonly name: string = 'ɵNotFound';\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * Type guard for checking if an unknown value is a NotFound.\n */\nexport function isNotFound(e: unknown): e is NotFound {\n return e === NOT_FOUND || (e as NotFoundError)?.name === 'ɵNotFound';\n}\n\n/**\n * Type union of NotFound and NotFoundError.\n */\nexport type NotFound = typeof NOT_FOUND | NotFoundError;\n"],"names":["_currentInjector","undefined","getCurrentInjector","setCurrentInjector","injector","former","inject","token","options","currentInjector","Error","ɵprov","retrieve","NOT_FOUND","Symbol","NotFoundError","name","constructor","message","isNotFound","e"],"mappings":";;;;;;AAqBA,IAAIA,gBAAgB,GAAgCC,SAAS;SAE7CC,kBAAkBA,GAAA;AAChC,EAAA,OAAOF,gBAAgB;AACzB;AAEM,SAAUG,kBAAkBA,CAChCC,QAAqC,EAAA;EAErC,MAAMC,MAAM,GAAGL,gBAAgB;AAC/BA,EAAAA,gBAAgB,GAAGI,QAAQ;AAC3B,EAAA,OAAOC,MAAM;AACf;AAGgB,SAAAC,MAAMA,CACpBC,KAAyC,EACzCC,OAAiB,EAAA;AAEjB,EAAA,MAAMC,eAAe,GAAGP,kBAAkB,EAAE;EAC5C,IAAI,CAACO,eAAe,EAAE;AACpB,IAAA,MAAM,IAAIC,KAAK,CAAC,8BAA8B,CAAC;AACjD;AACA,EAAA,IAAI,CAAEH,KAA2B,CAACI,KAAK,EAAE;AACvC,IAAA,MAAM,IAAID,KAAK,CAAC,4BAA4B,CAAC;AAC/C;AACA,EAAA,OAAOD,eAAe,CAACG,QAAQ,CAACL,KAA0B,EAAEC,OAAO,CAAC;AACtE;;MCpCaK,SAAS,GAAkBC,MAAM,CAAC,UAAU;AAMnD,MAAOC,aAAc,SAAQL,KAAK,CAAA;AACpBM,EAAAA,IAAI,GAAW,WAAW;EAC5CC,WAAAA,CAAYC,OAAe,EAAA;IACzB,KAAK,CAACA,OAAO,CAAC;AAChB;AACD;AAKK,SAAUC,UAAUA,CAACC,CAAU,EAAA;EACnC,OAAOA,CAAC,KAAKP,SAAS,IAAKO,CAAmB,EAAEJ,IAAI,KAAK,WAAW;AACtE;;;;"} -------------------------------------------------------------------------------- /schematics/bundles/router-current-navigation.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | require('@angular/compiler-cli'); 11 | require('@angular/compiler-cli/private/migrations'); 12 | require('node:path'); 13 | var project_paths = require('./project_paths-DvD50ouC.cjs'); 14 | var imports = require('./imports-DP72APSx.cjs'); 15 | var symbol = require('./symbol-BObKoqes.cjs'); 16 | require('@angular-devkit/core'); 17 | require('node:path/posix'); 18 | require('@angular-devkit/schematics'); 19 | require('./project_tsconfig_paths-CDVxT6Ov.cjs'); 20 | 21 | /** Name of the method being replaced. */ 22 | const METHOD_NAME = 'getCurrentNavigation'; 23 | /** Migration that replaces `Router.getCurrentNavigation` usages with `Router.currentNavigation()`. */ 24 | class RouterCurrentNavigationMigration extends project_paths.TsurgeFunnelMigration { 25 | async analyze(info) { 26 | const locations = []; 27 | for (const sourceFile of info.sourceFiles) { 28 | const routerSpecifier = imports.getImportSpecifier(sourceFile, '@angular/router', 'Router'); 29 | if (routerSpecifier === null) { 30 | continue; 31 | } 32 | const typeChecker = info.program.getTypeChecker(); 33 | sourceFile.forEachChild(function walk(node) { 34 | if (ts.isPropertyAccessExpression(node) && 35 | node.name.text === METHOD_NAME && 36 | isRouterType(typeChecker, node.expression, routerSpecifier)) { 37 | locations.push({ file: project_paths.projectFile(sourceFile, info), position: node.name.getStart() }); 38 | } 39 | else { 40 | node.forEachChild(walk); 41 | } 42 | }); 43 | } 44 | return project_paths.confirmAsSerializable({ locations }); 45 | } 46 | async migrate(globalData) { 47 | const replacements = globalData.locations.map(({ file, position }) => { 48 | return new project_paths.Replacement(file, new project_paths.TextUpdate({ 49 | position: position, 50 | end: position + METHOD_NAME.length, 51 | toInsert: 'currentNavigation', 52 | })); 53 | }); 54 | return project_paths.confirmAsSerializable({ replacements }); 55 | } 56 | async combine(unitA, unitB) { 57 | const seen = new Set(); 58 | const locations = []; 59 | const combined = [...unitA.locations, ...unitB.locations]; 60 | for (const location of combined) { 61 | const key = `${location.file.id}#${location.position}`; 62 | if (!seen.has(key)) { 63 | seen.add(key); 64 | locations.push(location); 65 | } 66 | } 67 | return project_paths.confirmAsSerializable({ locations }); 68 | } 69 | async globalMeta(combinedData) { 70 | return project_paths.confirmAsSerializable(combinedData); 71 | } 72 | async stats() { 73 | return project_paths.confirmAsSerializable({}); 74 | } 75 | } 76 | /** 77 | * Checks if the given symbol represents a Router type. 78 | */ 79 | function isRouterType(typeChecker, expression, routerSpecifier) { 80 | const expressionType = typeChecker.getTypeAtLocation(expression); 81 | const expressionSymbol = expressionType.getSymbol(); 82 | if (!expressionSymbol) { 83 | return false; 84 | } 85 | const declarations = expressionSymbol.getDeclarations() ?? []; 86 | for (const declaration of declarations) { 87 | if (symbol.isReferenceToImport(typeChecker, declaration, routerSpecifier)) { 88 | return true; 89 | } 90 | } 91 | return declarations.some((decl) => decl === routerSpecifier); 92 | } 93 | 94 | function migrate() { 95 | return async (tree) => { 96 | await project_paths.runMigrationInDevkit({ 97 | tree, 98 | getMigration: () => new RouterCurrentNavigationMigration(), 99 | }); 100 | }; 101 | } 102 | 103 | exports.migrate = migrate; 104 | -------------------------------------------------------------------------------- /schematics/bundles/router-last-successful-navigation.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | require('@angular/compiler-cli'); 11 | require('@angular/compiler-cli/private/migrations'); 12 | require('node:path'); 13 | var project_paths = require('./project_paths-DvD50ouC.cjs'); 14 | var imports = require('./imports-DP72APSx.cjs'); 15 | var symbol = require('./symbol-BObKoqes.cjs'); 16 | require('@angular-devkit/core'); 17 | require('node:path/posix'); 18 | require('@angular-devkit/schematics'); 19 | require('./project_tsconfig_paths-CDVxT6Ov.cjs'); 20 | 21 | /** Name of the method being replaced. */ 22 | const METHOD_NAME = 'lastSuccessfulNavigation'; 23 | /** Migration that replaces `Router.lastSuccessfulNavigation` usages with `Router.lastSuccessfulNavigation()`. */ 24 | class RouterLastSuccessfulNavigationMigration extends project_paths.TsurgeFunnelMigration { 25 | async analyze(info) { 26 | const locations = []; 27 | for (const sourceFile of info.sourceFiles) { 28 | const routerSpecifier = imports.getImportSpecifier(sourceFile, '@angular/router', 'Router'); 29 | if (routerSpecifier === null) { 30 | continue; 31 | } 32 | const typeChecker = info.program.getTypeChecker(); 33 | sourceFile.forEachChild(function walk(node) { 34 | if (ts.isPropertyAccessExpression(node) && 35 | node.name.text === METHOD_NAME && 36 | isRouterType(typeChecker, node.expression, routerSpecifier)) { 37 | locations.push({ file: project_paths.projectFile(sourceFile, info), position: node.name.getStart() }); 38 | } 39 | else { 40 | node.forEachChild(walk); 41 | } 42 | }); 43 | } 44 | return project_paths.confirmAsSerializable({ locations }); 45 | } 46 | async migrate(globalData) { 47 | const replacements = globalData.locations.map(({ file, position }) => { 48 | return new project_paths.Replacement(file, new project_paths.TextUpdate({ 49 | position: position, 50 | end: position + METHOD_NAME.length, 51 | toInsert: 'lastSuccessfulNavigation()', 52 | })); 53 | }); 54 | return project_paths.confirmAsSerializable({ replacements }); 55 | } 56 | async combine(unitA, unitB) { 57 | const seen = new Set(); 58 | const locations = []; 59 | const combined = [...unitA.locations, ...unitB.locations]; 60 | for (const location of combined) { 61 | const key = `${location.file.id}#${location.position}`; 62 | if (!seen.has(key)) { 63 | seen.add(key); 64 | locations.push(location); 65 | } 66 | } 67 | return project_paths.confirmAsSerializable({ locations }); 68 | } 69 | async globalMeta(combinedData) { 70 | return project_paths.confirmAsSerializable(combinedData); 71 | } 72 | async stats() { 73 | return project_paths.confirmAsSerializable({}); 74 | } 75 | } 76 | /** 77 | * Checks if the given symbol represents a Router type. 78 | */ 79 | function isRouterType(typeChecker, expression, routerSpecifier) { 80 | const expressionType = typeChecker.getTypeAtLocation(expression); 81 | const expressionSymbol = expressionType.getSymbol(); 82 | if (!expressionSymbol) { 83 | return false; 84 | } 85 | const declarations = expressionSymbol.getDeclarations() ?? []; 86 | for (const declaration of declarations) { 87 | if (symbol.isReferenceToImport(typeChecker, declaration, routerSpecifier)) { 88 | return true; 89 | } 90 | } 91 | return declarations.some((decl) => decl === routerSpecifier); 92 | } 93 | 94 | function migrate() { 95 | return async (tree) => { 96 | await project_paths.runMigrationInDevkit({ 97 | tree, 98 | getMigration: () => new RouterLastSuccessfulNavigationMigration(), 99 | }); 100 | }; 101 | } 102 | 103 | exports.migrate = migrate; 104 | -------------------------------------------------------------------------------- /schematics/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "schematics": { 3 | "standalone-migration": { 4 | "description": "Converts the entire application or a part of it to standalone", 5 | "factory": "./bundles/standalone-migration.cjs#migrate", 6 | "schema": "./ng-generate/standalone-migration/schema.json", 7 | "aliases": ["standalone"] 8 | }, 9 | "inject-migration": { 10 | "description": "Converts usages of constructor-based injection to the inject() function", 11 | "factory": "./bundles/inject-migration.cjs#migrate", 12 | "schema": "./ng-generate/inject-migration/schema.json", 13 | "aliases": ["inject"] 14 | }, 15 | "route-lazy-loading-migration": { 16 | "description": "Updates route definitions to use lazy-loading of components instead of eagerly referencing them", 17 | "factory": "./bundles/route-lazy-loading.cjs#migrate", 18 | "schema": "./ng-generate/route-lazy-loading/schema.json", 19 | "aliases": ["route-lazy-loading"] 20 | }, 21 | "signal-input-migration": { 22 | "description": "Updates `@Input` declarations to signal inputs, while also migrating all relevant references.", 23 | "factory": "./bundles/signal-input-migration.cjs#migrate", 24 | "schema": "./ng-generate/signal-input-migration/schema.json", 25 | "aliases": ["signal-inputs", "signal-input"] 26 | }, 27 | "signal-queries-migration": { 28 | "description": "Updates query declarations to signal queries, while also migrating all relevant references.", 29 | "factory": "./bundles/signal-queries-migration.cjs#migrate", 30 | "schema": "./ng-generate/signal-queries-migration/schema.json", 31 | "aliases": ["signal-queries", "signal-query", "signal-query-migration"] 32 | }, 33 | "output-migration": { 34 | "description": "Updates @output declarations to the functional equivalent, while also migrating all relevant references.", 35 | "factory": "./bundles/output-migration.cjs#migrate", 36 | "schema": "./ng-generate/output-migration/schema.json", 37 | "aliases": ["outputs"] 38 | }, 39 | "signals": { 40 | "description": "Combines all signals-related migrations into a single migration", 41 | "factory": "./bundles/signals.cjs#migrate", 42 | "schema": "./ng-generate/signals/schema.json" 43 | }, 44 | "cleanup-unused-imports": { 45 | "description": "Removes unused imports from standalone components.", 46 | "factory": "./bundles/cleanup-unused-imports.cjs#migrate", 47 | "schema": "./ng-generate/cleanup-unused-imports/schema.json" 48 | }, 49 | "self-closing-tags-migration": { 50 | "description": "Updates the components templates to use self-closing tags where possible", 51 | "factory": "./bundles/self-closing-tags-migration.cjs#migrate", 52 | "schema": "./ng-generate/self-closing-tags-migration/schema.json", 53 | "aliases": ["self-closing-tag"] 54 | }, 55 | "common-to-standalone-migration": { 56 | "description": "Replaces CommonModule with individual imports from @angular/common", 57 | "factory": "./bundles/common-to-standalone-migration.cjs#migrate", 58 | "schema": "./migrations/common-to-standalone-migration/schema.json", 59 | "aliases": ["common-to-standalone"] 60 | }, 61 | "control-flow-migration": { 62 | "description": "Converts the entire application to block control flow syntax", 63 | "factory": "./bundles/control-flow-migration.cjs#migrate", 64 | "schema": "./migrations/control-flow-migration/schema.json", 65 | "aliases": ["control-flow"] 66 | }, 67 | "ngclass-to-class-migration": { 68 | "description": "Updates usages of `ngClass` directives to the `class` bindings where possible", 69 | "factory": "./bundles/ngclass-to-class-migration.cjs#migrate", 70 | "schema": "./migrations/ngclass-to-class-migration/schema.json", 71 | "aliases": ["ngclass-to-class"] 72 | }, 73 | "ngstyle-to-style-migration": { 74 | "description": "Updates usages of `ngStyle` directives to the `style` bindings where possible", 75 | "factory": "./bundles/ngstyle-to-style-migration.cjs#migrate", 76 | "schema": "./migrations/ngstyle-to-style-migration/schema.json", 77 | "aliases": ["ngstyle-to-style"] 78 | }, 79 | "router-testing-module-migration": { 80 | "description": "Replaces deprecated RouterTestingModule with provideRouter() as recommended in the deprecation note", 81 | "factory": "./bundles/router-testing-module-migration.cjs#migrate", 82 | "schema": "./migrations/router-testing-module-migration/schema.json" 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /types/primitives-di.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | /** 8 | * @description 9 | * 10 | * Represents a type that a Component or other object is instances of. 11 | * 12 | * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is represented by 13 | * the `MyCustomComponent` constructor function. 14 | * 15 | * @publicApi 16 | */ 17 | declare const Type: FunctionConstructor; 18 | interface Type extends Function { 19 | new (...args: any[]): T; 20 | } 21 | 22 | /** 23 | * Information about how a type or `InjectionToken` interfaces with the DI 24 | * system. This describes: 25 | * 26 | * 1. *How* the type is provided 27 | * The declaration must specify only one of the following: 28 | * - A `value` which is a predefined instance of the type. 29 | * - A `factory` which defines how to create the given type `T`, possibly 30 | * requesting injection of other types if necessary. 31 | * - Neither, in which case the type is expected to already be present in the 32 | * injector hierarchy. This is used for internal use cases. 33 | * 34 | * 2. *Where* the type is stored (if it is stored) 35 | * - The `providedIn` parameter specifies which injector the type belongs to. 36 | * - The `token` is used as the key to store the type in the injector. 37 | */ 38 | interface ɵɵInjectableDeclaration { 39 | /** 40 | * Specifies that the given type belongs to a particular `Injector`, 41 | * `NgModule`, or a special scope (e.g. `'root'`). 42 | * 43 | * `any` is deprecated and will be removed soon. 44 | * 45 | * A value of `null` indicates that the injectable does not belong to any 46 | * scope, and won't be stored in any injector. For declarations with a 47 | * factory, this will create a new instance of the type each time it is 48 | * requested. 49 | */ 50 | providedIn: Type | 'root' | 'platform' | 'any' | null; 51 | /** 52 | * The token to which this definition belongs. 53 | * 54 | * Note that this may not be the same as the type that the `factory` will create. 55 | */ 56 | token: unknown; 57 | /** 58 | * Factory method to execute to create an instance of the injectable. 59 | */ 60 | factory?: (t?: Type) => T; 61 | /** 62 | * In a case of no explicit injector, a location where the instance of the injectable is stored. 63 | */ 64 | value?: T; 65 | } 66 | /** 67 | * A `Type` which has a `ɵprov: ɵɵInjectableDeclaration` static field. 68 | * 69 | * `InjectableType`s contain their own Dependency Injection metadata and are usable in an 70 | * `InjectorDef`-based `StaticInjector`. 71 | * 72 | * @publicApi 73 | */ 74 | interface InjectionToken { 75 | ɵprov: ɵɵInjectableDeclaration; 76 | } 77 | declare function defineInjectable(opts: { 78 | token: unknown; 79 | providedIn?: Type | 'root' | 'platform' | 'any' | 'environment' | null; 80 | factory: () => T; 81 | }): ɵɵInjectableDeclaration; 82 | type Constructor = Function & { 83 | prototype: T; 84 | }; 85 | declare function registerInjectable(ctor: unknown, declaration: ɵɵInjectableDeclaration): InjectionToken; 86 | 87 | /** 88 | * Value returned if the key-value pair couldn't be found in the context 89 | * hierarchy. 90 | */ 91 | declare const NOT_FOUND: unique symbol; 92 | /** 93 | * Error thrown when the key-value pair couldn't be found in the context 94 | * hierarchy. Context can be attached below. 95 | */ 96 | declare class NotFoundError extends Error { 97 | readonly name: string; 98 | constructor(message: string); 99 | } 100 | /** 101 | * Type guard for checking if an unknown value is a NotFound. 102 | */ 103 | declare function isNotFound(e: unknown): e is NotFound; 104 | /** 105 | * Type union of NotFound and NotFoundError. 106 | */ 107 | type NotFound = typeof NOT_FOUND | NotFoundError; 108 | 109 | interface Injector { 110 | retrieve(token: InjectionToken, options?: unknown): T | NotFound; 111 | } 112 | declare function getCurrentInjector(): Injector | undefined | null; 113 | declare function setCurrentInjector(injector: Injector | null | undefined): Injector | undefined | null; 114 | declare function inject(token: InjectionToken | Constructor): T; 115 | 116 | export { NOT_FOUND, NotFoundError, defineInjectable, getCurrentInjector, inject, isNotFound, registerInjectable, setCurrentInjector }; 117 | export type { InjectionToken, Injector, NotFound, ɵɵInjectableDeclaration }; 118 | -------------------------------------------------------------------------------- /schematics/bundles/imports-DP72APSx.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | 11 | /** Gets import information about the specified identifier by using the Type checker. */ 12 | function getImportOfIdentifier(typeChecker, node) { 13 | const symbol = typeChecker.getSymbolAtLocation(node); 14 | if (!symbol || symbol.declarations === undefined || !symbol.declarations.length) { 15 | return null; 16 | } 17 | const decl = symbol.declarations[0]; 18 | if (!ts.isImportSpecifier(decl)) { 19 | return null; 20 | } 21 | const importDecl = decl.parent.parent.parent; 22 | if (!ts.isImportDeclaration(importDecl) || !ts.isStringLiteral(importDecl.moduleSpecifier)) { 23 | return null; 24 | } 25 | return { 26 | // Handles aliased imports: e.g. "import {Component as myComp} from ..."; 27 | name: decl.propertyName ? decl.propertyName.text : decl.name.text, 28 | importModule: importDecl.moduleSpecifier.text, 29 | node: importDecl, 30 | }; 31 | } 32 | /** 33 | * Gets a top-level import specifier with a specific name that is imported from a particular module. 34 | * E.g. given a file that looks like: 35 | * 36 | * ```ts 37 | * import { Component, Directive } from '@angular/core'; 38 | * import { Foo } from './foo'; 39 | * ``` 40 | * 41 | * Calling `getImportSpecifier(sourceFile, '@angular/core', 'Directive')` will yield the node 42 | * referring to `Directive` in the top import. 43 | * 44 | * @param sourceFile File in which to look for imports. 45 | * @param moduleName Name of the import's module. 46 | * @param specifierName Original name of the specifier to look for. Aliases will be resolved to 47 | * their original name. 48 | */ 49 | function getImportSpecifier(sourceFile, moduleName, specifierName) { 50 | return getImportSpecifiers(sourceFile, moduleName, specifierName)[0] ?? null; 51 | } 52 | /** 53 | * Note: returns only matching imports specifiers, 54 | * Unmatched imports will be ignored (you won't get undefined), but a shorter array. 55 | */ 56 | function getImportSpecifiers(sourceFile, moduleName, specifierOrSpecifiers) { 57 | const matches = []; 58 | for (const node of sourceFile.statements) { 59 | if (!ts.isImportDeclaration(node) || !ts.isStringLiteral(node.moduleSpecifier)) { 60 | continue; 61 | } 62 | const namedBindings = node.importClause?.namedBindings; 63 | const isMatch = typeof moduleName === 'string' 64 | ? node.moduleSpecifier.text === moduleName 65 | : moduleName.test(node.moduleSpecifier.text); 66 | if (!isMatch || !namedBindings || !ts.isNamedImports(namedBindings)) { 67 | continue; 68 | } 69 | if (typeof specifierOrSpecifiers === 'string') { 70 | const match = findImportSpecifier(namedBindings.elements, specifierOrSpecifiers); 71 | if (match) { 72 | matches.push(match); 73 | } 74 | } 75 | else { 76 | for (const specifierName of specifierOrSpecifiers) { 77 | const match = findImportSpecifier(namedBindings.elements, specifierName); 78 | if (match) { 79 | matches.push(match); 80 | } 81 | } 82 | } 83 | } 84 | return matches; 85 | } 86 | function getNamedImports(sourceFile, moduleName) { 87 | for (const node of sourceFile.statements) { 88 | if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) { 89 | const isMatch = node.moduleSpecifier.text === moduleName 90 | ; 91 | const namedBindings = node.importClause?.namedBindings; 92 | if (isMatch && namedBindings && ts.isNamedImports(namedBindings)) { 93 | return namedBindings; 94 | } 95 | } 96 | } 97 | return null; 98 | } 99 | /** Finds an import specifier with a particular name. */ 100 | function findImportSpecifier(nodes, specifierName) { 101 | return nodes.find((element) => { 102 | const { name, propertyName } = element; 103 | return propertyName ? propertyName.text === specifierName : name.text === specifierName; 104 | }); 105 | } 106 | 107 | exports.getImportOfIdentifier = getImportOfIdentifier; 108 | exports.getImportSpecifier = getImportSpecifier; 109 | exports.getImportSpecifiers = getImportSpecifiers; 110 | exports.getNamedImports = getNamedImports; 111 | -------------------------------------------------------------------------------- /schematics/bundles/parse_html-8VLCL37B.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var compiler = require('@angular/compiler'); 10 | 11 | /** 12 | * parses the template string into the Html AST 13 | */ 14 | function parseTemplate(template) { 15 | let parsed; 16 | try { 17 | // Note: we use the HtmlParser here, instead of the `parseTemplate` function, because the 18 | // latter returns an Ivy AST, not an HTML AST. The HTML AST has the advantage of preserving 19 | // interpolated text as text nodes containing a mixture of interpolation tokens and text tokens, 20 | // rather than turning them into `BoundText` nodes like the Ivy AST does. This allows us to 21 | // easily get the text-only ranges without having to reconstruct the original text. 22 | parsed = new compiler.HtmlParser().parse(template, '', { 23 | // Allows for ICUs to be parsed. 24 | tokenizeExpansionForms: true, 25 | // Explicitly disable blocks so that their characters are treated as plain text. 26 | tokenizeBlocks: true, 27 | preserveLineEndings: true, 28 | }); 29 | // Don't migrate invalid templates. 30 | if (parsed.errors && parsed.errors.length > 0) { 31 | const errors = parsed.errors.map((e) => ({ type: 'parse', error: e })); 32 | return { tree: undefined, errors }; 33 | } 34 | } 35 | catch (e) { 36 | return { tree: undefined, errors: [{ type: 'parse', error: e }] }; 37 | } 38 | return { tree: parsed, errors: [] }; 39 | } 40 | function pipeMatchRegExpFor(name) { 41 | return new RegExp(`\\|\\s*${name}`); 42 | } 43 | const commonModulePipes = [ 44 | 'date', 45 | 'async', 46 | 'currency', 47 | 'number', 48 | 'i18nPlural', 49 | 'i18nSelect', 50 | 'json', 51 | 'keyvalue', 52 | 'slice', 53 | 'lowercase', 54 | 'uppercase', 55 | 'titlecase', 56 | 'percent', 57 | ].map((name) => pipeMatchRegExpFor(name)); 58 | function allFormsOf(selector) { 59 | return [selector, `*${selector}`, `[${selector}]`]; 60 | } 61 | const commonModuleDirectives = new Set([ 62 | ...allFormsOf('ngComponentOutlet'), 63 | ...allFormsOf('ngTemplateOutlet'), 64 | ...allFormsOf('ngClass'), 65 | ...allFormsOf('ngPlural'), 66 | ...allFormsOf('ngPluralCase'), 67 | ...allFormsOf('ngStyle'), 68 | ...allFormsOf('ngTemplateOutlet'), 69 | ...allFormsOf('ngComponentOutlet'), 70 | '[NgForOf]', 71 | '[NgForTrackBy]', 72 | '[ngIfElse]', 73 | '[ngIfThenElse]', 74 | '*ngIf', 75 | '*ngSwitch', 76 | '*ngFor', 77 | ]); 78 | /** 79 | * determines if the CommonModule can be safely removed from imports 80 | */ 81 | function canRemoveCommonModule(template) { 82 | const parsed = parseTemplate(template); 83 | let removeCommonModule = false; 84 | if (parsed.tree !== undefined) { 85 | const visitor = new CommonCollector(); 86 | compiler.visitAll(visitor, parsed.tree.rootNodes); 87 | removeCommonModule = visitor.count === 0; 88 | } 89 | return removeCommonModule; 90 | } 91 | /** Finds all non-control flow elements from common module. */ 92 | class CommonCollector extends compiler.RecursiveVisitor { 93 | count = 0; 94 | visitElement(el) { 95 | if (el.attrs.length > 0) { 96 | for (const attr of el.attrs) { 97 | if (this.hasDirectives(attr.name) || this.hasPipes(attr.value)) { 98 | this.count++; 99 | } 100 | } 101 | } 102 | super.visitElement(el, null); 103 | } 104 | visitBlock(ast) { 105 | for (const blockParam of ast.parameters) { 106 | if (this.hasPipes(blockParam.expression)) { 107 | this.count++; 108 | } 109 | } 110 | super.visitBlock(ast, null); 111 | } 112 | visitText(ast) { 113 | if (this.hasPipes(ast.value)) { 114 | this.count++; 115 | } 116 | } 117 | visitLetDeclaration(decl) { 118 | if (this.hasPipes(decl.value)) { 119 | this.count++; 120 | } 121 | super.visitLetDeclaration(decl, null); 122 | } 123 | hasDirectives(input) { 124 | return commonModuleDirectives.has(input); 125 | } 126 | hasPipes(input) { 127 | return commonModulePipes.some((regexp) => regexp.test(input)); 128 | } 129 | } 130 | 131 | exports.canRemoveCommonModule = canRemoveCommonModule; 132 | exports.parseTemplate = parseTemplate; 133 | -------------------------------------------------------------------------------- /schematics/bundles/add-bootstrap-context-to-server-main.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | require('@angular-devkit/core'); 10 | require('node:path/posix'); 11 | var project_paths = require('./project_paths-DvD50ouC.cjs'); 12 | var migrations = require('@angular/compiler-cli/private/migrations'); 13 | var ts = require('typescript'); 14 | var apply_import_manager = require('./apply_import_manager-1Zs_gpB6.cjs'); 15 | require('@angular/compiler-cli'); 16 | require('node:path'); 17 | require('@angular-devkit/schematics'); 18 | require('./project_tsconfig_paths-CDVxT6Ov.cjs'); 19 | 20 | function findArrowFunction(node) { 21 | let current = node; 22 | while (current) { 23 | if (ts.isArrowFunction(current)) { 24 | return current; 25 | } 26 | current = current.parent; 27 | } 28 | return undefined; 29 | } 30 | class AddBootstrapContextToServerMainMigration extends project_paths.TsurgeFunnelMigration { 31 | async analyze(info) { 32 | const replacements = []; 33 | let importManager = null; 34 | for (const sourceFile of info.sourceFiles) { 35 | if (!sourceFile.fileName.endsWith('main.server.ts')) { 36 | continue; 37 | } 38 | const bootstrapAppCalls = []; 39 | ts.forEachChild(sourceFile, function findCalls(node) { 40 | if (ts.isCallExpression(node) && 41 | ts.isIdentifier(node.expression) && 42 | node.expression.text === 'bootstrapApplication' && 43 | node.arguments.length < 3) { 44 | bootstrapAppCalls.push(node); 45 | } 46 | ts.forEachChild(node, findCalls); 47 | }); 48 | if (bootstrapAppCalls.length === 0) { 49 | continue; 50 | } 51 | for (const node of bootstrapAppCalls) { 52 | const end = node.arguments[node.arguments.length - 1].getEnd(); 53 | replacements.push(new project_paths.Replacement(project_paths.projectFile(sourceFile, info), new project_paths.TextUpdate({ 54 | position: end, 55 | end: end, 56 | toInsert: ', context', 57 | }))); 58 | const arrowFunction = findArrowFunction(node); 59 | if (arrowFunction && arrowFunction.parameters.length === 0) { 60 | replacements.push(new project_paths.Replacement(project_paths.projectFile(sourceFile, info), new project_paths.TextUpdate({ 61 | position: arrowFunction.parameters.end, 62 | end: arrowFunction.parameters.end, 63 | toInsert: 'context: BootstrapContext', 64 | }))); 65 | } 66 | } 67 | importManager ??= new migrations.ImportManager({ 68 | generateUniqueIdentifier: () => null, 69 | shouldUseSingleQuotes: () => true, 70 | }); 71 | importManager.addImport({ 72 | exportSymbolName: 'BootstrapContext', 73 | exportModuleSpecifier: '@angular/platform-browser', 74 | requestedFile: sourceFile, 75 | }); 76 | } 77 | if (importManager !== null) { 78 | apply_import_manager.applyImportManagerChanges(importManager, replacements, info.sourceFiles, info); 79 | } 80 | return project_paths.confirmAsSerializable({ replacements }); 81 | } 82 | async migrate(globalData) { 83 | return project_paths.confirmAsSerializable(globalData); 84 | } 85 | async combine(unitA, unitB) { 86 | const seen = new Set(); 87 | const combined = []; 88 | [unitA.replacements, unitB.replacements].forEach((replacements) => { 89 | replacements.forEach((current) => { 90 | const { position, end, toInsert } = current.update.data; 91 | const key = current.projectFile.id + '/' + position + '/' + end + '/' + toInsert; 92 | if (!seen.has(key)) { 93 | seen.add(key); 94 | combined.push(current); 95 | } 96 | }); 97 | }); 98 | return project_paths.confirmAsSerializable({ replacements: combined }); 99 | } 100 | async globalMeta(combinedData) { 101 | return project_paths.confirmAsSerializable(combinedData); 102 | } 103 | async stats() { 104 | return project_paths.confirmAsSerializable({}); 105 | } 106 | } 107 | 108 | function migrate() { 109 | return async (tree) => { 110 | await project_paths.runMigrationInDevkit({ 111 | tree, 112 | getMigration: () => new AddBootstrapContextToServerMainMigration(), 113 | }); 114 | }; 115 | } 116 | 117 | exports.migrate = migrate; 118 | -------------------------------------------------------------------------------- /types/primitives-signals.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { ReactiveNode, ValueEqualityFn, SIGNAL } from './_formatter-chunk.js'; 8 | export { REACTIVE_NODE, Reactive, ReactiveHookFn, ReactiveNodeKind, Version, consumerAfterComputation, consumerBeforeComputation, consumerDestroy, consumerMarkDirty, consumerPollProducersForChange, defaultEquals, finalizeConsumerAfterComputation, getActiveConsumer, installDevToolsSignalFormatter, isInNotificationPhase, isReactive, producerAccessed, producerIncrementEpoch, producerMarkClean, producerNotifyConsumers, producerUpdateValueVersion, producerUpdatesAllowed, resetConsumerBeforeComputation, runPostProducerCreatedFn, setActiveConsumer, setPostProducerCreatedFn } from './_formatter-chunk.js'; 9 | import { SignalNode } from './_effect-chunk.js'; 10 | export { BASE_EFFECT_NODE, BaseEffectNode, SIGNAL_NODE, SignalGetter, createSignal, runEffect, runPostSignalSetFn, setPostSignalSetFn, signalGetFn, signalSetFn, signalUpdateFn } from './_effect-chunk.js'; 11 | export { setAlternateWeakRefImpl } from './_weak_ref-chunk.js'; 12 | 13 | /** 14 | * A computation, which derives a value from a declarative reactive expression. 15 | * 16 | * `Computed`s are both producers and consumers of reactivity. 17 | */ 18 | interface ComputedNode extends ReactiveNode { 19 | /** 20 | * Current value of the computation, or one of the sentinel values above (`UNSET`, `COMPUTING`, 21 | * `ERROR`). 22 | */ 23 | value: T; 24 | /** 25 | * If `value` is `ERRORED`, the error caught from the last computation attempt which will 26 | * be re-thrown. 27 | */ 28 | error: unknown; 29 | /** 30 | * The computation function which will produce a new value. 31 | */ 32 | computation: () => T; 33 | equal: ValueEqualityFn; 34 | } 35 | type ComputedGetter = (() => T) & { 36 | [SIGNAL]: ComputedNode; 37 | }; 38 | /** 39 | * Create a computed signal which derives a reactive value from an expression. 40 | */ 41 | declare function createComputed(computation: () => T, equal?: ValueEqualityFn): ComputedGetter; 42 | 43 | type ComputationFn = (source: S, previous?: PreviousValue) => D; 44 | type PreviousValue = { 45 | source: S; 46 | value: D; 47 | }; 48 | interface LinkedSignalNode extends ReactiveNode { 49 | /** 50 | * Value of the source signal that was used to derive the computed value. 51 | */ 52 | sourceValue: S; 53 | /** 54 | * Current state value, or one of the sentinel values (`UNSET`, `COMPUTING`, 55 | * `ERROR`). 56 | */ 57 | value: D; 58 | /** 59 | * If `value` is `ERRORED`, the error caught from the last computation attempt which will 60 | * be re-thrown. 61 | */ 62 | error: unknown; 63 | /** 64 | * The source function represents reactive dependency based on which the linked state is reset. 65 | */ 66 | source: () => S; 67 | /** 68 | * The computation function which will produce a new value based on the source and, optionally - previous values. 69 | */ 70 | computation: ComputationFn; 71 | equal: ValueEqualityFn; 72 | } 73 | type LinkedSignalGetter = (() => D) & { 74 | [SIGNAL]: LinkedSignalNode; 75 | }; 76 | declare function createLinkedSignal(sourceFn: () => S, computationFn: ComputationFn, equalityFn?: ValueEqualityFn): LinkedSignalGetter; 77 | declare function linkedSignalSetFn(node: LinkedSignalNode, newValue: D): void; 78 | declare function linkedSignalUpdateFn(node: LinkedSignalNode, updater: (value: D) => D): void; 79 | 80 | declare function setThrowInvalidWriteToSignalError(fn: (node: SignalNode) => never): void; 81 | 82 | /** 83 | * A cleanup function that can be optionally registered from the watch logic. If registered, the 84 | * cleanup logic runs before the next watch execution. 85 | */ 86 | type WatchCleanupFn = () => void; 87 | /** 88 | * A callback passed to the watch function that makes it possible to register cleanup logic. 89 | */ 90 | type WatchCleanupRegisterFn = (cleanupFn: WatchCleanupFn) => void; 91 | interface Watch { 92 | notify(): void; 93 | /** 94 | * Execute the reactive expression in the context of this `Watch` consumer. 95 | * 96 | * Should be called by the user scheduling algorithm when the provided 97 | * `schedule` hook is called by `Watch`. 98 | */ 99 | run(): void; 100 | cleanup(): void; 101 | /** 102 | * Destroy the watcher: 103 | * - disconnect it from the reactive graph; 104 | * - mark it as destroyed so subsequent run and notify operations are noop. 105 | */ 106 | destroy(): void; 107 | [SIGNAL]: WatchNode; 108 | } 109 | interface WatchNode extends ReactiveNode { 110 | fn: ((onCleanup: WatchCleanupRegisterFn) => void) | null; 111 | schedule: ((watch: Watch) => void) | null; 112 | cleanupFn: WatchCleanupFn; 113 | ref: Watch; 114 | } 115 | declare function createWatch(fn: (onCleanup: WatchCleanupRegisterFn) => void, schedule: (watch: Watch) => void, allowSignalWrites: boolean): Watch; 116 | 117 | /** 118 | * Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function 119 | * can, optionally, return a value. 120 | */ 121 | declare function untracked(nonReactiveReadsFn: () => T): T; 122 | 123 | export { ReactiveNode, SIGNAL, SignalNode, ValueEqualityFn, createComputed, createLinkedSignal, createWatch, linkedSignalSetFn, linkedSignalUpdateFn, setThrowInvalidWriteToSignalError, untracked }; 124 | export type { ComputationFn, ComputedNode, LinkedSignalGetter, LinkedSignalNode, PreviousValue, Watch, WatchCleanupFn, WatchCleanupRegisterFn }; 125 | -------------------------------------------------------------------------------- /fesm2022/primitives-signals.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { SIGNAL, consumerMarkDirty, REACTIVE_NODE, consumerDestroy, isInNotificationPhase, consumerPollProducersForChange, consumerBeforeComputation, consumerAfterComputation } from './_effect-chunk.mjs'; 8 | export { BASE_EFFECT_NODE, SIGNAL_NODE, createComputed, createSignal, defaultEquals, finalizeConsumerAfterComputation, getActiveConsumer, isReactive, producerAccessed, producerIncrementEpoch, producerMarkClean, producerNotifyConsumers, producerUpdateValueVersion, producerUpdatesAllowed, resetConsumerBeforeComputation, runEffect, runPostProducerCreatedFn, runPostSignalSetFn, setActiveConsumer, setPostProducerCreatedFn, setPostSignalSetFn, setThrowInvalidWriteToSignalError, signalGetFn, signalSetFn, signalUpdateFn, untracked } from './_effect-chunk.mjs'; 9 | export { createLinkedSignal, linkedSignalSetFn, linkedSignalUpdateFn } from './_linked_signal-chunk.mjs'; 10 | export { setAlternateWeakRefImpl } from './_weak_ref-chunk.mjs'; 11 | 12 | const formatter = { 13 | header: (sig, config) => { 14 | if (!isSignal(sig) || config?.ngSkipFormatting) return null; 15 | let value; 16 | try { 17 | value = sig(); 18 | } catch (e) { 19 | return ['span', `Signal(⚠️ Error)${e.message ? `: ${e.message}` : ''}`]; 20 | } 21 | const kind = 'computation' in sig[SIGNAL] ? 'Computed' : 'Signal'; 22 | const isPrimitive = value === null || !Array.isArray(value) && typeof value !== 'object'; 23 | return ['span', {}, ['span', {}, `${kind}(`], (() => { 24 | if (isSignal(value)) { 25 | return formatter.header(value, config); 26 | } else if (isPrimitive && value !== undefined && typeof value !== 'function') { 27 | return ['object', { 28 | object: value 29 | }]; 30 | } else { 31 | return prettifyPreview(value); 32 | } 33 | })(), ['span', {}, `)`]]; 34 | }, 35 | hasBody: (sig, config) => { 36 | if (!isSignal(sig)) return false; 37 | try { 38 | sig(); 39 | } catch { 40 | return false; 41 | } 42 | return !config?.ngSkipFormatting; 43 | }, 44 | body: (sig, config) => { 45 | const color = 'var(--sys-color-primary)'; 46 | return ['div', { 47 | style: `background: #FFFFFF10; padding-left: 4px; padding-top: 2px; padding-bottom: 2px;` 48 | }, ['div', { 49 | style: `color: ${color}` 50 | }, 'Signal value: '], ['div', { 51 | style: `padding-left: .5rem;` 52 | }, ['object', { 53 | object: sig(), 54 | config 55 | }]], ['div', { 56 | style: `color: ${color}` 57 | }, 'Signal function: '], ['div', { 58 | style: `padding-left: .5rem;` 59 | }, ['object', { 60 | object: sig, 61 | config: { 62 | ...config, 63 | ngSkipFormatting: true 64 | } 65 | }]]]; 66 | } 67 | }; 68 | function prettifyPreview(value) { 69 | if (value === null) return 'null'; 70 | if (Array.isArray(value)) return `Array(${value.length})`; 71 | if (value instanceof Element) return `<${value.tagName.toLowerCase()}>`; 72 | if (value instanceof URL) return `URL`; 73 | switch (typeof value) { 74 | case 'undefined': 75 | { 76 | return 'undefined'; 77 | } 78 | case 'function': 79 | { 80 | if ('prototype' in value) { 81 | return 'class'; 82 | } else { 83 | return '() => {…}'; 84 | } 85 | } 86 | case 'object': 87 | { 88 | if (value.constructor.name === 'Object') { 89 | return '{…}'; 90 | } else { 91 | return `${value.constructor.name} {}`; 92 | } 93 | } 94 | default: 95 | { 96 | return ['object', { 97 | object: value, 98 | config: { 99 | ngSkipFormatting: true 100 | } 101 | }]; 102 | } 103 | } 104 | } 105 | function isSignal(value) { 106 | return value[SIGNAL] !== undefined; 107 | } 108 | function installDevToolsSignalFormatter() { 109 | globalThis.devtoolsFormatters ??= []; 110 | if (!globalThis.devtoolsFormatters.some(f => f === formatter)) { 111 | globalThis.devtoolsFormatters.push(formatter); 112 | } 113 | } 114 | 115 | function createWatch(fn, schedule, allowSignalWrites) { 116 | const node = Object.create(WATCH_NODE); 117 | if (allowSignalWrites) { 118 | node.consumerAllowSignalWrites = true; 119 | } 120 | node.fn = fn; 121 | node.schedule = schedule; 122 | const registerOnCleanup = cleanupFn => { 123 | node.cleanupFn = cleanupFn; 124 | }; 125 | function isWatchNodeDestroyed(node) { 126 | return node.fn === null && node.schedule === null; 127 | } 128 | function destroyWatchNode(node) { 129 | if (!isWatchNodeDestroyed(node)) { 130 | consumerDestroy(node); 131 | node.cleanupFn(); 132 | node.fn = null; 133 | node.schedule = null; 134 | node.cleanupFn = NOOP_CLEANUP_FN; 135 | } 136 | } 137 | const run = () => { 138 | if (node.fn === null) { 139 | return; 140 | } 141 | if (isInNotificationPhase()) { 142 | throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Schedulers cannot synchronously execute watches while scheduling.' : ''); 143 | } 144 | node.dirty = false; 145 | if (node.version > 0 && !consumerPollProducersForChange(node)) { 146 | return; 147 | } 148 | node.version++; 149 | const prevConsumer = consumerBeforeComputation(node); 150 | try { 151 | node.cleanupFn(); 152 | node.cleanupFn = NOOP_CLEANUP_FN; 153 | node.fn(registerOnCleanup); 154 | } finally { 155 | consumerAfterComputation(node, prevConsumer); 156 | } 157 | }; 158 | node.ref = { 159 | notify: () => consumerMarkDirty(node), 160 | run, 161 | cleanup: () => node.cleanupFn(), 162 | destroy: () => destroyWatchNode(node), 163 | [SIGNAL]: node 164 | }; 165 | return node.ref; 166 | } 167 | const NOOP_CLEANUP_FN = () => {}; 168 | const WATCH_NODE = /* @__PURE__ */(() => { 169 | return { 170 | ...REACTIVE_NODE, 171 | consumerIsAlwaysLive: true, 172 | consumerAllowSignalWrites: false, 173 | consumerMarkedDirty: node => { 174 | if (node.schedule !== null) { 175 | node.schedule(node.ref); 176 | } 177 | }, 178 | cleanupFn: NOOP_CLEANUP_FN 179 | }; 180 | })(); 181 | 182 | if (typeof ngDevMode === 'undefined' || ngDevMode) { 183 | installDevToolsSignalFormatter(); 184 | } 185 | 186 | export { REACTIVE_NODE, SIGNAL, consumerAfterComputation, consumerBeforeComputation, consumerDestroy, consumerMarkDirty, consumerPollProducersForChange, createWatch, installDevToolsSignalFormatter, isInNotificationPhase }; 187 | //# sourceMappingURL=primitives-signals.mjs.map 188 | -------------------------------------------------------------------------------- /schematics/bundles/ng_component_template-Dsuq1Lw7.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | var compilerCli = require('@angular/compiler-cli'); 11 | var ng_decorators = require('./ng_decorators-DSFlWYQY.cjs'); 12 | var property_name = require('./property_name-BBwFuqMe.cjs'); 13 | 14 | /** 15 | * Unwraps a given expression TypeScript node. Expressions can be wrapped within multiple 16 | * parentheses or as expression. e.g. "(((({exp}))))()". The function should return the 17 | * TypeScript node referring to the inner expression. e.g "exp". 18 | */ 19 | function unwrapExpression(node) { 20 | if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node)) { 21 | return unwrapExpression(node.expression); 22 | } 23 | else { 24 | return node; 25 | } 26 | } 27 | 28 | /** Extracts `@Directive` or `@Component` metadata from the given class. */ 29 | function extractAngularClassMetadata(typeChecker, node) { 30 | const decorators = ts.getDecorators(node); 31 | if (!decorators || !decorators.length) { 32 | return null; 33 | } 34 | const ngDecorators = ng_decorators.getAngularDecorators(typeChecker, decorators); 35 | const componentDecorator = ngDecorators.find((dec) => dec.name === 'Component'); 36 | const directiveDecorator = ngDecorators.find((dec) => dec.name === 'Directive'); 37 | const decorator = componentDecorator ?? directiveDecorator; 38 | // In case no decorator could be found on the current class, skip. 39 | if (!decorator) { 40 | return null; 41 | } 42 | const decoratorCall = decorator.node.expression; 43 | // In case the decorator call is not valid, skip this class declaration. 44 | if (decoratorCall.arguments.length !== 1) { 45 | return null; 46 | } 47 | const metadata = unwrapExpression(decoratorCall.arguments[0]); 48 | // Ensure that the metadata is an object literal expression. 49 | if (!ts.isObjectLiteralExpression(metadata)) { 50 | return null; 51 | } 52 | return { 53 | type: componentDecorator ? 'component' : 'directive', 54 | node: metadata, 55 | }; 56 | } 57 | 58 | const LF_CHAR = 10; 59 | const CR_CHAR = 13; 60 | const LINE_SEP_CHAR = 8232; 61 | const PARAGRAPH_CHAR = 8233; 62 | /** Gets the line and character for the given position from the line starts map. */ 63 | function getLineAndCharacterFromPosition(lineStartsMap, position) { 64 | const lineIndex = findClosestLineStartPosition(lineStartsMap, position); 65 | return { character: position - lineStartsMap[lineIndex], line: lineIndex }; 66 | } 67 | /** 68 | * Computes the line start map of the given text. This can be used in order to 69 | * retrieve the line and character of a given text position index. 70 | */ 71 | function computeLineStartsMap(text) { 72 | const result = [0]; 73 | let pos = 0; 74 | while (pos < text.length) { 75 | const char = text.charCodeAt(pos++); 76 | // Handles the "CRLF" line break. In that case we peek the character 77 | // after the "CR" and check if it is a line feed. 78 | if (char === CR_CHAR) { 79 | if (text.charCodeAt(pos) === LF_CHAR) { 80 | pos++; 81 | } 82 | result.push(pos); 83 | } 84 | else if (char === LF_CHAR || char === LINE_SEP_CHAR || char === PARAGRAPH_CHAR) { 85 | result.push(pos); 86 | } 87 | } 88 | result.push(pos); 89 | return result; 90 | } 91 | /** Finds the closest line start for the given position. */ 92 | function findClosestLineStartPosition(linesMap, position, low = 0, high = linesMap.length - 1) { 93 | while (low <= high) { 94 | const pivotIdx = Math.floor((low + high) / 2); 95 | const pivotEl = linesMap[pivotIdx]; 96 | if (pivotEl === position) { 97 | return pivotIdx; 98 | } 99 | else if (position > pivotEl) { 100 | low = pivotIdx + 1; 101 | } 102 | else { 103 | high = pivotIdx - 1; 104 | } 105 | } 106 | // In case there was no exact match, return the closest "lower" line index. We also 107 | // subtract the index by one because want the index of the previous line start. 108 | return low - 1; 109 | } 110 | 111 | /** 112 | * Visitor that can be used to determine Angular templates referenced within given 113 | * TypeScript source files (inline templates or external referenced templates) 114 | */ 115 | class NgComponentTemplateVisitor { 116 | typeChecker; 117 | resolvedTemplates = []; 118 | fs = compilerCli.getFileSystem(); 119 | constructor(typeChecker) { 120 | this.typeChecker = typeChecker; 121 | } 122 | visitNode(node) { 123 | if (node.kind === ts.SyntaxKind.ClassDeclaration) { 124 | this.visitClassDeclaration(node); 125 | } 126 | ts.forEachChild(node, (n) => this.visitNode(n)); 127 | } 128 | visitClassDeclaration(node) { 129 | const metadata = extractAngularClassMetadata(this.typeChecker, node); 130 | if (metadata === null || metadata.type !== 'component') { 131 | return; 132 | } 133 | const sourceFile = node.getSourceFile(); 134 | const sourceFileName = sourceFile.fileName; 135 | // Walk through all component metadata properties and determine the referenced 136 | // HTML templates (either external or inline) 137 | metadata.node.properties.forEach((property) => { 138 | if (!ts.isPropertyAssignment(property)) { 139 | return; 140 | } 141 | const propertyName = property_name.getPropertyNameText(property.name); 142 | // In case there is an inline template specified, ensure that the value is statically 143 | // analyzable by checking if the initializer is a string literal-like node. 144 | if (propertyName === 'template' && ts.isStringLiteralLike(property.initializer)) { 145 | // Need to add an offset of one to the start because the template quotes are 146 | // not part of the template content. 147 | // The `getText()` method gives us the original raw text. 148 | // We could have used the `text` property, but if the template is defined as a backtick 149 | // string then the `text` property contains a "cooked" version of the string. Such cooked 150 | // strings will have converted CRLF characters to only LF. This messes up string 151 | // replacements in template migrations. 152 | // The raw text returned by `getText()` includes the enclosing quotes so we change the 153 | // `content` and `start` values accordingly. 154 | const content = property.initializer.getText().slice(1, -1); 155 | const start = property.initializer.getStart() + 1; 156 | this.resolvedTemplates.push({ 157 | filePath: sourceFileName, 158 | container: node, 159 | content, 160 | inline: true, 161 | start: start, 162 | getCharacterAndLineOfPosition: (pos) => ts.getLineAndCharacterOfPosition(sourceFile, pos + start), 163 | }); 164 | } 165 | if (propertyName === 'templateUrl' && ts.isStringLiteralLike(property.initializer)) { 166 | const absolutePath = this.fs.resolve(this.fs.dirname(sourceFileName), property.initializer.text); 167 | if (!this.fs.exists(absolutePath)) { 168 | return; 169 | } 170 | const fileContent = this.fs.readFile(absolutePath); 171 | const lineStartsMap = computeLineStartsMap(fileContent); 172 | this.resolvedTemplates.push({ 173 | filePath: absolutePath, 174 | container: node, 175 | content: fileContent, 176 | inline: false, 177 | start: 0, 178 | getCharacterAndLineOfPosition: (pos) => getLineAndCharacterFromPosition(lineStartsMap, pos), 179 | }); 180 | } 181 | }); 182 | } 183 | } 184 | 185 | exports.NgComponentTemplateVisitor = NgComponentTemplateVisitor; 186 | -------------------------------------------------------------------------------- /fesm2022/_linked_signal-chunk.mjs.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"_linked_signal-chunk.mjs","sources":["../../../../../k8-fastbuild-ST-fdfa778d11ba/bin/packages/core/primitives/signals/src/linked_signal.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {COMPUTING, ERRORED, UNSET} from './computed';\nimport {defaultEquals, ValueEqualityFn} from './equality';\nimport {\n consumerAfterComputation,\n consumerBeforeComputation,\n producerAccessed,\n producerMarkClean,\n producerUpdateValueVersion,\n REACTIVE_NODE,\n ReactiveNode,\n runPostProducerCreatedFn,\n SIGNAL,\n} from './graph';\nimport {signalSetFn, signalUpdateFn} from './signal';\n\n// Required as the signals library is in a separate package, so we need to explicitly ensure the\n// global `ngDevMode` type is defined.\ndeclare const ngDevMode: boolean | undefined;\n\nexport type ComputationFn = (source: S, previous?: PreviousValue) => D;\nexport type PreviousValue = {source: S; value: D};\n\nexport interface LinkedSignalNode extends ReactiveNode {\n /**\n * Value of the source signal that was used to derive the computed value.\n */\n sourceValue: S;\n\n /**\n * Current state value, or one of the sentinel values (`UNSET`, `COMPUTING`,\n * `ERROR`).\n */\n value: D;\n\n /**\n * If `value` is `ERRORED`, the error caught from the last computation attempt which will\n * be re-thrown.\n */\n error: unknown;\n\n /**\n * The source function represents reactive dependency based on which the linked state is reset.\n */\n source: () => S;\n\n /**\n * The computation function which will produce a new value based on the source and, optionally - previous values.\n */\n computation: ComputationFn;\n\n equal: ValueEqualityFn;\n}\n\nexport type LinkedSignalGetter = (() => D) & {\n [SIGNAL]: LinkedSignalNode;\n};\n\nexport function createLinkedSignal(\n sourceFn: () => S,\n computationFn: ComputationFn,\n equalityFn?: ValueEqualityFn,\n): LinkedSignalGetter {\n const node: LinkedSignalNode = Object.create(LINKED_SIGNAL_NODE);\n\n node.source = sourceFn;\n node.computation = computationFn;\n if (equalityFn != undefined) {\n node.equal = equalityFn;\n }\n\n const linkedSignalGetter = () => {\n // Check if the value needs updating before returning it.\n producerUpdateValueVersion(node);\n\n // Record that someone looked at this signal.\n producerAccessed(node);\n\n if (node.value === ERRORED) {\n throw node.error;\n }\n\n return node.value;\n };\n\n const getter = linkedSignalGetter as LinkedSignalGetter;\n getter[SIGNAL] = node;\n if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n const debugName = node.debugName ? ' (' + node.debugName + ')' : '';\n getter.toString = () => `[LinkedSignal${debugName}: ${node.value}]`;\n }\n\n runPostProducerCreatedFn(node);\n\n return getter;\n}\n\nexport function linkedSignalSetFn(node: LinkedSignalNode, newValue: D) {\n producerUpdateValueVersion(node);\n signalSetFn(node, newValue);\n producerMarkClean(node);\n}\n\nexport function linkedSignalUpdateFn(\n node: LinkedSignalNode,\n updater: (value: D) => D,\n): void {\n producerUpdateValueVersion(node);\n signalUpdateFn(node, updater);\n producerMarkClean(node);\n}\n\n// Note: Using an IIFE here to ensure that the spread assignment is not considered\n// a side-effect, ending up preserving `LINKED_SIGNAL_NODE` and `REACTIVE_NODE`.\n// TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.\nexport const LINKED_SIGNAL_NODE: object = /* @__PURE__ */ (() => {\n return {\n ...REACTIVE_NODE,\n value: UNSET,\n dirty: true,\n error: null,\n equal: defaultEquals,\n kind: 'linkedSignal',\n\n producerMustRecompute(node: LinkedSignalNode): boolean {\n // Force a recomputation if there's no current value, or if the current value is in the\n // process of being calculated (which should throw an error).\n return node.value === UNSET || node.value === COMPUTING;\n },\n\n producerRecomputeValue(node: LinkedSignalNode): void {\n if (node.value === COMPUTING) {\n // Our computation somehow led to a cyclic read of itself.\n throw new Error(\n typeof ngDevMode !== 'undefined' && ngDevMode ? 'Detected cycle in computations.' : '',\n );\n }\n\n const oldValue = node.value;\n node.value = COMPUTING;\n\n const prevConsumer = consumerBeforeComputation(node);\n let newValue: unknown;\n try {\n const newSourceValue = node.source();\n const prev =\n oldValue === UNSET || oldValue === ERRORED\n ? undefined\n : {\n source: node.sourceValue,\n value: oldValue,\n };\n newValue = node.computation(newSourceValue, prev);\n node.sourceValue = newSourceValue;\n } catch (err) {\n newValue = ERRORED;\n node.error = err;\n } finally {\n consumerAfterComputation(node, prevConsumer);\n }\n\n if (oldValue !== UNSET && newValue !== ERRORED && node.equal(oldValue, newValue)) {\n // No change to `valueVersion` - old and new values are\n // semantically equivalent.\n node.value = oldValue;\n return;\n }\n\n node.value = newValue;\n node.version++;\n },\n };\n})();\n"],"names":["createLinkedSignal","sourceFn","computationFn","equalityFn","node","Object","create","LINKED_SIGNAL_NODE","source","computation","undefined","equal","linkedSignalGetter","producerUpdateValueVersion","producerAccessed","value","ERRORED","error","getter","SIGNAL","ngDevMode","debugName","toString","runPostProducerCreatedFn","linkedSignalSetFn","newValue","signalSetFn","producerMarkClean","linkedSignalUpdateFn","updater","signalUpdateFn","REACTIVE_NODE","UNSET","dirty","defaultEquals","kind","producerMustRecompute","COMPUTING","producerRecomputeValue","Error","oldValue","prevConsumer","consumerBeforeComputation","newSourceValue","prev","sourceValue","err","consumerAfterComputation","version"],"mappings":";;;;;;;;SAiEgBA,kBAAkBA,CAChCC,QAAiB,EACjBC,aAAkC,EAClCC,UAA+B,EAAA;AAE/B,EAAA,MAAMC,IAAI,GAA2BC,MAAM,CAACC,MAAM,CAACC,kBAAkB,CAAC;EAEtEH,IAAI,CAACI,MAAM,GAAGP,QAAQ;EACtBG,IAAI,CAACK,WAAW,GAAGP,aAAa;EAChC,IAAIC,UAAU,IAAIO,SAAS,EAAE;IAC3BN,IAAI,CAACO,KAAK,GAAGR,UAAU;AACzB;EAEA,MAAMS,kBAAkB,GAAGA,MAAK;IAE9BC,0BAA0B,CAACT,IAAI,CAAC;IAGhCU,gBAAgB,CAACV,IAAI,CAAC;AAEtB,IAAA,IAAIA,IAAI,CAACW,KAAK,KAAKC,OAAO,EAAE;MAC1B,MAAMZ,IAAI,CAACa,KAAK;AAClB;IAEA,OAAOb,IAAI,CAACW,KAAK;GAClB;EAED,MAAMG,MAAM,GAAGN,kBAA8C;AAC7DM,EAAAA,MAAM,CAACC,MAAM,CAAC,GAAGf,IAAI;AACrB,EAAA,IAAI,OAAOgB,SAAS,KAAK,WAAW,IAAIA,SAAS,EAAE;AACjD,IAAA,MAAMC,SAAS,GAAGjB,IAAI,CAACiB,SAAS,GAAG,IAAI,GAAGjB,IAAI,CAACiB,SAAS,GAAG,GAAG,GAAG,EAAE;IACnEH,MAAM,CAACI,QAAQ,GAAG,MAAM,CAAA,aAAA,EAAgBD,SAAS,CAAKjB,EAAAA,EAAAA,IAAI,CAACW,KAAK,CAAG,CAAA,CAAA;AACrE;EAEAQ,wBAAwB,CAACnB,IAAI,CAAC;AAE9B,EAAA,OAAOc,MAAM;AACf;AAEgB,SAAAM,iBAAiBA,CAAOpB,IAA4B,EAAEqB,QAAW,EAAA;EAC/EZ,0BAA0B,CAACT,IAAI,CAAC;AAChCsB,EAAAA,WAAW,CAACtB,IAAI,EAAEqB,QAAQ,CAAC;EAC3BE,iBAAiB,CAACvB,IAAI,CAAC;AACzB;AAEgB,SAAAwB,oBAAoBA,CAClCxB,IAA4B,EAC5ByB,OAAwB,EAAA;EAExBhB,0BAA0B,CAACT,IAAI,CAAC;AAChC0B,EAAAA,cAAc,CAAC1B,IAAI,EAAEyB,OAAO,CAAC;EAC7BF,iBAAiB,CAACvB,IAAI,CAAC;AACzB;AAKO,MAAMG,kBAAkB,kBAA2B,CAAC,MAAK;EAC9D,OAAO;AACL,IAAA,GAAGwB,aAAa;AAChBhB,IAAAA,KAAK,EAAEiB,KAAK;AACZC,IAAAA,KAAK,EAAE,IAAI;AACXhB,IAAAA,KAAK,EAAE,IAAI;AACXN,IAAAA,KAAK,EAAEuB,aAAa;AACpBC,IAAAA,IAAI,EAAE,cAAc;IAEpBC,qBAAqBA,CAAChC,IAAwC,EAAA;MAG5D,OAAOA,IAAI,CAACW,KAAK,KAAKiB,KAAK,IAAI5B,IAAI,CAACW,KAAK,KAAKsB,SAAS;KACxD;IAEDC,sBAAsBA,CAAClC,IAAwC,EAAA;AAC7D,MAAA,IAAIA,IAAI,CAACW,KAAK,KAAKsB,SAAS,EAAE;AAE5B,QAAA,MAAM,IAAIE,KAAK,CACb,OAAOnB,SAAS,KAAK,WAAW,IAAIA,SAAS,GAAG,iCAAiC,GAAG,EAAE,CACvF;AACH;AAEA,MAAA,MAAMoB,QAAQ,GAAGpC,IAAI,CAACW,KAAK;MAC3BX,IAAI,CAACW,KAAK,GAAGsB,SAAS;AAEtB,MAAA,MAAMI,YAAY,GAAGC,yBAAyB,CAACtC,IAAI,CAAC;AACpD,MAAA,IAAIqB,QAAiB;MACrB,IAAI;AACF,QAAA,MAAMkB,cAAc,GAAGvC,IAAI,CAACI,MAAM,EAAE;QACpC,MAAMoC,IAAI,GACRJ,QAAQ,KAAKR,KAAK,IAAIQ,QAAQ,KAAKxB,OAAO,GACtCN,SAAS,GACT;UACEF,MAAM,EAAEJ,IAAI,CAACyC,WAAW;AACxB9B,UAAAA,KAAK,EAAEyB;SACR;QACPf,QAAQ,GAAGrB,IAAI,CAACK,WAAW,CAACkC,cAAc,EAAEC,IAAI,CAAC;QACjDxC,IAAI,CAACyC,WAAW,GAAGF,cAAc;OACnC,CAAE,OAAOG,GAAG,EAAE;AACZrB,QAAAA,QAAQ,GAAGT,OAAO;QAClBZ,IAAI,CAACa,KAAK,GAAG6B,GAAG;AAClB,OAAA,SAAU;AACRC,QAAAA,wBAAwB,CAAC3C,IAAI,EAAEqC,YAAY,CAAC;AAC9C;AAEA,MAAA,IAAID,QAAQ,KAAKR,KAAK,IAAIP,QAAQ,KAAKT,OAAO,IAAIZ,IAAI,CAACO,KAAK,CAAC6B,QAAQ,EAAEf,QAAQ,CAAC,EAAE;QAGhFrB,IAAI,CAACW,KAAK,GAAGyB,QAAQ;AACrB,QAAA;AACF;MAEApC,IAAI,CAACW,KAAK,GAAGU,QAAQ;MACrBrB,IAAI,CAAC4C,OAAO,EAAE;AAChB;GACD;AACH,CAAC,GAAG;;;;"} -------------------------------------------------------------------------------- /types/rxjs-interop.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { ValueEqualityFn } from './_formatter-chunk.js'; 8 | import { OutputRef, DestroyRef, Injector, Signal } from './_chrome_dev_tools_performance-chunk.js'; 9 | import { OutputOptions, BaseResourceOptions, ResourceLoaderParams, ResourceRef } from './_api-chunk.js'; 10 | import './_event_dispatcher-chunk.js'; 11 | import { Observable, MonoTypeOperatorFunction, Subscribable } from 'rxjs'; 12 | 13 | /** 14 | * Declares an Angular output that is using an RxJS observable as a source 15 | * for events dispatched to parent subscribers. 16 | * 17 | * The behavior for an observable as source is defined as followed: 18 | * 1. New values are forwarded to the Angular output (next notifications). 19 | * 2. Errors notifications are not handled by Angular. You need to handle these manually. 20 | * For example by using `catchError`. 21 | * 3. Completion notifications stop the output from emitting new values. 22 | * 23 | * @usageNotes 24 | * Initialize an output in your directive by declaring a 25 | * class field and initializing it with the `outputFromObservable()` function. 26 | * 27 | * ```ts 28 | * @Directive({..}) 29 | * export class MyDir { 30 | * nameChange$ = ; 31 | * nameChange = outputFromObservable(this.nameChange$); 32 | * } 33 | * ``` 34 | * @see [RxJS interop with component and directive outputs](ecosystem/rxjs-interop/output-interop) 35 | * 36 | * @publicApi 19.0 37 | */ 38 | declare function outputFromObservable(observable: Observable, opts?: OutputOptions): OutputRef; 39 | 40 | /** 41 | * Converts an Angular output declared via `output()` or `outputFromObservable()` 42 | * to an observable. 43 | * It creates an observable that represents the stream of "events firing" in an output. 44 | * 45 | * You can subscribe to the output via `Observable.subscribe` then. 46 | * 47 | * @see [RxJS interop with component and directive outputs](ecosystem/rxjs-interop/output-interop) 48 | * 49 | * @publicApi 19.0 50 | */ 51 | declare function outputToObservable(ref: OutputRef): Observable; 52 | 53 | /** 54 | * Operator which completes the Observable when the calling context (component, directive, service, 55 | * etc) is destroyed. 56 | * 57 | * @param destroyRef optionally, the `DestroyRef` representing the current context. This can be 58 | * passed explicitly to use `takeUntilDestroyed` outside of an [injection 59 | * context](guide/di/dependency-injection-context). Otherwise, the current `DestroyRef` is injected. 60 | * 61 | * @see [Unsubscribing with takeUntilDestroyed](ecosystem/rxjs-interop/take-until-destroyed) 62 | * 63 | * @publicApi 19.0 64 | */ 65 | declare function takeUntilDestroyed(destroyRef?: DestroyRef): MonoTypeOperatorFunction; 66 | 67 | /** 68 | * Options for `toObservable`. 69 | * 70 | * @publicApi 20.0 71 | */ 72 | interface ToObservableOptions { 73 | /** 74 | * The `Injector` to use when creating the underlying `effect` which watches the signal. 75 | * 76 | * If this isn't specified, the current [injection context](guide/di/dependency-injection-context) 77 | * will be used. 78 | */ 79 | injector?: Injector; 80 | } 81 | /** 82 | * Exposes the value of an Angular `Signal` as an RxJS `Observable`. 83 | * As it reflects a state, the observable will always emit the latest value upon subscription. 84 | * 85 | * The signal's value will be propagated into the `Observable`'s subscribers using an `effect`. 86 | * 87 | * `toObservable` must be called in an injection context unless an injector is provided via options. 88 | * 89 | * @see [RxJS interop with Angular signals](ecosystem/rxjs-interop) 90 | * @see [Create an RxJS Observable from a signal with toObservable](ecosystem/rxjs-interop#create-an-rxjs-observable-from-a-signal-with-toobservable) 91 | * 92 | * @publicApi 20.0 93 | */ 94 | declare function toObservable(source: Signal, options?: ToObservableOptions): Observable; 95 | 96 | /** 97 | * Options for `toSignal`. 98 | * 99 | * @publicApi 20.0 100 | */ 101 | interface ToSignalOptions { 102 | /** 103 | * Initial value for the signal produced by `toSignal`. 104 | * 105 | * This will be the value of the signal until the observable emits its first value. 106 | */ 107 | initialValue?: unknown; 108 | /** 109 | * Whether to require that the observable emits synchronously when `toSignal` subscribes. 110 | * 111 | * If this is `true`, `toSignal` will assert that the observable produces a value immediately upon 112 | * subscription. Setting this option removes the need to either deal with `undefined` in the 113 | * signal type or provide an `initialValue`, at the cost of a runtime error if this requirement is 114 | * not met. 115 | */ 116 | requireSync?: boolean; 117 | /** 118 | * `Injector` which will provide the `DestroyRef` used to clean up the Observable subscription. 119 | * 120 | * If this is not provided, a `DestroyRef` will be retrieved from the current [injection 121 | * context](guide/di/dependency-injection-context), unless manual cleanup is requested. 122 | */ 123 | injector?: Injector; 124 | /** 125 | * Whether the subscription should be automatically cleaned up (via `DestroyRef`) when 126 | * `toSignal`'s creation context is destroyed. 127 | * 128 | * If manual cleanup is enabled, then `DestroyRef` is not used, and the subscription will persist 129 | * until the `Observable` itself completes. 130 | */ 131 | manualCleanup?: boolean; 132 | /** 133 | * A comparison function which defines equality for values emitted by the observable. 134 | * 135 | * Equality comparisons are executed against the initial value if one is provided. 136 | */ 137 | equal?: ValueEqualityFn; 138 | /** 139 | * A debug name for the signal. Used in Angular DevTools to identify the signal. 140 | */ 141 | debugName?: string; 142 | } 143 | declare function toSignal(source: Observable | Subscribable): Signal; 144 | declare function toSignal(source: Observable | Subscribable, options: NoInfer> & { 145 | initialValue?: undefined; 146 | requireSync?: false; 147 | }): Signal; 148 | declare function toSignal(source: Observable | Subscribable, options: NoInfer> & { 149 | initialValue?: null; 150 | requireSync?: false; 151 | }): Signal; 152 | declare function toSignal(source: Observable | Subscribable, options: NoInfer> & { 153 | initialValue?: undefined; 154 | requireSync: true; 155 | }): Signal; 156 | declare function toSignal(source: Observable | Subscribable, options: NoInfer> & { 157 | initialValue: U; 158 | requireSync?: false; 159 | }): Signal; 160 | 161 | /** 162 | * Operator which makes the application unstable until the observable emits, completes, errors, or is unsubscribed. 163 | * 164 | * Use this operator in observables whose subscriptions are important for rendering and should be included in SSR serialization. 165 | * 166 | * @param injector The `Injector` to use during creation. If this is not provided, the current injection context will be used instead (via `inject`). 167 | * 168 | * @developerPreview 20.0 169 | */ 170 | declare function pendingUntilEvent(injector?: Injector): MonoTypeOperatorFunction; 171 | 172 | /** 173 | * Like `ResourceOptions` but uses an RxJS-based `loader`. 174 | * 175 | * @experimental 176 | */ 177 | interface RxResourceOptions extends BaseResourceOptions { 178 | stream: (params: ResourceLoaderParams) => Observable; 179 | } 180 | /** 181 | * Like `resource` but uses an RxJS based `loader` which maps the request to an `Observable` of the 182 | * resource's value. 183 | * 184 | * @see [Using rxResource for async data](ecosystem/rxjs-interop#using-rxresource-for-async-data) 185 | * 186 | * @experimental 187 | */ 188 | declare function rxResource(opts: RxResourceOptions & { 189 | defaultValue: NoInfer; 190 | }): ResourceRef; 191 | /** 192 | * Like `resource` but uses an RxJS based `loader` which maps the request to an `Observable` of the 193 | * resource's value. 194 | * 195 | * @experimental 196 | */ 197 | declare function rxResource(opts: RxResourceOptions): ResourceRef; 198 | 199 | export { outputFromObservable, outputToObservable, pendingUntilEvent, rxResource, takeUntilDestroyed, toObservable, toSignal }; 200 | export type { RxResourceOptions, ToObservableOptions, ToSignalOptions }; 201 | -------------------------------------------------------------------------------- /fesm2022/rxjs-interop.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { Observable, ReplaySubject } from 'rxjs'; 8 | import { takeUntil } from 'rxjs/operators'; 9 | import { assertInInjectionContext, inject, DestroyRef, RuntimeError, Injector, effect, untracked, assertNotInReactiveContext, signal, PendingTasks } from './_untracked-chunk.mjs'; 10 | import { getOutputDestroyRef, computed, resource, encapsulateResourceError } from './_resource-chunk.mjs'; 11 | import './_effect-chunk.mjs'; 12 | import './_not_found-chunk.mjs'; 13 | import '@angular/core/primitives/signals'; 14 | import '@angular/core/primitives/di'; 15 | import './_linked_signal-chunk.mjs'; 16 | 17 | function takeUntilDestroyed(destroyRef) { 18 | if (!destroyRef) { 19 | ngDevMode && assertInInjectionContext(takeUntilDestroyed); 20 | destroyRef = inject(DestroyRef); 21 | } 22 | const destroyed$ = new Observable(subscriber => { 23 | if (destroyRef.destroyed) { 24 | subscriber.next(); 25 | return; 26 | } 27 | const unregisterFn = destroyRef.onDestroy(subscriber.next.bind(subscriber)); 28 | return unregisterFn; 29 | }); 30 | return source => { 31 | return source.pipe(takeUntil(destroyed$)); 32 | }; 33 | } 34 | 35 | class OutputFromObservableRef { 36 | source; 37 | destroyed = false; 38 | destroyRef = inject(DestroyRef); 39 | constructor(source) { 40 | this.source = source; 41 | this.destroyRef.onDestroy(() => { 42 | this.destroyed = true; 43 | }); 44 | } 45 | subscribe(callbackFn) { 46 | if (this.destroyed) { 47 | throw new RuntimeError(953, ngDevMode && 'Unexpected subscription to destroyed `OutputRef`. ' + 'The owning directive/component is destroyed.'); 48 | } 49 | const subscription = this.source.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({ 50 | next: value => callbackFn(value) 51 | }); 52 | return { 53 | unsubscribe: () => subscription.unsubscribe() 54 | }; 55 | } 56 | } 57 | function outputFromObservable(observable, opts) { 58 | ngDevMode && assertInInjectionContext(outputFromObservable); 59 | return new OutputFromObservableRef(observable); 60 | } 61 | 62 | function outputToObservable(ref) { 63 | const destroyRef = getOutputDestroyRef(ref); 64 | return new Observable(observer => { 65 | const unregisterOnDestroy = destroyRef?.onDestroy(() => observer.complete()); 66 | const subscription = ref.subscribe(v => observer.next(v)); 67 | return () => { 68 | subscription.unsubscribe(); 69 | unregisterOnDestroy?.(); 70 | }; 71 | }); 72 | } 73 | 74 | function toObservable(source, options) { 75 | if (ngDevMode && !options?.injector) { 76 | assertInInjectionContext(toObservable); 77 | } 78 | const injector = options?.injector ?? inject(Injector); 79 | const subject = new ReplaySubject(1); 80 | const watcher = effect(() => { 81 | let value; 82 | try { 83 | value = source(); 84 | } catch (err) { 85 | untracked(() => subject.error(err)); 86 | return; 87 | } 88 | untracked(() => subject.next(value)); 89 | }, { 90 | injector, 91 | manualCleanup: true 92 | }); 93 | injector.get(DestroyRef).onDestroy(() => { 94 | watcher.destroy(); 95 | subject.complete(); 96 | }); 97 | return subject.asObservable(); 98 | } 99 | 100 | function toSignal(source, options) { 101 | typeof ngDevMode !== 'undefined' && ngDevMode && assertNotInReactiveContext(toSignal, 'Invoking `toSignal` causes new subscriptions every time. ' + 'Consider moving `toSignal` outside of the reactive context and read the signal value where needed.'); 102 | const requiresCleanup = !options?.manualCleanup; 103 | if (ngDevMode && requiresCleanup && !options?.injector) { 104 | assertInInjectionContext(toSignal); 105 | } 106 | const cleanupRef = requiresCleanup ? options?.injector?.get(DestroyRef) ?? inject(DestroyRef) : null; 107 | const equal = makeToSignalEqual(options?.equal); 108 | let state; 109 | if (options?.requireSync) { 110 | state = signal({ 111 | kind: 0 112 | }, { 113 | equal, 114 | ...(ngDevMode ? createDebugNameObject(options?.debugName, 'state') : undefined) 115 | }); 116 | } else { 117 | state = signal({ 118 | kind: 1, 119 | value: options?.initialValue 120 | }, { 121 | equal, 122 | ...(ngDevMode ? createDebugNameObject(options?.debugName, 'state') : undefined) 123 | }); 124 | } 125 | let destroyUnregisterFn; 126 | const sub = source.subscribe({ 127 | next: value => state.set({ 128 | kind: 1, 129 | value 130 | }), 131 | error: error => { 132 | state.set({ 133 | kind: 2, 134 | error 135 | }); 136 | destroyUnregisterFn?.(); 137 | }, 138 | complete: () => { 139 | destroyUnregisterFn?.(); 140 | } 141 | }); 142 | if (options?.requireSync && state().kind === 0) { 143 | throw new RuntimeError(601, (typeof ngDevMode === 'undefined' || ngDevMode) && '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.'); 144 | } 145 | destroyUnregisterFn = cleanupRef?.onDestroy(sub.unsubscribe.bind(sub)); 146 | return computed(() => { 147 | const current = state(); 148 | switch (current.kind) { 149 | case 1: 150 | return current.value; 151 | case 2: 152 | throw current.error; 153 | case 0: 154 | throw new RuntimeError(601, (typeof ngDevMode === 'undefined' || ngDevMode) && '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.'); 155 | } 156 | }, { 157 | equal: options?.equal, 158 | ...(ngDevMode ? createDebugNameObject(options?.debugName, 'source') : undefined) 159 | }); 160 | } 161 | function makeToSignalEqual(userEquality = Object.is) { 162 | return (a, b) => a.kind === 1 && b.kind === 1 && userEquality(a.value, b.value); 163 | } 164 | function createDebugNameObject(toSignalDebugName, internalSignalDebugName) { 165 | return { 166 | debugName: `toSignal${toSignalDebugName ? '#' + toSignalDebugName : ''}.${internalSignalDebugName}` 167 | }; 168 | } 169 | 170 | function pendingUntilEvent(injector) { 171 | if (injector === undefined) { 172 | ngDevMode && assertInInjectionContext(pendingUntilEvent); 173 | injector = inject(Injector); 174 | } 175 | const taskService = injector.get(PendingTasks); 176 | return sourceObservable => { 177 | return new Observable(originalSubscriber => { 178 | const removeTask = taskService.add(); 179 | let cleanedUp = false; 180 | function cleanupTask() { 181 | if (cleanedUp) { 182 | return; 183 | } 184 | removeTask(); 185 | cleanedUp = true; 186 | } 187 | const innerSubscription = sourceObservable.subscribe({ 188 | next: v => { 189 | originalSubscriber.next(v); 190 | cleanupTask(); 191 | }, 192 | complete: () => { 193 | originalSubscriber.complete(); 194 | cleanupTask(); 195 | }, 196 | error: e => { 197 | originalSubscriber.error(e); 198 | cleanupTask(); 199 | } 200 | }); 201 | innerSubscription.add(() => { 202 | originalSubscriber.unsubscribe(); 203 | cleanupTask(); 204 | }); 205 | return innerSubscription; 206 | }); 207 | }; 208 | } 209 | 210 | function rxResource(opts) { 211 | if (ngDevMode && !opts?.injector) { 212 | assertInInjectionContext(rxResource); 213 | } 214 | return resource({ 215 | ...opts, 216 | loader: undefined, 217 | stream: params => { 218 | let sub; 219 | const onAbort = () => sub?.unsubscribe(); 220 | params.abortSignal.addEventListener('abort', onAbort); 221 | const stream = signal({ 222 | value: undefined 223 | }); 224 | let resolve; 225 | const promise = new Promise(r => resolve = r); 226 | function send(value) { 227 | stream.set(value); 228 | resolve?.(stream); 229 | resolve = undefined; 230 | } 231 | const streamFn = opts.stream ?? opts.loader; 232 | if (streamFn === undefined) { 233 | throw new RuntimeError(990, ngDevMode && `Must provide \`stream\` option.`); 234 | } 235 | sub = streamFn(params).subscribe({ 236 | next: value => send({ 237 | value 238 | }), 239 | error: error => { 240 | send({ 241 | error: encapsulateResourceError(error) 242 | }); 243 | params.abortSignal.removeEventListener('abort', onAbort); 244 | }, 245 | complete: () => { 246 | if (resolve) { 247 | send({ 248 | error: new RuntimeError(991, ngDevMode && 'Resource completed before producing a value') 249 | }); 250 | } 251 | params.abortSignal.removeEventListener('abort', onAbort); 252 | } 253 | }); 254 | return promise; 255 | } 256 | }); 257 | } 258 | 259 | export { outputFromObservable, outputToObservable, pendingUntilEvent, rxResource, takeUntilDestroyed, toObservable, toSignal }; 260 | //# sourceMappingURL=rxjs-interop.mjs.map 261 | -------------------------------------------------------------------------------- /schematics/bundles/self-closing-tags-migration.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @license Angular v21.1.0-next.3+sha-9fa77af 4 | * (c) 2010-2025 Google LLC. https://angular.io/ 5 | * License: MIT 6 | */ 7 | 'use strict'; 8 | 9 | var ts = require('typescript'); 10 | require('@angular/compiler-cli'); 11 | require('@angular/compiler-cli/private/migrations'); 12 | require('node:path'); 13 | var project_paths = require('./project_paths-DvD50ouC.cjs'); 14 | var ng_component_template = require('./ng_component_template-Dsuq1Lw7.cjs'); 15 | var compiler = require('@angular/compiler'); 16 | var parse_html = require('./parse_html-8VLCL37B.cjs'); 17 | require('@angular-devkit/core'); 18 | require('node:path/posix'); 19 | require('@angular-devkit/schematics'); 20 | require('./project_tsconfig_paths-CDVxT6Ov.cjs'); 21 | require('./ng_decorators-DSFlWYQY.cjs'); 22 | require('./imports-DP72APSx.cjs'); 23 | require('./property_name-BBwFuqMe.cjs'); 24 | 25 | function migrateTemplateToSelfClosingTags(template) { 26 | let parsed = parse_html.parseTemplate(template); 27 | if (parsed.tree === undefined) { 28 | return { migrated: template, changed: false, replacementCount: 0 }; 29 | } 30 | const visitor = new AngularElementCollector(); 31 | compiler.visitAll(visitor, parsed.tree.rootNodes); 32 | let newTemplate = template; 33 | let changedOffset = 0; 34 | let replacementCount = 0; 35 | for (let element of visitor.elements) { 36 | const { start, end, tagName } = element; 37 | const currentLength = newTemplate.length; 38 | const templatePart = newTemplate.slice(start + changedOffset, end + changedOffset); 39 | const convertedTemplate = replaceWithSelfClosingTag(templatePart, tagName); 40 | // if the template has changed, replace the original template with the new one 41 | if (convertedTemplate.length !== templatePart.length) { 42 | newTemplate = replaceTemplate(newTemplate, convertedTemplate, start, end, changedOffset); 43 | changedOffset += newTemplate.length - currentLength; 44 | replacementCount++; 45 | } 46 | } 47 | return { migrated: newTemplate, changed: changedOffset !== 0, replacementCount }; 48 | } 49 | function replaceWithSelfClosingTag(html, tagName) { 50 | const pattern = new RegExp(`<\\s*${tagName}\\s*([^>]*?(?:"[^"]*"|'[^']*'|[^'">])*)\\s*>([\\s\\S]*?)<\\s*/\\s*${tagName}\\s*>`, 'gi'); 51 | return html.replace(pattern, (_, content) => `<${tagName}${content ? ` ${content}` : ''} />`); 52 | } 53 | /** 54 | * Replace the value in the template with the new value based on the start and end position + offset 55 | */ 56 | function replaceTemplate(template, replaceValue, start, end, offset) { 57 | return template.slice(0, start + offset) + replaceValue + template.slice(end + offset); 58 | } 59 | const ALL_HTML_TAGS = new compiler.DomElementSchemaRegistry().allKnownElementNames(); 60 | class AngularElementCollector extends compiler.RecursiveVisitor { 61 | elements = []; 62 | constructor() { 63 | super(); 64 | } 65 | visitElement(element) { 66 | if (!element.isSelfClosing && 67 | !ALL_HTML_TAGS.includes(element.name) && 68 | this.elementHasNoContent(element)) { 69 | this.elements.push({ 70 | tagName: element.name, 71 | start: element.sourceSpan.start.offset, 72 | end: element.sourceSpan.end.offset, 73 | }); 74 | } 75 | return super.visitElement(element, null); 76 | } 77 | elementHasNoContent(element) { 78 | if (!element.children?.length) { 79 | return true; 80 | } 81 | if (element.children.length === 1) { 82 | const child = element.children[0]; 83 | return child instanceof compiler.Text && /^\s*$/.test(child.value); 84 | } 85 | return false; 86 | } 87 | } 88 | 89 | class SelfClosingTagsMigration extends project_paths.TsurgeFunnelMigration { 90 | config; 91 | constructor(config = {}) { 92 | super(); 93 | this.config = config; 94 | } 95 | async analyze(info) { 96 | const { sourceFiles, program } = info; 97 | const typeChecker = program.getTypeChecker(); 98 | const tagReplacements = []; 99 | for (const sf of sourceFiles) { 100 | ts.forEachChild(sf, (node) => { 101 | // Skipping any non component declarations 102 | if (!ts.isClassDeclaration(node)) { 103 | return; 104 | } 105 | const file = project_paths.projectFile(node.getSourceFile(), info); 106 | if (this.config.shouldMigrate && this.config.shouldMigrate(file) === false) { 107 | return; 108 | } 109 | const templateVisitor = new ng_component_template.NgComponentTemplateVisitor(typeChecker); 110 | templateVisitor.visitNode(node); 111 | templateVisitor.resolvedTemplates.forEach((template) => { 112 | const { migrated, changed, replacementCount } = migrateTemplateToSelfClosingTags(template.content); 113 | if (!changed) { 114 | return; 115 | } 116 | const fileToMigrate = template.inline 117 | ? file 118 | : project_paths.projectFile(template.filePath, info); 119 | const end = template.start + template.content.length; 120 | const replacements = [ 121 | prepareTextReplacement(fileToMigrate, migrated, template.start, end), 122 | ]; 123 | const fileReplacements = tagReplacements.find((tagReplacement) => tagReplacement.file === file); 124 | if (fileReplacements) { 125 | fileReplacements.replacements.push(...replacements); 126 | fileReplacements.replacementCount += replacementCount; 127 | } 128 | else { 129 | tagReplacements.push({ file, replacements, replacementCount }); 130 | } 131 | }); 132 | }); 133 | } 134 | return project_paths.confirmAsSerializable({ tagReplacements }); 135 | } 136 | async combine(unitA, unitB) { 137 | return project_paths.confirmAsSerializable({ 138 | tagReplacements: [...unitA.tagReplacements, ...unitB.tagReplacements], 139 | }); 140 | } 141 | async globalMeta(combinedData) { 142 | const globalMeta = { 143 | tagReplacements: combinedData.tagReplacements, 144 | }; 145 | return project_paths.confirmAsSerializable(globalMeta); 146 | } 147 | async stats(globalMetadata) { 148 | const touchedFilesCount = globalMetadata.tagReplacements.length; 149 | const replacementCount = globalMetadata.tagReplacements.reduce((acc, cur) => acc + cur.replacementCount, 0); 150 | return project_paths.confirmAsSerializable({ 151 | touchedFilesCount, 152 | replacementCount, 153 | }); 154 | } 155 | async migrate(globalData) { 156 | return { replacements: globalData.tagReplacements.flatMap(({ replacements }) => replacements) }; 157 | } 158 | } 159 | function prepareTextReplacement(file, replacement, start, end) { 160 | return new project_paths.Replacement(file, new project_paths.TextUpdate({ 161 | position: start, 162 | end: end, 163 | toInsert: replacement, 164 | })); 165 | } 166 | 167 | function migrate(options) { 168 | return async (tree, context) => { 169 | await project_paths.runMigrationInDevkit({ 170 | tree, 171 | getMigration: (fs) => new SelfClosingTagsMigration({ 172 | shouldMigrate: (file) => { 173 | return (file.rootRelativePath.startsWith(fs.normalize(options.path)) && 174 | !/(^|\/)node_modules\//.test(file.rootRelativePath)); 175 | }, 176 | }), 177 | beforeProgramCreation: (tsconfigPath, stage) => { 178 | if (stage === project_paths.MigrationStage.Analysis) { 179 | context.logger.info(`Preparing analysis for: ${tsconfigPath}...`); 180 | } 181 | else { 182 | context.logger.info(`Running migration for: ${tsconfigPath}...`); 183 | } 184 | }, 185 | beforeUnitAnalysis: (tsconfigPath) => { 186 | context.logger.info(`Scanning for component tags: ${tsconfigPath}...`); 187 | }, 188 | afterAllAnalyzed: () => { 189 | context.logger.info(``); 190 | context.logger.info(`Processing analysis data between targets...`); 191 | context.logger.info(``); 192 | }, 193 | afterAnalysisFailure: () => { 194 | context.logger.error('Migration failed unexpectedly with no analysis data'); 195 | }, 196 | whenDone: ({ touchedFilesCount, replacementCount }) => { 197 | context.logger.info(''); 198 | context.logger.info(`Successfully migrated to self-closing tags 🎉`); 199 | context.logger.info(` -> Migrated ${replacementCount} components to self-closing tags in ${touchedFilesCount} component files.`); 200 | }, 201 | }); 202 | }; 203 | } 204 | 205 | exports.migrate = migrate; 206 | -------------------------------------------------------------------------------- /types/_formatter-chunk.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | /** 8 | * A comparison function which can determine if two values are equal. 9 | */ 10 | type ValueEqualityFn = (a: T, b: T) => boolean; 11 | /** 12 | * The default equality function used for `signal` and `computed`, which uses referential equality. 13 | */ 14 | declare function defaultEquals(a: T, b: T): boolean; 15 | 16 | type Version = number & { 17 | __brand: 'Version'; 18 | }; 19 | type ReactiveHookFn = (node: ReactiveNode) => void; 20 | /** 21 | * Symbol used to tell `Signal`s apart from other functions. 22 | * 23 | * This can be used to auto-unwrap signals in various cases, or to auto-wrap non-signal values. 24 | */ 25 | declare const SIGNAL: unique symbol; 26 | declare function setActiveConsumer(consumer: ReactiveNode | null): ReactiveNode | null; 27 | declare function getActiveConsumer(): ReactiveNode | null; 28 | declare function isInNotificationPhase(): boolean; 29 | interface Reactive { 30 | [SIGNAL]: ReactiveNode; 31 | } 32 | declare function isReactive(value: unknown): value is Reactive; 33 | declare const REACTIVE_NODE: ReactiveNode; 34 | interface ReactiveLink { 35 | producer: ReactiveNode; 36 | consumer: ReactiveNode; 37 | lastReadVersion: number; 38 | prevConsumer: ReactiveLink | undefined; 39 | nextConsumer: ReactiveLink | undefined; 40 | nextProducer: ReactiveLink | undefined; 41 | } 42 | type ReactiveNodeKind = 'signal' | 'computed' | 'effect' | 'template' | 'linkedSignal' | 'afterRenderEffectPhase' | 'unknown'; 43 | /** 44 | * A producer and/or consumer which participates in the reactive graph. 45 | * 46 | * Producer `ReactiveNode`s which are accessed when a consumer `ReactiveNode` is the 47 | * `activeConsumer` are tracked as dependencies of that consumer. 48 | * 49 | * Certain consumers are also tracked as "live" consumers and create edges in the other direction, 50 | * from producer to consumer. These edges are used to propagate change notifications when a 51 | * producer's value is updated. 52 | * 53 | * A `ReactiveNode` may be both a producer and consumer. 54 | */ 55 | interface ReactiveNode { 56 | /** 57 | * Version of the value that this node produces. 58 | * 59 | * This is incremented whenever a new value is produced by this node which is not equal to the 60 | * previous value (by whatever definition of equality is in use). 61 | */ 62 | version: Version; 63 | /** 64 | * Epoch at which this node is verified to be clean. 65 | * 66 | * This allows skipping of some polling operations in the case where no signals have been set 67 | * since this node was last read. 68 | */ 69 | lastCleanEpoch: Version; 70 | /** 71 | * Whether this node (in its consumer capacity) is dirty. 72 | * 73 | * Only live consumers become dirty, when receiving a change notification from a dependency 74 | * producer. 75 | */ 76 | dirty: boolean; 77 | /** 78 | * Whether this node is currently rebuilding its producer list. 79 | */ 80 | recomputing: boolean; 81 | /** 82 | * Producers which are dependencies of this consumer. 83 | */ 84 | producers: ReactiveLink | undefined; 85 | /** 86 | * Points to the last linked list node in the `producers` linked list. 87 | * 88 | * When this node is recomputing, this is used to track the producers that we have accessed so far. 89 | */ 90 | producersTail: ReactiveLink | undefined; 91 | /** 92 | * Linked list of consumers of this producer that are "live" (they require push notifications). 93 | * 94 | * The length of this list is effectively our reference count for this node. 95 | */ 96 | consumers: ReactiveLink | undefined; 97 | consumersTail: ReactiveLink | undefined; 98 | /** 99 | * Whether writes to signals are allowed when this consumer is the `activeConsumer`. 100 | * 101 | * This is used to enforce guardrails such as preventing writes to writable signals in the 102 | * computation function of computed signals, which is supposed to be pure. 103 | */ 104 | consumerAllowSignalWrites: boolean; 105 | readonly consumerIsAlwaysLive: boolean; 106 | /** 107 | * Tracks whether producers need to recompute their value independently of the reactive graph (for 108 | * example, if no initial value has been computed). 109 | */ 110 | producerMustRecompute(node: unknown): boolean; 111 | producerRecomputeValue(node: unknown): void; 112 | consumerMarkedDirty(node: unknown): void; 113 | /** 114 | * Called when a signal is read within this consumer. 115 | */ 116 | consumerOnSignalRead(node: unknown): void; 117 | /** 118 | * A debug name for the reactive node. Used in Angular DevTools to identify the node. 119 | */ 120 | debugName?: string; 121 | /** 122 | * Kind of node. Example: 'signal', 'computed', 'input', 'effect'. 123 | * 124 | * ReactiveNode has this as 'unknown' by default, but derived node types should override this to 125 | * make available the kind of signal that particular instance of a ReactiveNode represents. 126 | * 127 | * Used in Angular DevTools to identify the kind of signal. 128 | */ 129 | kind: ReactiveNodeKind; 130 | } 131 | /** 132 | * Called by implementations when a producer's signal is read. 133 | */ 134 | declare function producerAccessed(node: ReactiveNode): void; 135 | /** 136 | * Increment the global epoch counter. 137 | * 138 | * Called by source producers (that is, not computeds) whenever their values change. 139 | */ 140 | declare function producerIncrementEpoch(): void; 141 | /** 142 | * Ensure this producer's `version` is up-to-date. 143 | */ 144 | declare function producerUpdateValueVersion(node: ReactiveNode): void; 145 | /** 146 | * Propagate a dirty notification to live consumers of this producer. 147 | */ 148 | declare function producerNotifyConsumers(node: ReactiveNode): void; 149 | /** 150 | * Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates, 151 | * based on the current consumer context. 152 | */ 153 | declare function producerUpdatesAllowed(): boolean; 154 | declare function consumerMarkDirty(node: ReactiveNode): void; 155 | declare function producerMarkClean(node: ReactiveNode): void; 156 | /** 157 | * Prepare this consumer to run a computation in its reactive context and set 158 | * it as the active consumer. 159 | * 160 | * Must be called by subclasses which represent reactive computations, before those computations 161 | * begin. 162 | */ 163 | declare function consumerBeforeComputation(node: ReactiveNode | null): ReactiveNode | null; 164 | /** 165 | * Prepare this consumer to run a computation in its reactive context. 166 | * 167 | * We expose this mainly for code where we manually batch effects into a single 168 | * consumer. In those cases we may wish to "reopen" a consumer multiple times 169 | * in initial render before finalizing it. Most code should just call 170 | * `consumerBeforeComputation` instead of calling this directly. 171 | */ 172 | declare function resetConsumerBeforeComputation(node: ReactiveNode): void; 173 | /** 174 | * Finalize this consumer's state and set previous consumer as the active consumer after a 175 | * reactive computation has run. 176 | * 177 | * Must be called by subclasses which represent reactive computations, after those computations 178 | * have finished. 179 | */ 180 | declare function consumerAfterComputation(node: ReactiveNode | null, prevConsumer: ReactiveNode | null): void; 181 | /** 182 | * Finalize this consumer's state after a reactive computation has run. 183 | * 184 | * We expose this mainly for code where we manually batch effects into a single 185 | * consumer. In those cases we may wish to "reopen" a consumer multiple times 186 | * in initial render before finalizing it. Most code should just call 187 | * `consumerAfterComputation` instead of calling this directly. 188 | */ 189 | declare function finalizeConsumerAfterComputation(node: ReactiveNode): void; 190 | /** 191 | * Determine whether this consumer has any dependencies which have changed since the last time 192 | * they were read. 193 | */ 194 | declare function consumerPollProducersForChange(node: ReactiveNode): boolean; 195 | /** 196 | * Disconnect this consumer from the graph. 197 | */ 198 | declare function consumerDestroy(node: ReactiveNode): void; 199 | declare function runPostProducerCreatedFn(node: ReactiveNode): void; 200 | declare function setPostProducerCreatedFn(fn: ReactiveHookFn | null): ReactiveHookFn | null; 201 | 202 | declare global { 203 | var devtoolsFormatters: any[]; 204 | } 205 | /** 206 | * Installs the custom formatter into custom formatting on Signals in the devtools. 207 | * 208 | * Supported by both Chrome and Firefox. 209 | * 210 | * @see https://firefox-source-docs.mozilla.org/devtools-user/custom_formatters/index.html 211 | */ 212 | declare function installDevToolsSignalFormatter(): void; 213 | 214 | export { REACTIVE_NODE, SIGNAL, consumerAfterComputation, consumerBeforeComputation, consumerDestroy, consumerMarkDirty, consumerPollProducersForChange, defaultEquals, finalizeConsumerAfterComputation, getActiveConsumer, installDevToolsSignalFormatter, isInNotificationPhase, isReactive, producerAccessed, producerIncrementEpoch, producerMarkClean, producerNotifyConsumers, producerUpdateValueVersion, producerUpdatesAllowed, resetConsumerBeforeComputation, runPostProducerCreatedFn, setActiveConsumer, setPostProducerCreatedFn }; 215 | export type { Reactive, ReactiveHookFn, ReactiveNode, ReactiveNodeKind, ValueEqualityFn, Version }; 216 | -------------------------------------------------------------------------------- /types/_api-chunk.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { OutputRef, OutputRefSubscription, DestroyRef, Signal, WritableSignal, ValueEqualityFn, Injector } from './_chrome_dev_tools_performance-chunk.js'; 8 | 9 | /** 10 | * An `OutputEmitterRef` is created by the `output()` function and can be 11 | * used to emit values to consumers of your directive or component. 12 | * 13 | * Consumers of your directive/component can bind to the output and 14 | * subscribe to changes via the bound event syntax. For example: 15 | * 16 | * ```html 17 | * 18 | * ``` 19 | * 20 | * @see [Custom events with outputs](guide/components/outputs) 21 | * 22 | * @publicAPI 23 | */ 24 | declare class OutputEmitterRef implements OutputRef { 25 | private destroyed; 26 | private listeners; 27 | private errorHandler; 28 | constructor(); 29 | subscribe(callback: (value: T) => void): OutputRefSubscription; 30 | /** Emits a new value to the output. */ 31 | emit(value: T): void; 32 | } 33 | /** Gets the owning `DestroyRef` for the given output. */ 34 | declare function getOutputDestroyRef(ref: OutputRef): DestroyRef | undefined; 35 | 36 | /** 37 | * Options for declaring an output. 38 | * 39 | * @see [Customizing output names](guide/components/outputs#customizing-output-names) 40 | * 41 | * @publicApi 19.0 42 | */ 43 | interface OutputOptions { 44 | alias?: string; 45 | } 46 | /** 47 | * The `output` function allows declaration of Angular outputs in 48 | * directives and components. 49 | * 50 | * You can use outputs to emit values to parent directives and component. 51 | * Parents can subscribe to changes via: 52 | * 53 | * - template event bindings. For example, `(myOutput)="doSomething($event)"` 54 | * - programmatic subscription by using `OutputRef#subscribe`. 55 | * 56 | * @usageNotes 57 | * 58 | * To use `output()`, import the function from `@angular/core`. 59 | * 60 | * ```ts 61 | * import {output} from '@angular/core'; 62 | * ``` 63 | * 64 | * Inside your component, introduce a new class member and initialize 65 | * it with a call to `output`. 66 | * 67 | * ```ts 68 | * @Directive({ 69 | * ... 70 | * }) 71 | * export class MyDir { 72 | * nameChange = output(); // OutputEmitterRef 73 | * onClick = output(); // OutputEmitterRef 74 | * } 75 | * ``` 76 | * 77 | * You can emit values to consumers of your directive, by using 78 | * the `emit` method from `OutputEmitterRef`. 79 | * 80 | * ```ts 81 | * updateName(newName: string): void { 82 | * this.nameChange.emit(newName); 83 | * } 84 | * ``` 85 | * 86 | * @see [Custom events with outputs](guide/components/outputs#customizing-output-names) 87 | * 88 | * @initializerApiFunction {"showTypesInSignaturePreview": true} 89 | * @publicApi 19.0 90 | */ 91 | declare function output(opts?: OutputOptions): OutputEmitterRef; 92 | 93 | /** 94 | * String value capturing the status of a `Resource`. 95 | * 96 | * Possible statuses are: 97 | * 98 | * `idle` - The resource has no valid request and will not perform any loading. `value()` will be 99 | * `undefined`. 100 | * 101 | * `loading` - The resource is currently loading a new value as a result of a change in its reactive 102 | * dependencies. `value()` will be `undefined`. 103 | * 104 | * `reloading` - The resource is currently reloading a fresh value for the same reactive 105 | * dependencies. `value()` will continue to return the previously fetched value during the reloading 106 | * operation. 107 | * 108 | * `error` - Loading failed with an error. `value()` will be `undefined`. 109 | * 110 | * `resolved` - Loading has completed and the resource has the value returned from the loader. 111 | * 112 | * `local` - The resource's value was set locally via `.set()` or `.update()`. 113 | * 114 | * @experimental 115 | */ 116 | type ResourceStatus = 'idle' | 'error' | 'loading' | 'reloading' | 'resolved' | 'local'; 117 | /** 118 | * A Resource is an asynchronous dependency (for example, the results of an API call) that is 119 | * managed and delivered through signals. 120 | * 121 | * The usual way of creating a `Resource` is through the `resource` function, but various other APIs 122 | * may present `Resource` instances to describe their own concepts. 123 | * 124 | * @experimental 125 | */ 126 | interface Resource { 127 | /** 128 | * The current value of the `Resource`, or throws an error if the resource is in an error state. 129 | */ 130 | readonly value: Signal; 131 | /** 132 | * The current status of the `Resource`, which describes what the resource is currently doing and 133 | * what can be expected of its `value`. 134 | */ 135 | readonly status: Signal; 136 | /** 137 | * When in the `error` state, this returns the last known error from the `Resource`. 138 | */ 139 | readonly error: Signal; 140 | /** 141 | * Whether this resource is loading a new value (or reloading the existing one). 142 | */ 143 | readonly isLoading: Signal; 144 | /** 145 | * Whether this resource has a valid current value. 146 | * 147 | * This function is reactive. 148 | */ 149 | hasValue(this: T extends undefined ? this : never): this is Resource>; 150 | hasValue(): boolean; 151 | } 152 | /** 153 | * A `Resource` with a mutable value. 154 | * 155 | * Overwriting the value of a resource sets it to the 'local' state. 156 | * 157 | * @experimental 158 | */ 159 | interface WritableResource extends Resource { 160 | readonly value: WritableSignal; 161 | hasValue(this: T extends undefined ? this : never): this is WritableResource>; 162 | hasValue(): boolean; 163 | /** 164 | * Convenience wrapper for `value.set`. 165 | */ 166 | set(value: T): void; 167 | /** 168 | * Convenience wrapper for `value.update`. 169 | */ 170 | update(updater: (value: T) => T): void; 171 | asReadonly(): Resource; 172 | /** 173 | * Instructs the resource to re-load any asynchronous dependency it may have. 174 | * 175 | * Note that the resource will not enter its reloading state until the actual backend request is 176 | * made. 177 | * 178 | * @returns true if a reload was initiated, false if a reload was unnecessary or unsupported 179 | */ 180 | reload(): boolean; 181 | } 182 | /** 183 | * A `WritableResource` created through the `resource` function. 184 | * 185 | * @experimental 186 | */ 187 | interface ResourceRef extends WritableResource { 188 | hasValue(this: T extends undefined ? this : never): this is ResourceRef>; 189 | hasValue(): boolean; 190 | /** 191 | * Manually destroy the resource, which cancels pending requests and returns it to `idle` state. 192 | */ 193 | destroy(): void; 194 | } 195 | /** 196 | * Parameter to a `ResourceLoader` which gives the request and other options for the current loading 197 | * operation. 198 | * 199 | * @experimental 200 | */ 201 | interface ResourceLoaderParams { 202 | params: NoInfer>; 203 | abortSignal: AbortSignal; 204 | previous: { 205 | status: ResourceStatus; 206 | }; 207 | } 208 | /** 209 | * Loading function for a `Resource`. 210 | * 211 | * @experimental 212 | */ 213 | type ResourceLoader = (param: ResourceLoaderParams) => PromiseLike; 214 | /** 215 | * Streaming loader for a `Resource`. 216 | * 217 | * @experimental 218 | */ 219 | type ResourceStreamingLoader = (param: ResourceLoaderParams) => PromiseLike>>; 220 | /** 221 | * Options to the `resource` function, for creating a resource. 222 | * 223 | * @experimental 224 | */ 225 | interface BaseResourceOptions { 226 | /** 227 | * A reactive function which determines the request to be made. Whenever the request changes, the 228 | * loader will be triggered to fetch a new value for the resource. 229 | * 230 | * If a params function isn't provided, the loader won't rerun unless the resource is reloaded. 231 | */ 232 | params?: () => R; 233 | /** 234 | * The value which will be returned from the resource when a server value is unavailable, such as 235 | * when the resource is still loading. 236 | */ 237 | defaultValue?: NoInfer; 238 | /** 239 | * Equality function used to compare the return value of the loader. 240 | */ 241 | equal?: ValueEqualityFn; 242 | /** 243 | * Overrides the `Injector` used by `resource`. 244 | */ 245 | injector?: Injector; 246 | } 247 | /** 248 | * Options to the `resource` function, for creating a resource. 249 | * 250 | * @experimental 251 | */ 252 | interface PromiseResourceOptions extends BaseResourceOptions { 253 | /** 254 | * Loading function which returns a `Promise` of the resource's value for a given request. 255 | */ 256 | loader: ResourceLoader; 257 | /** 258 | * Cannot specify `stream` and `loader` at the same time. 259 | */ 260 | stream?: never; 261 | } 262 | /** 263 | * Options to the `resource` function, for creating a resource. 264 | * 265 | * @experimental 266 | */ 267 | interface StreamingResourceOptions extends BaseResourceOptions { 268 | /** 269 | * Loading function which returns a `Promise` of a signal of the resource's value for a given 270 | * request, which can change over time as new values are received from a stream. 271 | */ 272 | stream: ResourceStreamingLoader; 273 | /** 274 | * Cannot specify `stream` and `loader` at the same time. 275 | */ 276 | loader?: never; 277 | } 278 | /** 279 | * @experimental 280 | */ 281 | type ResourceOptions = (PromiseResourceOptions | StreamingResourceOptions) & { 282 | /** 283 | * A debug name for the reactive node. Used in Angular DevTools to identify the node. 284 | */ 285 | debugName?: string; 286 | }; 287 | /** 288 | * @experimental 289 | */ 290 | type ResourceStreamItem = { 291 | value: T; 292 | } | { 293 | error: Error; 294 | }; 295 | 296 | export { OutputEmitterRef, getOutputDestroyRef, output }; 297 | export type { BaseResourceOptions, OutputOptions, PromiseResourceOptions, Resource, ResourceLoader, ResourceLoaderParams, ResourceOptions, ResourceRef, ResourceStatus, ResourceStreamItem, ResourceStreamingLoader, StreamingResourceOptions, WritableResource }; 298 | -------------------------------------------------------------------------------- /fesm2022/_resource-chunk.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | import { inject, ErrorHandler, DestroyRef, RuntimeError, formatRuntimeError, signalAsReadonlyFn, assertInInjectionContext, Injector, effect, PendingTasks, untracked, signal } from './_untracked-chunk.mjs'; 8 | import { setActiveConsumer, createComputed, SIGNAL } from './_effect-chunk.mjs'; 9 | import { createLinkedSignal, linkedSignalSetFn, linkedSignalUpdateFn } from './_linked_signal-chunk.mjs'; 10 | 11 | class OutputEmitterRef { 12 | destroyed = false; 13 | listeners = null; 14 | errorHandler = inject(ErrorHandler, { 15 | optional: true 16 | }); 17 | destroyRef = inject(DestroyRef); 18 | constructor() { 19 | this.destroyRef.onDestroy(() => { 20 | this.destroyed = true; 21 | this.listeners = null; 22 | }); 23 | } 24 | subscribe(callback) { 25 | if (this.destroyed) { 26 | throw new RuntimeError(953, ngDevMode && 'Unexpected subscription to destroyed `OutputRef`. ' + 'The owning directive/component is destroyed.'); 27 | } 28 | (this.listeners ??= []).push(callback); 29 | return { 30 | unsubscribe: () => { 31 | const idx = this.listeners?.indexOf(callback); 32 | if (idx !== undefined && idx !== -1) { 33 | this.listeners?.splice(idx, 1); 34 | } 35 | } 36 | }; 37 | } 38 | emit(value) { 39 | if (this.destroyed) { 40 | console.warn(formatRuntimeError(953, ngDevMode && 'Unexpected emit for destroyed `OutputRef`. ' + 'The owning directive/component is destroyed.')); 41 | return; 42 | } 43 | if (this.listeners === null) { 44 | return; 45 | } 46 | const previousConsumer = setActiveConsumer(null); 47 | try { 48 | for (const listenerFn of this.listeners) { 49 | try { 50 | listenerFn(value); 51 | } catch (err) { 52 | this.errorHandler?.handleError(err); 53 | } 54 | } 55 | } finally { 56 | setActiveConsumer(previousConsumer); 57 | } 58 | } 59 | } 60 | function getOutputDestroyRef(ref) { 61 | return ref.destroyRef; 62 | } 63 | 64 | function computed(computation, options) { 65 | const getter = createComputed(computation, options?.equal); 66 | if (ngDevMode) { 67 | getter.toString = () => `[Computed: ${getter()}]`; 68 | getter[SIGNAL].debugName = options?.debugName; 69 | } 70 | return getter; 71 | } 72 | 73 | const identityFn = v => v; 74 | function linkedSignal(optionsOrComputation, options) { 75 | if (typeof optionsOrComputation === 'function') { 76 | const getter = createLinkedSignal(optionsOrComputation, identityFn, options?.equal); 77 | return upgradeLinkedSignalGetter(getter, options?.debugName); 78 | } else { 79 | const getter = createLinkedSignal(optionsOrComputation.source, optionsOrComputation.computation, optionsOrComputation.equal); 80 | return upgradeLinkedSignalGetter(getter, optionsOrComputation.debugName); 81 | } 82 | } 83 | function upgradeLinkedSignalGetter(getter, debugName) { 84 | if (ngDevMode) { 85 | getter.toString = () => `[LinkedSignal: ${getter()}]`; 86 | getter[SIGNAL].debugName = debugName; 87 | } 88 | const node = getter[SIGNAL]; 89 | const upgradedGetter = getter; 90 | upgradedGetter.set = newValue => linkedSignalSetFn(node, newValue); 91 | upgradedGetter.update = updateFn => linkedSignalUpdateFn(node, updateFn); 92 | upgradedGetter.asReadonly = signalAsReadonlyFn.bind(getter); 93 | return upgradedGetter; 94 | } 95 | 96 | function resource(options) { 97 | if (ngDevMode && !options?.injector) { 98 | assertInInjectionContext(resource); 99 | } 100 | const oldNameForParams = options.request; 101 | const params = options.params ?? oldNameForParams ?? (() => null); 102 | return new ResourceImpl(params, getLoader(options), options.defaultValue, options.equal ? wrapEqualityFn(options.equal) : undefined, options.debugName, options.injector ?? inject(Injector)); 103 | } 104 | class BaseWritableResource { 105 | value; 106 | isLoading; 107 | constructor(value, debugName) { 108 | this.value = value; 109 | this.value.set = this.set.bind(this); 110 | this.value.update = this.update.bind(this); 111 | this.value.asReadonly = signalAsReadonlyFn; 112 | this.isLoading = computed(() => this.status() === 'loading' || this.status() === 'reloading', ngDevMode ? createDebugNameObject(debugName, 'isLoading') : undefined); 113 | } 114 | isError = computed(() => this.status() === 'error'); 115 | update(updateFn) { 116 | this.set(updateFn(untracked(this.value))); 117 | } 118 | isValueDefined = computed(() => { 119 | if (this.isError()) { 120 | return false; 121 | } 122 | return this.value() !== undefined; 123 | }); 124 | hasValue() { 125 | return this.isValueDefined(); 126 | } 127 | asReadonly() { 128 | return this; 129 | } 130 | } 131 | class ResourceImpl extends BaseWritableResource { 132 | loaderFn; 133 | equal; 134 | debugName; 135 | pendingTasks; 136 | state; 137 | extRequest; 138 | effectRef; 139 | pendingController; 140 | resolvePendingTask = undefined; 141 | destroyed = false; 142 | unregisterOnDestroy; 143 | status; 144 | error; 145 | constructor(request, loaderFn, defaultValue, equal, debugName, injector) { 146 | super(computed(() => { 147 | const streamValue = this.state().stream?.(); 148 | if (!streamValue) { 149 | return defaultValue; 150 | } 151 | if (this.state().status === 'loading' && this.error()) { 152 | return defaultValue; 153 | } 154 | if (!isResolved(streamValue)) { 155 | throw new ResourceValueError(this.error()); 156 | } 157 | return streamValue.value; 158 | }, { 159 | equal, 160 | ...(ngDevMode ? createDebugNameObject(debugName, 'value') : undefined) 161 | }), debugName); 162 | this.loaderFn = loaderFn; 163 | this.equal = equal; 164 | this.debugName = debugName; 165 | this.extRequest = linkedSignal({ 166 | source: request, 167 | computation: request => ({ 168 | request, 169 | reload: 0 170 | }), 171 | ...(ngDevMode ? createDebugNameObject(debugName, 'extRequest') : undefined) 172 | }); 173 | this.state = linkedSignal({ 174 | source: this.extRequest, 175 | computation: (extRequest, previous) => { 176 | const status = extRequest.request === undefined ? 'idle' : 'loading'; 177 | if (!previous) { 178 | return { 179 | extRequest, 180 | status, 181 | previousStatus: 'idle', 182 | stream: undefined 183 | }; 184 | } else { 185 | return { 186 | extRequest, 187 | status, 188 | previousStatus: projectStatusOfState(previous.value), 189 | stream: previous.value.extRequest.request === extRequest.request ? previous.value.stream : undefined 190 | }; 191 | } 192 | }, 193 | ...(ngDevMode ? createDebugNameObject(debugName, 'state') : undefined) 194 | }); 195 | this.effectRef = effect(this.loadEffect.bind(this), { 196 | injector, 197 | manualCleanup: true, 198 | ...(ngDevMode ? createDebugNameObject(debugName, 'loadEffect') : undefined) 199 | }); 200 | this.pendingTasks = injector.get(PendingTasks); 201 | this.unregisterOnDestroy = injector.get(DestroyRef).onDestroy(() => this.destroy()); 202 | this.status = computed(() => projectStatusOfState(this.state()), ngDevMode ? createDebugNameObject(debugName, 'status') : undefined); 203 | this.error = computed(() => { 204 | const stream = this.state().stream?.(); 205 | return stream && !isResolved(stream) ? stream.error : undefined; 206 | }, ngDevMode ? createDebugNameObject(debugName, 'error') : undefined); 207 | } 208 | set(value) { 209 | if (this.destroyed) { 210 | return; 211 | } 212 | const error = untracked(this.error); 213 | const state = untracked(this.state); 214 | if (!error) { 215 | const current = untracked(this.value); 216 | if (state.status === 'local' && (this.equal ? this.equal(current, value) : current === value)) { 217 | return; 218 | } 219 | } 220 | this.state.set({ 221 | extRequest: state.extRequest, 222 | status: 'local', 223 | previousStatus: 'local', 224 | stream: signal({ 225 | value 226 | }, ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined) 227 | }); 228 | this.abortInProgressLoad(); 229 | } 230 | reload() { 231 | const { 232 | status 233 | } = untracked(this.state); 234 | if (status === 'idle' || status === 'loading') { 235 | return false; 236 | } 237 | this.extRequest.update(({ 238 | request, 239 | reload 240 | }) => ({ 241 | request, 242 | reload: reload + 1 243 | })); 244 | return true; 245 | } 246 | destroy() { 247 | this.destroyed = true; 248 | this.unregisterOnDestroy(); 249 | this.effectRef.destroy(); 250 | this.abortInProgressLoad(); 251 | this.state.set({ 252 | extRequest: { 253 | request: undefined, 254 | reload: 0 255 | }, 256 | status: 'idle', 257 | previousStatus: 'idle', 258 | stream: undefined 259 | }); 260 | } 261 | async loadEffect() { 262 | const extRequest = this.extRequest(); 263 | const { 264 | status: currentStatus, 265 | previousStatus 266 | } = untracked(this.state); 267 | if (extRequest.request === undefined) { 268 | return; 269 | } else if (currentStatus !== 'loading') { 270 | return; 271 | } 272 | this.abortInProgressLoad(); 273 | let resolvePendingTask = this.resolvePendingTask = this.pendingTasks.add(); 274 | const { 275 | signal: abortSignal 276 | } = this.pendingController = new AbortController(); 277 | try { 278 | const stream = await untracked(() => { 279 | return this.loaderFn({ 280 | params: extRequest.request, 281 | request: extRequest.request, 282 | abortSignal, 283 | previous: { 284 | status: previousStatus 285 | } 286 | }); 287 | }); 288 | if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) { 289 | return; 290 | } 291 | this.state.set({ 292 | extRequest, 293 | status: 'resolved', 294 | previousStatus: 'resolved', 295 | stream 296 | }); 297 | } catch (err) { 298 | if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) { 299 | return; 300 | } 301 | this.state.set({ 302 | extRequest, 303 | status: 'resolved', 304 | previousStatus: 'error', 305 | stream: signal({ 306 | error: encapsulateResourceError(err) 307 | }, ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined) 308 | }); 309 | } finally { 310 | resolvePendingTask?.(); 311 | resolvePendingTask = undefined; 312 | } 313 | } 314 | abortInProgressLoad() { 315 | untracked(() => this.pendingController?.abort()); 316 | this.pendingController = undefined; 317 | this.resolvePendingTask?.(); 318 | this.resolvePendingTask = undefined; 319 | } 320 | } 321 | function wrapEqualityFn(equal) { 322 | return (a, b) => a === undefined || b === undefined ? a === b : equal(a, b); 323 | } 324 | function getLoader(options) { 325 | if (isStreamingResourceOptions(options)) { 326 | return options.stream; 327 | } 328 | return async params => { 329 | try { 330 | return signal({ 331 | value: await options.loader(params) 332 | }, ngDevMode ? createDebugNameObject(options.debugName, 'stream') : undefined); 333 | } catch (err) { 334 | return signal({ 335 | error: encapsulateResourceError(err) 336 | }, ngDevMode ? createDebugNameObject(options.debugName, 'stream') : undefined); 337 | } 338 | }; 339 | } 340 | function isStreamingResourceOptions(options) { 341 | return !!options.stream; 342 | } 343 | function projectStatusOfState(state) { 344 | switch (state.status) { 345 | case 'loading': 346 | return state.extRequest.reload === 0 ? 'loading' : 'reloading'; 347 | case 'resolved': 348 | return isResolved(state.stream()) ? 'resolved' : 'error'; 349 | default: 350 | return state.status; 351 | } 352 | } 353 | function isResolved(state) { 354 | return state.error === undefined; 355 | } 356 | function createDebugNameObject(resourceDebugName, internalSignalDebugName) { 357 | return { 358 | debugName: `Resource${resourceDebugName ? '#' + resourceDebugName : ''}.${internalSignalDebugName}` 359 | }; 360 | } 361 | function encapsulateResourceError(error) { 362 | if (isErrorLike(error)) { 363 | return error; 364 | } 365 | return new ResourceWrappedError(error); 366 | } 367 | function isErrorLike(error) { 368 | return error instanceof Error || typeof error === 'object' && typeof error.name === 'string' && typeof error.message === 'string'; 369 | } 370 | class ResourceValueError extends Error { 371 | constructor(error) { 372 | super(ngDevMode ? `Resource is currently in an error state (see Error.cause for details): ${error.message}` : error.message, { 373 | cause: error 374 | }); 375 | } 376 | } 377 | class ResourceWrappedError extends Error { 378 | constructor(error) { 379 | super(ngDevMode ? `Resource returned an error that's not an Error instance: ${String(error)}. Check this error's .cause for the actual error.` : String(error), { 380 | cause: error 381 | }); 382 | } 383 | } 384 | 385 | export { OutputEmitterRef, ResourceImpl, computed, encapsulateResourceError, getOutputDestroyRef, linkedSignal, resource }; 386 | //# sourceMappingURL=_resource-chunk.mjs.map 387 | -------------------------------------------------------------------------------- /fesm2022/_effect-chunk.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | let activeConsumer = null; 8 | let inNotificationPhase = false; 9 | let epoch = 1; 10 | let postProducerCreatedFn = null; 11 | const SIGNAL = /* @__PURE__ */Symbol('SIGNAL'); 12 | function setActiveConsumer(consumer) { 13 | const prev = activeConsumer; 14 | activeConsumer = consumer; 15 | return prev; 16 | } 17 | function getActiveConsumer() { 18 | return activeConsumer; 19 | } 20 | function isInNotificationPhase() { 21 | return inNotificationPhase; 22 | } 23 | function isReactive(value) { 24 | return value[SIGNAL] !== undefined; 25 | } 26 | const REACTIVE_NODE = { 27 | version: 0, 28 | lastCleanEpoch: 0, 29 | dirty: false, 30 | producers: undefined, 31 | producersTail: undefined, 32 | consumers: undefined, 33 | consumersTail: undefined, 34 | recomputing: false, 35 | consumerAllowSignalWrites: false, 36 | consumerIsAlwaysLive: false, 37 | kind: 'unknown', 38 | producerMustRecompute: () => false, 39 | producerRecomputeValue: () => {}, 40 | consumerMarkedDirty: () => {}, 41 | consumerOnSignalRead: () => {} 42 | }; 43 | function producerAccessed(node) { 44 | if (inNotificationPhase) { 45 | throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? `Assertion error: signal read during notification phase` : ''); 46 | } 47 | if (activeConsumer === null) { 48 | return; 49 | } 50 | activeConsumer.consumerOnSignalRead(node); 51 | const prevProducerLink = activeConsumer.producersTail; 52 | if (prevProducerLink !== undefined && prevProducerLink.producer === node) { 53 | return; 54 | } 55 | let nextProducerLink = undefined; 56 | const isRecomputing = activeConsumer.recomputing; 57 | if (isRecomputing) { 58 | nextProducerLink = prevProducerLink !== undefined ? prevProducerLink.nextProducer : activeConsumer.producers; 59 | if (nextProducerLink !== undefined && nextProducerLink.producer === node) { 60 | activeConsumer.producersTail = nextProducerLink; 61 | nextProducerLink.lastReadVersion = node.version; 62 | return; 63 | } 64 | } 65 | const prevConsumerLink = node.consumersTail; 66 | if (prevConsumerLink !== undefined && prevConsumerLink.consumer === activeConsumer && (!isRecomputing || isValidLink(prevConsumerLink, activeConsumer))) { 67 | return; 68 | } 69 | const isLive = consumerIsLive(activeConsumer); 70 | const newLink = { 71 | producer: node, 72 | consumer: activeConsumer, 73 | nextProducer: nextProducerLink, 74 | prevConsumer: prevConsumerLink, 75 | lastReadVersion: node.version, 76 | nextConsumer: undefined 77 | }; 78 | activeConsumer.producersTail = newLink; 79 | if (prevProducerLink !== undefined) { 80 | prevProducerLink.nextProducer = newLink; 81 | } else { 82 | activeConsumer.producers = newLink; 83 | } 84 | if (isLive) { 85 | producerAddLiveConsumer(node, newLink); 86 | } 87 | } 88 | function producerIncrementEpoch() { 89 | epoch++; 90 | } 91 | function producerUpdateValueVersion(node) { 92 | if (consumerIsLive(node) && !node.dirty) { 93 | return; 94 | } 95 | if (!node.dirty && node.lastCleanEpoch === epoch) { 96 | return; 97 | } 98 | if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) { 99 | producerMarkClean(node); 100 | return; 101 | } 102 | node.producerRecomputeValue(node); 103 | producerMarkClean(node); 104 | } 105 | function producerNotifyConsumers(node) { 106 | if (node.consumers === undefined) { 107 | return; 108 | } 109 | const prev = inNotificationPhase; 110 | inNotificationPhase = true; 111 | try { 112 | for (let link = node.consumers; link !== undefined; link = link.nextConsumer) { 113 | const consumer = link.consumer; 114 | if (!consumer.dirty) { 115 | consumerMarkDirty(consumer); 116 | } 117 | } 118 | } finally { 119 | inNotificationPhase = prev; 120 | } 121 | } 122 | function producerUpdatesAllowed() { 123 | return activeConsumer?.consumerAllowSignalWrites !== false; 124 | } 125 | function consumerMarkDirty(node) { 126 | node.dirty = true; 127 | producerNotifyConsumers(node); 128 | node.consumerMarkedDirty?.(node); 129 | } 130 | function producerMarkClean(node) { 131 | node.dirty = false; 132 | node.lastCleanEpoch = epoch; 133 | } 134 | function consumerBeforeComputation(node) { 135 | if (node) resetConsumerBeforeComputation(node); 136 | return setActiveConsumer(node); 137 | } 138 | function resetConsumerBeforeComputation(node) { 139 | node.producersTail = undefined; 140 | node.recomputing = true; 141 | } 142 | function consumerAfterComputation(node, prevConsumer) { 143 | setActiveConsumer(prevConsumer); 144 | if (node) finalizeConsumerAfterComputation(node); 145 | } 146 | function finalizeConsumerAfterComputation(node) { 147 | node.recomputing = false; 148 | const producersTail = node.producersTail; 149 | let toRemove = producersTail !== undefined ? producersTail.nextProducer : node.producers; 150 | if (toRemove !== undefined) { 151 | if (consumerIsLive(node)) { 152 | do { 153 | toRemove = producerRemoveLiveConsumerLink(toRemove); 154 | } while (toRemove !== undefined); 155 | } 156 | if (producersTail !== undefined) { 157 | producersTail.nextProducer = undefined; 158 | } else { 159 | node.producers = undefined; 160 | } 161 | } 162 | } 163 | function consumerPollProducersForChange(node) { 164 | for (let link = node.producers; link !== undefined; link = link.nextProducer) { 165 | const producer = link.producer; 166 | const seenVersion = link.lastReadVersion; 167 | if (seenVersion !== producer.version) { 168 | return true; 169 | } 170 | producerUpdateValueVersion(producer); 171 | if (seenVersion !== producer.version) { 172 | return true; 173 | } 174 | } 175 | return false; 176 | } 177 | function consumerDestroy(node) { 178 | if (consumerIsLive(node)) { 179 | let link = node.producers; 180 | while (link !== undefined) { 181 | link = producerRemoveLiveConsumerLink(link); 182 | } 183 | } 184 | node.producers = undefined; 185 | node.producersTail = undefined; 186 | node.consumers = undefined; 187 | node.consumersTail = undefined; 188 | } 189 | function producerAddLiveConsumer(node, link) { 190 | const consumersTail = node.consumersTail; 191 | const wasLive = consumerIsLive(node); 192 | if (consumersTail !== undefined) { 193 | link.nextConsumer = consumersTail.nextConsumer; 194 | consumersTail.nextConsumer = link; 195 | } else { 196 | link.nextConsumer = undefined; 197 | node.consumers = link; 198 | } 199 | link.prevConsumer = consumersTail; 200 | node.consumersTail = link; 201 | if (!wasLive) { 202 | for (let link = node.producers; link !== undefined; link = link.nextProducer) { 203 | producerAddLiveConsumer(link.producer, link); 204 | } 205 | } 206 | } 207 | function producerRemoveLiveConsumerLink(link) { 208 | const producer = link.producer; 209 | const nextProducer = link.nextProducer; 210 | const nextConsumer = link.nextConsumer; 211 | const prevConsumer = link.prevConsumer; 212 | link.nextConsumer = undefined; 213 | link.prevConsumer = undefined; 214 | if (nextConsumer !== undefined) { 215 | nextConsumer.prevConsumer = prevConsumer; 216 | } else { 217 | producer.consumersTail = prevConsumer; 218 | } 219 | if (prevConsumer !== undefined) { 220 | prevConsumer.nextConsumer = nextConsumer; 221 | } else { 222 | producer.consumers = nextConsumer; 223 | if (!consumerIsLive(producer)) { 224 | let producerLink = producer.producers; 225 | while (producerLink !== undefined) { 226 | producerLink = producerRemoveLiveConsumerLink(producerLink); 227 | } 228 | } 229 | } 230 | return nextProducer; 231 | } 232 | function consumerIsLive(node) { 233 | return node.consumerIsAlwaysLive || node.consumers !== undefined; 234 | } 235 | function runPostProducerCreatedFn(node) { 236 | postProducerCreatedFn?.(node); 237 | } 238 | function setPostProducerCreatedFn(fn) { 239 | const prev = postProducerCreatedFn; 240 | postProducerCreatedFn = fn; 241 | return prev; 242 | } 243 | function isValidLink(checkLink, consumer) { 244 | const producersTail = consumer.producersTail; 245 | if (producersTail !== undefined) { 246 | let link = consumer.producers; 247 | do { 248 | if (link === checkLink) { 249 | return true; 250 | } 251 | if (link === producersTail) { 252 | break; 253 | } 254 | link = link.nextProducer; 255 | } while (link !== undefined); 256 | } 257 | return false; 258 | } 259 | 260 | function defaultEquals(a, b) { 261 | return Object.is(a, b); 262 | } 263 | 264 | function createComputed(computation, equal) { 265 | const node = Object.create(COMPUTED_NODE); 266 | node.computation = computation; 267 | if (equal !== undefined) { 268 | node.equal = equal; 269 | } 270 | const computed = () => { 271 | producerUpdateValueVersion(node); 272 | producerAccessed(node); 273 | if (node.value === ERRORED) { 274 | throw node.error; 275 | } 276 | return node.value; 277 | }; 278 | computed[SIGNAL] = node; 279 | if (typeof ngDevMode !== 'undefined' && ngDevMode) { 280 | const debugName = node.debugName ? ' (' + node.debugName + ')' : ''; 281 | computed.toString = () => `[Computed${debugName}: ${node.value}]`; 282 | } 283 | runPostProducerCreatedFn(node); 284 | return computed; 285 | } 286 | const UNSET = /* @__PURE__ */Symbol('UNSET'); 287 | const COMPUTING = /* @__PURE__ */Symbol('COMPUTING'); 288 | const ERRORED = /* @__PURE__ */Symbol('ERRORED'); 289 | const COMPUTED_NODE = /* @__PURE__ */(() => { 290 | return { 291 | ...REACTIVE_NODE, 292 | value: UNSET, 293 | dirty: true, 294 | error: null, 295 | equal: defaultEquals, 296 | kind: 'computed', 297 | producerMustRecompute(node) { 298 | return node.value === UNSET || node.value === COMPUTING; 299 | }, 300 | producerRecomputeValue(node) { 301 | if (node.value === COMPUTING) { 302 | throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Detected cycle in computations.' : ''); 303 | } 304 | const oldValue = node.value; 305 | node.value = COMPUTING; 306 | const prevConsumer = consumerBeforeComputation(node); 307 | let newValue; 308 | let wasEqual = false; 309 | try { 310 | newValue = node.computation(); 311 | setActiveConsumer(null); 312 | wasEqual = oldValue !== UNSET && oldValue !== ERRORED && newValue !== ERRORED && node.equal(oldValue, newValue); 313 | } catch (err) { 314 | newValue = ERRORED; 315 | node.error = err; 316 | } finally { 317 | consumerAfterComputation(node, prevConsumer); 318 | } 319 | if (wasEqual) { 320 | node.value = oldValue; 321 | return; 322 | } 323 | node.value = newValue; 324 | node.version++; 325 | } 326 | }; 327 | })(); 328 | 329 | function defaultThrowError() { 330 | throw new Error(); 331 | } 332 | let throwInvalidWriteToSignalErrorFn = defaultThrowError; 333 | function throwInvalidWriteToSignalError(node) { 334 | throwInvalidWriteToSignalErrorFn(node); 335 | } 336 | function setThrowInvalidWriteToSignalError(fn) { 337 | throwInvalidWriteToSignalErrorFn = fn; 338 | } 339 | 340 | let postSignalSetFn = null; 341 | function createSignal(initialValue, equal) { 342 | const node = Object.create(SIGNAL_NODE); 343 | node.value = initialValue; 344 | if (equal !== undefined) { 345 | node.equal = equal; 346 | } 347 | const getter = () => signalGetFn(node); 348 | getter[SIGNAL] = node; 349 | if (typeof ngDevMode !== 'undefined' && ngDevMode) { 350 | const debugName = node.debugName ? ' (' + node.debugName + ')' : ''; 351 | getter.toString = () => `[Signal${debugName}: ${node.value}]`; 352 | } 353 | runPostProducerCreatedFn(node); 354 | const set = newValue => signalSetFn(node, newValue); 355 | const update = updateFn => signalUpdateFn(node, updateFn); 356 | return [getter, set, update]; 357 | } 358 | function setPostSignalSetFn(fn) { 359 | const prev = postSignalSetFn; 360 | postSignalSetFn = fn; 361 | return prev; 362 | } 363 | function signalGetFn(node) { 364 | producerAccessed(node); 365 | return node.value; 366 | } 367 | function signalSetFn(node, newValue) { 368 | if (!producerUpdatesAllowed()) { 369 | throwInvalidWriteToSignalError(node); 370 | } 371 | if (!node.equal(node.value, newValue)) { 372 | node.value = newValue; 373 | signalValueChanged(node); 374 | } 375 | } 376 | function signalUpdateFn(node, updater) { 377 | if (!producerUpdatesAllowed()) { 378 | throwInvalidWriteToSignalError(node); 379 | } 380 | signalSetFn(node, updater(node.value)); 381 | } 382 | function runPostSignalSetFn(node) { 383 | postSignalSetFn?.(node); 384 | } 385 | const SIGNAL_NODE = /* @__PURE__ */(() => { 386 | return { 387 | ...REACTIVE_NODE, 388 | equal: defaultEquals, 389 | value: undefined, 390 | kind: 'signal' 391 | }; 392 | })(); 393 | function signalValueChanged(node) { 394 | node.version++; 395 | producerIncrementEpoch(); 396 | producerNotifyConsumers(node); 397 | postSignalSetFn?.(node); 398 | } 399 | 400 | function untracked(nonReactiveReadsFn) { 401 | const prevConsumer = setActiveConsumer(null); 402 | try { 403 | return nonReactiveReadsFn(); 404 | } finally { 405 | setActiveConsumer(prevConsumer); 406 | } 407 | } 408 | 409 | const BASE_EFFECT_NODE = /* @__PURE__ */(() => ({ 410 | ...REACTIVE_NODE, 411 | consumerIsAlwaysLive: true, 412 | consumerAllowSignalWrites: true, 413 | dirty: true, 414 | kind: 'effect' 415 | }))(); 416 | function runEffect(node) { 417 | node.dirty = false; 418 | if (node.version > 0 && !consumerPollProducersForChange(node)) { 419 | return; 420 | } 421 | node.version++; 422 | const prevNode = consumerBeforeComputation(node); 423 | try { 424 | node.cleanup(); 425 | node.fn(); 426 | } finally { 427 | consumerAfterComputation(node, prevNode); 428 | } 429 | } 430 | 431 | export { BASE_EFFECT_NODE, COMPUTING, ERRORED, REACTIVE_NODE, SIGNAL, SIGNAL_NODE, UNSET, consumerAfterComputation, consumerBeforeComputation, consumerDestroy, consumerMarkDirty, consumerPollProducersForChange, createComputed, createSignal, defaultEquals, finalizeConsumerAfterComputation, getActiveConsumer, isInNotificationPhase, isReactive, producerAccessed, producerIncrementEpoch, producerMarkClean, producerNotifyConsumers, producerUpdateValueVersion, producerUpdatesAllowed, resetConsumerBeforeComputation, runEffect, runPostProducerCreatedFn, runPostSignalSetFn, setActiveConsumer, setPostProducerCreatedFn, setPostSignalSetFn, setThrowInvalidWriteToSignalError, signalGetFn, signalSetFn, signalUpdateFn, untracked }; 432 | //# sourceMappingURL=_effect-chunk.mjs.map 433 | -------------------------------------------------------------------------------- /types/_event_dispatcher-chunk.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Angular v21.1.0-next.3+sha-9fa77af 3 | * (c) 2010-2025 Google LLC. https://angular.dev/ 4 | * License: MIT 5 | */ 6 | 7 | declare global { 8 | /** 9 | * Values of ngDevMode 10 | * Depending on the current state of the application, ngDevMode may have one of several values. 11 | * 12 | * For convenience, the “truthy” value which enables dev mode is also an object which contains 13 | * Angular’s performance counters. This is not necessary, but cuts down on boilerplate for the 14 | * perf counters. 15 | * 16 | * ngDevMode may also be set to false. This can happen in one of a few ways: 17 | * - The user explicitly sets `window.ngDevMode = false` somewhere in their app. 18 | * - The user calls `enableProdMode()`. 19 | * - The URL contains a `ngDevMode=false` text. 20 | * Finally, ngDevMode may not have been defined at all. 21 | */ 22 | const ngDevMode: null | NgDevModePerfCounters; 23 | interface NgDevModePerfCounters { 24 | hydratedNodes: number; 25 | hydratedComponents: number; 26 | dehydratedViewsRemoved: number; 27 | dehydratedViewsCleanupRuns: number; 28 | componentsSkippedHydration: number; 29 | deferBlocksWithIncrementalHydration: number; 30 | } 31 | } 32 | 33 | /** 34 | * Records information about the action that should handle a given `Event`. 35 | */ 36 | interface ActionInfo { 37 | name: string; 38 | element: Element; 39 | } 40 | type ActionInfoInternal = [name: string, element: Element]; 41 | /** 42 | * Records information for later handling of events. This type is 43 | * shared, and instances of it are passed, between the eventcontract 44 | * and the dispatcher jsbinary. Therefore, the fields of this type are 45 | * referenced by string literals rather than property literals 46 | * throughout the code. 47 | * 48 | * 'targetElement' is the element the action occurred on, 'actionElement' 49 | * is the element that has the jsaction handler. 50 | * 51 | * A null 'actionElement' identifies an EventInfo instance that didn't match a 52 | * jsaction attribute. This allows us to execute global event handlers with the 53 | * appropriate event type (including a11y clicks and custom events). 54 | * The declare portion of this interface creates a set of externs that make sure 55 | * renaming doesn't happen for EventInfo. This is important since EventInfo 56 | * is shared across multiple binaries. 57 | */ 58 | declare interface EventInfo { 59 | eventType: string; 60 | event: Event; 61 | targetElement: Element; 62 | /** The element that is the container for this Event. */ 63 | eic: Element; 64 | timeStamp: number; 65 | /** 66 | * The action parsed from the JSAction element. 67 | */ 68 | eia?: ActionInfoInternal; 69 | /** 70 | * Whether this `Event` is a replay event, meaning no dispatcher was 71 | * installed when this `Event` was originally dispatched. 72 | */ 73 | eirp?: boolean; 74 | /** 75 | * Whether this `Event` represents a `keydown` event that should be processed 76 | * as a `click`. Only used when a11y click events is on. 77 | */ 78 | eiack?: boolean; 79 | /** Whether action resolution has already run on this `EventInfo`. */ 80 | eir?: boolean; 81 | } 82 | /** 83 | * Utility class around an `EventInfo`. 84 | * 85 | * This should be used in compilation units that are less sensitive to code 86 | * size. 87 | */ 88 | declare class EventInfoWrapper { 89 | readonly eventInfo: EventInfo; 90 | constructor(eventInfo: EventInfo); 91 | getEventType(): string; 92 | setEventType(eventType: string): void; 93 | getEvent(): Event; 94 | setEvent(event: Event): void; 95 | getTargetElement(): Element; 96 | setTargetElement(targetElement: Element): void; 97 | getContainer(): Element; 98 | setContainer(container: Element): void; 99 | getTimestamp(): number; 100 | setTimestamp(timestamp: number): void; 101 | getAction(): { 102 | name: string; 103 | element: Element; 104 | } | undefined; 105 | setAction(action: ActionInfo | undefined): void; 106 | getIsReplay(): boolean | undefined; 107 | setIsReplay(replay: boolean): void; 108 | getResolved(): boolean | undefined; 109 | setResolved(resolved: boolean): void; 110 | clone(): EventInfoWrapper; 111 | } 112 | 113 | declare interface EarlyJsactionDataContainer { 114 | _ejsa?: EarlyJsactionData; 115 | _ejsas?: { 116 | [appId: string]: EarlyJsactionData | undefined; 117 | }; 118 | } 119 | declare global { 120 | interface Window { 121 | _ejsa?: EarlyJsactionData; 122 | _ejsas?: { 123 | [appId: string]: EarlyJsactionData | undefined; 124 | }; 125 | } 126 | } 127 | /** 128 | * Defines the early jsaction data types. 129 | */ 130 | declare interface EarlyJsactionData { 131 | /** List used to keep track of the early JSAction event types. */ 132 | et: string[]; 133 | /** List used to keep track of the early JSAction capture event types. */ 134 | etc: string[]; 135 | /** Early JSAction handler for all events. */ 136 | h: (event: Event) => void; 137 | /** Dispatcher handler. Initializes to populating `q`. */ 138 | d: (eventInfo: EventInfo) => void; 139 | /** List used to push `EventInfo` objects if the dispatcher is not registered. */ 140 | q: EventInfo[]; 141 | /** Container for listening to events. */ 142 | c: HTMLElement; 143 | } 144 | 145 | /** 146 | * An `EventContractContainerManager` provides the common interface for managing 147 | * containers. 148 | */ 149 | interface EventContractContainerManager { 150 | addEventListener(eventType: string, getHandler: (element: Element) => (event: Event) => void, passive?: boolean): void; 151 | cleanUp(): void; 152 | } 153 | /** 154 | * A class representing a container node and all the event handlers 155 | * installed on it. Used so that handlers can be cleaned up if the 156 | * container is removed from the contract. 157 | */ 158 | declare class EventContractContainer implements EventContractContainerManager { 159 | readonly element: Element; 160 | /** 161 | * Array of event handlers and their corresponding event types that are 162 | * installed on this container. 163 | * 164 | */ 165 | private handlerInfos; 166 | /** 167 | * @param element The container Element. 168 | */ 169 | constructor(element: Element); 170 | /** 171 | * Installs the provided installer on the element owned by this container, 172 | * and maintains a reference to resulting handler in order to remove it 173 | * later if desired. 174 | */ 175 | addEventListener(eventType: string, getHandler: (element: Element) => (event: Event) => void, passive?: boolean): void; 176 | /** 177 | * Removes all the handlers installed on this container. 178 | */ 179 | cleanUp(): void; 180 | } 181 | 182 | /** 183 | * @fileoverview An enum to control who can call certain jsaction APIs. 184 | */ 185 | declare enum Restriction { 186 | I_AM_THE_JSACTION_FRAMEWORK = 0 187 | } 188 | 189 | /** 190 | * @fileoverview Implements the local event handling contract. This 191 | * allows DOM objects in a container that enters into this contract to 192 | * define event handlers which are executed in a local context. 193 | * 194 | * One EventContract instance can manage the contract for multiple 195 | * containers, which are added using the addContainer() method. 196 | * 197 | * Events can be registered using the addEvent() method. 198 | * 199 | * A Dispatcher is added using the registerDispatcher() method. Until there is 200 | * a dispatcher, events are queued. The idea is that the EventContract 201 | * class is inlined in the HTML of the top level page and instantiated 202 | * right after the start of . The Dispatcher class is contained 203 | * in the external deferred js, and instantiated and registered with 204 | * EventContract when the external javascript in the page loads. The 205 | * external javascript will also register the jsaction handlers, which 206 | * then pick up the queued events at the time of registration. 207 | * 208 | * Since this class is meant to be inlined in the main page HTML, the 209 | * size of the binary compiled from this file MUST be kept as small as 210 | * possible and thus its dependencies to a minimum. 211 | */ 212 | 213 | /** 214 | * The API of an EventContract that is safe to call from any compilation unit. 215 | */ 216 | declare interface UnrenamedEventContract { 217 | ecrd(dispatcher: Dispatcher, restriction: Restriction): void; 218 | } 219 | /** A function that is called to handle events captured by the EventContract. */ 220 | type Dispatcher = (eventInfo: EventInfo, globalDispatch?: boolean) => void; 221 | /** 222 | * A function that handles an event dispatched from the browser. 223 | * 224 | * eventType: May differ from `event.type` if JSAction uses a 225 | * short-hand name or is patching over an non-bubbling event with a bubbling 226 | * variant. 227 | * event: The native browser event. 228 | * container: The container for this dispatch. 229 | */ 230 | type EventHandler = (eventType: string, event: Event, container: Element) => void; 231 | /** 232 | * EventContract intercepts events in the bubbling phase at the 233 | * boundary of a container element, and maps them to generic actions 234 | * which are specified using the custom jsaction attribute in 235 | * HTML. Behavior of the application is then specified in terms of 236 | * handler for such actions, cf. jsaction.Dispatcher in dispatcher.js. 237 | * 238 | * This has several benefits: (1) No DOM event handlers need to be 239 | * registered on the specific elements in the UI. (2) The set of 240 | * events that the application has to handle can be specified in terms 241 | * of the semantics of the application, rather than in terms of DOM 242 | * events. (3) Invocation of handlers can be delayed and handlers can 243 | * be delay loaded in a generic way. 244 | */ 245 | declare class EventContract implements UnrenamedEventContract { 246 | static MOUSE_SPECIAL_SUPPORT: boolean; 247 | private containerManager; 248 | /** 249 | * The DOM events which this contract covers. Used to prevent double 250 | * registration of event types. The value of the map is the 251 | * internally created DOM event handler function that handles the 252 | * DOM events. See addEvent(). 253 | * 254 | */ 255 | private eventHandlers; 256 | private browserEventTypeToExtraEventTypes; 257 | /** 258 | * The dispatcher function. Events are passed to this function for 259 | * handling once it was set using the registerDispatcher() method. This is 260 | * done because the function is passed from another jsbinary, so passing the 261 | * instance and invoking the method here would require to leave the method 262 | * unobfuscated. 263 | */ 264 | private dispatcher; 265 | /** 266 | * The list of suspended `EventInfo` that will be dispatched 267 | * as soon as the `Dispatcher` is registered. 268 | */ 269 | private queuedEventInfos; 270 | constructor(containerManager: EventContractContainerManager); 271 | private handleEvent; 272 | /** 273 | * Handle an `EventInfo`. 274 | */ 275 | private handleEventInfo; 276 | /** 277 | * Enables jsaction handlers to be called for the event type given by 278 | * name. 279 | * 280 | * If the event is already registered, this does nothing. 281 | * 282 | * @param prefixedEventType If supplied, this event is used in 283 | * the actual browser event registration instead of the name that is 284 | * exposed to jsaction. Use this if you e.g. want users to be able 285 | * to subscribe to jsaction="transitionEnd:foo" while the underlying 286 | * event is webkitTransitionEnd in one browser and mozTransitionEnd 287 | * in another. 288 | * 289 | * @param passive A boolean value that, if `true`, indicates that the event 290 | * handler will never call `preventDefault()`. 291 | */ 292 | addEvent(eventType: string, prefixedEventType?: string, passive?: boolean): void; 293 | /** 294 | * Gets the queued early events and replay them using the appropriate handler 295 | * in the provided event contract. Once all the events are replayed, it cleans 296 | * up the early contract. 297 | */ 298 | replayEarlyEvents(earlyJsactionData?: EarlyJsactionData | undefined): void; 299 | /** 300 | * Replays all the early `EventInfo` objects, dispatching them through the normal 301 | * `EventContract` flow. 302 | */ 303 | replayEarlyEventInfos(earlyEventInfos: EventInfo[]): void; 304 | /** 305 | * Returns all JSAction event types that have been registered for a given 306 | * browser event type. 307 | */ 308 | private getEventTypesForBrowserEventType; 309 | /** 310 | * Returns the event handler function for a given event type. 311 | */ 312 | handler(eventType: string): EventHandler | undefined; 313 | /** 314 | * Cleans up the event contract. This resets all of the `EventContract`'s 315 | * internal state. Users are responsible for not using this `EventContract` 316 | * after it has been cleaned up. 317 | */ 318 | cleanUp(): void; 319 | /** 320 | * Register a dispatcher function. Event info of each event mapped to 321 | * a jsaction is passed for handling to this callback. The queued 322 | * events are passed as well to the dispatcher for later replaying 323 | * once the dispatcher is registered. Clears the event queue to null. 324 | * 325 | * @param dispatcher The dispatcher function. 326 | * @param restriction 327 | */ 328 | registerDispatcher(dispatcher: Dispatcher, restriction: Restriction): void; 329 | /** 330 | * Unrenamed alias for registerDispatcher. Necessary for any codebases that 331 | * split the `EventContract` and `Dispatcher` code into different compilation 332 | * units. 333 | */ 334 | ecrd(dispatcher: Dispatcher, restriction: Restriction): void; 335 | } 336 | 337 | /** An internal symbol used to indicate whether propagation should be stopped or not. */ 338 | declare const PROPAGATION_STOPPED_SYMBOL: unique symbol; 339 | /** Extra event phases beyond what the browser provides. */ 340 | declare const EventPhase: { 341 | REPLAY: number; 342 | }; 343 | declare global { 344 | interface Event { 345 | [PROPAGATION_STOPPED_SYMBOL]?: boolean; 346 | } 347 | } 348 | /** 349 | * A dispatcher that uses browser-based `Event` semantics, for example bubbling, `stopPropagation`, 350 | * `currentTarget`, etc. 351 | */ 352 | declare class EventDispatcher { 353 | private readonly dispatchDelegate; 354 | private readonly clickModSupport; 355 | private readonly actionResolver; 356 | private readonly dispatcher; 357 | constructor(dispatchDelegate: (event: Event, actionName: string) => void, clickModSupport?: boolean); 358 | /** 359 | * The entrypoint for the `EventContract` dispatch. 360 | */ 361 | dispatch(eventInfo: EventInfo): void; 362 | /** Internal method that does basic disaptching. */ 363 | private dispatchToDelegate; 364 | } 365 | /** 366 | * Registers deferred functionality for an EventContract and a Jsaction 367 | * Dispatcher. 368 | */ 369 | declare function registerDispatcher(eventContract: UnrenamedEventContract, dispatcher: EventDispatcher): void; 370 | 371 | export { EventContract, EventContractContainer, EventDispatcher, EventInfoWrapper, EventPhase, Restriction, registerDispatcher }; 372 | export type { EarlyJsactionDataContainer, EventInfo }; 373 | --------------------------------------------------------------------------------