diff --git a/projects/ngx-meta/src/core/public-api.ts b/projects/ngx-meta/src/core/public-api.ts index ede00ad8..a771dd51 100644 --- a/projects/ngx-meta/src/core/public-api.ts +++ b/projects/ngx-meta/src/core/public-api.ts @@ -6,21 +6,19 @@ export { provideCore as provideNgxMetaCore, withDefaults as withNgxMetaDefaults, } from './src/provide-core' -export * from './src/base-scoped-metadata' export * from './src/composable-meta-property' export * from './src/global-metadata' -export * from './src/global-metadata-definition' export * from './src/global-metadata-image' export * from './src/global-metadata-key' +export * from './src/make-global-metadata' +export * from './src/make-metadata' export * from './src/meta-content' export * from './src/meta-property' export * from './src/meta.service' export * from './src/metadata' -export * from './src/metadata-definition' +export * from './src/metadata-provider' export * from './src/metadata-setter' export * from './src/metadata-values' export * from './src/metadata.service' -export * from './src/provide-metadata' export * from './src/provide-metadata-factory' -export * from './src/scoped-metadata-definition' export * from './src/string-key-of' diff --git a/projects/ngx-meta/src/core/src/__tests__/make-global-metadata-definition.ts b/projects/ngx-meta/src/core/src/__tests__/make-global-metadata-definition.ts deleted file mode 100644 index 884f90c6..00000000 --- a/projects/ngx-meta/src/core/src/__tests__/make-global-metadata-definition.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { GlobalMetadataDefinition } from '../global-metadata-definition' - -export function makeGlobalMetadataDefinition( - id?: Id, -): GlobalMetadataDefinition { - return new GlobalMetadataDefinition(id ?? 'dummyId') -} diff --git a/projects/ngx-meta/src/core/src/__tests__/make-metadata-provider.ts b/projects/ngx-meta/src/core/src/__tests__/make-metadata-provider.ts new file mode 100644 index 00000000..a887bc42 --- /dev/null +++ b/projects/ngx-meta/src/core/src/__tests__/make-metadata-provider.ts @@ -0,0 +1,16 @@ +import { MetadataProvider } from '../metadata-provider' +import { makeGlobalMetadata } from '../make-global-metadata' + +export function makeMetadataProvider( + opts: { + id?: Id + spyName?: string + } = {}, +) { + const id = opts.id ?? 'dummy' + const metadata: MetadataProvider = { + metadata: makeGlobalMetadata(id), + set: jasmine.createSpy(opts.spyName ?? id), + } + return metadata +} diff --git a/projects/ngx-meta/src/core/src/__tests__/make-metadata.ts b/projects/ngx-meta/src/core/src/__tests__/make-metadata.ts deleted file mode 100644 index c2f8cc1d..00000000 --- a/projects/ngx-meta/src/core/src/__tests__/make-metadata.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Metadata } from '../metadata' -import { makeGlobalMetadataDefinition } from './make-global-metadata-definition' - -export function makeMetadata( - opts: { - id?: Id - spyName?: string - } = {}, -) { - const id = opts.id ?? 'dummy' - const metadata: Metadata = { - definition: makeGlobalMetadataDefinition(id), - set: jasmine.createSpy(opts.spyName ?? id), - } - return metadata -} diff --git a/projects/ngx-meta/src/core/src/__tests__/make-scoped-metadata-definition.ts b/projects/ngx-meta/src/core/src/__tests__/make-scoped-metadata-definition.ts deleted file mode 100644 index dfdeedfd..00000000 --- a/projects/ngx-meta/src/core/src/__tests__/make-scoped-metadata-definition.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MetadataDefinition } from '../metadata-definition' -import { ScopedMetadataDefinition } from '../scoped-metadata-definition' - -export function makeScopedMetadataDefinition( - opts: { - scope?: string - name?: string - global?: string - } = {}, -): MetadataDefinition { - return new ScopedMetadataDefinition( - opts.scope ?? 'dummy scope', - opts.name ?? 'dummy name', - opts.global, - ) -} diff --git a/projects/ngx-meta/src/core/src/base-global-metadata.ts b/projects/ngx-meta/src/core/src/base-global-metadata.ts deleted file mode 100644 index 1c492259..00000000 --- a/projects/ngx-meta/src/core/src/base-global-metadata.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { BaseMetadata } from './base-metadata' -import { GlobalMetadataDefinition } from './global-metadata-definition' -import { GlobalMetadata } from './global-metadata' -import { StringKeyOf } from './string-key-of' - -export abstract class BaseGlobalMetadata< - Global extends StringKeyOf, - Globals extends object = GlobalMetadata, -> extends BaseMetadata { - protected constructor( - ...args: ConstructorParameters< - typeof GlobalMetadataDefinition> - > - ) { - super(new GlobalMetadataDefinition(...args)) - } -} diff --git a/projects/ngx-meta/src/core/src/base-metadata.ts b/projects/ngx-meta/src/core/src/base-metadata.ts deleted file mode 100644 index 822de6a9..00000000 --- a/projects/ngx-meta/src/core/src/base-metadata.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Metadata } from './metadata' -import { MetadataDefinition } from './metadata-definition' - -export abstract class BaseMetadata< - Value, - Global extends string = string, -> extends Metadata { - protected constructor( - public readonly definition: MetadataDefinition, - ) { - super() - } -} diff --git a/projects/ngx-meta/src/core/src/base-scoped-metadata.ts b/projects/ngx-meta/src/core/src/base-scoped-metadata.ts deleted file mode 100644 index fce26c2a..00000000 --- a/projects/ngx-meta/src/core/src/base-scoped-metadata.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { StringKeyOf } from './string-key-of' -import { GlobalMetadataKey } from './global-metadata-key' -import { BaseMetadata } from './base-metadata' -import { ScopedMetadataDefinition } from './scoped-metadata-definition' - -export abstract class BaseScopedMetadata< - ScopeValues, - ScopeKey extends StringKeyOf, - Global extends string = GlobalMetadataKey, -> extends BaseMetadata { - protected constructor( - ...args: ConstructorParameters< - typeof ScopedMetadataDefinition - > - ) { - super(new ScopedMetadataDefinition(...args)) - } -} diff --git a/projects/ngx-meta/src/core/src/global-metadata-definition.ts b/projects/ngx-meta/src/core/src/global-metadata-definition.ts deleted file mode 100644 index 3059b79e..00000000 --- a/projects/ngx-meta/src/core/src/global-metadata-definition.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { MetadataDefinition } from './metadata-definition' - -export class GlobalMetadataDefinition - implements MetadataDefinition -{ - public readonly jsonPath = [this.id] - - constructor(public readonly id: Global) {} -} diff --git a/projects/ngx-meta/src/core/src/make-global-metadata.ts b/projects/ngx-meta/src/core/src/make-global-metadata.ts new file mode 100644 index 00000000..f9286389 --- /dev/null +++ b/projects/ngx-meta/src/core/src/make-global-metadata.ts @@ -0,0 +1,6 @@ +import { Metadata } from './metadata' +import { makeMetadata } from './make-metadata' + +export const makeGlobalMetadata = ( + global: Global, +): Metadata => makeMetadata([global]) diff --git a/projects/ngx-meta/src/core/src/make-metadata.ts b/projects/ngx-meta/src/core/src/make-metadata.ts new file mode 100644 index 00000000..7634aa3b --- /dev/null +++ b/projects/ngx-meta/src/core/src/make-metadata.ts @@ -0,0 +1,10 @@ +import { Metadata } from './metadata' + +export const makeMetadata = ( + jsonPath: ReadonlyArray, + global?: Global, +): Metadata => ({ + id: jsonPath.join('.'), + jsonPath, + global, +}) diff --git a/projects/ngx-meta/src/core/src/metadata-definition.ts b/projects/ngx-meta/src/core/src/metadata-definition.ts deleted file mode 100644 index ca3565bd..00000000 --- a/projects/ngx-meta/src/core/src/metadata-definition.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface MetadataDefinition { - readonly id: string - readonly jsonPath: ReadonlyArray - readonly global?: Global -} diff --git a/projects/ngx-meta/src/core/src/metadata-json-resolver.spec.ts b/projects/ngx-meta/src/core/src/metadata-json-resolver.spec.ts index 6800aaaf..70849657 100644 --- a/projects/ngx-meta/src/core/src/metadata-json-resolver.spec.ts +++ b/projects/ngx-meta/src/core/src/metadata-json-resolver.spec.ts @@ -1,9 +1,9 @@ import { TestBed } from '@angular/core/testing' import { MetadataJsonResolver } from './metadata-json-resolver' import { MetadataValues } from './metadata-values' -import { MetadataDefinition } from './metadata-definition' -import { makeScopedMetadataDefinition } from './__tests__/make-scoped-metadata-definition' -import { makeGlobalMetadataDefinition } from './__tests__/make-global-metadata-definition' +import { Metadata } from './metadata' +import { makeMetadata } from './make-metadata' +import { makeGlobalMetadata } from './make-global-metadata' describe('MetadataJsonResolver', () => { let sut: MetadataJsonResolver @@ -13,41 +13,34 @@ describe('MetadataJsonResolver', () => { }) describe('get', () => { - const scope = 'scope' + const key = 'key' + const subKey = 'subKey' const global = 'global' - const name = 'name' const value = 'value' function testGlobalMayBeRetrieved( - metadataDefinition: MetadataDefinition, + metadata: Metadata, values: MetadataValues, ) { describe('when global is not defined', () => { it('should return undefined', () => { - expect(sut.get(metadataDefinition, values)).toBeUndefined() + expect(sut.get(metadata, values)).toBeUndefined() }) }) describe('when global is defined', () => { - const metadataDefinitionWithGlobal = makeScopedMetadataDefinition({ - ...metadataDefinition, - global, - }) + const metadataWithGlobal = makeMetadata(metadata.jsonPath, global) describe('but global value does not exist', () => { it('should return undefined', () => { - expect( - sut.get(metadataDefinitionWithGlobal, values), - ).toBeUndefined() + expect(sut.get(metadataWithGlobal, values)).toBeUndefined() }) }) describe('and global value exists', () => { const valuesWithGlobal = { [global]: value, ...values } it('should return global value', () => { - expect( - sut.get(metadataDefinitionWithGlobal, valuesWithGlobal), - ).toEqual(value) + expect(sut.get(metadataWithGlobal, valuesWithGlobal)).toEqual(value) }) }) }) @@ -58,123 +51,73 @@ describe('MetadataJsonResolver', () => { const values = undefined it('should return undefined', () => { - expect( - sut.get(makeGlobalMetadataDefinition(), values), - ).toBeUndefined() + expect(sut.get(makeGlobalMetadata('dummy'), values)).toBeUndefined() }) }) - describe('like when scope does not exist', () => { - const metadataDefinition = makeScopedMetadataDefinition({ - scope, - }) + describe('like when key does not exist', () => { + const metadata = makeMetadata([key, subKey]) const values = {} - testGlobalMayBeRetrieved(metadataDefinition, values) + testGlobalMayBeRetrieved(metadata, values) }) - describe('like when scope is defined but property name does not exist', () => { - const metadataDefinition = makeScopedMetadataDefinition({ - scope, - name, - }) + describe('like when key is defined but sub key does not exist', () => { + const metadata = makeMetadata([key, subKey]) const values = { - [scope]: {}, + [key]: {}, } - testGlobalMayBeRetrieved(metadataDefinition, values) - }) - - describe('like when scope is null', () => { - const metadataDefinition = makeScopedMetadataDefinition({ - scope, - }) - - const values = { [scope]: null } - - it('should return null', () => { - expect(sut.get(metadataDefinition, values)).toBeNull() - }) + testGlobalMayBeRetrieved(metadata, values) }) - describe('like when scope value is null and there is sub scope', () => { - const metadataDefinition = makeScopedMetadataDefinition({ - scope: `${scope}.subScope`, - name, - }) - - const values = { [scope]: null } + describe('like when key is null', () => { + const metadata = makeMetadata([key, subKey]) + const values = { [key]: null } it('should return null', () => { - expect(sut.get(metadataDefinition, values)).toBeNull() + expect(sut.get(metadata, values)).toBeNull() }) }) - describe('like when scope is not an object', () => { - const metadataDefinition = makeScopedMetadataDefinition({ scope }) + describe('like when value in key is not an object', () => { + const metadata = makeMetadata([key, subKey]) const values = { - [scope]: 42, + [key]: 42, } - testGlobalMayBeRetrieved(metadataDefinition, values) + testGlobalMayBeRetrieved(metadata, values) }) }) describe('when specific value is defined', () => { - describe('like when scope does not contain sub scopes', () => { - const metadataDefinition = makeScopedMetadataDefinition({ - scope, - name, - }) + describe('like when there is a key and sub key', () => { + const metadata = makeMetadata([key, subKey]) const values = { - [scope]: { - [name]: value, + [key]: { + [subKey]: value, }, } - it('should return value using scope and name as keys', () => { - expect(sut.get(metadataDefinition, values)).toEqual(value) + it('should return value using key and sub key as path', () => { + expect(sut.get(metadata, values)).toEqual(value) }) }) - describe('like when scope contains sub scopes', () => { - const subScope = 'subScope' - const metadataDefinition = makeScopedMetadataDefinition({ - scope: `${scope}.${subScope}`, - name, - }) - - const values = { - [scope]: { - [subScope]: { - [name]: value, - }, - }, - } - - it('should return value using sub scope, scope and name as keys', () => { - expect(sut.get(metadataDefinition, values)).toEqual(value) - }) - }) describe('and it is and object, and a global object exists too', () => { const valueObject = { value: 'value', prop: 'value' } const globalValueObject = { globalValue: 'globalValue', prop: 'globalValue', } - const metadataDefinition = makeScopedMetadataDefinition({ - scope, - name, - global, - }) - + const metadata = makeMetadata([key, subKey], global) const values = { [global]: globalValueObject, - [scope]: { - [name]: valueObject, + [key]: { + [subKey]: valueObject, }, } it('should merge both objects, with specific value taking priority', () => { - expect(sut.get(metadataDefinition, values)).toEqual({ + expect(sut.get(metadata, values)).toEqual({ ...globalValueObject, ...valueObject, }) diff --git a/projects/ngx-meta/src/core/src/metadata-json-resolver.ts b/projects/ngx-meta/src/core/src/metadata-json-resolver.ts index e89f9deb..f115e1a9 100644 --- a/projects/ngx-meta/src/core/src/metadata-json-resolver.ts +++ b/projects/ngx-meta/src/core/src/metadata-json-resolver.ts @@ -1,4 +1,4 @@ -import { MetadataDefinition } from './metadata-definition' +import { Metadata } from './metadata' import { MetadataValues } from './metadata-values' import { MaybeUndefined } from './maybe-undefined' import { isObject } from './is-object' @@ -6,10 +6,7 @@ import { Injectable } from '@angular/core' @Injectable({ providedIn: 'root' }) export class MetadataJsonResolver { - get( - definition: MetadataDefinition, - values?: MetadataValues, - ): T | undefined { + get(definition: Metadata, values?: MetadataValues): T | undefined { if (values === undefined) { return } diff --git a/projects/ngx-meta/src/core/src/metadata-provider.ts b/projects/ngx-meta/src/core/src/metadata-provider.ts new file mode 100644 index 00000000..d02c5d0e --- /dev/null +++ b/projects/ngx-meta/src/core/src/metadata-provider.ts @@ -0,0 +1,6 @@ +import { Metadata } from './metadata' + +export abstract class MetadataProvider { + abstract readonly metadata: Metadata + abstract set(value: Value | null): void +} diff --git a/projects/ngx-meta/src/core/src/metadata-registry.spec.ts b/projects/ngx-meta/src/core/src/metadata-registry.spec.ts index bc92f4b0..b2db3f07 100644 --- a/projects/ngx-meta/src/core/src/metadata-registry.spec.ts +++ b/projects/ngx-meta/src/core/src/metadata-registry.spec.ts @@ -1,59 +1,59 @@ import { MetadataRegistry } from './metadata-registry' import { TestBed } from '@angular/core/testing' -import { makeMetadata } from './__tests__/make-metadata' -import { Metadata } from './metadata' +import { makeMetadataProvider } from './__tests__/make-metadata-provider' +import { MetadataProvider } from './metadata-provider' import { MockProvider } from 'ng-mocks' describe('MetadataRegistry', () => { const dummyId = 'dummyId' - const dummyMetadata = makeMetadata({ id: dummyId }) + const dummyMetadataProvider = makeMetadataProvider({ id: dummyId }) it('should register metadata from DI system', () => { - const sut = makeSut({ metadata: [dummyMetadata] }) + const sut = makeSut({ metadataProviders: [dummyMetadataProvider] }) const allMetadata = [...sut.getAll()] expect(allMetadata).toHaveSize(1) - expect(allMetadata).toEqual([dummyMetadata]) + expect(allMetadata).toEqual([dummyMetadataProvider]) }) it('should register the given metadata', () => { const sut = makeSut() - sut.register(dummyMetadata) + sut.register(dummyMetadataProvider) const allMetadata = [...sut.getAll()] expect(allMetadata).toHaveSize(1) - expect(allMetadata).toEqual([dummyMetadata]) + expect(allMetadata).toEqual([dummyMetadataProvider]) }) it('should not register twice the same metadata', () => { - const sameDummyMetadata = makeMetadata({ + const sameDummyMetadataProvider = makeMetadataProvider({ id: dummyId, spyName: 'duplicated metadata set', }) const sut = makeSut() - sut.register(dummyMetadata) - sut.register(sameDummyMetadata) + sut.register(dummyMetadataProvider) + sut.register(sameDummyMetadataProvider) const allMetadata = [...sut.getAll()] expect(allMetadata).toHaveSize(1) - expect(allMetadata).toEqual([dummyMetadata]) + expect(allMetadata).toEqual([dummyMetadataProvider]) }) }) function makeSut( opts: { - metadata?: ReadonlyArray> + metadataProviders?: ReadonlyArray> } = {}, ) { TestBed.configureTestingModule({ providers: [ //👇 Mocking sut to ensure injected metadata calls registry function MetadataRegistry, - ...(opts.metadata - ? opts.metadata.map((metadata) => - MockProvider(Metadata, metadata, 'useValue', true), + ...(opts.metadataProviders + ? opts.metadataProviders.map((metadata) => + MockProvider(MetadataProvider, metadata, 'useValue', true), ) : []), ], diff --git a/projects/ngx-meta/src/core/src/metadata-registry.ts b/projects/ngx-meta/src/core/src/metadata-registry.ts index ed709aa7..e7a556e8 100644 --- a/projects/ngx-meta/src/core/src/metadata-registry.ts +++ b/projects/ngx-meta/src/core/src/metadata-registry.ts @@ -1,26 +1,28 @@ import { Inject, Injectable, Optional } from '@angular/core' -import { Metadata } from './metadata' +import { MetadataProvider } from './metadata-provider' @Injectable({ providedIn: 'root' }) export class MetadataRegistry { - private readonly byId = new Map>() + private readonly byId = new Map>() constructor( @Optional() - @Inject(Metadata) - private readonly injectedMetadata: ReadonlyArray> | null, + @Inject(MetadataProvider) + private readonly injectedProviders: ReadonlyArray< + MetadataProvider + > | null, ) { - this.injectedMetadata?.forEach((metadata) => this.register(metadata)) + this.injectedProviders?.forEach((metadata) => this.register(metadata)) } - register(metadata: Metadata) { - if (this.byId.has(metadata.definition.id)) { + register(provider: MetadataProvider) { + if (this.byId.has(provider.metadata.id)) { return } - this.byId.set(metadata.definition.id, metadata) + this.byId.set(provider.metadata.id, provider) } - getAll(): Iterable> { + getAll(): Iterable> { return this.byId.values() } } diff --git a/projects/ngx-meta/src/core/src/metadata-resolver.spec.ts b/projects/ngx-meta/src/core/src/metadata-resolver.spec.ts index e713cf6a..9e278466 100644 --- a/projects/ngx-meta/src/core/src/metadata-resolver.spec.ts +++ b/projects/ngx-meta/src/core/src/metadata-resolver.spec.ts @@ -6,21 +6,21 @@ import { MockProviders } from 'ng-mocks' import { enableAutoSpy } from '../../__tests__/enable-auto-spy' import { MetadataJsonResolver } from './metadata-json-resolver' import { RouteMetadataValues } from './route-metadata-values' -import { MetadataDefinition } from './metadata-definition' +import { Metadata } from './metadata' import { MetadataValues } from './metadata-values' -import { makeGlobalMetadataDefinition } from './__tests__/make-global-metadata-definition' import { MaybeUndefined } from './maybe-undefined' +import { makeGlobalMetadata } from './make-global-metadata' describe('MetadataResolver', () => { enableAutoSpy() let sut: MetadataResolver - let dummyMetadataDefinition: MetadataDefinition + let dummyMetadata: Metadata let jsonResolver: jasmine.SpyObj let routeMetadataValues: jasmine.SpyObj let defaultsService: jasmine.SpyObj beforeEach(() => { - dummyMetadataDefinition = makeGlobalMetadataDefinition() + dummyMetadata = makeGlobalMetadata('dummy') sut = makeSut() jsonResolver = TestBed.inject( MetadataJsonResolver, @@ -35,7 +35,7 @@ describe('MetadataResolver', () => { function mockJsonResolver(returnMap: Map) { jsonResolver.get.and.callFake( - (def: MetadataDefinition, values: MetadataValues) => + (metadata: Metadata, values: MetadataValues) => returnMap.get(values) as MaybeUndefined, ) } @@ -56,16 +56,16 @@ describe('MetadataResolver', () => { }) it('should resolve value using values', () => { - sut.get(dummyMetadataDefinition, dummyValues) + sut.get(dummyMetadata, dummyValues) expect(jsonResolver.get).toHaveBeenCalledWith( - dummyMetadataDefinition, + dummyMetadata, dummyValues, ) }) it('should return its value', () => { - expect(sut.get(dummyMetadataDefinition, dummyValues)).toEqual(value) + expect(sut.get(dummyMetadata, dummyValues)).toEqual(value) }) }) @@ -76,17 +76,17 @@ describe('MetadataResolver', () => { }) it('should resolve value using route metadata values', () => { - sut.get(dummyMetadataDefinition, dummyValues) + sut.get(dummyMetadata, dummyValues) expect(routeMetadataValues.get).toHaveBeenCalledOnceWith() expect(jsonResolver.get).toHaveBeenCalledWith( - dummyMetadataDefinition, + dummyMetadata, routeValues, ) }) it('should return value obtained from route metadata values', () => { - expect(sut.get(dummyMetadataDefinition, dummyValues)).toEqual(value) + expect(sut.get(dummyMetadata, dummyValues)).toEqual(value) }) }) @@ -97,17 +97,17 @@ describe('MetadataResolver', () => { }) it('should resolve value using default values', () => { - sut.get(dummyMetadataDefinition, dummyValues) + sut.get(dummyMetadata, dummyValues) expect(defaultsService.get).toHaveBeenCalledOnceWith() expect(jsonResolver.get).toHaveBeenCalledWith( - dummyMetadataDefinition, + dummyMetadata, defaultValues, ) }) it('should return value obtained from defaults', () => { - expect(sut.get(dummyMetadataDefinition, dummyValues)).toEqual(value) + expect(sut.get(dummyMetadata, dummyValues)).toEqual(value) }) }) @@ -129,7 +129,7 @@ describe('MetadataResolver', () => { }) it('should return the merged object, with value props having more priority', () => { - expect(sut.get(dummyMetadataDefinition, dummyValues)).toEqual({ + expect(sut.get(dummyMetadata, dummyValues)).toEqual({ ...routeValueObject, ...valueObject, }) @@ -141,29 +141,23 @@ describe('MetadataResolver', () => { beforeEach(() => { routeMetadataValues.get.and.returnValue(routeValues) - jsonResolver.get.and.callFake( - (def: MetadataDefinition, values: MetadataValues) => { - switch (values) { - case routeValues: - return routeValue as T - case values: - return value as T - default: - throw new Error('Unexpected values, cannot mock') - } - }, + mockJsonResolver( + new Map([ + [routeValues, routeValue], + [dummyValues, value], + ]), ) }) it('should return value from values object', () => { - expect(sut.get(dummyMetadataDefinition, dummyValues)).toEqual(value) + expect(sut.get(dummyMetadata, dummyValues)).toEqual(value) }) }) }) describe('when neither value, route value or default value exists', () => { it('should return nothing', () => { - expect(sut.get(dummyMetadataDefinition, dummyValues)).toBeUndefined() + expect(sut.get(dummyMetadata, dummyValues)).toBeUndefined() }) }) }) diff --git a/projects/ngx-meta/src/core/src/metadata-resolver.ts b/projects/ngx-meta/src/core/src/metadata-resolver.ts index 51be6dbf..3b43fbc0 100644 --- a/projects/ngx-meta/src/core/src/metadata-resolver.ts +++ b/projects/ngx-meta/src/core/src/metadata-resolver.ts @@ -4,7 +4,7 @@ import { MetadataJsonResolver } from './metadata-json-resolver' import { MetadataValues } from './metadata-values' import { RouteMetadataValues } from './route-metadata-values' import { isObject } from './is-object' -import { MetadataDefinition } from './metadata-definition' +import { Metadata } from './metadata' import { MaybeUndefined } from './maybe-undefined' @Injectable({ providedIn: 'root' }) @@ -15,17 +15,14 @@ export class MetadataResolver { private readonly defaultsService: DefaultsService, ) {} - get( - metadataDefinition: MetadataDefinition, - values: MetadataValues, - ): T | undefined { - const value = this.jsonResolver.get(metadataDefinition, values) + get(metadata: Metadata, values: MetadataValues): T | undefined { + const value = this.jsonResolver.get(metadata, values) const routeValue = this.jsonResolver.get( - metadataDefinition, + metadata, this.routeMetadataValues.get(), ) const defaultValue = this.jsonResolver.get( - metadataDefinition, + metadata, this.defaultsService.get(), ) const effectiveValue = diff --git a/projects/ngx-meta/src/core/src/metadata.service.spec.ts b/projects/ngx-meta/src/core/src/metadata.service.spec.ts index 35abbddd..a2a3c9cc 100644 --- a/projects/ngx-meta/src/core/src/metadata.service.spec.ts +++ b/projects/ngx-meta/src/core/src/metadata.service.spec.ts @@ -1,13 +1,13 @@ import { TestBed } from '@angular/core/testing' import { MetadataService } from './metadata.service' import { MockProviders } from 'ng-mocks' -import { makeMetadata } from './__tests__/make-metadata' +import { makeMetadataProvider } from './__tests__/make-metadata-provider' import { enableAutoSpy } from '../../__tests__/enable-auto-spy' import { MetadataResolver } from './metadata-resolver' import { RouteMetadataValues } from './route-metadata-values' import { MetadataRegistry } from './metadata-registry' import { MaybeUndefined } from './maybe-undefined' -import { MetadataDefinition } from './metadata-definition' +import { Metadata } from './metadata' describe('MetadataService', () => { enableAutoSpy() @@ -22,12 +22,15 @@ describe('MetadataService', () => { }) describe('set', () => { - const firstMetadata = makeMetadata({ id: 'first' }) - const secondMetadata = makeMetadata({ id: 'second' }) + const firstMetadataProvider = makeMetadataProvider({ id: 'first' }) + const secondMetadataProvider = makeMetadataProvider({ id: 'second' }) const dummyValues = {} beforeEach(() => { - metadataRegistry.getAll.and.returnValue([firstMetadata, secondMetadata]) + metadataRegistry.getAll.and.returnValue([ + firstMetadataProvider, + secondMetadataProvider, + ]) }) it('should set each metadata using resolved values', () => { @@ -36,14 +39,14 @@ describe('MetadataService', () => { ) as unknown as jasmine.SpyObj const dummyFirstMetadataValue = 'firstMetadataValue' const dummySecondMetadataValue = 'secondMetadataValue' - resolver.get.and.callFake((definition: MetadataDefinition) => { + resolver.get.and.callFake((definition: Metadata) => { switch (definition) { - case firstMetadata.definition: + case firstMetadataProvider.metadata: return dummyFirstMetadataValue as MaybeUndefined - case secondMetadata.definition: + case secondMetadataProvider.metadata: return dummySecondMetadataValue as MaybeUndefined default: - throw new Error('Unexpected metadata definition') + throw new Error('Unexpected metadata') } }) sut.set(dummyValues) @@ -51,15 +54,19 @@ describe('MetadataService', () => { expect(metadataRegistry.getAll).toHaveBeenCalledOnceWith() expect(resolver.get).toHaveBeenCalledTimes(2) expect(resolver.get).toHaveBeenCalledWith( - firstMetadata.definition, + firstMetadataProvider.metadata, dummyValues, ) - expect(firstMetadata.set).toHaveBeenCalledWith(dummyFirstMetadataValue) + expect(firstMetadataProvider.set).toHaveBeenCalledWith( + dummyFirstMetadataValue, + ) expect(resolver.get).toHaveBeenCalledWith( - secondMetadata.definition, + secondMetadataProvider.metadata, dummyValues, ) - expect(secondMetadata.set).toHaveBeenCalledWith(dummySecondMetadataValue) + expect(secondMetadataProvider.set).toHaveBeenCalledWith( + dummySecondMetadataValue, + ) }) it('should set values for route when finished', () => { diff --git a/projects/ngx-meta/src/core/src/metadata.service.ts b/projects/ngx-meta/src/core/src/metadata.service.ts index 3d77a1b4..8e690aa8 100644 --- a/projects/ngx-meta/src/core/src/metadata.service.ts +++ b/projects/ngx-meta/src/core/src/metadata.service.ts @@ -15,7 +15,7 @@ export class MetadataService { public set(values: MetadataValues = {}): void { const allMetadata = this.registry.getAll() for (const metadata of allMetadata) { - metadata.set(this.resolver.get(metadata.definition, values)) + metadata.set(this.resolver.get(metadata.metadata, values)) } this.routeValues.set(values) } diff --git a/projects/ngx-meta/src/core/src/metadata.ts b/projects/ngx-meta/src/core/src/metadata.ts index 295db1d5..d35469c4 100644 --- a/projects/ngx-meta/src/core/src/metadata.ts +++ b/projects/ngx-meta/src/core/src/metadata.ts @@ -1,6 +1,5 @@ -import { MetadataDefinition } from './metadata-definition' - -export abstract class Metadata { - abstract readonly definition: MetadataDefinition - abstract set(value: Value | null): void +export interface Metadata { + readonly id: string + readonly jsonPath: ReadonlyArray + readonly global?: Global } diff --git a/projects/ngx-meta/src/core/src/provide-metadata-factory.ts b/projects/ngx-meta/src/core/src/provide-metadata-factory.ts index 0fc19dd4..220a2fce 100644 --- a/projects/ngx-meta/src/core/src/provide-metadata-factory.ts +++ b/projects/ngx-meta/src/core/src/provide-metadata-factory.ts @@ -1,32 +1,30 @@ -import { Metadata } from './metadata' +import { MetadataProvider } from './metadata-provider' import { FactoryProvider } from '@angular/core' -import { MetadataDefinition } from './metadata-definition' +import { Metadata } from './metadata' import { MetadataSetter } from './metadata-setter' export type MetadataSetterFactory = ( ...deps: Exclude ) => MetadataSetter -const makeMetadata = ( - definition: MetadataDefinition, +const makeMetadataProvider = ( + metadata: Metadata, set: MetadataSetter, -): Metadata => { - return { - definition, - set, - } -} +): MetadataProvider => ({ + metadata, + set, +}) export function provideMetadataFactory( - definition: MetadataDefinition, + definition: Metadata, setterFactory: MetadataSetterFactory, deps?: FactoryProvider['deps'], ): FactoryProvider { return { - provide: Metadata, + provide: MetadataProvider, multi: true, useFactory: (...deps: unknown[]) => - makeMetadata(definition, setterFactory(...deps)), + makeMetadataProvider(definition, setterFactory(...deps)), deps, } } diff --git a/projects/ngx-meta/src/core/src/provide-metadata.ts b/projects/ngx-meta/src/core/src/provide-metadata.ts deleted file mode 100644 index 9780b940..00000000 --- a/projects/ngx-meta/src/core/src/provide-metadata.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Metadata } from './metadata' -import { Provider, Type } from '@angular/core' - -export function provideMetadata>>( - klass: M, -): Provider { - return { - provide: Metadata, - useClass: klass, - multi: true, - } -} diff --git a/projects/ngx-meta/src/core/src/scoped-metadata-definition.spec.ts b/projects/ngx-meta/src/core/src/scoped-metadata-definition.spec.ts deleted file mode 100644 index 1bf001d8..00000000 --- a/projects/ngx-meta/src/core/src/scoped-metadata-definition.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ScopedMetadataDefinition } from './scoped-metadata-definition' - -describe('ScopedMetadataDefinition', () => { - const scope = 'scope' - const name = 'name' - - describe('id', () => { - it('should return scope and name joined by a dot', () => { - const sut = new ScopedMetadataDefinition(scope, name) - - expect(sut.id).toEqual(`${scope}.${name}`) - }) - }) - - describe('jsonPath', () => { - it('should return scope split by dots and name', () => { - const outerScope = 'outerScope' - const midScope = 'midScope' - const innerScope = 'innerScope' - const sut = new ScopedMetadataDefinition( - `${outerScope}.${midScope}.${innerScope}`, - name, - ) - - expect(sut.jsonPath).toEqual([outerScope, midScope, innerScope, name]) - }) - }) -}) diff --git a/projects/ngx-meta/src/core/src/scoped-metadata-definition.ts b/projects/ngx-meta/src/core/src/scoped-metadata-definition.ts deleted file mode 100644 index 4ca94d50..00000000 --- a/projects/ngx-meta/src/core/src/scoped-metadata-definition.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MetadataDefinition } from './metadata-definition' - -export class ScopedMetadataDefinition< - Scope extends string = string, - Name extends string = string, - Global extends string = string, -> implements MetadataDefinition -{ - constructor( - public readonly scope: Scope, - public readonly name: Name, - public readonly global?: Global, - ) {} - - public get id() { - return [this.scope, this.name].join(SEPARATOR) - } - - public get jsonPath(): ReadonlyArray { - return [...this.scope.split(SEPARATOR), this.name] - } -} - -const SEPARATOR = '.' diff --git a/projects/ngx-meta/src/json-ld/src/json-ld-metadata-provider.ts b/projects/ngx-meta/src/json-ld/src/json-ld-metadata-provider.ts index 034cdf02..4ecfaa37 100644 --- a/projects/ngx-meta/src/json-ld/src/json-ld-metadata-provider.ts +++ b/projects/ngx-meta/src/json-ld/src/json-ld-metadata-provider.ts @@ -1,7 +1,7 @@ import { DOCUMENT } from '@angular/common' import { GlobalMetadata, - GlobalMetadataDefinition, + makeGlobalMetadata, MetadataSetterFactory, provideMetadataFactory, } from '@davidlj95/ngx-meta/core' @@ -30,7 +30,7 @@ export const JSON_LD_METADATA_SETTER_FACTORY: MetadataSetterFactory< } export const JSON_LD_METADATA_PROVIDER = provideMetadataFactory( - new GlobalMetadataDefinition('jsonLd'), + makeGlobalMetadata('jsonLd'), JSON_LD_METADATA_SETTER_FACTORY, [DOCUMENT], ) diff --git a/projects/ngx-meta/src/open-graph-profile/src/make-open-graph-profile-metadata-provider.ts b/projects/ngx-meta/src/open-graph-profile/src/make-open-graph-profile-metadata-provider.ts index dd6a1c6f..85fa8ca1 100644 --- a/projects/ngx-meta/src/open-graph-profile/src/make-open-graph-profile-metadata-provider.ts +++ b/projects/ngx-meta/src/open-graph-profile/src/make-open-graph-profile-metadata-provider.ts @@ -1,12 +1,16 @@ import { + makeMetadata, MetaService, provideMetadataFactory, StringKeyOf, } from '@davidlj95/ngx-meta/core' import { FactoryProvider } from '@angular/core' -import { OpenGraphProfileMetadataDefinition } from './open-graph-profile-metadata-definition' import { OpenGraphProfileMetaProperty } from './open-graph-profile-meta-property' import { OpenGraphProfile } from './open-graph-profile' +import { OpenGraphProfileMetadata } from './open-graph-profile-metadata' + +const OG_KEY: keyof OpenGraphProfileMetadata = 'openGraph' +const KEY: keyof OpenGraphProfileMetadata[typeof OG_KEY] = 'profile' export const makeOpenGraphProfileMetadataProvider = < Key extends StringKeyOf, @@ -18,7 +22,7 @@ export const makeOpenGraphProfileMetadataProvider = < } = {}, ): FactoryProvider => provideMetadataFactory( - new OpenGraphProfileMetadataDefinition(key), + makeMetadata([OG_KEY, KEY, key]), (metaService) => (value: OpenGraphProfile[typeof key]) => metaService.set(new OpenGraphProfileMetaProperty(opts.p ?? key), value), [MetaService], diff --git a/projects/ngx-meta/src/open-graph-profile/src/open-graph-profile-metadata-definition.ts b/projects/ngx-meta/src/open-graph-profile/src/open-graph-profile-metadata-definition.ts deleted file mode 100644 index 775b942e..00000000 --- a/projects/ngx-meta/src/open-graph-profile/src/open-graph-profile-metadata-definition.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ScopedMetadataDefinition } from '@davidlj95/ngx-meta/core' -import { OpenGraphProfileMetadata } from './open-graph-profile-metadata' - -export const OG_SCOPE: keyof OpenGraphProfileMetadata = 'openGraph' -const SCOPE: keyof OpenGraphProfileMetadata[typeof OG_SCOPE] = 'profile' - -export class OpenGraphProfileMetadataDefinition extends ScopedMetadataDefinition { - constructor(name: string, global?: string) { - super(`${OG_SCOPE}.${SCOPE}`, name, global) - } -} diff --git a/projects/ngx-meta/src/open-graph/src/make-open-graph-metadata-provider.ts b/projects/ngx-meta/src/open-graph/src/make-open-graph-metadata-provider.ts index 7dc619e4..f716b410 100644 --- a/projects/ngx-meta/src/open-graph/src/make-open-graph-metadata-provider.ts +++ b/projects/ngx-meta/src/open-graph/src/make-open-graph-metadata-provider.ts @@ -1,5 +1,6 @@ import { GlobalMetadataKey, + makeMetadata, MetadataSetterFactory, MetaService, provideMetadataFactory, @@ -7,8 +8,10 @@ import { } from '@davidlj95/ngx-meta/core' import { OpenGraph } from './open-graph' import { FactoryProvider } from '@angular/core' -import { OpenGraphMetadataDefinition } from './open-graph-metadata-definition' import { OpenGraphMetaProperty } from './open-graph-meta-property' +import { OpenGraphMetadata } from './open-graph-metadata' + +const KEY: keyof OpenGraphMetadata = 'openGraph' export const makeOpenGraphMetadataProvider = < Key extends StringKeyOf, @@ -24,7 +27,7 @@ export const makeOpenGraphMetadataProvider = < } = {}, ): FactoryProvider => provideMetadataFactory( - new OpenGraphMetadataDefinition(key, opts.g), + makeMetadata([KEY, key], opts.g), opts.s ?? ((metaService) => (value: OpenGraph[typeof key]) => metaService.set(new OpenGraphMetaProperty(opts.p ?? key), value)), diff --git a/projects/ngx-meta/src/open-graph/src/open-graph-metadata-definition.ts b/projects/ngx-meta/src/open-graph/src/open-graph-metadata-definition.ts deleted file mode 100644 index 0cdbfb24..00000000 --- a/projects/ngx-meta/src/open-graph/src/open-graph-metadata-definition.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ScopedMetadataDefinition } from '@davidlj95/ngx-meta/core' -import { OpenGraphMetadata } from './open-graph-metadata' - -const SCOPE: keyof OpenGraphMetadata = 'openGraph' - -export class OpenGraphMetadataDefinition extends ScopedMetadataDefinition { - constructor(name: string, global?: string) { - super(SCOPE, name, global) - } -} diff --git a/projects/ngx-meta/src/open-graph/src/open-graph-scope.ts b/projects/ngx-meta/src/open-graph/src/open-graph-scope.ts deleted file mode 100644 index fa5f794d..00000000 --- a/projects/ngx-meta/src/open-graph/src/open-graph-scope.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { OpenGraphMetadataRouteData } from './open-graph-metadata' - -export const OPEN_GRAPH_SCOPE: keyof OpenGraphMetadataRouteData['meta'] = - 'openGraph' diff --git a/projects/ngx-meta/src/standard/src/make-standard-metadata-provider.ts b/projects/ngx-meta/src/standard/src/make-standard-metadata-provider.ts index 7d4c80fc..92697d86 100644 --- a/projects/ngx-meta/src/standard/src/make-standard-metadata-provider.ts +++ b/projects/ngx-meta/src/standard/src/make-standard-metadata-provider.ts @@ -1,5 +1,6 @@ import { GlobalMetadataKey, + makeMetadata, MetadataSetterFactory, MetaService, provideMetadataFactory, @@ -7,8 +8,10 @@ import { } from '@davidlj95/ngx-meta/core' import { FactoryProvider } from '@angular/core' import { Standard } from './standard' -import { StandardMetadataDefinition } from './standard-metadata-definition' import { StandardMetaProperty } from './standard-meta-property' +import { StandardMetadata } from './standard-metadata' + +const KEY: keyof StandardMetadata = 'standard' export const makeStandardMetadataProvider = >( key: Key, @@ -24,7 +27,7 @@ export const makeStandardMetadataProvider = >( } = {}, ): FactoryProvider => provideMetadataFactory( - new StandardMetadataDefinition(key, opts.g), + makeMetadata([KEY, key], opts.g), opts.s ?? ((metaService) => (value: Standard[typeof key]) => metaService.set(new StandardMetaProperty(opts.n ?? key), value)), diff --git a/projects/ngx-meta/src/standard/src/standard-metadata-definition.ts b/projects/ngx-meta/src/standard/src/standard-metadata-definition.ts deleted file mode 100644 index 653a84b0..00000000 --- a/projects/ngx-meta/src/standard/src/standard-metadata-definition.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ScopedMetadataDefinition } from '@davidlj95/ngx-meta/core' -import { StandardMetadata } from './standard-metadata' - -const SCOPE: keyof StandardMetadata = 'standard' - -export class StandardMetadataDefinition extends ScopedMetadataDefinition { - constructor(name: string, global?: string) { - super(SCOPE, name, global) - } -} diff --git a/projects/ngx-meta/src/twitter-card/src/make-twitter-card-metadata-provider.ts b/projects/ngx-meta/src/twitter-card/src/make-twitter-card-metadata-provider.ts index 46039e65..8ada98ce 100644 --- a/projects/ngx-meta/src/twitter-card/src/make-twitter-card-metadata-provider.ts +++ b/projects/ngx-meta/src/twitter-card/src/make-twitter-card-metadata-provider.ts @@ -1,5 +1,6 @@ import { GlobalMetadataKey, + makeMetadata, MetadataSetterFactory, MetaService, provideMetadataFactory, @@ -7,8 +8,10 @@ import { } from '@davidlj95/ngx-meta/core' import { FactoryProvider } from '@angular/core' import { TwitterCard } from './twitter-card' -import { TwitterCardMetadataDefinition } from './twitter-card-metadata-definition' import { TwitterCardMetaProperty } from './twitter-card-meta-property' +import { TwitterCardMetadata } from './twitter-card-metadata' + +const KEY: keyof TwitterCardMetadata = 'twitterCard' export const makeTwitterCardMetadataProvider = < Key extends StringKeyOf, @@ -24,7 +27,7 @@ export const makeTwitterCardMetadataProvider = < } = {}, ): FactoryProvider => provideMetadataFactory( - new TwitterCardMetadataDefinition(key, opts.g), + makeMetadata([KEY, key], opts.g), opts.s ?? ((metaService) => (value: TwitterCard[typeof key]) => metaService.set(new TwitterCardMetaProperty(opts.p ?? key), value)), diff --git a/projects/ngx-meta/src/twitter-card/src/twitter-card-metadata-definition.ts b/projects/ngx-meta/src/twitter-card/src/twitter-card-metadata-definition.ts deleted file mode 100644 index 0446e2fe..00000000 --- a/projects/ngx-meta/src/twitter-card/src/twitter-card-metadata-definition.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ScopedMetadataDefinition } from '@davidlj95/ngx-meta/core' -import { TwitterCardMetadata } from './twitter-card-metadata' - -const SCOPE: keyof TwitterCardMetadata = 'twitterCard' - -export class TwitterCardMetadataDefinition extends ScopedMetadataDefinition { - constructor(name: string, global?: string) { - super(SCOPE, name, global) - } -}