{"ScriptPreparationCode":null,"TestCases":[{"Name":"createConstructor","Code":"// utility functions for Immutability and Multiple Inheritance\r\nconst createConstructor = function (funcArgs = {}) {\r\n const { classesToInherit, classProps, defaultArgs, methods } = funcArgs\r\n\r\n function deepFreeze(obj) {\r\n Object.getOwnPropertyNames(obj).map(key =\u003E {\r\n if (typeof obj[key] === \u0027object\u0027 \u0026\u0026 obj[key] !== null)\r\n deepFreeze(obj[key])\r\n })\r\n \r\n Object.freeze(obj)\r\n }\r\n\r\n // the passed constructor\r\n function InnerFunc (args = {}) {\r\n //set object props\r\n Object.assign(this, defaultArgs, args)\r\n \r\n //bind the methods per object\r\n const targetProto = Object.getPrototypeOf(this)\r\n\r\n Object.getOwnPropertyNames(targetProto).map(key =\u003E {\r\n if (key !== \u0027constructor\u0027) {\r\n Object.defineProperty(this, key, {\r\n enumerable: false,\r\n value: targetProto[key] instanceof Function ?\r\n targetProto[key].bind(this) :\r\n targetProto[key]\r\n })\r\n }\r\n })\r\n\r\n //freeze the object\r\n deepFreeze(this)\r\n }\r\n\r\n // set constructor props\r\n Object.assign(InnerFunc, classProps)\r\n\r\n // set inherited methods\r\n classesToInherit.map(constr =\u003E\r\n Object.getOwnPropertyNames(constr.prototype).map(key =\u003E {\r\n if (key !== \u0027constructor\u0027) {\r\n InnerFunc.prototype[key] = constr.prototype[key]\r\n }\r\n })\r\n )\r\n\r\n // set manually defined methods\r\n Object.assign(InnerFunc.prototype, methods)\r\n\r\n // method to copy object with some props changed\r\n InnerFunc.prototype.copyWithProps = function(props = {}) {\r\n return new this.constructor(Object.assign({}, this, props))\r\n }\r\n\r\n // freeze the constructor\r\n deepFreeze(InnerFunc)\r\n\r\n return InnerFunc\r\n}\r\n\r\n\r\n// BADLY WRITTEN CLASSES\r\nclass Height {\r\n constructor(args = {}) {\r\n this.height = args.height\r\n }\r\n \r\n getHeight() { return \u0060Height: ${this.height}\u0060 }\r\n \r\n static heightInternal() { return 3 }\r\n}\r\nclass Weight {\r\n constructor(args = {}) {\r\n this.weight = args.weight\r\n }\r\n \r\n getWeight() { return \u0060Weight: ${this.weight}\u0060 }\r\n \r\n static weightInternal() { return 3 }\r\n}\r\n\r\n\r\n\r\n// WELL WRITTEN CLASSES\r\nconst Person = createConstructor({\r\n classesToInherit: [ Height, Weight ],\r\n classProps: {\r\n species: \u0027humans\u0027,\r\n internalMethod() {\r\n return \u0027Hello from inside the constructor\u0027\r\n }\r\n },\r\n defaultArgs: {\r\n name: \u0027John\u0027,\r\n age: 20,\r\n weight: 60,\r\n height: 160\r\n },\r\n methods: {\r\n // Uncomment to replace the inherited one\r\n //getHeight() { return \u0027CORRECT\u0027 },\r\n \r\n // combines native with inherited methods\r\n greet() {\r\n console.log(\r\n \u0060Hello, ${this.name}. \u0060 \u002B\r\n \u0060${this.getWeight()}, ${this.getHeight()}\u0060\r\n )\r\n },\r\n\r\n // calculates the method name first\r\n [\u0027get\u0027 \u002B \u0027Info\u0027]() { return \u0060Name: ${this.name}, age: ${this.age}\u0060 },\r\n\r\n // can also use async, * generator\r\n // which can also be static\r\n }\r\n})\r\n\r\nfor (let i = 0; i \u003C 50; i\u002B\u002B) {\r\n mark = new Person({ name: \u0027Mark\u0027, weight: 90, otherArg: true }) \r\n skinnyMark = mark.copyWithProps({ age: 32, weight: 75 })\r\n skinnyMark.greet()\r\n mark.greet()\r\n}\r\n","IsDeferred":false},{"Name":"ClassUtils","Code":"// utility functions for Immutability and Multiple Inheritance\r\nconst ClassUtils = class Self {\r\n copyWithProps(props = {}) {\r\n return new this.constructor(Object.assign({}, this, props))\r\n }\r\n\r\n finalizeInstance(props = {}) {\r\n if (!Object.isFrozen(this)) {\r\n //set object props\r\n Object.assign(this, props)\r\n \r\n //bind the methods per object\r\n const targetProto = Object.getPrototypeOf(this)\r\n\r\n Object.getOwnPropertyNames(targetProto).map(key =\u003E {\r\n if (key !== \u0027constructor\u0027) {\r\n Object.defineProperty(this, key, {\r\n enumerable: false,\r\n value: targetProto[key] instanceof Function ?\r\n targetProto[key].bind(this) :\r\n targetProto[key]\r\n })\r\n }\r\n })\r\n\r\n //freeze the object\r\n Self.deepFreeze(this)\r\n }\r\n }\r\n\r\n static deepFreeze(obj) {\r\n Object.getOwnPropertyNames(obj).map(key =\u003E {\r\n if (typeof obj[key] === \u0027object\u0027 \u0026\u0026 obj[key] !== null)\r\n Self.deepFreeze(obj[key])\r\n })\r\n \r\n Object.freeze(obj)\r\n }\r\n \r\n static finalizeClass({ target, props = {}, sources = [] }) {\r\n if (!Object.isFrozen(target)) {\r\n // set constructor props\r\n Object.assign(target, props)\r\n\r\n // set prototype methods\r\n sources.concat([Self, target]).map(constr =\u003E\r\n Object.getOwnPropertyNames(constr.prototype).map(key =\u003E {\r\n if (key !== \u0027constructor\u0027) {\r\n target.prototype[key] = constr.prototype[key]\r\n }\r\n })\r\n )\r\n\r\n // freeze the constructor\r\n Self.deepFreeze(target)\r\n }\r\n }\r\n}\r\n\r\nClassUtils.deepFreeze(ClassUtils)\r\n\r\n\r\n// BADLY WRITTEN CLASSES\r\nclass Height {\r\n constructor(args = {}) {\r\n this.height = args.height\r\n }\r\n \r\n getHeight() { return \u0060Height: ${this.height}\u0060 }\r\n \r\n static heightInternal() { return 3 }\r\n}\r\nclass Weight {\r\n constructor(args = {}) {\r\n this.weight = args.weight\r\n }\r\n \r\n getWeight() { return \u0060Weight: ${this.weight}\u0060 }\r\n \r\n static weightInternal() { return 3 }\r\n}\r\n\r\n\r\n// WELL WRITTEN CLASSES\r\nconst Person = class Self {\r\n constructor({ name, age, weight, height } = {}) {\r\n this.finalizeInstance({\r\n name: name || \u0027John\u0027,\r\n age: age || 20,\r\n weight: weight || 60,\r\n height: height || 160\r\n })\r\n }\r\n\r\n // Uncomment to replace the inherited one\r\n //getHeight() { return \u0027CORRECT\u0027 }\r\n \r\n // combines native with inherited methods\r\n greet() { console.log(\u0060Hello, ${this.name}. ${this.getWeight()}, ${this.getHeight()}\u0060) }\r\n\r\n // calculates the method name first\r\n [\u0027get\u0027 \u002B \u0027Info\u0027]() { return \u0060Name: ${this.name}, age: ${this.age}\u0060 } \r\n\r\n // class method\r\n static internalMethod() {\r\n return \u0027Hello from inside the constructor\u0027\r\n }\r\n \r\n // can also use async, * generator\r\n // which can also be static\r\n}\r\n\r\nClassUtils.finalizeClass({\r\n target: Person,\r\n sources: [ Height, Weight ],\r\n props: { species: \u0027humans\u0027 }\r\n})\r\n\r\nfor (let i = 0; i \u003C 50; i\u002B\u002B) {\r\n mark = new Person({ name: \u0027Mark\u0027, weight: 90, otherArg: true }) \r\n skinnyMark = mark.copyWithProps({ age: 32, weight: 75 })\r\n skinnyMark.greet()\r\n mark.greet()\r\n}\r\n","IsDeferred":false}]}