diff --git a/projects/ngx-meta/schematics/ng-add/index.spec.ts b/projects/ngx-meta/schematics/ng-add/index.spec.ts index e9bd1554..976458de 100644 --- a/projects/ngx-meta/schematics/ng-add/index.spec.ts +++ b/projects/ngx-meta/schematics/ng-add/index.spec.ts @@ -2,7 +2,7 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing' import { Tree } from '@angular-devkit/schematics' import { beforeEach, describe } from '@jest/globals' import { join } from 'path' -import { Schema as NgAddSchema } from './schema' +import { MetadataModules, Schema as NgAddSchema } from './schema' import { ProviderTestCase } from './testing/provider-test-case' import { createTestApp } from '../testing/create-test-app' import { shouldAddRootProvider } from './testing/should-add-root-provider' @@ -35,6 +35,36 @@ describe('ng-add schematic', () => { name: 'routing', symbol: 'provideNgxMetaRouting', }) + const PROVIDERS_BY_MODULE_NAME: { + // 👇 With this type we ensure that all possible types are tested + // If we miss one, the type will be incomplete + [K in MetadataModules]: ProviderTestCase + } = { + 'json-ld': new ProviderTestCase({ + name: 'JSON-LD', + symbol: 'provideNgxMetaJsonLd', + entrypoint: 'json-ld', + }), + 'open-graph': new ProviderTestCase({ + name: 'Open Graph', + symbol: 'provideNgxMetaOpenGraph', + entrypoint: 'open-graph', + }), + 'open-graph-profile': new ProviderTestCase({ + name: 'Open Graph (profile)', + symbol: 'provideNgxMetaOpenGraphProfile', + entrypoint: 'open-graph', + }), + standard: new ProviderTestCase({ + name: 'standard', + symbol: 'provideNgxMetaStandard', + }), + 'twitter-card': new ProviderTestCase({ + name: 'Twitter Card', + symbol: 'provideNgxMetaTwitterCard', + entrypoint: 'twitter-card', + }), + } ;([true, false] as const).forEach((standalone) => { const appKind = standalone ? 'standalone' : 'module-based' @@ -59,6 +89,9 @@ describe('ng-add schematic', () => { shouldAddRootProvider(CORE_PROVIDER, () => tree, standalone) shouldNotAddRootProvider(ROUTING_PROVIDER, () => tree, standalone) + Object.values(PROVIDERS_BY_MODULE_NAME).forEach((provider) => { + shouldNotAddRootProvider(provider, () => tree, standalone) + }) }) ;[true, false].forEach((routing) => { describe(`when routing option is ${routing}`, () => { @@ -77,6 +110,27 @@ describe('ng-add schematic', () => { : shouldNotAddRootProvider(ROUTING_PROVIDER, () => tree, standalone) }) }) + Object.keys(PROVIDERS_BY_MODULE_NAME).forEach( + (metadataModule: MetadataModules) => { + describe(`when metadata module option contains '${metadataModule}'`, () => { + let tree: Tree + + beforeEach(async () => { + tree = await runner.runSchematic>( + SCHEMATIC_NAME, + { ...defaultOptions, metadataModules: [metadataModule] }, + appTree, + ) + }) + + shouldAddRootProvider( + PROVIDERS_BY_MODULE_NAME[metadataModule], + () => tree, + standalone, + ) + }) + }, + ) }) }) }) diff --git a/projects/ngx-meta/schematics/ng-add/index.ts b/projects/ngx-meta/schematics/ng-add/index.ts index b2255ea3..970fa37f 100644 --- a/projects/ngx-meta/schematics/ng-add/index.ts +++ b/projects/ngx-meta/schematics/ng-add/index.ts @@ -1,23 +1,31 @@ import { chain, noop, Rule } from '@angular-devkit/schematics' import { addRootProvider } from '@schematics/angular/utility' -import { Schema } from './schema' +import { MetadataModules, Schema } from './schema' import { classify } from '@angular-devkit/core/src/utils/strings' +const ENTRYPOINTS = new Set([ + 'json-ld', + 'open-graph', + 'standard', + 'twitter-card', +]) // noinspection JSUnusedGlobalSymbols (actually used in `collection.json`) export function ngAdd(options: Schema): Rule { - const maybeAddNgxMetaRootProvider = (name?: string): Rule => { - if (!name) { - return noop() - } + const addNgxMetaRootProvider = (name: string): Rule => { + const entrypoint = + [...ENTRYPOINTS].find((entrypoint) => name.startsWith(entrypoint)) ?? name return addRootProvider( options.project, ({ code, external }) => - code`${external(`provideNgxMeta${classify(name)}`, `@davidlj95/ngx-meta/${name}`)}()`, + code`${external(`provideNgxMeta${classify(name)}`, `@davidlj95/ngx-meta/${entrypoint}`)}()`, ) } return chain([ - maybeAddNgxMetaRootProvider('core'), - maybeAddNgxMetaRootProvider(options.routing ? 'routing' : undefined), + addNgxMetaRootProvider('core'), + options.routing ? addNgxMetaRootProvider('routing') : noop(), + ...options.metadataModules.map((metadataModule) => + addNgxMetaRootProvider(metadataModule), + ), ]) } diff --git a/projects/ngx-meta/schematics/ng-add/schema.json b/projects/ngx-meta/schematics/ng-add/schema.json index 7d3f4f76..be9720ab 100644 --- a/projects/ngx-meta/schematics/ng-add/schema.json +++ b/projects/ngx-meta/schematics/ng-add/schema.json @@ -17,6 +17,38 @@ "default": false, "//todo": "Enable x-prompts for this and metadata modules to include when both are ready", "//x-prompt": "Would you like to provide metadata in Angular routes' data?" + }, + "metadataModules": { + "type": "array", + "description": "Built-in metadata modules to use", + "default": [], + "//todo": "Enable x-prompts for this and metadata modules to include when both are ready", + "//x-prompt": { + "type": "list", + "message": "What metadata would you like to set?", + "items": [ + { + "label": "JSON-LD [ https://ngx-meta.dev/built-in-modules/json-ld/ ]", + "value": "json-ld" + }, + { + "label": "Open Graph [ https://ngx-meta.dev/built-in-modules/open-graph/ ]", + "value": "open-graph" + }, + { + "label": "Open Graph's profile [ https://ngx-meta.dev/built-in-modules/open-graph/#profile ]", + "value": "open-graph-profile" + }, + { + "label": "Standard [ https://ngx-meta.dev/built-in-modules/standard/ ]", + "value": "standard" + }, + { + "label": "Twitter Card [ https://ngx-meta.dev/built-in-modules/twitter-cards/ ]", + "value": "twitter-card" + } + ] + } } }, "required": [] diff --git a/projects/ngx-meta/schematics/ng-add/schema.ts b/projects/ngx-meta/schematics/ng-add/schema.ts index a3da68f4..e1c5f7d5 100644 --- a/projects/ngx-meta/schematics/ng-add/schema.ts +++ b/projects/ngx-meta/schematics/ng-add/schema.ts @@ -1,4 +1,12 @@ export interface Schema { project: string routing: boolean + metadataModules: ReadonlyArray } + +export type MetadataModules = + | 'json-ld' + | 'open-graph' + | 'open-graph-profile' + | 'standard' + | 'twitter-card' diff --git a/projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts b/projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts index 76b8ef1b..7be6b403 100644 --- a/projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts +++ b/projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts @@ -17,7 +17,7 @@ export const shouldAddRootProvider = ( standalone, ) expect(appConfigOrAppModuleContents).toContain( - `import { ${providerTestCase.symbol} } from '${LIB_NAME}/${providerTestCase.entrypoint}`, + `import { ${providerTestCase.symbol} } from '${LIB_NAME}/${providerTestCase.entrypoint}'`, ) expect(stripWhitespace(appConfigOrAppModuleContents)).toMatch( new RegExp(`providers:\\[.*${regexpEscape(providerTestCase.code)}.*]`),