From 10bc2090389c749f5dabace830eec6530d7b787f Mon Sep 17 00:00:00 2001 From: Nicolas Date: Fri, 18 Sep 2026 13:59:58 +0200 Subject: [PATCH] Ajouter @lightweight-sdk/service-registry (packages/common) Registre de services en singleton avec injection par decorateurs : - ServiceRepository : singleton central, uid genere automatiquement (crypto.randomUUID) a l'enregistrement, une seule instance partagee par service. - @RegisterService() : decorateur de classe, instancie et enregistre automatiquement la classe decoree (constructeur sans argument). - @Service(target) : decorateur de propriete, injection paresseuse et memoisee par reference de classe (resolution au premier acces, pas a la decoration - insensible a l'ordre d'evaluation des modules). Fix connexe dans tsconfig.base.json : useDefineForClassFields desactive (target ES2022 l'active par defaut), sinon un champ de classe sans initialiseur est reinitialise a undefined sur l'instance a la construction et masque l'accesseur pose sur le prototype par un decorateur de propriete - touche @Service ici et @LinkToDom dans web-component. Documente dans spec/architecture.md. Fix connexe dans scripts/create-package.mjs : execFileSync('pnpm', ...) ne resout pas le shim .cmd de pnpm sous Windows sans shell: true (trouve en re-testant le script sur ce package). Co-Authored-By: Claude Sonnet 5 --- .changeset/add-service-registry-package.md | 5 + packages/common/service-registry/README.md | 49 ++++++++ packages/common/service-registry/package.json | 23 ++++ .../common/service-registry/src/index.test.ts | 24 ++++ packages/common/service-registry/src/index.ts | 4 + .../src/register-service.decorator.test.ts | 41 +++++++ .../src/register-service.decorator.ts | 33 +++++ .../src/service-repository.test.ts | 70 +++++++++++ .../src/service-repository.ts | 115 ++++++++++++++++++ .../src/service.decorator.test.ts | 80 ++++++++++++ .../service-registry/src/service.decorator.ts | 58 +++++++++ packages/common/service-registry/src/types.ts | 14 +++ .../common/service-registry/tsconfig.json | 8 ++ scripts/create-package.mjs | 6 +- spec/architecture.md | 4 + spec/packages.md | 1 + tsconfig.base.json | 3 +- tsconfig.json | 9 +- 18 files changed, 543 insertions(+), 4 deletions(-) create mode 100644 .changeset/add-service-registry-package.md create mode 100644 packages/common/service-registry/README.md create mode 100644 packages/common/service-registry/package.json create mode 100644 packages/common/service-registry/src/index.test.ts create mode 100644 packages/common/service-registry/src/index.ts create mode 100644 packages/common/service-registry/src/register-service.decorator.test.ts create mode 100644 packages/common/service-registry/src/register-service.decorator.ts create mode 100644 packages/common/service-registry/src/service-repository.test.ts create mode 100644 packages/common/service-registry/src/service-repository.ts create mode 100644 packages/common/service-registry/src/service.decorator.test.ts create mode 100644 packages/common/service-registry/src/service.decorator.ts create mode 100644 packages/common/service-registry/src/types.ts create mode 100644 packages/common/service-registry/tsconfig.json diff --git a/.changeset/add-service-registry-package.md b/.changeset/add-service-registry-package.md new file mode 100644 index 0000000..5deed3b --- /dev/null +++ b/.changeset/add-service-registry-package.md @@ -0,0 +1,5 @@ +--- +"@lightweight-sdk/service-registry": minor +--- + +Ajout du package `@lightweight-sdk/service-registry` : registre de services en singleton avec `@RegisterService()` (enregistrement automatique à la décoration de classe) et `@Service(target)` (injection paresseuse et mémoïsée par référence de classe sur un membre). diff --git a/packages/common/service-registry/README.md b/packages/common/service-registry/README.md new file mode 100644 index 0000000..99bc669 --- /dev/null +++ b/packages/common/service-registry/README.md @@ -0,0 +1,49 @@ +# @lightweight-sdk/service-registry + +Registre de services en singleton, avec enregistrement et injection par décorateurs. Package `common` : isomorphe, aucune dépendance DOM ou Node-only. + +## Installation + +```bash +pnpm add @lightweight-sdk/service-registry +``` + +## Usage + +```ts +import { RegisterService, Service } from '@lightweight-sdk/service-registry'; + +@RegisterService() +class LoggerService { + public log(message: string): void { + console.log(message); + } +} + +class ReportGenerator { + @Service(LoggerService) + private readonly logger!: LoggerService; + + public run(): void { + this.logger.log('generating report'); + } +} +``` + +## Concepts + +- **`ServiceRepository`** — singleton central qui stocke une instance unique de chaque service, indexée par un uid généré automatiquement (`crypto.randomUUID()`) à l'enregistrement. Accès direct rarement nécessaire : `RegisterService`/`Service` couvrent l'usage courant. +- **`@RegisterService()`** — décorateur de classe. Instancie la classe décorée (constructeur sans argument obligatoire) et l'enregistre dans le `ServiceRepository`. +- **`@Service(TargetClass)`** — décorateur de propriété. Injecte l'instance partagée de `TargetClass` dans le membre décoré. La résolution est **paresseuse** (au premier accès à la propriété, pas à la décoration) : peu importe que la classe consommatrice soit évaluée avant ou après l'enregistrement du service. Après le premier accès, la propriété est remplacée par la valeur résolue (pas de nouvelle recherche ensuite). + +## Contraintes + +- Une classe décorée par `@RegisterService()` doit avoir un constructeur sans argument obligatoire — ses propres dépendances doivent elles-mêmes être injectées via `@Service`, pas passées au constructeur. +- `experimentalDecorators: true` doit être activé côté consommateur (déjà le cas dans ce monorepo via `tsconfig.base.json`). + +## API + +- `RegisterService()` — décorateur de classe. +- `Service(target)` — décorateur de propriété. +- `ServiceRepository` — singleton (`getInstance()`, `registerClass`, `resolveClass`, `resolve`, `getUidForClass`, `hasClass`). `resetForTesting()` est réservé aux tests. +- `ServiceConstructor`, `ServiceUid` — types associés. diff --git a/packages/common/service-registry/package.json b/packages/common/service-registry/package.json new file mode 100644 index 0000000..9229ff2 --- /dev/null +++ b/packages/common/service-registry/package.json @@ -0,0 +1,23 @@ +{ + "name": "@lightweight-sdk/service-registry", + "version": "0.0.1", + "description": "Registre de services en singleton avec injection par décorateurs (@RegisterService, @Service).", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "engines": { + "node": ">=22" + }, + "publishConfig": { + "access": "restricted", + "registry": "https://git.dev.kyuno.fr/api/packages/kyuno/npm/" + }, + "typedocOptions": { + "entryPoints": [ + "src/index.ts" + ], + "readme": "README.md" + } +} diff --git a/packages/common/service-registry/src/index.test.ts b/packages/common/service-registry/src/index.test.ts new file mode 100644 index 0000000..9b7cada --- /dev/null +++ b/packages/common/service-registry/src/index.test.ts @@ -0,0 +1,24 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { RegisterService, Service, ServiceRepository } from './index'; + +beforeEach(() => { + ServiceRepository.resetForTesting(); +}); + +describe('public API (barrel export)', () => { + it('registers and injects a service end to end through the public exports', () => { + @RegisterService() + class ClockService { + public now(): number { + return 1234; + } + } + + class Consumer { + @Service(ClockService) + public readonly clock!: ClockService; + } + + expect(new Consumer().clock.now()).toBe(1234); + }); +}); diff --git a/packages/common/service-registry/src/index.ts b/packages/common/service-registry/src/index.ts new file mode 100644 index 0000000..17b5a85 --- /dev/null +++ b/packages/common/service-registry/src/index.ts @@ -0,0 +1,4 @@ +export { RegisterService } from './register-service.decorator'; +export { Service } from './service.decorator'; +export { ServiceRepository } from './service-repository'; +export { ServiceConstructor, ServiceUid } from './types'; diff --git a/packages/common/service-registry/src/register-service.decorator.test.ts b/packages/common/service-registry/src/register-service.decorator.test.ts new file mode 100644 index 0000000..61476ee --- /dev/null +++ b/packages/common/service-registry/src/register-service.decorator.test.ts @@ -0,0 +1,41 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { RegisterService } from './register-service.decorator'; +import { ServiceRepository } from './service-repository'; + +beforeEach(() => { + ServiceRepository.resetForTesting(); +}); + +describe('RegisterService', () => { + it('registers the decorated class in the global repository', () => { + @RegisterService() + class GreeterService { + public greet(name: string): string { + return `Hello, ${name}!`; + } + } + + const repository = ServiceRepository.getInstance(); + expect(repository.hasClass(GreeterService)).toBe(true); + expect(repository.resolveClass(GreeterService)).toBeInstanceOf(GreeterService); + }); + + it('shares a single instance across every resolution', () => { + @RegisterService() + class StateService { + public value = 0; + } + + const repository = ServiceRepository.getInstance(); + repository.resolveClass(StateService).value = 42; + + expect(repository.resolveClass(StateService).value).toBe(42); + }); + + it('rethrows if the class is registered twice', () => { + class DuplicateService {} + RegisterService()(DuplicateService); + + expect(() => RegisterService()(DuplicateService)).toThrow(/already registered/); + }); +}); diff --git a/packages/common/service-registry/src/register-service.decorator.ts b/packages/common/service-registry/src/register-service.decorator.ts new file mode 100644 index 0000000..ac6033a --- /dev/null +++ b/packages/common/service-registry/src/register-service.decorator.ts @@ -0,0 +1,33 @@ +import { ServiceRepository } from './service-repository'; +import type { ServiceConstructor } from './types'; + +const LOG_PREFIX = '[lightweight-sdk:service-registry]'; + +/** + * Class decorator that instantiates the decorated class and registers the + * resulting instance in the global {@link ServiceRepository}, making it + * resolvable from anywhere via {@link Service}. The decorated class must + * have a no-argument constructor — any dependencies it needs should + * themselves be injected with {@link Service} rather than passed as + * constructor parameters. + * @returns a class decorator + * @example + * ```ts + * ⁣@RegisterService() + * export class LoggerService { + * public log(message: string): void { + * console.log(message); + * } + * } + * ``` + */ +export function RegisterService(): (target: ServiceConstructor) => void { + return (target: ServiceConstructor): void => { + try { + ServiceRepository.getInstance().registerClass(target); + } catch (error) { + console.error(`${LOG_PREFIX} Failed to register service "${target.name}".`, error); + throw error; + } + }; +} diff --git a/packages/common/service-registry/src/service-repository.test.ts b/packages/common/service-registry/src/service-repository.test.ts new file mode 100644 index 0000000..914e2d3 --- /dev/null +++ b/packages/common/service-registry/src/service-repository.test.ts @@ -0,0 +1,70 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { ServiceRepository } from './service-repository'; + +class Counter { + public value = 0; +} + +beforeEach(() => { + ServiceRepository.resetForTesting(); +}); + +describe('ServiceRepository', () => { + it('returns the same instance on every call to getInstance', () => { + expect(ServiceRepository.getInstance()).toBe(ServiceRepository.getInstance()); + }); + + it('registers a class and resolves the same instance by class reference', () => { + const repository = ServiceRepository.getInstance(); + + repository.registerClass(Counter); + const first = repository.resolveClass(Counter); + const second = repository.resolveClass(Counter); + + expect(first).toBeInstanceOf(Counter); + expect(first).toBe(second); + }); + + it('assigns a unique uid on registration and resolves the same instance by that uid', () => { + const repository = ServiceRepository.getInstance(); + + const uid = repository.registerClass(Counter); + + expect(typeof uid).toBe('string'); + expect(uid.length).toBeGreaterThan(0); + expect(repository.resolve(uid)).toBe(repository.resolveClass(Counter)); + expect(repository.getUidForClass(Counter)).toBe(uid); + }); + + it('reports whether a class is registered', () => { + const repository = ServiceRepository.getInstance(); + + expect(repository.hasClass(Counter)).toBe(false); + repository.registerClass(Counter); + expect(repository.hasClass(Counter)).toBe(true); + }); + + it('throws when registering the same class twice', () => { + const repository = ServiceRepository.getInstance(); + repository.registerClass(Counter); + + expect(() => repository.registerClass(Counter)).toThrow(/already registered/); + }); + + it('throws when resolving a class that was never registered', () => { + expect(() => ServiceRepository.getInstance().resolveClass(Counter)).toThrow(/not registered/); + }); + + it('throws when resolving an unknown uid', () => { + expect(() => ServiceRepository.getInstance().resolve('does-not-exist')).toThrow( + /No service registered/, + ); + }); + + it('starts fresh after resetForTesting', () => { + ServiceRepository.getInstance().registerClass(Counter); + ServiceRepository.resetForTesting(); + + expect(ServiceRepository.getInstance().hasClass(Counter)).toBe(false); + }); +}); diff --git a/packages/common/service-registry/src/service-repository.ts b/packages/common/service-registry/src/service-repository.ts new file mode 100644 index 0000000..074e896 --- /dev/null +++ b/packages/common/service-registry/src/service-repository.ts @@ -0,0 +1,115 @@ +import type { ServiceConstructor, ServiceUid } from './types'; + +const LOG_PREFIX = '[lightweight-sdk:service-registry]'; + +/** + * Central singleton registry that holds the single shared instance of every + * service registered via {@link RegisterService}, keyed by a unique id + * generated at registration time. Consumers rarely call this class directly + * — {@link RegisterService} and {@link Service} are the intended public API + * — but it is exported for advanced use cases (manual registration, uid + * lookups, diagnostics). + */ +export class ServiceRepository { + private static instance: ServiceRepository | undefined; + + private instancesByUid = new Map(); + private uidsByConstructor = new WeakMap(); + + /** Private to enforce the singleton pattern — use {@link ServiceRepository.getInstance}. */ + private constructor() {} + + /** + * Returns the single shared instance of the repository, creating it on first access. + * @returns the singleton {@link ServiceRepository} + */ + public static getInstance(): ServiceRepository { + if (ServiceRepository.instance === undefined) { + ServiceRepository.instance = new ServiceRepository(); + } + return ServiceRepository.instance; + } + + /** + * Discards the singleton instance so the next {@link ServiceRepository.getInstance} + * call starts from an empty registry. Intended for resetting state between + * test cases — application code should not call this. + */ + public static resetForTesting(): void { + ServiceRepository.instance = undefined; + } + + /** + * Instantiates `target` (its constructor must take no arguments) and + * registers the resulting instance under a freshly generated unique id. + * Called by {@link RegisterService} — most callers should use that + * decorator instead of calling this method directly. + * @param target the service class to instantiate and register + * @returns the uid assigned to this service + * @throws {Error} if `target` is already registered + */ + public registerClass(target: ServiceConstructor): ServiceUid { + if (this.uidsByConstructor.has(target)) { + throw new Error(`Service "${target.name}" is already registered.`); + } + + const uid = globalThis.crypto.randomUUID(); + const instance = new target(); + + this.instancesByUid.set(uid, instance); + this.uidsByConstructor.set(target, uid); + + console.debug(`${LOG_PREFIX} Registered service "${target.name}" (${uid}).`); + + return uid; + } + + /** + * Resolves the shared instance registered for `target`. Called by + * {@link Service} — most callers should use that decorator instead of + * calling this method directly. + * @param target the service class previously registered via {@link RegisterService} + * @returns the shared instance of `target` + * @throws {Error} if `target` was never registered + */ + public resolveClass(target: ServiceConstructor): T { + const uid = this.uidsByConstructor.get(target); + if (uid === undefined) { + throw new Error( + `Service "${target.name}" is not registered. Did you forget @RegisterService?`, + ); + } + return this.resolve(uid); + } + + /** + * Resolves a registered service instance directly by its uid. + * @param uid the service's unique identifier, as returned by {@link ServiceRepository.registerClass} + * @returns the instance registered under `uid` + * @throws {Error} if no service is registered under `uid` + */ + public resolve(uid: ServiceUid): T { + if (!this.instancesByUid.has(uid)) { + throw new Error(`No service registered with uid "${uid}".`); + } + return this.instancesByUid.get(uid) as T; + } + + /** + * Looks up the uid assigned to a registered service class. + * @param target the service class to look up + * @returns the assigned uid, or `undefined` if `target` is not registered + */ + public getUidForClass(target: ServiceConstructor): ServiceUid | undefined { + return this.uidsByConstructor.get(target); + } + + /** + * Checks whether a service class is currently registered. + * @param target the service class to check + * @returns `true` if `target` has been registered + */ + public hasClass(target: ServiceConstructor): boolean { + return this.uidsByConstructor.has(target); + } +} diff --git a/packages/common/service-registry/src/service.decorator.test.ts b/packages/common/service-registry/src/service.decorator.test.ts new file mode 100644 index 0000000..44a1465 --- /dev/null +++ b/packages/common/service-registry/src/service.decorator.test.ts @@ -0,0 +1,80 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { RegisterService } from './register-service.decorator'; +import { Service } from './service.decorator'; +import { ServiceRepository } from './service-repository'; + +beforeEach(() => { + ServiceRepository.resetForTesting(); +}); + +describe('Service', () => { + it('injects the shared instance registered for the target class', () => { + @RegisterService() + class LoggerService { + public readonly messages: string[] = []; + + public log(message: string): void { + this.messages.push(message); + } + } + + class ReportGenerator { + @Service(LoggerService) + public readonly logger!: LoggerService; + } + + const generator = new ReportGenerator(); + generator.logger.log('hello'); + + expect(generator.logger).toBeInstanceOf(LoggerService); + expect(ServiceRepository.getInstance().resolveClass(LoggerService).messages).toEqual(['hello']); + }); + + it('resolves lazily: decoration does not require the service to be registered yet', () => { + class LateService { + public readonly ok = true; + } + + class Consumer { + @Service(LateService) + public readonly svc!: LateService; + } + + // Consumer (and its @Service decoration) already ran above, yet LateService + // is only registered now — proves decoration itself never required it. + RegisterService()(LateService); + + expect(new Consumer().svc.ok).toBe(true); + }); + + it('memoizes the resolved value on the instance after the first access', () => { + @RegisterService() + class LoggerService { + public log(_message: string): void {} + } + + class Consumer { + @Service(LoggerService) + public readonly logger!: LoggerService; + } + + const consumer = new Consumer(); + expect(Object.getOwnPropertyDescriptor(consumer, 'logger')).toBeUndefined(); + + void consumer.logger; + + const descriptor = Object.getOwnPropertyDescriptor(consumer, 'logger'); + expect(descriptor?.get).toBeUndefined(); + expect(descriptor?.value).toBeInstanceOf(LoggerService); + }); + + it('throws when the target service was never registered', () => { + class UnregisteredService {} + class Consumer { + @Service(UnregisteredService) + public readonly dep!: UnregisteredService; + } + + expect(() => new Consumer().dep).toThrow(/not registered/); + }); +}); diff --git a/packages/common/service-registry/src/service.decorator.ts b/packages/common/service-registry/src/service.decorator.ts new file mode 100644 index 0000000..9c07567 --- /dev/null +++ b/packages/common/service-registry/src/service.decorator.ts @@ -0,0 +1,58 @@ +import { ServiceRepository } from './service-repository'; +import type { ServiceConstructor } from './types'; + +const LOG_PREFIX = '[lightweight-sdk:service-registry]'; + +/** + * Property decorator that injects the shared instance of `target` + * (previously registered via {@link RegisterService}) into the decorated + * class member. + * + * Resolution is lazy and memoized: the service is looked up in the + * {@link ServiceRepository} the first time the property is read, not at + * decoration time — this avoids depending on module evaluation order + * between a service and its consumers. After the first read, the property + * is replaced by the resolved value on the instance, so later accesses skip + * the repository lookup entirely. + * @param target the service class to inject, previously registered with {@link RegisterService} + * @returns a property decorator + * @example + * ```ts + * class ReportGenerator { + * ⁣@Service(LoggerService) + * private readonly logger!: LoggerService; + * + * public run(): void { + * this.logger.log('generating report'); + * } + * } + * ``` + */ +export function Service( + target: ServiceConstructor, +): (prototype: object, propertyKey: string | symbol) => void { + return (prototype: object, propertyKey: string | symbol): void => { + Object.defineProperty(prototype, propertyKey, { + configurable: true, + enumerable: true, + get(this: object): T { + let resolved: T; + try { + resolved = ServiceRepository.getInstance().resolveClass(target); + } catch (error) { + console.error( + `${LOG_PREFIX} Failed to inject service "${target.name}" into member "${String(propertyKey)}".`, + error, + ); + throw error; + } + Object.defineProperty(this, propertyKey, { + value: resolved, + enumerable: true, + configurable: true, + }); + return resolved; + }, + }); + }; +} diff --git a/packages/common/service-registry/src/types.ts b/packages/common/service-registry/src/types.ts new file mode 100644 index 0000000..9b747ef --- /dev/null +++ b/packages/common/service-registry/src/types.ts @@ -0,0 +1,14 @@ +/** + * A concrete class that {@link ServiceRepository} can instantiate on its own, + * i.e. one whose constructor takes no arguments. Services registered via + * {@link RegisterService} must satisfy this shape. + */ +export interface ServiceConstructor { + new (): T; +} + +/** + * Unique identifier assigned to a service when it is registered in the + * {@link ServiceRepository}. + */ +export type ServiceUid = string; diff --git a/packages/common/service-registry/tsconfig.json b/packages/common/service-registry/tsconfig.json new file mode 100644 index 0000000..2ab4a4c --- /dev/null +++ b/packages/common/service-registry/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/scripts/create-package.mjs b/scripts/create-package.mjs index e69d7d9..d7555c0 100644 --- a/scripts/create-package.mjs +++ b/scripts/create-package.mjs @@ -123,7 +123,9 @@ writeFileSync(packagesSpecPath, packagesSpec.trimEnd() + '\n' + newRow); console.log(`Package ${npmName} créé dans packages/${category}/${name}/.`); try { - execFileSync('pnpm', ['install'], { cwd: ROOT, stdio: 'inherit' }); + // shell: true est nécessaire sous Windows, où `pnpm` est un shim .cmd/.ps1 + // que execFileSync ne résout pas via PATHEXT sans passer par un shell. + execFileSync('pnpm', ['install'], { cwd: ROOT, stdio: 'inherit', shell: true }); execFileSync( 'pnpm', [ @@ -135,7 +137,7 @@ try { 'tsconfig.json', 'spec/packages.md', ], - { cwd: ROOT, stdio: 'inherit' }, + { cwd: ROOT, stdio: 'inherit', shell: true }, ); } catch (error) { console.error('Étape automatique échouée, à relancer toi-même :'); diff --git a/spec/architecture.md b/spec/architecture.md index 78bf6d4..4622fcf 100644 --- a/spec/architecture.md +++ b/spec/architecture.md @@ -30,6 +30,10 @@ Un nouveau package se crée avec `pnpm create-package =22"` | Node 20 est end-of-life depuis avril 2026 | +## Décorateurs et `useDefineForClassFields` + +`tsconfig.base.json` force `"useDefineForClassFields": false`, bien que la cible soit `ES2022` (où ce flag vaut `true` par défaut). Sans ça, un champ de classe déclaré sans initialiseur (`logger!: LoggerService;`) est réinitialisé à `undefined` **sur l'instance** au moment de la construction, ce qui masque silencieusement tout accesseur posé sur le prototype par un décorateur de propriété (`@Service` de `@lightweight-sdk/service-registry`, `@LinkToDom` de `web-component`). C'est une interaction connue entre `useDefineForClassFields` et les décorateurs legacy (`experimentalDecorators`) — désactiver ce flag restaure la sémantique classique où un champ sans initialiseur n'émet aucun code, laissant l'accesseur du prototype pleinement fonctionner. + ## Dépendances entre packages Les dépendances internes entre packages du monorepo utilisent le protocole `workspace:*` (résolu localement par pnpm, jamais via le registre distant). Le registre npm privé n'est utilisé que pour la publication et pour la consommation depuis des projets *externes* à ce monorepo. diff --git a/spec/packages.md b/spec/packages.md index b208143..278e2ec 100644 --- a/spec/packages.md +++ b/spec/packages.md @@ -30,3 +30,4 @@ Le code source de ce package a été migré strictement à l'identique depuis l' - Le style de formatage d'origine (4 espaces, guillemets doubles) diffère de la config Biome du monorepo (tabulations, guillemets simples) — le formatter Biome est désactivé pour ce package via le même `overrides`. - `REQUEST_DOM_LINK_KEY` semble ne plus être utilisé nulle part dans le code (le mécanisme actif est le tableau `__linkedProperties`) — potentiellement mort, mais pas supprimé. - Quelques typos mineures ("atatched", "attriute") et un commentaire en français dans `LinkToDom` qui ne correspond plus exactement au comportement (`throw` au lieu d'un simple avertissement). +| `@lightweight-sdk/service-registry` | common | 0.0.1 | brouillon | diff --git a/tsconfig.base.json b/tsconfig.base.json index a04f7f5..62ef3a1 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -13,6 +13,7 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, - "experimentalDecorators": true + "experimentalDecorators": true, + "useDefineForClassFields": false } } diff --git a/tsconfig.json b/tsconfig.json index 446a9fb..d752f19 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,11 @@ { "files": [], - "references": [{ "path": "./packages/client/web-component" }] + "references": [ + { + "path": "./packages/client/web-component" + }, + { + "path": "./packages/common/service-registry" + } + ] }