From 7f303de4abc82936fd0b886775d2e4ecda2c8649 Mon Sep 17 00:00:00 2001 From: splincode Date: Tue, 11 Mar 2025 12:51:43 +0300 Subject: [PATCH 1/2] fix: support primitive context in templates and components --- .../ng-polymorpheus/src/directives/outlet.ts | 17 ++++++++++-- .../ng-polymorpheus/src/tests/outlet.spec.ts | 8 ++++++ .../src/tests/primitive.spec.ts | 27 +++++++++++++++++++ .../ng-polymorpheus/src/utils/is-primitive.ts | 11 ++++++++ projects/ng-polymorpheus/tsconfig.lib.json | 2 +- 5 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 projects/ng-polymorpheus/src/tests/primitive.spec.ts create mode 100644 projects/ng-polymorpheus/src/utils/is-primitive.ts diff --git a/projects/ng-polymorpheus/src/directives/outlet.ts b/projects/ng-polymorpheus/src/directives/outlet.ts index d1288878..f3c91300 100644 --- a/projects/ng-polymorpheus/src/directives/outlet.ts +++ b/projects/ng-polymorpheus/src/directives/outlet.ts @@ -13,6 +13,7 @@ import {PolymorpheusComponent} from '../classes/component'; import {PolymorpheusContext} from '../classes/context'; import type {PolymorpheusContent} from '../types/content'; import type {PolymorpheusPrimitive} from '../types/primitive'; +import {isPrimitive} from '../utils/is-primitive'; import {PolymorpheusTemplate} from './template'; @Directive({ @@ -53,9 +54,11 @@ export class PolymorpheusOutlet implements OnChanges, DoCheck { const proxy = context && - (new Proxy(context as object, { + (new Proxy(ensureContext(context) as object, { get: (_, key) => - this.getContext()?.[key as keyof (C | PolymorpheusContext)], + ensureContext(this.getContext())?.[ + key as keyof (C | PolymorpheusContext) + ], }) as unknown as C); if (isComponent(this.content)) { @@ -117,3 +120,13 @@ function isTemplate( ): content is PolymorpheusTemplate | TemplateRef { return isDirective(content) || content instanceof TemplateRef; } + +function ensureContext( + context: C | PolymorpheusContext | undefined, +): C | PolymorpheusContext | undefined { + if (context && isPrimitive(context)) { + return new PolymorpheusContext(context); + } + + return context; +} diff --git a/projects/ng-polymorpheus/src/tests/outlet.spec.ts b/projects/ng-polymorpheus/src/tests/outlet.spec.ts index a9688110..884e2363 100644 --- a/projects/ng-polymorpheus/src/tests/outlet.spec.ts +++ b/projects/ng-polymorpheus/src/tests/outlet.spec.ts @@ -285,5 +285,13 @@ describe('PolymorpheusOutlet', () => { expect(text()).toBe('Component: number'); expect(COUNTER).toBe(counter); }); + + it('create a non-object context', () => { + testComponent.context = 'Hello World'; + testComponent.content = new PolymorpheusComponent(ComponentContent); + fixture.detectChanges(); + + expect(text()).toBe('Component: Hello World'); + }); }); }); diff --git a/projects/ng-polymorpheus/src/tests/primitive.spec.ts b/projects/ng-polymorpheus/src/tests/primitive.spec.ts new file mode 100644 index 00000000..67299e25 --- /dev/null +++ b/projects/ng-polymorpheus/src/tests/primitive.spec.ts @@ -0,0 +1,27 @@ +/* eslint-disable sonarjs/no-primitive-wrappers,no-new-wrappers,unicorn/new-for-builtins */ +import {describe, expect, it} from '@jest/globals'; + +import {isPrimitive} from '../utils/is-primitive'; + +describe('isPrimitive', () => { + it('should return true for primitive', () => { + expect(isPrimitive(undefined)).toBe(true); + expect(isPrimitive(null)).toBe(true); + expect(isPrimitive(12)).toBe(true); + expect(isPrimitive(Number(12))).toBe(true); + expect(isPrimitive(Number(12))).toBe(true); + expect(isPrimitive('Hello world')).toBe(true); + // noinspection JSPrimitiveTypeWrapperUsage + expect(isPrimitive(new String('Hello world'))).toBe(true); + expect(isPrimitive(true)).toBe(true); + // noinspection JSPrimitiveTypeWrapperUsage + expect(isPrimitive(new Boolean(true))).toBe(true); + }); + + it('should return false for non primitive', () => { + expect(isPrimitive([])).toBe(false); + expect(isPrimitive({})).toBe(false); + expect(isPrimitive(() => {})).toBe(false); + expect(isPrimitive(new (class {})())).toBe(false); + }); +}); diff --git a/projects/ng-polymorpheus/src/utils/is-primitive.ts b/projects/ng-polymorpheus/src/utils/is-primitive.ts new file mode 100644 index 00000000..9adc8ba5 --- /dev/null +++ b/projects/ng-polymorpheus/src/utils/is-primitive.ts @@ -0,0 +1,11 @@ +export function isPrimitive(value: unknown): boolean { + return ( + value === null || + !(typeof value === 'object' || typeof value === 'function') || + value instanceof Number || + value instanceof String || + value instanceof Boolean || + value instanceof Symbol || + value instanceof BigInt + ); +} diff --git a/projects/ng-polymorpheus/tsconfig.lib.json b/projects/ng-polymorpheus/tsconfig.lib.json index d351c7a6..029d1b99 100644 --- a/projects/ng-polymorpheus/tsconfig.lib.json +++ b/projects/ng-polymorpheus/tsconfig.lib.json @@ -6,7 +6,7 @@ "declaration": true, "inlineSources": true, "types": [], - "lib": ["dom", "es2018"] + "lib": ["dom", "es2020"] }, "angularCompilerOptions": { "annotateForClosureCompiler": true, From 470d35652c2256f03c5c573d22c8bd218e8fdeaa Mon Sep 17 00:00:00 2001 From: splincode Date: Wed, 12 Mar 2025 14:22:44 +0300 Subject: [PATCH 2/2] chore: update --- projects/ng-polymorpheus/src/tests/primitive.spec.ts | 10 ++++++---- projects/ng-polymorpheus/src/utils/is-primitive.ts | 10 +--------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/projects/ng-polymorpheus/src/tests/primitive.spec.ts b/projects/ng-polymorpheus/src/tests/primitive.spec.ts index 67299e25..bcf9734f 100644 --- a/projects/ng-polymorpheus/src/tests/primitive.spec.ts +++ b/projects/ng-polymorpheus/src/tests/primitive.spec.ts @@ -11,11 +11,7 @@ describe('isPrimitive', () => { expect(isPrimitive(Number(12))).toBe(true); expect(isPrimitive(Number(12))).toBe(true); expect(isPrimitive('Hello world')).toBe(true); - // noinspection JSPrimitiveTypeWrapperUsage - expect(isPrimitive(new String('Hello world'))).toBe(true); expect(isPrimitive(true)).toBe(true); - // noinspection JSPrimitiveTypeWrapperUsage - expect(isPrimitive(new Boolean(true))).toBe(true); }); it('should return false for non primitive', () => { @@ -23,5 +19,11 @@ describe('isPrimitive', () => { expect(isPrimitive({})).toBe(false); expect(isPrimitive(() => {})).toBe(false); expect(isPrimitive(new (class {})())).toBe(false); + + // noinspection JSPrimitiveTypeWrapperUsage + expect(isPrimitive(new String('Hello world'))).toBe(false); + + // noinspection JSPrimitiveTypeWrapperUsage + expect(isPrimitive(new Boolean(true))).toBe(false); }); }); diff --git a/projects/ng-polymorpheus/src/utils/is-primitive.ts b/projects/ng-polymorpheus/src/utils/is-primitive.ts index 9adc8ba5..981143a5 100644 --- a/projects/ng-polymorpheus/src/utils/is-primitive.ts +++ b/projects/ng-polymorpheus/src/utils/is-primitive.ts @@ -1,11 +1,3 @@ export function isPrimitive(value: unknown): boolean { - return ( - value === null || - !(typeof value === 'object' || typeof value === 'function') || - value instanceof Number || - value instanceof String || - value instanceof Boolean || - value instanceof Symbol || - value instanceof BigInt - ); + return Object(value) !== value; }