UNPKG

@final-hill/decorator-contracts

Version:

Code Contracts for TypeScript and ECMAScript classes

1 lines 25.8 kB
{"version":3,"file":"index.mjs","mappings":"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","sources":["webpack://@final-hill/decorator-contracts/./src/types.mts","webpack://@final-hill/decorator-contracts/./src/AssertionError.mts","webpack://@final-hill/decorator-contracts/./src/assert.mts","webpack://@final-hill/decorator-contracts/./src/iff.mts","webpack://@final-hill/decorator-contracts/./src/implies.mts","webpack://@final-hill/decorator-contracts/./src/invariant.mts","webpack://@final-hill/decorator-contracts/./src/demands.mts","webpack://@final-hill/decorator-contracts/./src/ensures.mts","webpack://@final-hill/decorator-contracts/./src/rescue.mts","webpack://@final-hill/decorator-contracts/./src/Contracted.mts"],"sourcesContent":["// Polyfill Symbol.metadata if not present\r\n// ref: https://github.com/microsoft/TypeScript/issues/53461#issuecomment-1736996954\r\n// ref: https://github.com/tc39/proposal-decorator-metadata\r\n(Symbol as any).metadata ??= Symbol.for(\"Symbol.metadata\");\r\n\r\n// Extend the global SymbolConstructor type to include metadata\r\ndeclare global {\r\n interface SymbolConstructor {\r\n readonly metadata: symbol;\r\n }\r\n}\r\n\r\nexport type Constructor<T> = new (...args: any[]) => T\r\n\r\nexport type FeatureDecoratorContext = Exclude<ClassMemberDecoratorContext, ClassAccessorDecoratorContext>;","/**\r\n * An AssertionError represents a failed assertion with an associated message\r\n */\r\nexport class AssertionError extends Error { }\r\n","import { AssertionError } from \"./AssertionError.mjs\";\r\n\r\n/**\r\n * An assertion is an expression of a property that must be true at a particular\r\n * point of step of program execution. It consists of a boolean expression\r\n * and a message. This function tests the provided condition. If the condition\r\n * is false an AssertionError is raised with an optional message.\r\n * If the provided condition is true then the function returns without raising an error\r\n *\r\n * @param condition - The condition to test. If it is false an error is raised.\r\n * @param message - The message to display if the condition is false. If not provided a default message is used.\r\n * @throws {AssertionError} If the condition is false an AssertionError is raised.\r\n *\r\n * @example\r\n * ```ts\r\n * import assert from \"assert.mjs\";\r\n *\r\n * let x = 15;\r\n * assert(x > 5, `Expected: x > 5. Actual: x = ${x}`);\r\n * ```\r\n */\r\n\r\nexport function assert(condition: unknown, message: string = 'Assertion Error'): asserts condition {\r\n if (Boolean(condition) == false)\r\n throw new AssertionError(message);\r\n}\r\n","/**\r\n * Biconditional.\r\n * p ↔ q.\r\n * \"P if and only if Q\".\r\n * An example of usage is the encoding of \"You can ride the train if and only if you have a ticket\"\r\n * This is logically equivalent to: implies(p,q) && implies(q,p)\r\n *\r\n * @param p - The first boolean value (the antecedent).\r\n * @param q - The second boolean value (the consequent).\r\n * @returns - The result (biconditional) of p and q.\r\n *\r\n * @example\r\n * ```ts\r\n * import { iff } from '@final-hill/decorator-contracts';\r\n *\r\n * // You can ride the train if and only if you have a ticket\r\n * iff(person.hasTicket, person.ridesTrain)\r\n * ```\r\n */\r\n\r\nexport function iff(p: boolean, q: boolean): boolean {\r\n return (p && q) || (!p && !q);\r\n}\r\n","/**\r\n * Material Implication.\r\n * `p → q`\r\n * Also referred to as `if-then`.\r\n * An example of usage is the encoding of \"sunny weather is a precondition of visiting the beach\"\r\n * This is logically equivalent to: !p || q\r\n *\r\n * @param p - The first boolean value (the antecedent).\r\n * @param q - The second boolean value (the consequent).\r\n * @returns - The result (material implication) of p and q.\r\n *\r\n * @example\r\n * ```ts\r\n * import { implies } from '@final-hill/decorator-contracts';\r\n *\r\n * // Sunny weather is a precondition of visiting the beach\r\n * implies(weather.isSunny, person.visitsBeach)\r\n * ```\r\n */\r\n\r\nexport function implies(p: boolean, q: boolean): boolean {\r\n return !p || q;\r\n}\r\n","import { assert } from './assert.mjs';\r\nimport { checkedMode, Contracted } from './Contracted.mjs';\r\n\r\nexport type InvariantPredicate<Class extends typeof Contracted> = (self: InstanceType<Class>) => boolean;\r\n\r\nexport type InvariantDecorator = <Class extends typeof Contracted>(\r\n predicate: InvariantPredicate<Class>\r\n) => (\r\n value: Class,\r\n context: ClassDecoratorContext<Class>\r\n) => Class | void;\r\n\r\nexport function assertInvariants<C extends typeof Contracted, T extends InstanceType<C>>(Class: C, instance: T) {\r\n if (!Contracted[checkedMode]) return;\r\n\r\n Contracted[checkedMode] = false; // Disable checked mode to avoid infinite recursion \r\n\r\n const invariants = (Class[Symbol.metadata]?.['invariants'] ?? []) as InvariantPredicate<C>[];\r\n\r\n try {\r\n for (const inv of invariants)\r\n assert(\r\n inv(instance),\r\n `Invariant violated in class ${Class.name}: ${inv.toString()}`\r\n );\r\n } finally {\r\n Contracted[checkedMode] = true;\r\n }\r\n}\r\n\r\nexport const invariant: InvariantDecorator = (predicate) => (OriginalClass, { kind, metadata }) => {\r\n assert(kind === 'class', '@invariant decorator can only be applied to classes');\r\n assert(OriginalClass.prototype instanceof Contracted, '@invariant decorator can only be applied to classes that extend Contracted');\r\n\r\n const existing = (metadata.invariants ?? []) as InvariantPredicate<typeof OriginalClass>[]\r\n metadata.invariants = [...existing, predicate];\r\n};\r\n","import { assert } from './assert.mjs';\r\nimport { checkedMode, Contracted } from \"./Contracted.mjs\";\r\nimport type { FeatureDecoratorContext } from './types.mjs';\r\n\r\nexport type DemandsPredicate<This extends Contracted> = (self: This, ...args: any[]) => boolean;\r\n\r\nexport type DemandsDecorator = <This extends Contracted, Feature = unknown>(\r\n predicate: DemandsPredicate<This>\r\n) => (\r\n value: Feature,\r\n context: FeatureDecoratorContext\r\n) => Feature | void;\r\n\r\nexport const demands: DemandsDecorator = (predicate) => (_feature, ctx) => {\r\n assert([\"method\", \"getter\", \"setter\"].includes(ctx.kind), '@demands decorator can only be applied to methods, getters, or setters');\r\n assert(ctx.static === false, '@demands decorator cannot be applied to static features');\r\n assert(ctx.private === false, '@demands decorator cannot be applied to private/protected features');\r\n assert(!String(ctx.name).startsWith('_'), '@demands decorator cannot be applied to private/protected features');\r\n\r\n ctx.addInitializer(function () {\r\n assert(this instanceof Contracted, '@demands decorator can only be applied to classes that extend Contracted');\r\n const ds = [\r\n ...(ctx.metadata as any)?.demands?.[ctx.name] ?? [],\r\n predicate\r\n ]\r\n\r\n ctx.metadata.demands = {\r\n ...(ctx.metadata?.demands ?? {}),\r\n [ctx.name]: ds\r\n };\r\n })\r\n}\r\n\r\nexport function assertDemands(instance: Contracted, propertyKey: PropertyKey, ...args: any[]) {\r\n if (!Contracted[checkedMode]) return;\r\n\r\n Contracted[checkedMode] = false; // Disable checked mode to avoid infinite recursion \r\n\r\n const Class = instance.constructor as typeof Contracted,\r\n ds = Class[Symbol.metadata]?.demands?.[propertyKey] ?? [] as DemandsPredicate<Contracted>[];\r\n\r\n try {\r\n if (ds.length === 0) return;\r\n\r\n // If ANY demand is true then the obligation is considered fulfilled\r\n for (const d of ds)\r\n if (d(instance, ...args)) return;\r\n\r\n // If we reach here, it means all demands were false\r\n assert(false, `No demands were satisfied for ${instance.constructor.name}.${String(propertyKey)}`);\r\n } finally {\r\n Contracted[checkedMode] = true;\r\n }\r\n}","import { assert } from './assert.mjs';\r\nimport { checkedMode, Contracted } from './Contracted.mjs';\r\nimport type { FeatureDecoratorContext } from './types.mjs';\r\n\r\nexport type EnsuresPredicate<This extends Contracted> = (self: This, args: any[], old: This) => boolean;\r\n\r\nexport type EnsuresDecorator = <\r\n This extends Contracted\r\n>(\r\n predicate: EnsuresPredicate<This>\r\n) => (\r\n value: unknown,\r\n context: FeatureDecoratorContext\r\n) => void;\r\n\r\nexport const ensures: EnsuresDecorator = (predicate) => (_feature, ctx) => {\r\n assert([\"method\", \"getter\", \"setter\"].includes(ctx.kind), '@ensures decorator can only be applied to methods, getters, or setters');\r\n assert(ctx.static === false, '@ensures decorator cannot be applied to static features');\r\n assert(ctx.private === false, '@ensures decorator cannot be applied to private features');\r\n assert(!String(ctx.name).startsWith('_'), '@ensures decorator cannot be applied to private/protected features');\r\n\r\n ctx.addInitializer(function () {\r\n assert(this instanceof Contracted, '@ensures decorator can only be applied to classes that extend Contracted');\r\n const es = [\r\n ...(ctx.metadata as any)?.ensures?.[ctx.name] ?? [],\r\n predicate\r\n ]\r\n\r\n ctx.metadata.ensures = {\r\n ...(ctx.metadata?.ensures ?? {}),\r\n [ctx.name]: es\r\n };\r\n })\r\n}\r\n\r\nexport function assertEnsures(instance: Contracted, old: Contracted, propertyKey: PropertyKey, args: any) {\r\n if (!Contracted[checkedMode]) return;\r\n\r\n Contracted[checkedMode] = false; // Disable checked mode to avoid infinite recursion\r\n\r\n const Class = instance.constructor as typeof Contracted,\r\n es = Class[Symbol.metadata]?.ensures?.[propertyKey] ?? [] as EnsuresPredicate<Contracted>[];\r\n\r\n try {\r\n if (es.length === 0) return;\r\n\r\n // ALL ensures must be true for the obligation to be fulfilled\r\n for (const e of es)\r\n if (!e(instance, args, old))\r\n\r\n assert(false, `No ensurances were satisfied for ${instance.constructor.name}.${String(propertyKey)}`);\r\n // If we reach here, it means all ensures were true\r\n } finally {\r\n Contracted[checkedMode] = true;\r\n }\r\n}\r\n","import { assert } from './assert.mjs';\r\nimport { checkedMode, Contracted } from './Contracted.mjs';\r\nimport type { FeatureDecoratorContext } from './types.mjs';\r\n\r\nexport type RescueHandler<This extends Contracted> =\r\n (self: This, error: unknown, args: any[], retry: (this: This, ...args: any[]) => any) => void\r\n\r\nexport type RescueDecorator = <This extends Contracted>(\r\n handler: RescueHandler<This>\r\n) => (\r\n value: unknown,\r\n context: FeatureDecoratorContext\r\n) => void;\r\n\r\nexport const rescue: RescueDecorator = (handler) => (_feature, ctx) => {\r\n assert([\"method\", \"getter\", \"setter\"].includes(ctx.kind), '@rescue decorator can only be applied to methods, getters, or setters');\r\n assert(ctx.static === false, '@rescue decorator cannot be applied to static features');\r\n assert(ctx.private === false, '@rescue decorator cannot be applied to private features');\r\n assert(!String(ctx.name).startsWith('_'), '@rescue decorator cannot be applied to private/protected features');\r\n\r\n ctx.addInitializer(function () {\r\n assert(this instanceof Contracted, '@rescue decorator can only be applied to classes that extend Contracted');\r\n\r\n ctx.metadata.rescue = {\r\n ...(ctx.metadata?.rescue ?? {}),\r\n [ctx.name]: handler\r\n }\r\n })\r\n}\r\n\r\nexport const applyRescueHandler = (descriptorType: 'get' | 'set' | 'func', instance: Contracted, propertyKey: PropertyKey, error: unknown, args: any) => {\r\n if (!Contracted[checkedMode]) return error;\r\n\r\n const Class = instance.constructor as typeof Contracted,\r\n descriptor = Object.getOwnPropertyDescriptor(Class.prototype, propertyKey)!,\r\n r = Class[Symbol.metadata]?.rescue?.[propertyKey] as RescueHandler<Contracted> | undefined;\r\n\r\n if (!r) throw error;\r\n\r\n let hasRetried = false;\r\n Contracted[checkedMode] = false; // Disable checked mode to avoid infinite recursion\r\n let result: any\r\n try {\r\n r.call(instance, instance, error, args, (...args: any[]) => {\r\n assert(!hasRetried, 'retry can only be called once');\r\n hasRetried = true;\r\n Contracted[checkedMode] = true;\r\n if (descriptorType == 'get')\r\n result = Reflect.get(instance, propertyKey, instance);\r\n else if (descriptorType == 'set')\r\n result = Reflect.set(instance, propertyKey, args[0], instance);\r\n else if (descriptorType == 'func')\r\n result = Reflect.apply(descriptor.value, instance, args);\r\n })\r\n if (!hasRetried)\r\n throw error;\r\n } finally {\r\n Contracted[checkedMode] = true;\r\n }\r\n\r\n return result;\r\n}\r\n","import { assertInvariants, InvariantPredicate } from './invariant.mjs';\r\nimport { assertDemands, DemandsPredicate } from './demands.mjs';\r\nimport { assertEnsures, EnsuresPredicate } from './ensures.mjs';\r\nimport { applyRescueHandler as applyRescueHandler, RescueHandler } from './rescue.mjs';\r\n\r\n// Symbol to store checked mode state\r\nexport const checkedMode = Symbol.for('Contracted.checkedMode');\r\n\r\nconst populateOld = (target: Contracted) => {\r\n if (!Contracted[checkedMode]) return;\r\n\r\n Contracted[checkedMode] = false; // Disable checked mode to avoid infinite recursion\r\n\r\n const old = Object.create(target)\r\n for (const key in target)\r\n Reflect.set(old, key, Reflect.get(target, key));\r\n\r\n Contracted[checkedMode] = true;\r\n\r\n return old;\r\n}\r\n\r\n// Utility to walk up the prototype chain to find a property descriptor\r\nfunction getPropertyDescriptor(obj: object, prop: PropertyKey): PropertyDescriptor | undefined {\r\n let proto = obj;\r\n while (proto && proto !== Object.prototype) {\r\n const desc = Object.getOwnPropertyDescriptor(proto, prop);\r\n if (desc) return desc;\r\n proto = Object.getPrototypeOf(proto);\r\n }\r\n return undefined;\r\n}\r\n\r\nconst proxyHandler: ProxyHandler<Contracted> = {\r\n get(target, prop, receiver) {\r\n if (!Contracted[checkedMode]) return Reflect.get(target, prop, receiver);\r\n\r\n const Class = target.constructor as typeof Contracted,\r\n descriptor = getPropertyDescriptor(Object.getPrototypeOf(target), prop),\r\n es = Class[Symbol.metadata]?.ensures?.[prop] ?? [] as EnsuresPredicate<Contracted>[],\r\n hasEnsures = es.length > 0,\r\n old = hasEnsures ? populateOld(target) : undefined;\r\n\r\n if (typeof descriptor?.value === 'function') {\r\n return function (this: Contracted, ...methodArgs: any[]) {\r\n assertInvariants(Class, target);\r\n assertDemands(target, prop, methodArgs);\r\n let result\r\n try {\r\n result = Reflect.apply(descriptor.value, target, methodArgs);\r\n if (hasEnsures) assertEnsures(target, old, prop, methodArgs);\r\n } catch (error) {\r\n result = applyRescueHandler('func', target, prop as keyof Contracted, error, methodArgs);\r\n } finally {\r\n assertInvariants(Class, target);\r\n }\r\n return result;\r\n }\r\n } else if (typeof descriptor?.get === 'function') {\r\n assertInvariants(Class, target);\r\n assertDemands(target, prop, []);\r\n let result\r\n try {\r\n result = Reflect.get(target, prop, receiver);\r\n if (hasEnsures) assertEnsures(target, old, prop, [result]);\r\n } catch (error) {\r\n result = applyRescueHandler('get', target, prop, error, []);\r\n } finally {\r\n assertInvariants(Class, target);\r\n }\r\n return result;\r\n } else {\r\n return Reflect.get(target, prop, receiver);\r\n }\r\n },\r\n set(target, prop, value, receiver) {\r\n if (!Contracted[checkedMode]) return Reflect.set(target, prop, value, receiver);\r\n\r\n const descriptor = getPropertyDescriptor(Object.getPrototypeOf(target), prop)\r\n\r\n if (!(descriptor && typeof descriptor.set === 'function'))\r\n if (typeof prop === 'string' && !prop.startsWith('_'))\r\n throw new TypeError(`Cannot assign to property '${String(prop)}': only properties starting with '_' or with a setter can be set on Contracted instances.`);\r\n\r\n const Class = target.constructor as typeof Contracted,\r\n es = Class[Symbol.metadata]?.ensures?.[prop] ?? [] as EnsuresPredicate<Contracted>[],\r\n hasEnsures = es.length > 0,\r\n old = hasEnsures ? populateOld(target) : undefined;\r\n assertInvariants(Class, target);\r\n assertDemands(target, prop, [value]);\r\n let result\r\n try {\r\n result = Reflect.set(target, prop, value, receiver);\r\n if (hasEnsures) assertEnsures(target, old, prop, [value]);\r\n } catch (error) {\r\n result = applyRescueHandler('set', target, prop as keyof Contracted, error, [value])\r\n } finally {\r\n assertInvariants(Class, target);\r\n }\r\n\r\n return result;\r\n },\r\n deleteProperty(target, prop) {\r\n throw new TypeError(`Cannot delete property '${String(prop)}' from Contracted instances.`);\r\n },\r\n};\r\n\r\nexport class Contracted {\r\n static [Symbol.metadata]: {\r\n invariants: InvariantPredicate<typeof Contracted>[];\r\n demands: Record<PropertyKey, DemandsPredicate<Contracted>[]>;\r\n ensures: Record<PropertyKey, EnsuresPredicate<Contracted>[]>;\r\n rescue: Record<PropertyKey, RescueHandler<Contracted>>;\r\n };\r\n\r\n // Prevents direct instantiation of the class\r\n protected static _allowConstruction = false;\r\n\r\n // Symbol-based checked mode state\r\n public static [checkedMode]: boolean = true;\r\n\r\n static new<\r\n C extends typeof Contracted,\r\n Args extends ConstructorParameters<C>,\r\n >(this: C, ...args: Args): InstanceType<C> {\r\n (this as any)._allowConstruction = true;\r\n try {\r\n const instance = new this(...args) as InstanceType<C>;\r\n assertInvariants(this, instance);\r\n\r\n return new Proxy<InstanceType<C>>(instance, proxyHandler);\r\n } finally {\r\n (this as any)._allowConstruction = false;\r\n }\r\n }\r\n\r\n constructor(..._args: any[]) {\r\n const Class = this.constructor as typeof Contracted;\r\n if (!Class._allowConstruction)\r\n throw new TypeError(\"Use the static 'new' method to instantiate this class.\")\r\n }\r\n}"],"names":["Symbol","metadata","for","AssertionError","Error","assert","condition","message","Boolean","iff","p","q","implies","assertInvariants","Class","instance","Contracted","checkedMode","invariants","inv","name","toString","invariant","predicate","OriginalClass","kind","prototype","existing","demands","_feature","ctx","includes","static","private","String","startsWith","addInitializer","this","ds","assertDemands","propertyKey","args","constructor","length","d","ensures","es","assertEnsures","old","e","rescue","handler","applyRescueHandler","descriptorType","error","descriptor","Object","getOwnPropertyDescriptor","r","result","hasRetried","call","Reflect","get","set","apply","value","populateOld","target","create","key","getPropertyDescriptor","obj","prop","proto","desc","getPrototypeOf","proxyHandler","receiver","hasEnsures","undefined","methodArgs","TypeError","deleteProperty","_allowConstruction","Proxy","_args"],"sourceRoot":""}