Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 37x 37x 37x 37x 239x 37x 545x 37x 301x 239x 545x 2x 543x 543x 543x 8x 238x 240x 238x 238x 240x 238x 2x 37x 238x | import { BasicContract } from "@jonloucks/contracts-ts/api/BasicContract";
import { Config, Contract } from "@jonloucks/contracts-ts/api/Contract";
import { ContractException } from "@jonloucks/contracts-ts/api/ContractException";
import { OptionalType, RequiredType, isNotPresent, isPresent } from "@jonloucks/contracts-ts/api/Types";
/**
* A RatifiedContract is a Contract that has been verified to have either a test or cast function.
* This ensures that the contract can actually perform some form of validation or transformation.
* A type guard is required to create a RatifiedContract.
*
* @param <T> the type of deliverable for this Contract
* @param config the configuration for the RatifiedContract
* @returns the created RatifiedContract
*/
export function create<T>(config?: Config<T> | undefined): Contract<T> {
return RatifiedContract.create<T>(config);
}
/**
* Checks if the given instance is a RatifiedContract.
* @param instance the instance to check
* @returns true if the instance is a RatifiedContract, false otherwise
*/
export function isRatifiedContract(instance: unknown): instance is RatifiedContract<unknown> {
return RatifiedContract.isRatifiedContract(instance);
}
/**
* Checks if the given configuration is ratifiable.
*
* @param config the configuration to check
* @returns true if the configuration is ratifiable, false otherwise
*/
export function isRatifiableConfig<T>(config?: OptionalType<Config<T>>): config is RequiredType<Config<T>> {
return isPresent(config) && isPresent(config.test);
}
/**
* A RatifiedContract is a Contract that has been verified to have either a test or cast function.
* This ensures that the contract can actually perform some form of validation or transformation.
*
* @param <T> the type of deliverable for this Contract
*/
class RatifiedContract<T> extends BasicContract<T> {
/**
* Create a contract derived from the given configuration
*
* @param config the name for the contract, null is not allowed
* @param <T> the type of deliverable for this Contract
* @return the new Contract
*/
static create<T>(config?: Config<T> | undefined): Contract<T> {
return new RatifiedContract<T>(config);
}
static isRatifiedContract(instance: unknown): instance is RatifiedContract<unknown> {
if (isNotPresent(instance)) {
return false;
}
try {
const candidate = instance as RatifiedContract<unknown>;
return candidate.#secret === RatifiedContract.#SECRET;
} catch {
return false;
}
}
/**
* Being a RatifiedContract means something special. It is not something that you proclaim
* by extending the class or duck-typing.
* This is an integrity check to prevent duck-typing or extending Contract class.
* Since private constructors can still be invoked.
* This is not a security mechanism, just an integrity check.
* This relies on TypeScript private fields which are enforced at runtime.
*
* @throws ContractException when integrity check fails
*/
private integrityCheck(): void {
Iif (this.#secret !== RatifiedContract.#SECRET) {
throw new ContractException('Integrity violation detected. This is not permitted.');
}
}
private constructor(config?: OptionalType<Config<T>>) {
super(RatifiedContract.validateConfig(config));
Object.freeze(this);
this.integrityCheck();
}
private static validateConfig<T>(config?: OptionalType<Config<T>>): RequiredType<Config<T>> {
if (isRatifiableConfig(config)) {
return config as RequiredType<Config<T>>;
}
throw new ContractException("RatifiedContract requires either a test or cast function must be present.");
}
static readonly #SECRET: symbol = Symbol("Contract");
readonly #secret: symbol = RatifiedContract.#SECRET;
} |