Skip to content

Commit

Permalink
Add docs for reflection utils
Browse files Browse the repository at this point in the history
  • Loading branch information
aedart committed Mar 4, 2024
1 parent 16aecf5 commit bd1cbe1
Show file tree
Hide file tree
Showing 18 changed files with 530 additions and 14 deletions.
16 changes: 16 additions & 0 deletions docs/.vuepress/archive/Version0x.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,24 @@ export default PagesCollection.make('v0.x', '/v0x', [
collapsible: true,
children: [
'packages/support/reflections/',
'packages/support/reflections/assertHasPrototypeProperty',
'packages/support/reflections/classLooksLike',
'packages/support/reflections/classOwnKeys',
'packages/support/reflections/getAllParentsOfClass',
'packages/support/reflections/getClassPropertyDescriptor',
'packages/support/reflections/getClassPropertyDescriptors',
'packages/support/reflections/getConstructorName',
'packages/support/reflections/getNameOrDesc',
'packages/support/reflections/getParentOfClass',
'packages/support/reflections/hasAllMethods',
'packages/support/reflections/hasMethod',
'packages/support/reflections/hasPrototypeProperty',
'packages/support/reflections/isConstructor',
'packages/support/reflections/isKeySafe',
'packages/support/reflections/isKeyUnsafe',
'packages/support/reflections/isSubclass',
'packages/support/reflections/isSubclassOrLooksLike',
'packages/support/reflections/isWeakKind',
]
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: Assert Has Prototype Prop.
description: Assert that object has a "prototype" property.
sidebarDepth: 0
---

# `assertHasPrototypeProperty` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Assert that given target object has a `prototype` property defined.
Throws a `TypeError` if target object does not have a `prototype` property

_See [`hasPrototypeProperty`](./hasPrototypeProperty.md) for details._

```js
import { assertHasPrototypeProperty } from '@aedart/support/reflections';

assertHasPrototypeProperty({ __proto__: null }); // TypeError
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: Class Looks Like
description: Determine if a class looks like blueprint.
sidebarDepth: 0
---

# `classLooksLike` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Determines if a target class _"looks like"_ the provided class "blueprint".

[[TOC]]

## Arguments

`classLooksLike()` accepts the following arguments:

- `target: object` - the target class object.
- `blueprint: ClassBlueprint` - a blueprint that defines the expected members of a class (_see [Class Blueprint](#class-blueprint) for details._).

```js
import { classLooksLike } from '@aedart/support/reflections';

class A {}

class B {
foo() {}
}

const blueprint = { members: [ 'foo' ] };

classLooksLike(A, blueprint); // false
classLooksLike(B, blueprint); // true
```

## Class Blueprint

The class "blueprint" is an object that defines the expected members (_property keys_) of a target class.
All defined members must exist in target class' prototype, before the `classLooksLike()` returns `true`.

You can specify either or both of the following properties in a class blueprint object:

- `members: PropertyKey[]` - (_optional_) Properties or methods expected to exist in class' prototype.
- `staticMembers: PropertyKey[]` - (_optional_) Properties or methods expected to exist in class as static members.

**Note:** _If you do not specify either `members` or `staticMembers`, then a `TypeError` is thrown._

```js
class A {
foo() {}

bar() {}
}

class B {
foo() {}

static bar() {}
}

const blueprint = { members: [ 'foo' ], staticMembers: [ 'bar' ] };

classLooksLike(A, blueprint); // false
classLooksLike(B, blueprint); // true
```

## Recursive

`classLooksLike()` traverses target class' prototype chain. This means that you can compare a subclass against a blueprint
and inherited members will automatically be included in the check.

```js
class A {
foo() {}
}

class B extends A {
bar() {}
}

const blueprint = { members: [ 'foo', 'bar' ]};

classLooksLike(A, blueprint); // false
classLooksLike(B, blueprint); // true
```
36 changes: 36 additions & 0 deletions docs/archive/current/packages/support/reflections/classOwnKeys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Class Own Keys
description: Get property keys of target class.
sidebarDepth: 0
---

# `classOwnKeys` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Returns property keys that are defined target class's prototype.
It accepts the following arguments:

- `target: ConstructorOrAbstractConstructor` - The target class
- `recursive: boolean = false` - (_optional_) If `true`, then target's prototype chain is traversed and all property keys are returned.

```js
import { classOwnKeys } from '@aedart/support/reflections';

class A {
foo() {}
}

class B extends A {
get bar() {}
}

classOwnKeys(B); // [ 'constructor', 'bar' ]
classOwnKeys(B, true); // [ 'constructor', 'foo', 'bar' ]
```

::: warning Caution
`classOwnKeys()` throws `TypeError` if target does not have a `prototype` property.
:::

## Limitation

The `classOwnKeys()` function does not return static members of a target class.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: Get All Parents Of Class
description: Get all parents of a class
sidebarDepth: 0
---

# `getAllParentsOfClass` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Returns all parents of target class.
It accepts the following arguments:

- `target: ConstructorOrAbstractConstructor` - The target class.
- `includeTarget: boolean = false` - (_optional_) If `true`, then given target is included in the output as the first element.

```js
import { getAllParentsOfClass } from '@aedart/support/reflections';

class A {}

class B extends A {}

class C extends B {}

getAllParentsOfClass(C); // [ B, A ]
getAllParentsOfClass(C, true); // [ C, B, A ]
```

_See also [`getParentOfClass()`](./getParentOfClass.md)._
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: Get Class Prop. Descriptor
description: Get property descriptor of target class property.
sidebarDepth: 0
---

# `getClassPropertyDescriptor` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Returns [`PropertyDescriptor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/getOwnPropertyDescriptor),
from target's prototype that matches given property key.

It accepts the following arguments:

- `target: ConstructorOrAbstractConstructor` - The target class.
- `key: PropertyKey` - Name of the property.

```js
import { getClassPropertyDescriptor } from '@aedart/support/reflections';

class A {
set name(v) {}
get name() {}
}

getClassPropertyDescriptor(A, 'name'); // see "output"...
```

The above show example results in the given output:

```js
const output = {
get: function () { /* ...Not shown... */ },
set: function (v) { /* ..Not shown... */ },
enumerable: false,
configurable: true
};
```

::: tip Note
`getClassPropertyDescriptor()` returns `undefined` if requested key does not exist in class' prototype.
:::

::: warning Caution
`getClassPropertyDescriptor()` throws `TypeError` if target does not have a `prototype` property.
:::
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: Get Class Prop. Descriptors
description: Get all property descriptors of target class.
sidebarDepth: 0
---

# `getClassPropertyDescriptors` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Returns all property [`descriptors`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/getOwnPropertyDescriptor) that are defined target's prototype.

It accepts the following arguments:

- `target: ConstructorOrAbstractConstructor` - The target class.
- `recursive: boolean = false` - (_optional_) If `true`, then target's parent prototypes are traversed. Descriptors are merged, such that the top-most class' descriptors are returned.

```js
import { getClassPropertyDescriptors } from '@aedart/support/reflections';

class A {
set name(v) {}
get name() {}
bar() {}
[MY_SYMBOL]() {}
}

getClassPropertyDescriptors(A); // { bar: {...}, name: {...}, [MY_SYMBOL]: {...} }
```

When `recursive` is set to `true`, then all property descriptors are returned from the target class' prototype chain.

```js
import { getClassPropertyDescriptors } from '@aedart/support/reflections';

class A {
set name(v) {}
get name() {}
foo() {}
[MY_SYMBOL]() {}
}

class B extends A {
set bar(v) {}
get bar() {}
}

getClassPropertyDescriptors(B, true);
// { bar: {...}, foo: {...}, name: {...}, [MY_SYMBOL]: {...} }
```

::: warning Caution
`getClassPropertyDescriptors()` throws `TypeError` if target does not have a `prototype` property.
:::
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Get Constructor Name
description: Get name of target class' constructor
sidebarDepth: 0
---

# `getConstructorName` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Returns target class' constructor name, if available.

It accepts the following arguments:

- `target: ConstructorOrAbstractConstructor` - The target class
- `defaultValue: string|null = null` - (_optional_) A default string value to return if target has no constructor name.

```js
import { getConstructorName } from '@aedart/support/reflections';

class Box {}

getConstructorName(Box); // Box
getConstructorName(class {}); // null
getConstructorName(class {}, 'MyBox'); // MyBox
```
18 changes: 18 additions & 0 deletions docs/archive/current/packages/support/reflections/getNameOrDesc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: Get Name Or Desc. Tag
description: Get name of target class' constructor, or description tag
sidebarDepth: 0
---

# `getNameOrDesc` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Returns target class' [constructor name](./getConstructorName.md), or [description tag](../misc/descTag.md) if name is not available.

```js
import { getNameOrDesc } from '@aedart/support/reflections';

class ApiService {}

getNameOrDesc(ApiService); // ApiService
getNameOrDesc(class {}); // [object Function]
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Get Parent Of Class
description: Get parent class.
sidebarDepth: 0
---

# `getParentOfClass` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Returns the parent class of given target class, or `null` if class does not have a parent.

```js
import { getParentOfClass } from '@aedart/support/reflections';

class A {}

class B extends A {}

class C extends B {}

getParentOfClass(A); // null
getParentOfClass(B); // A
getParentOfClass(C); // B
```

_See also [`getAllParentsOfClass()`](./getAllParentsOfClass.md)._
26 changes: 26 additions & 0 deletions docs/archive/current/packages/support/reflections/hasAllMethods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Has All Methods
description: Determine if target has all methods
sidebarDepth: 0
---

# `hasAllMethods` <Badge type="tip" text="Available since v0.9" vertical="middle" />

Determine if given target object contains all given methods.

It accepts the following arguments:

- `target: object` - The target.
- `...methods: PropertyKey[]` - Names of the methods to check for.

```js
import { hasAllMethods } from '@aedart/support/reflections';

const a = {
foo: () => { /* ...not shown... */ },
bar: () => { /* ...not shown... */ },
}

hasAllMethods(a, 'foo', 'bar'); // true
hasAllMethods(a, 'foo', 'bar', 'zar'); // false
```
Loading

0 comments on commit bd1cbe1

Please sign in to comment.