ts-code-contracts
Version:
Design by contract with TypeScript.
258 lines (257 loc) • 9.34 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.unreachable = exports.error = exports.isDefined = exports.asserts = exports.ensuresNonNullish = exports.ensures = exports.checksNonNullish = exports.checks = exports.requiresNonNullish = exports.requires = exports.AssertionError = exports.PostconditionError = exports.IllegalStateError = exports.PreconditionError = exports.ContractError = void 0;
/**
* An error thrown by a code contract.
*/
var ContractError = /** @class */ (function (_super) {
__extends(ContractError, _super);
function ContractError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return ContractError;
}(Error));
exports.ContractError = ContractError;
/**
* An error thrown, if a precondition for a function or method is not met.
*/
var PreconditionError = /** @class */ (function (_super) {
__extends(PreconditionError, _super);
function PreconditionError(message) {
var _this = _super.call(this, message) || this;
_this.name = 'PreconditionError';
return _this;
}
return PreconditionError;
}(ContractError));
exports.PreconditionError = PreconditionError;
/**
* An error thrown, if an object is an illegal state.
*/
var IllegalStateError = /** @class */ (function (_super) {
__extends(IllegalStateError, _super);
function IllegalStateError(message) {
var _this = _super.call(this, message) || this;
_this.name = 'IllegalStateError';
return _this;
}
return IllegalStateError;
}(ContractError));
exports.IllegalStateError = IllegalStateError;
/**
* An error thrown, if a function or method could not fulfil a postcondition.
*/
var PostconditionError = /** @class */ (function (_super) {
__extends(PostconditionError, _super);
function PostconditionError(message) {
var _this = _super.call(this, message) || this;
_this.name = 'PostconditionError';
return _this;
}
return PostconditionError;
}(ContractError));
exports.PostconditionError = PostconditionError;
/**
* An error thrown, if an assertion has failed.
*/
var AssertionError = /** @class */ (function (_super) {
__extends(AssertionError, _super);
function AssertionError(message) {
var _this = _super.call(this, message) || this;
_this.name = 'AssertionError';
return _this;
}
return AssertionError;
}(ContractError));
exports.AssertionError = AssertionError;
/**
* Throws a `PreconditionError` if the `condition` is `false`.
* @param condition the precondition that should be `true`
* @param message an optional message for the error
* @throws PreconditionError if the condition is `false`
* @see PreconditionError
* @example
* function myFun(name: string) {
* requires(name.length > 10, 'Name must be longer than 10 chars');
* }
*/
function requires(condition, message) {
if (message === void 0) { message = 'Unmet precondition'; }
if (!condition) {
throw new PreconditionError(message);
}
}
exports.requires = requires;
/**
* Returns the given value unchanged if it is not `null` or `undefined`.
* Throws a `PreconditionError` otherwise.
* @param value the value that should not be `null` or `undefined`
* @param message an optional message for the error
* @throws PreconditionError if the value is `null` or `undefined`
* @see requires
* @example
* function myFun(name: string | null) {
* const nameNonNull = requiresNonNullish(name, 'Name must be defined');
* nameNonNull.toUpperCase(); // no compiler error!
* }
*/
function requiresNonNullish(value, message) {
if (message === void 0) { message = 'Value must not be null or undefined'; }
requires(isDefined(value), message);
return value;
}
exports.requiresNonNullish = requiresNonNullish;
/**
* Throws a `IllegalStateError` if the `condition` is `false`.
* @param condition the condition that should be `true`
* @param message an optional message for the error
* @throws IllegalStateError if the condition is `false`
* @see IllegalStateError
* @example
* class Socket {
* private isOpen = false;
* send(data: Data) {
* check(this.isOpen, 'Socket must be open');
* }
* open() {
* this.isOpen = true;
* }
* }
*/
function checks(condition, message) {
if (message === void 0) { message = 'Callee invariant violation'; }
if (!condition) {
throw new IllegalStateError(message);
}
}
exports.checks = checks;
/**
* Returns the given value unchanged if it is not `null` or `undefined`.
* Throws a `IllegalStateError` otherwise.
* @param value the value that should not be `null` or `undefined`
* @param message an optional message for the error
* @throws IllegalStateError if the value is `null` or `undefined`
* @see checks
* @example
* class Socket {
* data: Data | null = null;
* send() {
* const validData = checksNonNullish(this.data, 'Data must be available');
* validData.send(); // no compiler error!
* }
* }
*/
function checksNonNullish(value, message) {
if (message === void 0) { message = 'Value must not be null or undefined'; }
checks(isDefined(value), message);
return value;
}
exports.checksNonNullish = checksNonNullish;
/**
* Throws a `PostconditionError` if the `condition` is `false`.
* @param condition the condition that should be `true`
* @param message an optional message for the error
* @throws PostconditionError if the condition is `false`
* @see PostconditionError
* @example
* function myFun() {
* createPerson({ id: 0, name: 'John' });
* const entity = findById(0); // returns null if not present
* return ensures(isDefined(entity), 'Failed to persist entity');
* }
*/
function ensures(condition, message) {
if (message === void 0) { message = 'Unmet postcondition'; }
if (!condition) {
throw new PostconditionError(message);
}
}
exports.ensures = ensures;
/**
* Returns the given value unchanged if it is not `null` or `undefined`.
* Throws a `PostconditionError` otherwise.
* @param value the value that must not be `null` or `undefined`
* @param message an optional message for the error
* @throws PostconditionError if the value is `null` or `undefined`
* @see ensures
* @example
* function myFun(): Person {
* createPerson({ id: 0, name: 'John' });
* const entity = findById(0); // returns null if not present
* return ensuresNonNullish(entity, 'Failed to persist entity');
* }
*/
function ensuresNonNullish(value, message) {
if (message === void 0) { message = 'Value must not be null or undefined'; }
ensures(isDefined(value), message);
return value;
}
exports.ensuresNonNullish = ensuresNonNullish;
/**
* Throws a `AssertionError` if the `condition` is `false`.
* @param condition the condition that must be `true`
* @param message an optional message for the error
* @throws AssertionError if the condition is `false`
* @see AssertionError
*/
function asserts(condition, message) {
if (!condition) {
throw new AssertionError(message);
}
}
exports.asserts = asserts;
/**
* Returns `true` if the value is not `null` or `undefined`.
* @param value the value to test
* @example
* const x: string | null = 'Hello';
* if (isDefined(x)) {
* x.toLowerCase(); // no compiler error!
* }
*/
function isDefined(value) {
return value != null;
}
exports.isDefined = isDefined;
function error(errorType, message) {
throw errorType == null || typeof errorType === 'string'
? new IllegalStateError(errorType)
: new errorType(message);
}
exports.error = error;
/* eslint-enable @typescript-eslint/no-explicit-any, new-cap */
/* eslint-disable @typescript-eslint/no-unused-vars */
/**
* Asserts that a code branch is unreachable. If it is, the compiler will throw a type error.
* If this function is reached at runtime, an error will be thrown.
* @param value a value
* @param message an optional message for the error
* @throws AssertionError in any case
* @example
* function myFun(foo: MyEnum): string {
* switch(foo) {
* case MyEnum.A: return 'a';
* case MyEnum.B: return 'b';
* // no compiler error if MyEnum only has A and B
* default: unreachable(foo);
* }
* }
*/
function unreachable(value, message) {
if (message === void 0) { message = 'Reached an unreachable case'; }
throw new AssertionError(message);
}
exports.unreachable = unreachable;