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..bcf9734f --- /dev/null +++ b/projects/ng-polymorpheus/src/tests/primitive.spec.ts @@ -0,0 +1,29 @@ +/* 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); + expect(isPrimitive(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); + + // 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 new file mode 100644 index 00000000..981143a5 --- /dev/null +++ b/projects/ng-polymorpheus/src/utils/is-primitive.ts @@ -0,0 +1,3 @@ +export function isPrimitive(value: unknown): boolean { + return Object(value) !== value; +} 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,