Skip to content

Commit

Permalink
feat(core): adds options for validation and normalization
Browse files Browse the repository at this point in the history
  • Loading branch information
rafamel committed Oct 16, 2019
1 parent dcdfddc commit c0d80ce
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 9 deletions.
31 changes: 28 additions & 3 deletions packages/core/src/inspect/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ import { isTreeImplementation } from './is';

// TODO: validate collection object (ajv) + check schemas are valid

export interface ValidateInspectOptions {
/**
* If specified, it will also throw if the collection is not a full implementation or solely a declaration, in each case. Default: `null`.
*/
as?: 'implementation' | 'declaration' | null;
/**
* Doesn't check reference types do exist in a collection. Default: `false`.
*/
skipReferences?: boolean | string[];
}

/**
* It will throw if a collection:
* - Is either fully a implementation or not at all.
Expand All @@ -17,9 +28,23 @@ import { isTreeImplementation } from './is';
* @returns `true` if a collection is a `CollectionTreeImplementation`.
*/
export function validate(
collection: CollectionTree
collection: CollectionTree,
options?: ValidateInspectOptions
): collection is CollectionTreeImplementation {
const opts = Object.assign({ as: null, skipReferences: false }, options);

routes(collection);
normalize(collection);
return isTreeImplementation(collection, true);
normalize(collection, opts);

const isImplementation = isTreeImplementation(collection, true);
if (opts.as) {
if (opts.as === 'implementation' && !isImplementation) {
throw Error(`Collection is not a implementation`);
}
if (opts.as === 'declaration' && isImplementation) {
throw Error(`Collection is not a declaration`);
}
}

return isImplementation;
}
22 changes: 17 additions & 5 deletions packages/core/src/transform/normalize/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import isequal from 'lodash.isequal';
export function normalizeServiceTypes(
name: string,
service: Service,
skip: boolean | string[],
types: { source: TreeTypes; normal: TreeTypes },
transform: (str: string, isExplicit: boolean) => string
): Service {
Expand All @@ -21,16 +22,17 @@ export function normalizeServiceTypes(
for (const kind of ['request', 'response'] as ['request', 'response']) {
const type = service.types[kind];
if (typeof type === 'string') {
service.types[kind] = checkSourceType(kind, type, types, transform);
service.types[kind] = checkSourceType(kind, type, skip, types, transform);
} else {
const pascal = name + transform('R' + kind.slice(1), false);
normalizeServiceType(kind, pascal, type, types, transform);
normalizeServiceType(kind, pascal, type, skip, types, transform);
service.types[kind] = pascal;
}
}

service.types.errors = normalizeErrors(
service.types.errors,
skip,
types,
transform
);
Expand All @@ -44,7 +46,7 @@ export function normalizeServiceTypes(
for (const intercept of service.intercepts) {
intercepts.push({
...intercept,
errors: normalizeErrors(intercept.errors, types, transform)
errors: normalizeErrors(intercept.errors, skip, types, transform)
});
}
service.intercepts = intercepts;
Expand All @@ -55,27 +57,29 @@ export function normalizeServiceTypes(

export function normalizeErrors(
errors: ServiceErrors,
skip: boolean | string[],
types: { source: TreeTypes; normal: TreeTypes },
transform: (str: string, isExplicit: boolean) => string
): ServiceErrors {
const result: ServiceErrors = {};
for (const [key, error] of Object.entries(errors)) {
if (typeof error === 'string') {
let id = checkSourceType('error', error, types, transform);
let id = checkSourceType('error', error, skip, types, transform);
if (key !== error) {
id = transform(key, true);
normalizeServiceType(
'error',
id,
types.source[error],
skip,
types,
transform
);
}
result[id] = id;
} else {
const id = transform(key, true);
normalizeServiceType('error', id, error, types, transform);
normalizeServiceType('error', id, error, skip, types, transform);
result[id] = id;
}
}
Expand All @@ -86,6 +90,7 @@ export function normalizeServiceType(
kind: string,
name: string,
type: Type,
skip: boolean | string[],
types: { source: TreeTypes; normal: TreeTypes },
transform: (str: string, isExplicit: boolean) => string
): void {
Expand Down Expand Up @@ -131,6 +136,7 @@ export function normalizeServiceType(
item.children[key] = normalizeServiceTypes(
name + transform(key, false),
service,
skip,
types,
transform
) as QueryService | SubscriptionService;
Expand All @@ -148,10 +154,16 @@ export function normalizeServiceType(
export function checkSourceType(
kind: string,
name: string,
skip: boolean | string[],
types: { source: TreeTypes; normal: TreeTypes },
transform: (str: string, isExplicit: boolean) => string
): string {
const pascal = transform(name, true);

if (skip && (typeof skip === 'boolean' || skip.includes(name))) {
return pascal;
}

if (
!Object.hasOwnProperty.call(types.source, name) ||
!Object.hasOwnProperty.call(types.normal, pascal)
Expand Down
14 changes: 13 additions & 1 deletion packages/core/src/transform/normalize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import { normalizeServiceTypes } from './helpers';
import { replace } from '../replace';
import { isElementType, isElementService, isElementTree } from '~/inspect/is';

export interface NormalizeTransformOptions {
/**
* Doesn't check reference types do exist in a collection. Default: `false`.
*/
skipReferences?: boolean | string[];
}

/**
* Extracts all service inline types of a collection to its top level `CollectionTree.types`, naming them according to their scope, service, and kind. It additionally transforms all type names to pascal case. It will throw if a collection:
* - Produces conflicting type names.
Expand All @@ -18,8 +25,11 @@ import { isElementType, isElementService, isElementTree } from '~/inspect/is';
* - Contains services with inline types or type references of the wrong kind.
*/
export function normalize<T extends CollectionTree>(
collection: T
collection: T,
options?: NormalizeTransformOptions
): NormalCollection<T> {
const opts = Object.assign({ skipReferences: false }, options);

const transform = (str: string, _isExplicit: boolean): string => {
return camelcase(str, { pascalCase: true });
};
Expand Down Expand Up @@ -66,6 +76,7 @@ export function normalize<T extends CollectionTree>(
response.children[key] = normalizeServiceTypes(
name + transform(key, false),
service,
opts.skipReferences,
types,
transform
) as QueryService | SubscriptionService;
Expand All @@ -79,6 +90,7 @@ export function normalize<T extends CollectionTree>(
? transform(route[route.length - 2], false) + name
: name,
element,
opts.skipReferences,
types,
transform
);
Expand Down

0 comments on commit c0d80ce

Please sign in to comment.