Skip to content

Commit

Permalink
feat(kernel): add resource definition helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
fkleuver committed Oct 20, 2019
1 parent b85bb6e commit a318317
Showing 1 changed file with 77 additions and 0 deletions.
77 changes: 77 additions & 0 deletions packages/kernel/src/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,80 @@ export const Protocol = {
resource,
};

// eslint-disable-next-line @typescript-eslint/unbound-method
const hasOwn = Object.prototype.hasOwnProperty;

/**
* The order in which the values are checked:
* 1. Annotations (usually set by decorators) have the highest priority; they override the definition as well as static properties on the type.
* 2. Definition properties (usually set by the customElement decorator object literal) come next. They override static properties on the type.
* 3. Static properties on the type come last. Note that this does not look up the prototype chain (bindables are an exception here, but we do that differently anyway)
* 4. The default property that is provided last. The function is only called if the default property is needed
*/
export function fromAnnotationOrDefinitionOrTypeOrDefault<
TDef extends PartialResourceDefinition,
K extends keyof TDef,
>(
name: K,
def: TDef,
Type: Constructable,
getDefault: () => Required<TDef>[K],
): Required<TDef>[K] {
let value = Metadata.getOwn(Protocol.annotation.keyFor(name as string), Type) as TDef[K] | undefined;
if (value === void 0) {
value = def[name];
if (value === void 0) {
value = (Type as Constructable & TDef)[name] as TDef[K] | undefined;
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (value === void 0 || !hasOwn.call(Type, name)) { // First just check the value (common case is faster), but do make sure it doesn't come from the proto chain
return getDefault();
}
return value;
}
return value;
}
return value;
}

/**
* The order in which the values are checked:
* 1. Annotations (usually set by decorators) have the highest priority; they override static properties on the type.
* 2. Static properties on the typ. Note that this does not look up the prototype chain (bindables are an exception here, but we do that differently anyway)
* 3. The default property that is provided last. The function is only called if the default property is needed
*/
export function fromAnnotationOrTypeOrDefault<T, K extends keyof T, V>(
name: K,
Type: T,
getDefault: () => V,
): V {
let value = Metadata.getOwn(Protocol.annotation.keyFor(name as string), Type) as V;
if (value === void 0) {
value = Type[name] as unknown as V;
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (value === void 0 || !hasOwn.call(Type, name)) { // First just check the value (common case is faster), but do make sure it doesn't come from the proto chain
return getDefault();
}
return value;
}
return value;
}

/**
* The order in which the values are checked:
* 1. Definition properties.
* 2. The default property that is provided last. The function is only called if the default property is needed
*/
export function fromDefinitionOrDefault<
TDef extends PartialResourceDefinition,
K extends keyof TDef,
>(
name: K,
def: TDef,
getDefault: () => Required<TDef>[K],
): Required<TDef>[K] {
const value = def[name];
if (value === void 0) {
return getDefault();
}
return value;
}

0 comments on commit a318317

Please sign in to comment.