diff --git a/goldens/public-api/core/index.md b/goldens/public-api/core/index.md index 93b8d269dafead..b068908a80f315 100644 --- a/goldens/public-api/core/index.md +++ b/goldens/public-api/core/index.md @@ -787,6 +787,9 @@ export interface InputDecorator { // @public export function isDevMode(): boolean; +// @public +export function isStandalone(type: Type): boolean; + // @public export interface IterableChangeRecord { readonly currentIndex: number | null; diff --git a/packages/compiler/test/expression_parser/lexer_spec.ts b/packages/compiler/test/expression_parser/lexer_spec.ts index 4c704cb5ae908a..af796850fc9e95 100644 --- a/packages/compiler/test/expression_parser/lexer_spec.ts +++ b/packages/compiler/test/expression_parser/lexer_spec.ts @@ -343,6 +343,12 @@ function expectErrorToken(token: Token, index: any, end: number, message: string lex('1_2_3._456')[0], 6, 6, 'Lexer Error: Invalid numeric separator at column 6 in expression [1_2_3._456]'); }); + + fit('should parse without escaping', () => { + const ast = lex('{{ 1 && 1 ? \' \' : \'lala\' }}'); + console.log(ast) + expect((ast)).toEqual([]); + }) }); }); } diff --git a/packages/compiler/test/expression_parser/parser_spec.ts b/packages/compiler/test/expression_parser/parser_spec.ts index 94556aec6cd669..26fa606291836d 100644 --- a/packages/compiler/test/expression_parser/parser_spec.ts +++ b/packages/compiler/test/expression_parser/parser_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteSourceSpan, ASTWithSource, BindingPipe, Call, EmptyExpr, Interpolation, ParserError, TemplateBinding, VariableBinding} from '@angular/compiler/src/expression_parser/ast'; +import {AbsoluteSourceSpan, ASTWithSource, BindingPipe, Call, Conditional, EmptyExpr, Interpolation, LiteralPrimitive, ParserError, TemplateBinding, VariableBinding} from '@angular/compiler/src/expression_parser/ast'; import {Lexer} from '@angular/compiler/src/expression_parser/lexer'; import {Parser, SplitInterpolation} from '@angular/compiler/src/expression_parser/parser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; diff --git a/packages/compiler/test/ml_parser/lexer_spec.ts b/packages/compiler/test/ml_parser/lexer_spec.ts index c1b73cc19d54c1..a9000f741de20e 100644 --- a/packages/compiler/test/ml_parser/lexer_spec.ts +++ b/packages/compiler/test/ml_parser/lexer_spec.ts @@ -755,6 +755,15 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u ]); }); + fit('should XXXXXXXX', () => { + const tok = tokenizeAndHumanizeParts('{{ 1 && 1 ? \' \' : \'lala\' }}'); + console.log(tok); + expect(tok).toEqual([ + [TokenType.TEXT, 'a'], + [TokenType.EOF, ''], + ]); + }); + it('should allow "<" in text nodes', () => { expect(tokenizeAndHumanizeParts('{{ a < b ? c : d }}')).toEqual([ [TokenType.TEXT, ''], diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 5a698caa3eabbc..ac1fe45cef8db9 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -38,6 +38,7 @@ export {SecurityContext} from './sanitization/security'; export {Sanitizer} from './sanitization/sanitizer'; export {createNgModule, createNgModuleRef, createEnvironmentInjector} from './render3/ng_module_ref'; export {createComponent, reflectComponentType, ComponentMirror} from './render3/component'; +export {isStandalone} from './render3/definition'; import {global} from './util/global'; if (typeof ngDevMode !== 'undefined' && ngDevMode) { diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 84ecfdd973aa7c..b9832acda5e9aa 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -248,7 +248,6 @@ export { export { compilePipe as ɵcompilePipe, } from './render3/jit/pipe'; -export { isStandalone as ɵisStandalone} from './render3/definition'; export { Profiler as ɵProfiler, ProfilerEvent as ɵProfilerEvent } from './render3/profiler'; export { publishDefaultGlobalUtils as ɵpublishDefaultGlobalUtils diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index 7d216319108e34..6ac880c736247d 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -7,7 +7,6 @@ */ import {ChangeDetectionStrategy} from '../change_detection/constants'; -import {NG_PROV_DEF} from '../di/interface/defs'; import {Mutable, Type} from '../interface/type'; import {NgModuleDef} from '../metadata/ng_module_def'; import {SchemaMetadata} from '../metadata/schema'; @@ -741,7 +740,15 @@ export function getPipeDef(type: any): PipeDef|null { return type[NG_PIPE_DEF] || null; } -export function isStandalone(type: Type): boolean { +/** + * Checks whether a given Component, Directive or Pipe is marked as standalone. + * This will false if passed anything other than a Component, Directive, or Pipe class + * See this guide for additional information: https://angular.io/guide/standalone-components + * + * @param type A reference to a Component, Directive or Pipe. + * @publicApi + */ +export function isStandalone(type: Type): boolean { const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef(type); return def !== null ? def.standalone : false; } diff --git a/packages/core/src/render3/jit/module.ts b/packages/core/src/render3/jit/module.ts index 8b511262440b6e..33105f463f8a17 100644 --- a/packages/core/src/render3/jit/module.ts +++ b/packages/core/src/render3/jit/module.ts @@ -173,9 +173,7 @@ export function compileNgModuleDefs( Object.defineProperty(moduleType, NG_INJ_DEF, { get: () => { if (ngInjectorDef === null) { - ngDevMode && - verifySemanticsOfNgModuleDef( - moduleType as any as NgModuleType, allowDuplicateDeclarationsInRoot); + ngDevMode && verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot); const meta: R3InjectorMetadataFacade = { name: moduleType.name, type: moduleType, diff --git a/packages/core/test/acceptance/standalone_spec.ts b/packages/core/test/acceptance/standalone_spec.ts index 7f3057848492a2..4ee8f144a3f4ba 100644 --- a/packages/core/test/acceptance/standalone_spec.ts +++ b/packages/core/test/acceptance/standalone_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule} from '@angular/common'; -import {Component, createEnvironmentInjector, Directive, EnvironmentInjector, forwardRef, Injector, Input, NgModule, NO_ERRORS_SCHEMA, OnInit, Pipe, PipeTransform, ViewChild, ViewContainerRef} from '@angular/core'; +import {Component, createEnvironmentInjector, Directive, EnvironmentInjector, forwardRef, Injector, Input, isStandalone, NgModule, NO_ERRORS_SCHEMA, OnInit, Pipe, PipeTransform, ViewChild, ViewContainerRef} from '@angular/core'; import {TestBed} from '@angular/core/testing'; describe('standalone components, directives, and pipes', () => { @@ -847,4 +847,68 @@ describe('standalone components, directives, and pipes', () => { expect(fixture.nativeElement.textContent).toBe(''); }); }); + + describe('isStandalone()', () => { + it('should return `true` if component is standalone', () => { + @Component({selector: 'standalone-cmp', standalone: true}) + class StandaloneCmp { + } + + expect(isStandalone(StandaloneCmp)).toBeTrue(); + }); + + it('should return `false` if component is not standalone', () => { + @Component({selector: 'standalone-cmp', standalone: false}) + class StandaloneCmp { + } + + expect(isStandalone(StandaloneCmp)).toBeFalse(); + }); + + it('should return `true` if directive is standalone', () => { + @Directive({selector: '[standaloneDir]', standalone: true}) + class StandAloneDirective { + } + + expect(isStandalone(StandAloneDirective)).toBeTrue(); + }); + + it('should return `false` if directive is standalone', () => { + @Directive({selector: '[standaloneDir]', standalone: false}) + class StandAloneDirective { + } + + expect(isStandalone(StandAloneDirective)).toBeFalse(); + }); + + it('should return `true` if pipe is standalone', () => { + @Pipe({name: 'standalonePipe', standalone: true}) + class StandAlonePipe { + } + + expect(isStandalone(StandAlonePipe)).toBeTrue(); + }); + + it('should return `false` if pipe is standalone', () => { + @Pipe({name: 'standalonePipe', standalone: false}) + class StandAlonePipe { + } + + expect(isStandalone(StandAlonePipe)).toBeFalse(); + }); + + it('should return `false` if the class is not annotated', () => { + class NonAnnotatedClass {} + + expect(isStandalone(NonAnnotatedClass)).toBeFalse(); + }); + + it('should return `false` if the class is an NgModule', () => { + @NgModule({}) + class Module { + } + + expect(isStandalone(Module)).toBeFalse(); + }); + }); }); diff --git a/packages/core/test/sanitization/html_sanitizer_spec.ts b/packages/core/test/sanitization/html_sanitizer_spec.ts index d66953f9a3be5d..1354878e4ccd8b 100644 --- a/packages/core/test/sanitization/html_sanitizer_spec.ts +++ b/packages/core/test/sanitization/html_sanitizer_spec.ts @@ -22,6 +22,7 @@ function sanitizeHtml(defaultDoc: any, unsafeHtmlInput: string): string { let logMsgs: string[]; beforeEach(() => { + console.log('html_sanitizer'); defaultDoc = document; logMsgs = []; originalLog = console.warn; // Monkey patch DOM.log. diff --git a/packages/router/src/utils/config.ts b/packages/router/src/utils/config.ts index 5e674df8ae0e04..87460271d111d7 100644 --- a/packages/router/src/utils/config.ts +++ b/packages/router/src/utils/config.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {createEnvironmentInjector, EnvironmentInjector, Type, ɵisStandalone as isStandalone, ɵRuntimeError as RuntimeError} from '@angular/core'; +import {createEnvironmentInjector, EnvironmentInjector, isStandalone, Type, ɵRuntimeError as RuntimeError} from '@angular/core'; import {EmptyOutletComponent} from '../components/empty_outlet'; import {RuntimeErrorCode} from '../errors';