123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- "use strict";
- module.metadata = {
- "stability": "deprecated"
- };
- var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
- function equivalentDescriptors(actual, expected) {
- return (actual.conflict && expected.conflict) ||
- (actual.required && expected.required) ||
- equalDescriptors(actual, expected);
- }
- function equalDescriptors(actual, expected) {
- return actual.get === expected.get &&
- actual.set === expected.set &&
- actual.value === expected.value &&
- !!actual.enumerable === !!expected.enumerable &&
- !!actual.configurable === !!expected.configurable &&
- !!actual.writable === !!expected.writable;
- }
- function throwConflictPropertyError(name) {
- throw new Error("Remaining conflicting property: `" + name + "`");
- }
- function throwRequiredPropertyError(name) {
- throw new Error("Missing required property: `" + name + "`");
- }
- function RequiredPropertyDescriptor(name) {
-
-
-
-
-
- var accessor = throwRequiredPropertyError.bind(null, name);
- return { get: accessor, set: accessor, required: true };
- }
- function ConflictPropertyDescriptor(name) {
-
- var accessor = throwConflictPropertyError.bind(null, name);
- return { get: accessor, set: accessor, conflict: true };
- }
- function isRequiredProperty(object, name) {
- return !!object[name].required;
- }
- function isConflictProperty(object, name) {
- return !!object[name].conflict;
- }
- function isBuiltInMethod(name, source) {
- var target = Object.prototype[name];
-
- return target == source ||
-
-
- (String(target) === String(source) && target.name === source.name);
- }
- function overrideBuiltInMethods(target, source) {
- if (isBuiltInMethod("toString", target.toString)) {
- Object.defineProperty(target, "toString", {
- value: source.toString,
- configurable: true,
- enumerable: false
- });
- }
- if (isBuiltInMethod("constructor", target.constructor)) {
- Object.defineProperty(target, "constructor", {
- value: source.constructor,
- configurable: true,
- enumerable: false
- });
- }
- }
- function exclude(names, trait) {
- var map = {};
- Object.keys(trait).forEach(function(name) {
-
-
-
- if (!~names.indexOf(name) || isRequiredProperty(trait, name))
- map[name] = { value: trait[name], enumerable: true };
-
-
- else
- map[name] = { value: RequiredPropertyDescriptor(name), enumerable: true };
- });
- return Object.create(Trait.prototype, map);
- }
- function rename(renames, trait) {
- var map = {};
-
-
-
-
- Object.keys(trait).forEach(function(name) {
- var alias;
-
-
-
- if (owns(renames, name) && !isRequiredProperty(trait, name)) {
- alias = renames[name];
-
-
-
-
-
-
- if (owns(map, alias) && !map[alias].value.required) {
- map[alias] = {
- value: ConflictPropertyDescriptor(alias),
- enumerable: true
- };
- }
- else {
- map[alias] = {
- value: trait[name],
- enumerable: true
- };
- }
-
-
-
-
-
-
- if (!owns(map, name)) {
- map[name] = {
- value: RequiredPropertyDescriptor(name),
- enumerable: true
- };
- }
- }
-
-
-
-
- else {
-
- if (!owns(map, name)) {
- map[name] = { value: trait[name], enumerable: true };
- }
-
-
-
-
- else if (!isRequiredProperty(trait, name)) {
- map[name] = {
- value: ConflictPropertyDescriptor(name),
- enumerable: true
- };
- }
- }
- });
- return Object.create(Trait.prototype, map);
- }
- function resolve(resolutions, trait) {
- var renames = {};
- var exclusions = [];
-
-
- Object.keys(resolutions).forEach(function(name) {
-
-
- if (resolutions[name])
- renames[name] = resolutions[name];
-
-
- else
- exclusions.push(name);
- });
-
-
- return rename(renames, exclude(exclusions, trait));
- }
- function trait(object) {
- var map;
- var trait = object;
- if (!(object instanceof Trait)) {
-
-
-
-
-
-
- map = {};
-
-
- Object.keys(object).forEach(function (name) {
-
-
-
- if (Trait.required ==
- Object.getOwnPropertyDescriptor(object, name).value) {
- map[name] = {
- value: RequiredPropertyDescriptor(name),
- enumerable: true
- };
- }
-
- else {
- map[name] = {
- value: Object.getOwnPropertyDescriptor(object, name),
- enumerable: true
- };
- }
- });
- trait = Object.create(Trait.prototype, map);
- }
- return trait;
- }
- function compose(trait1, trait2/*, ...*/) {
-
-
-
- var map = {};
-
- Array.prototype.forEach.call(arguments, function(trait) {
-
- Object.keys(trait).forEach(function(name) {
-
-
- if (owns(map, name) && !map[name].value.required) {
-
-
-
-
-
-
- if (!isRequiredProperty(trait, name) &&
- !equivalentDescriptors(map[name].value, trait[name])
- ) {
- map[name] = {
- value: ConflictPropertyDescriptor(name),
- enumerable: true
- };
- }
- }
-
-
-
-
- else {
- map[name] = { value: trait[name], enumerable: true };
- }
- });
- });
- return Object.create(Trait.prototype, map);
- }
- function defineProperties(object, properties) {
-
-
-
-
-
- var verifiedProperties = {};
-
-
- Object.keys(properties).forEach(function(name) {
-
-
-
-
- if (isRequiredProperty(properties, name)) {
- if (!(name in object))
- throwRequiredPropertyError(name);
- }
-
- else if (isConflictProperty(properties, name)) {
- throwConflictPropertyError(name);
- }
-
-
- else {
- verifiedProperties[name] = properties[name];
- }
- });
-
-
-
- return Object.defineProperties(object, verifiedProperties);
- }
- function create(prototype, properties) {
-
- var object = Object.create(prototype);
-
-
-
- overrideBuiltInMethods(object, Trait.prototype);
-
-
-
-
-
- return defineProperties(object, properties);
- }
- function Trait(trait1, trait2) {
-
-
-
-
-
-
-
- return trait2 === undefined ? trait(trait1) : compose.apply(null, arguments);
- }
- Object.freeze(Object.defineProperties(Trait.prototype, {
- toString: {
- value: function toString() {
- return "[object " + this.constructor.name + "]";
- }
- },
-
- create: {
- value: function createTrait(prototype) {
- return create(undefined === prototype ? Object.prototype : prototype,
- this);
- },
- enumerable: true
- },
-
- resolve: {
- value: function resolveTrait(resolutions) {
- return resolve(resolutions, this);
- },
- enumerable: true
- }
- }));
- Trait.compose = Object.freeze(compose);
- Object.freeze(compose.prototype);
- Trait.required = Object.freeze(Object.create(Object.prototype, {
- toString: {
- value: Object.freeze(function toString() {
- return "<Trait.required>";
- })
- }
- }));
- Object.freeze(Trait.required.toString.prototype);
- exports.Trait = Object.freeze(Trait);
|