Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"playwright": "^1.60.0",
"sass": "^1.99.0",
"tslib": "^2.8.1",
"turbo": "^2.9.12",
"turbo": "^2.9.14",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.3",
"vite": "^8.0.12",
Expand Down
7 changes: 5 additions & 2 deletions packages/contracts/src/support/meta/Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ export default interface Repository {
has(key: Key): boolean;

/**
* Returns all metadata for the bound target only (excludes inherited).
* Returns all metadata for the target.
*
* @param {boolean} [inherited=true] Returns all inherited metadata is return, if `true`.
* Otherwise, only this target's metadata is returned.
*
* @returns {Record<PropertyKey, unknown>}
*/
all(): Record<PropertyKey, unknown>;
all(inherited?: boolean): Record<PropertyKey, unknown>;

/**
* The target (class or member) this repository is bound to.
Expand Down
15 changes: 13 additions & 2 deletions packages/support/src/meta/MetaRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,20 @@ export default class MetaRepository implements Repository
/**
* @inheritdoc
*/
all(): Record<PropertyKey, unknown>
all(inherited = true): Record<PropertyKey, unknown>
{
return { ...this.#data };
const current = {
...this.#data,
};

if (!inherited || this.#parent === undefined) {
return current;
}

return {
...this.#parent.all(inherited),
...current,
};
}

/**
Expand Down
23 changes: 8 additions & 15 deletions packages/support/src/meta/Metadata.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ConstructorLike } from '@aedart/contracts';
import { Key } from '@aedart/contracts/support';
import { toParts } from '../objects/toParts.js';
import { isConstructor } from '../reflections/isConstructor.js';
import { getOrCreateRepository } from './getOrCreateRepository.js';
import { addressRegistry } from './registries.js';
Expand Down Expand Up @@ -49,12 +47,14 @@ export default class Metadata
* Returns all metadata for the given target only.
*
* @param {object} target
* @param {boolean} [inherited=true] Returns all inherited metadata is return, if `true`.
* Otherwise, only this target's metadata is returned.
*
* @returns {Record<PropertyKey, unknown>}
*/
static all(target: object): Record<PropertyKey, unknown>
static all(target: object, inherited = true): Record<PropertyKey, unknown>
{
return getOrCreateRepository(target).all();
return getOrCreateRepository(target).all(inherited);
}

/**
Expand Down Expand Up @@ -83,7 +83,7 @@ export default class Metadata
}

return {
resolvedTarget: this.resolveTarget(owner, resolvedKey),
resolvedTarget: this.resolveTarget(owner),
resolvedKey,
};
}
Expand All @@ -92,22 +92,15 @@ export default class Metadata
* Resolves the actual target for metadata lookup
*
* @param {object} target
* @param {PropertyKey} key
*
* @returns {object}
*
* @protected
*/
protected static resolveTarget(target: object, key: Key): object
protected static resolveTarget(target: object): object
{
if (isConstructor(target)) {
const parts = toParts(key);
const root = parts[0];

// If querying instance members via the Class, pivot to the Prototype.
if (root === 'methods' || root === 'fields') {
return (target as ConstructorLike).prototype as object;
}
if (!isConstructor(target)) {
return target.constructor;
}

return target;
Expand Down
2 changes: 1 addition & 1 deletion packages/support/src/meta/Resolved.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Key } from '@aedart/contracts/support';
import { type Key } from '@aedart/contracts/support';

/**
* Resolved target and key
Expand Down
64 changes: 0 additions & 64 deletions packages/support/src/meta/discoverAndFlush.ts

This file was deleted.

18 changes: 3 additions & 15 deletions packages/support/src/meta/findRepository.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
// @aedart/support/meta/findRepository.js
import { Repository } from '@aedart/contracts/support/meta';
import { registry } from './registries.js';

/**
* Find the nearest parent repository in the prototype chain.
* Find the meta repository for the given target
*
* @param {object|null} target
*
* @returns {Repository | undefined}
*/
export function findRepository(target: object | null): Repository | undefined
{
let current = target;
if (!target) return undefined;

while (current !== null) {
// 1. Check if the current target has a repository
const repo = registry.get(current);
if (repo !== undefined) {
return repo;
}

// 2. Move up to the prototype (parent class or parent prototype)
current = Object.getPrototypeOf(current) as object;
}

return undefined;
return registry.get(target);
}
32 changes: 0 additions & 32 deletions packages/support/src/meta/flush.ts

This file was deleted.

29 changes: 0 additions & 29 deletions packages/support/src/meta/getOrCreateBaseRepository.ts

This file was deleted.

54 changes: 47 additions & 7 deletions packages/support/src/meta/getOrCreateRepository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Repository } from '@aedart/contracts/support/meta/index.js';
import { discoverAndFlush } from './discoverAndFlush.js';
import { getOrCreateBaseRepository } from './getOrCreateBaseRepository.js';
import { ConstructorLike } from '@aedart/contracts';
import { Repository } from '@aedart/contracts/support/meta';
import MetaRepository from './MetaRepository.js';
import { registry } from './registries.js';

/**
* Gets the existing repository for a target, or creates a new one
Expand All @@ -12,9 +13,48 @@ import { getOrCreateBaseRepository } from './getOrCreateBaseRepository.js';
*/
export function getOrCreateRepository(target: object): Repository
{
// 1. Discovery & Flush (if not already flushed)
discoverAndFlush(target);
// Return repository if target already has one.
if (registry.has(target)) {
return registry.get(target)!;
}

// 2. Return the base repository
return getOrCreateBaseRepository(target);
// Collect the inheritance chain from child to root
const chain: object[] = [];
let current: object | null = target;

while (
current !== null
&& current !== Function.prototype
&& current !== Object.prototype
) {
// Skip further traversal if we hit a class already in the registry
if (registry.has(current)) {
chain.push(current);
break;
}

chain.push(current);
current = Object.getPrototypeOf(current) as ConstructorLike | null;
}

// Process the chain in reverse (from root / the deepest parent down to child)
let parentRepo: Repository | undefined = undefined;

for (let i = chain.length - 1; i >= 0; i--) {
const currentTarget = chain[i];

// If it already exists, just grab it to use as the next parentRepo
if (registry.has(currentTarget)) {
parentRepo = registry.get(currentTarget)!;
} else {
// Create, register, and link
const repo: Repository = new MetaRepository(currentTarget, parentRepo);
registry.set(currentTarget, repo);

parentRepo = repo;
}
}

// The final parentRepo will be the repository for the initial target
return parentRepo!;
}
3 changes: 0 additions & 3 deletions packages/support/src/meta/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ import OwnerContext from './OwnerContext.js';

export { Address, Metadata, MetaRepository, OwnerContext };

// export * from './discoverAndFlush.js'; // internal
export * from './findOrCreateMemberAddress.js';
export * from './findRepository.js';
// export * from './flush.js'; // internal
export * from './getOrCreateBaseRepository.js';
export * from './getOrCreateOwnerContext.js';
export * from './getOrCreateRepository.js';
export * from './inheritMeta.js';
Expand Down
Loading