Skip to content

Commit b29903f

Browse files
author
3y3k0
committed
initial
0 parents  commit b29903f

File tree

9 files changed

+153
-0
lines changed

9 files changed

+153
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/node_modules
2+
/build

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "@modelsjs/resolver",
3+
"version": "0.0.1",
4+
"type": "module",
5+
"main": "build/index.js",
6+
"types": "build/index.d.ts",
7+
"scripts": {
8+
"build": "tsc"
9+
},
10+
"dependencies": {
11+
"@modelsjs/model": "^0.0.1",
12+
"@modelsjs/tsconfig": "^0.0.1",
13+
"@modelsjs/types": "^0.0.1"
14+
}
15+
}

src/config.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { IStrategy } from './types';
2+
3+
const prop = <T>(key: string, defaults?: T) => ({
4+
get(): T {
5+
if (defaults) {
6+
return defaults;
7+
}
8+
9+
throw new Error(`Key '${key}' is not configured.`);
10+
},
11+
12+
set(value: T) {
13+
Object.defineProperty(this, key, {
14+
set() {
15+
throw new Error(`Key '${key}' is already configured.`);
16+
},
17+
18+
get() {
19+
return value;
20+
}
21+
});
22+
}
23+
});
24+
25+
export const config = Object.create(null, {
26+
defaultStrategy: prop<Nullable<IStrategy>>('defaultStrategy', null)
27+
});

src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type { IStrategy, TResolver } from './types';
2+
export { config } from './config';
3+
export { resolve } from './resolve';
4+
export { resolvable } from './resolvable';

src/resolvable.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { Model } from '@modelsjs/model';
2+
import type { IStrategy } from './types';
3+
import { config } from './config';
4+
import { ResolveStrategy } from './symbols';
5+
6+
type TStrategies = Record<symbol, IStrategy>;
7+
8+
export interface IResolvable<M extends Model> {
9+
[prop: string]: any;
10+
11+
[ResolveStrategy]: TStrategies;
12+
}
13+
14+
export function resolvable<M extends Model>(strategy: IStrategy): ClassDecorator
15+
export function resolvable<M extends Model>(target: ClassDescriptor): void
16+
export function resolvable<M extends Model>(target: any): any {
17+
const strategy: IStrategy = isClassDescriptor(target) ? config.defaultStrategy : target;
18+
19+
function decorator({elements}: ClassDescriptor) {
20+
elements.push({
21+
kind: 'field',
22+
placement: 'own',
23+
key: strategy.kind,
24+
descriptor: {},
25+
initializer: function() {
26+
return strategy;
27+
}
28+
} as FieldDescriptor);
29+
}
30+
31+
return isClassDescriptor(target) ? decorator(target) : decorator;
32+
}
33+
34+
resolvable.get = <M extends Model>(resolvable: Partial<IResolvable<M>>): TStrategies | null => {
35+
return resolvable[ResolveStrategy] || null;
36+
}
37+
38+
function isClassDescriptor(target: any): target is ClassDescriptor {
39+
return target?.kind === 'class' && Array.isArray(target.elements);
40+
}

src/resolve.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { Model } from '@modelsjs/model';
2+
import type { TResolver, ISyncResolver } from './types';
3+
4+
export async function resolve(models: Model[], resolvers: TResolver[]) {
5+
let [ resolved, rest ] = [ [] as Model[], models.slice() ];
6+
for (const resolver of resolvers) {
7+
if (!rest.length) {
8+
return;
9+
}
10+
11+
if (isSync(resolver)) {
12+
[ resolved, rest ] = resolver.sync(models);
13+
} else {
14+
[ resolved, rest ] = await resolver.async(models);
15+
}
16+
}
17+
}
18+
19+
resolve.sync = (models: Model[], resolvers: TResolver[]) => {
20+
let [ resolved, rest ] = [ [] as Model[], models.slice() ];
21+
for (const resolver of resolvers) {
22+
if (!rest.length) {
23+
return;
24+
}
25+
26+
if (isSync(resolver)) {
27+
[ resolved, rest ] = resolver.sync(models);
28+
}
29+
}
30+
}
31+
32+
function isSync(resolver: TResolver): resolver is ISyncResolver {
33+
return 'sync' in resolver;
34+
}

src/symbols.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const ResolveStrategy = Symbol('ResolveStrategy');

src/types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { Model } from '@modelsjs/model';
2+
3+
export type TDecorated<T> = T & {
4+
[prop: symbol]: IStrategy
5+
};
6+
7+
export interface ISyncResolver {
8+
sync(models: Model[]): [ Model[], Model[] ];
9+
}
10+
11+
export interface IAsyncResolver {
12+
async(models: Model[]): Promise<[ Model[], Model[] ]>;
13+
}
14+
15+
export type TResolver = OneOf<ISyncResolver & IAsyncResolver>;
16+
17+
export interface IStrategy {
18+
kind: symbol;
19+
}

tsconfig.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "@modelsjs/tsconfig/tsconfig",
3+
"compilerOptions": {
4+
"outDir": "build"
5+
},
6+
"include": [
7+
"src",
8+
"node_modules/@modelsjs/types",
9+
"../../node_modules/@modelsjs/types"
10+
]
11+
}

0 commit comments

Comments
 (0)