Skip to content

Commit

Permalink
fix(core): fixes circular dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
rafamel committed Oct 16, 2019
1 parent c96f0d0 commit bf81644
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,14 @@ import {
Element,
Service,
Type,
ServiceImplementation,
QueryService,
MutationService,
SubscriptionService,
ErrorType,
RequestType,
ResponseType,
TypeImplementation,
ScopeTree,
TreeImplementation
ScopeTree
} from '~/types';
import { traverse } from './traverse';
import { emptyCollection } from '~/utils';

export function isElement(item: any): item is Element {
return (
Expand Down Expand Up @@ -75,58 +70,3 @@ export function isTypeRequest(type: Type): type is RequestType {
export function isTypeResponse(type: Type): type is ResponseType {
return type.kind === 'response';
}

export function isTreeImplementation(
tree: Tree,
fail?: boolean
): tree is TreeImplementation {
const collection = isTreeCollection(tree)
? tree
: { ...emptyCollection(), scopes: { tree } };

let isImplementation: null | boolean = null;
try {
traverse(collection, (element, next) => {
next();

if (isElementService(element)) {
const is = isServiceImplementation(element);
if (isImplementation === null) {
isImplementation = is;
} else if (isImplementation !== is) {
throw Error(
`Both service implementations and declarations were found in tree`
);
}
}
});
} catch (err) {
if (fail) {
throw err;
} else {
isImplementation = false;
}
}

return isImplementation === null ? true : isImplementation;
}

export function isServiceImplementation(
service: Service
): service is ServiceImplementation {
return (
Object.hasOwnProperty.call(service, 'resolve') &&
typeof (service as any).resolve === 'function'
);
}

export function isTypeImplementation(type: Type): type is TypeImplementation {
return (
isTypeError(type) ||
isTypeRequest(type) ||
!type.children ||
Object.values(type.children).reduce((acc: boolean, service) => {
return acc && isServiceImplementation(service);
}, true)
);
}
71 changes: 71 additions & 0 deletions packages/core/src/inspect/is/implementation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
Tree,
TreeImplementation,
Service,
ServiceImplementation,
Type,
TypeImplementation
} from '~/types';
import {
isTreeCollection,
isElementService,
isTypeError,
isTypeRequest
} from './element';
import { emptyCollection } from '~/utils';
import { traverse } from '../traverse';

export function isTreeImplementation(
tree: Tree,
fail?: boolean
): tree is TreeImplementation {
const collection = isTreeCollection(tree)
? tree
: { ...emptyCollection(), scopes: { tree } };

let isImplementation: null | boolean = null;
try {
traverse(collection, (element, next) => {
next();

if (isElementService(element)) {
const is = isServiceImplementation(element);
if (isImplementation === null) {
isImplementation = is;
} else if (isImplementation !== is) {
throw Error(
`Both service implementations and declarations were found in tree`
);
}
}
});
} catch (err) {
if (fail) {
throw err;
} else {
isImplementation = false;
}
}

return isImplementation === null ? true : isImplementation;
}

export function isServiceImplementation(
service: Service
): service is ServiceImplementation {
return (
Object.hasOwnProperty.call(service, 'resolve') &&
typeof (service as any).resolve === 'function'
);
}

export function isTypeImplementation(type: Type): type is TypeImplementation {
return (
isTypeError(type) ||
isTypeRequest(type) ||
!type.children ||
Object.values(type.children).reduce((acc: boolean, service) => {
return acc && isServiceImplementation(service);
}, true)
);
}
2 changes: 2 additions & 0 deletions packages/core/src/inspect/is/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './element';
export * from './implementation';
2 changes: 1 addition & 1 deletion packages/core/src/transform/normalize/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
SubscriptionService,
InterceptImplementation
} from '~/types';
import { isServiceImplementation } from '~/inspect';
import { isServiceImplementation } from '~/inspect/is';
import isequal from 'lodash.isequal';

export function normalizeServiceTypes(
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/transform/replace/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import {
isElementTree,
isElementType,
isElementService
} from '~/inspect/is';
import { ReplaceTransformFn, ReplaceTransformData } from './replace';
} from '~/inspect/is/element';
import { ReplaceTransformData, ReplaceTransformFn } from './types';

export function next<E extends Element>(
element: E,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/transform/replace/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './replace';
export * from './types';
23 changes: 1 addition & 22 deletions packages/core/src/transform/replace/replace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,10 @@ import {
QueryService,
MutationService,
SubscriptionService,
Element,
CollectionTree
} from '~/types';
import { next } from './helpers';

export type ReplaceTransformFn<
Q extends QueryService = QueryService,
M extends MutationService = MutationService,
S extends SubscriptionService = SubscriptionService
> = (
element: Element<Q, M, S>,
next: ReplaceTransformNextFn<Q, M, S>,
data: ReplaceTransformData
) => Element;

export type ReplaceTransformNextFn<
Q extends QueryService = QueryService,
M extends MutationService = MutationService,
S extends SubscriptionService = SubscriptionService
> = (element?: Element<Q, M, S>) => Element;

export interface ReplaceTransformData {
path: string[];
route: string[];
}
import { ReplaceTransformFn } from './types';

/**
* Returns a new collection where `Element`s are substituted by the ones returned by `cb`. Performs a traversal.
Expand Down
27 changes: 27 additions & 0 deletions packages/core/src/transform/replace/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
QueryService,
MutationService,
SubscriptionService,
Element
} from '~/types';

export type ReplaceTransformFn<
Q extends QueryService = QueryService,
M extends MutationService = MutationService,
S extends SubscriptionService = SubscriptionService
> = (
element: Element<Q, M, S>,
next: ReplaceTransformNextFn<Q, M, S>,
data: ReplaceTransformData
) => Element;

export type ReplaceTransformNextFn<
Q extends QueryService = QueryService,
M extends MutationService = MutationService,
S extends SubscriptionService = SubscriptionService
> = (element?: Element<Q, M, S>) => Element;

export interface ReplaceTransformData {
path: string[];
route: string[];
}
7 changes: 6 additions & 1 deletion packages/core/src/transform/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ export interface RoutesTransformOptions {
* A non word character containing string. Default: `':'`.
*/
separator: string;
// TODO: (also check first-level/root service names don't collide with type names)
/**
* Whether to include response types with children as routes. Default: `true`.
*/
children: boolean;
}

/**
Expand All @@ -24,7 +29,7 @@ export function routes<T extends CollectionTree>(
collection: T,
options?: RoutesTransformOptions
): CollectionRoutes<T> {
const opts = Object.assign({ separator: ':' }, options);
const opts = Object.assign({ separator: ':', children: true }, options);
const routes: CollectionRoutes<any> = {};

if (!/[^\w]/.exec(opts.separator)) {
Expand Down

0 comments on commit bf81644

Please sign in to comment.