diff --git a/packages/docs/tools/inversify-code-examples/package.json b/packages/docs/tools/inversify-code-examples/package.json index c0a03e53..75e48577 100644 --- a/packages/docs/tools/inversify-code-examples/package.json +++ b/packages/docs/tools/inversify-code-examples/package.json @@ -5,7 +5,8 @@ }, "description": "InversifyJs docs code examples package", "dependencies": { - "inversify": "6.2.1" + "inversify": "6.2.1", + "inversify7": "npm:inversify@7.0.0-alpha.0" }, "devDependencies": { "@eslint/js": "9.18.0", diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingOnSyntaxApiOnActivation.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingOnSyntaxApiOnActivation.ts new file mode 100644 index 00000000..2105850b --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingOnSyntaxApiOnActivation.ts @@ -0,0 +1,36 @@ +import { Container, injectable, ResolutionContext } from 'inversify7'; + +const container: Container = new Container(); + +// Begin-example +@injectable() +class Katana { + public use(): string { + return 'hit!'; + } +} + +container + .bind('Katana') + .to(Katana) + .onActivation((_context: ResolutionContext, katana: Katana) => { + const handler: ProxyHandler<() => string> = { + apply: function ( + target: () => string, + thisArgument: unknown, + argumentsList: [], + ) { + console.log(`Starting: ${new Date().getTime().toString()}`); + const result: string = target.apply(thisArgument, argumentsList); + console.log(`Finished: ${new Date().getTime().toString()}`); + return result; + }, + }; + + katana.use = new Proxy(katana.use.bind(katana), handler); + + return katana; + }); +// End-example + +export { container, Katana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeRequest.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeRequest.int.spec.ts new file mode 100644 index 00000000..e752a2f0 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeRequest.int.spec.ts @@ -0,0 +1,10 @@ +import { describe, expect, it } from '@jest/globals'; + +import { isSameKatana, warriorHasSameKatana } from './bindingScopeRequest'; + +describe('BindingInSyntax API (inSingletonScope)', () => { + it('should provide same Katana', () => { + expect(isSameKatana).toBe(false); + expect(warriorHasSameKatana).toBe(true); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeRequest.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeRequest.ts new file mode 100644 index 00000000..e9e526fa --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeRequest.ts @@ -0,0 +1,38 @@ +import { Container, inject } from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +// Begin-example +export class LegendaryWarrior { + constructor( + @inject('Weapon') public readonly firstWeapon: Weapon, + @inject('Weapon') public readonly secondWeapon: Weapon, + @inject('Weapon') public readonly thirdWeapon: Weapon, + ) {} +} + +const container: Container = new Container(); +container.bind('Weapon').to(Katana).inRequestScope(); +container.bind(LegendaryWarrior).toSelf(); + +const firstKatana: Weapon = container.get('Weapon'); +const secondKatana: Weapon = container.get('Weapon'); + +const legendaryWarrior: LegendaryWarrior = container.get(LegendaryWarrior); + +// Returns false +const isSameKatana: boolean = firstKatana === secondKatana; + +// Returns true +const warriorHasSameKatana: boolean = + legendaryWarrior.firstWeapon === legendaryWarrior.secondWeapon && + legendaryWarrior.secondWeapon === legendaryWarrior.thirdWeapon; +// End-example + +export { isSameKatana, warriorHasSameKatana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeSingleton.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeSingleton.int.spec.ts new file mode 100644 index 00000000..4e4d9242 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeSingleton.int.spec.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from '@jest/globals'; + +import { isSameKatana } from './bindingScopeSingleton'; + +describe('BindingInSyntax API (inSingletonScope)', () => { + it('should provide same Katana', () => { + expect(isSameKatana).toBe(true); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeSingleton.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeSingleton.ts new file mode 100644 index 00000000..498f0457 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeSingleton.ts @@ -0,0 +1,22 @@ +import { Container } from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +// Begin-example +const container: Container = new Container(); +container.bind('Weapon').to(Katana).inSingletonScope(); + +const firstKatana: Weapon = container.get('Weapon'); +const secondKatana: Weapon = container.get('Weapon'); + +// Returns true +const isSameKatana: boolean = firstKatana === secondKatana; +// End-example + +export { isSameKatana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeTransient.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeTransient.int.spec.ts new file mode 100644 index 00000000..57c651c0 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeTransient.int.spec.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from '@jest/globals'; + +import { isSameKatana } from './bindingScopeTransient'; + +describe('BindingInSyntax API (inTransientScope)', () => { + it('should provide same Katana', () => { + expect(isSameKatana).toBe(false); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeTransient.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeTransient.ts new file mode 100644 index 00000000..35519d7c --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingScopeTransient.ts @@ -0,0 +1,22 @@ +import { Container } from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +// Begin-example +const container: Container = new Container(); +container.bind('Weapon').to(Katana).inTransientScope(); + +const firstKatana: Weapon = container.get('Weapon'); +const secondKatana: Weapon = container.get('Weapon'); + +// Returns false +const isSameKatana: boolean = firstKatana === secondKatana; +// End-example + +export { isSameKatana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiTo.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiTo.int.spec.ts new file mode 100644 index 00000000..e2507a46 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiTo.int.spec.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from '@jest/globals'; + +import { Katana, katana } from './bindingToSyntaxApiTo'; + +describe('BindingToSyntax API (to)', () => { + it('should bind Katana weapon', () => { + expect(katana).toBeInstanceOf(Katana); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiTo.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiTo.ts new file mode 100644 index 00000000..78c65c09 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiTo.ts @@ -0,0 +1,18 @@ +import { Container } from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +// Begin-example +const container: Container = new Container(); +container.bind('Weapon').to(Katana); + +const katana: Weapon = container.get('Weapon'); +// End-example + +export { katana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToConstantValue.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToConstantValue.int.spec.ts new file mode 100644 index 00000000..a159f34e --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToConstantValue.int.spec.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from '@jest/globals'; + +import { Katana, katana } from './bindingToSyntaxApiToConstantValue'; + +describe('BindingToSyntax API (toConstantValue)', () => { + it('should bind Katana weapon', () => { + expect(katana).toBeInstanceOf(Katana); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToConstantValue.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToConstantValue.ts new file mode 100644 index 00000000..654d3b3c --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToConstantValue.ts @@ -0,0 +1,18 @@ +import { Container } from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +// Begin-example +const container: Container = new Container(); +container.bind('Weapon').toConstantValue(new Katana()); + +const katana: Weapon = container.get('Weapon'); +// End-example + +export { katana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToDynamicValue.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToDynamicValue.int.spec.ts new file mode 100644 index 00000000..793e3a77 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToDynamicValue.int.spec.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from '@jest/globals'; + +import { Katana, katana } from './bindingToSyntaxApiToDynamicValue'; + +describe('BindingToSyntax API (toDynamicValue)', () => { + it('should bind Katana weapon', () => { + expect(katana).toBeInstanceOf(Katana); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToDynamicValue.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToDynamicValue.ts new file mode 100644 index 00000000..c8824b31 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToDynamicValue.ts @@ -0,0 +1,18 @@ +import { Container } from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +// Begin-example +const container: Container = new Container(); +container.bind('Weapon').toDynamicValue((): Weapon => new Katana()); + +const katana: Weapon = container.get('Weapon'); +// End-example + +export { katana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToFactory.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToFactory.int.spec.ts new file mode 100644 index 00000000..0455fc8e --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToFactory.int.spec.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from '@jest/globals'; + +import { + container, + DieselCarFactory, + DieselEngine, +} from './bindingToSyntaxApiToFactory'; + +describe('BindingToSyntax API (toFactory)', () => { + it('should provide a factory able to provide a diesel engine', () => { + container.bind(DieselCarFactory).toSelf(); + expect(container.get(DieselCarFactory).createEngine(3)).toBeInstanceOf( + DieselEngine, + ); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToFactory.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToFactory.ts new file mode 100644 index 00000000..40207862 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToFactory.ts @@ -0,0 +1,66 @@ +import { + Container, + Factory, + inject, + injectable, + ResolutionContext, +} from 'inversify7'; + +export interface Engine { + displacement: number; +} + +class BaseEngine implements Engine { + public displacement: number; + + constructor(displacement?: number) { + this.displacement = displacement ?? 0; + } +} + +export class DieselEngine extends BaseEngine {} + +export class PetrolEngine extends BaseEngine {} + +interface CarFactory { + createEngine(displacement: number): Engine; +} + +const container: Container = new Container(); + +// Begin-example +container.bind('Engine').to(PetrolEngine).whenNamed('petrol'); +container.bind('Engine').to(DieselEngine).whenNamed('diesel'); + +container + .bind Engine, [string]>>('Factory') + .toFactory((context: ResolutionContext) => { + return (named: string) => (displacement: number) => { + const engine: Engine = context.get('Engine', { + name: named, + }); + engine.displacement = displacement; + return engine; + }; + }); + +@injectable() +class DieselCarFactory implements CarFactory { + readonly #dieselFactory: (displacement: number) => Engine; + + constructor( + @inject('Factory') + factory: (category: string) => (displacement: number) => Engine, // Injecting an engine factory + ) { + // Creating a diesel engine factory + this.#dieselFactory = factory('diesel'); + } + + public createEngine(displacement: number): Engine { + // Creating a concrete diesel engine + return this.#dieselFactory(displacement); + } +} +// End-example + +export { container, DieselCarFactory }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToProvider.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToProvider.int.spec.ts new file mode 100644 index 00000000..3fce3ac5 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToProvider.int.spec.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from '@jest/globals'; + +import { + Katana, + notSoPowerfulGoldKatana, + powerfulGoldKatana, +} from './bindingToSyntaxApiToProvider'; + +describe('BindingToSyntax API (toFactory)', () => { + it('should provide a provider able to provide a katanas', async () => { + const expectedNotSoPowerfulKatana: Katana = new Katana(); + expectedNotSoPowerfulKatana.damage = 10; + expectedNotSoPowerfulKatana.material = 'gold'; + + const expectedPowerfulKatana: Katana = new Katana(); + expectedPowerfulKatana.damage = 100; + expectedPowerfulKatana.material = 'gold'; + + expect(await notSoPowerfulGoldKatana).toStrictEqual( + expectedNotSoPowerfulKatana, + ); + expect(await powerfulGoldKatana).toStrictEqual(expectedPowerfulKatana); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToProvider.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToProvider.ts new file mode 100644 index 00000000..4892b017 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToProvider.ts @@ -0,0 +1,48 @@ +/* eslint-disable @typescript-eslint/no-magic-numbers */ +import { Container, injectable, ResolutionContext } from 'inversify7'; + +// Begin-example +const container: Container = new Container(); + +interface Sword { + material: string; + damage: number; +} + +@injectable() +class Katana implements Sword { + public material!: string; + public damage!: number; +} + +type SwordProvider = (material: string, damage: number) => Promise; + +container.bind('Sword').to(Katana); + +container + .bind('SwordProvider') + .toProvider((context: ResolutionContext) => { + return async (material: string, damage: number): Promise => { + // Custom args! + return new Promise( + (resolve: (value: Sword | PromiseLike) => void) => { + setTimeout(() => { + const katana: Sword = context.get('Sword'); + katana.material = material; + katana.damage = damage; + resolve(katana); + }, 10); + }, + ); + }; + }); + +const katanaProvider: SwordProvider = + container.get('SwordProvider'); + +const powerfulGoldKatana: Promise = katanaProvider('gold', 100); + +const notSoPowerfulGoldKatana: Promise = katanaProvider('gold', 10); +// End-example + +export { Katana, notSoPowerfulGoldKatana, powerfulGoldKatana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToSelf.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToSelf.int.spec.ts new file mode 100644 index 00000000..1a9e8bfb --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToSelf.int.spec.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from '@jest/globals'; + +import { Katana, katana } from './bindingToSyntaxApiToSelf'; + +describe('BindingToSyntax API (toSelf)', () => { + it('should bind Katana weapon', () => { + expect(katana).toBeInstanceOf(Katana); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToSelf.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToSelf.ts new file mode 100644 index 00000000..e4262cdb --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToSelf.ts @@ -0,0 +1,18 @@ +import { Container } from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +// Begin-example +const container: Container = new Container(); +container.bind(Katana).toSelf(); + +const katana: Weapon = container.get(Katana); +// End-example + +export { katana }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToService.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToService.int.spec.ts new file mode 100644 index 00000000..a506f10b --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToService.int.spec.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from '@jest/globals'; + +import { + cardCatalogProviders, + LorcanaCardCatalogProvider, + MtgCardCatalogProvider, +} from './bindingToSyntaxApiToService'; + +describe('BindingToSyntax API (toService)', () => { + it('should bind catalog providers', () => { + expect(cardCatalogProviders).toStrictEqual([ + new LorcanaCardCatalogProvider(), + new MtgCardCatalogProvider(), + ]); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToService.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToService.ts new file mode 100644 index 00000000..941c8568 --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingToSyntaxApiToService.ts @@ -0,0 +1,61 @@ +import { Container } from 'inversify7'; + +interface CardCatalogProvider { + fetch(limit: number, offset: number): Promise; +} + +interface LorcanaCard { + cost: number; + name: string; +} + +interface MtgCard { + name: string; + color: string; +} + +export class LorcanaCardCatalogProvider + implements CardCatalogProvider +{ + public async fetch(_limit: number, _offset: number): Promise { + return []; + } +} + +export class MtgCardCatalogProvider implements CardCatalogProvider { + public async fetch(_limit: number, _offset: number): Promise { + return []; + } +} + +export const cardCatalogProviderSymbol: symbol = Symbol.for( + 'CardCatalogProvider', +); + +export const lorcanaCardCatalogProviderSymbol: symbol = Symbol.for( + 'LorcanaCardCatalogProvider', +); + +export const mtgCardCatalogProviderSymbol: symbol = Symbol.for( + 'MtgCardCatalogProvider', +); + +// Begin-example +const container: Container = new Container(); + +container.bind(lorcanaCardCatalogProviderSymbol).to(LorcanaCardCatalogProvider); +container.bind(mtgCardCatalogProviderSymbol).to(MtgCardCatalogProvider); + +container + .bind(cardCatalogProviderSymbol) + .toService(lorcanaCardCatalogProviderSymbol); +container + .bind(cardCatalogProviderSymbol) + .toService(mtgCardCatalogProviderSymbol); + +const cardCatalogProviders: CardCatalogProvider[] = container.getAll( + cardCatalogProviderSymbol, +); +// End-example + +export { cardCatalogProviders }; diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingWhenSyntaxApiWhen.int.spec.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingWhenSyntaxApiWhen.int.spec.ts new file mode 100644 index 00000000..d2b47baa --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingWhenSyntaxApiWhen.int.spec.ts @@ -0,0 +1,9 @@ +import { describe, expect, it } from '@jest/globals'; + +import { ninjaDamage } from './bindingWhenSyntaxApiWhen'; + +describe('BindingWhenSyntax API (when)', () => { + it('should bind right ninja weapon', () => { + expect(ninjaDamage).toBe(5); + }); +}); diff --git a/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingWhenSyntaxApiWhen.ts b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingWhenSyntaxApiWhen.ts new file mode 100644 index 00000000..49bc2f7a --- /dev/null +++ b/packages/docs/tools/inversify-code-examples/src/examples/v7/bindingWhenSyntaxApiWhen.ts @@ -0,0 +1,61 @@ +import { + BindingMetadata, + Container, + inject, + injectable, + named, +} from 'inversify7'; + +interface Weapon { + damage: number; +} + +export class Katana implements Weapon { + public readonly damage: number = 10; +} + +export class Shuriken implements Weapon { + public readonly damage: number = 5; +} + +const container: Container = new Container(); + +// Begin-example +const ninjaId: symbol = Symbol.for('Ninja'); +const weaponId: symbol = Symbol.for('Weapon'); + +@injectable() +class Ninja { + constructor( + @inject(weaponId) + @named('shuriken') + public readonly weapon: Weapon, + ) {} +} + +container.bind(ninjaId).to(Ninja); + +const whenTargetNamedConstraint: ( + name: string, +) => (bindingMetadata: BindingMetadata) => boolean = + (name: string) => + (bindingMetadata: BindingMetadata): boolean => + bindingMetadata.name === name; + +container + .bind(weaponId) + .to(Katana) + .when(whenTargetNamedConstraint('katana')); + +container + .bind(weaponId) + .to(Shuriken) + .when(whenTargetNamedConstraint('shuriken')); + +const ninja: Ninja = container.get(ninjaId); + +// Returns 5 +const ninjaDamage: number = ninja.weapon.damage; +// End-example + +export { ninjaDamage };