Skip to content

Commit

Permalink
Merge pull request #25 from fantasyland/davidchambers/es5
Browse files Browse the repository at this point in the history
support AMD, CommonJS, and direct browser use without transpilation
  • Loading branch information
davidchambers authored Aug 4, 2017
2 parents 4a64ace + a85b43c commit f62ffd9
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 149 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
"cli-table": "0.3.1",
"colors": "1.1.2",
"daggy": "1.0.0",
"eslint": "3.19.x",
"fantasy-combinators": "0.0.x",
"sanctuary-style": "0.5.x",
"standard": "8.6.0",
"tap": "10.0.0",
"xyz": "2.1.x"
},
"scripts": {
"lint": "standard bench/*.js src/*.js test/*.js",
"lint:fix": "npm run lint -- --fix",
"lint": "eslint --config node_modules/sanctuary-style/eslint-es3.json --env es3 --global define --global module --global require --global self -- src/daggy.js && standard bench/*.js test/*.js",
"release-major": "xyz --repo [email protected]:fantasyland/daggy.git --increment major",
"release-minor": "xyz --repo [email protected]:fantasyland/daggy.git --increment minor",
"release-patch": "xyz --repo [email protected]:fantasyland/daggy.git --increment patch",
Expand Down
311 changes: 164 additions & 147 deletions src/daggy.js
Original file line number Diff line number Diff line change
@@ -1,157 +1,174 @@
const { toString } = require('sanctuary-type-classes')
const type = require('sanctuary-type-identifiers')

// Names of prop used to store:
// * name of variant of a sum type
const TAG = '@@tag'
// * array of arguments used to create a value (to speed up `cata`)
const VALUES = '@@values'
// * `@@type` of it's returned results
const TYPE = '@@type'
// * `@@type` of variant constructor's returned results
const RET_TYPE = '@@ret_type'

const tagged = (typeName, fields) => {
const proto = {}
proto.toString = tagged$toString
// this way we avoid named function
const typeRep = makeConstructor(fields, proto)
typeRep.toString = typeRepToString
typeRep.prototype = proto
typeRep.is = isType
typeRep[TYPE] = typeName
proto.constructor = typeRep
return typeRep
}

const taggedSum = (typeName, constructors) => {
const proto = {}
proto.cata = sum$cata
proto.toString = sum$toString
const typeRep = {
toString: typeRepToString,
prototype: proto,
is: isType,
[TYPE]: typeName
(function(f) {

'use strict';

if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = f(require('sanctuary-type-classes'),
require('sanctuary-type-identifiers'));
} else if (typeof define === 'function' && define.amd != null) {
define(['sanctuary-type-classes',
'sanctuary-type-identifiers'],
f);
} else {
self.daggy = f(self.sanctuaryTypeClasses,
self.sanctuaryTypeIdentifiers);
}
proto.constructor = typeRep
Object.keys(constructors).forEach(tag => {
const fields = constructors[tag]
const tagProto = Object.create(proto)
defProp(tagProto, TAG, tag)
if (fields.length === 0) {
typeRep[tag] = makeValue(fields, tagProto, [], 0)
typeRep[tag].is = sum$isUnit
return

}(function(Z, type) {

'use strict';

// Names of prop used to store:
// * name of variant of a sum type
var TAG = '@@tag';
// * array of arguments used to create a value (to speed up `cata`)
var VALUES = '@@values';
// * `@@type` of its returned results
var TYPE = '@@type';
// * `@@type` of variant constructor's returned results
var RET_TYPE = '@@ret_type';

function tagged(typeName, fields) {
var proto = {toString: tagged$toString};
// this way we avoid named function
var typeRep = makeConstructor(fields, proto);
typeRep.toString = typeRepToString;
typeRep.prototype = proto;
typeRep.is = isType;
typeRep[TYPE] = typeName;
proto.constructor = typeRep;
return typeRep;
}

function taggedSum(typeName, constructors) {
var proto = {cata: sum$cata, toString: sum$toString};
var typeRep = proto.constructor = {
toString: typeRepToString,
prototype: proto,
is: isType,
'@@type': typeName
};
Object.keys(constructors).forEach(function(tag) {
var fields = constructors[tag];
var tagProto = Object.create(proto);
defProp(tagProto, TAG, tag);
if (fields.length === 0) {
typeRep[tag] = makeValue(fields, tagProto, [], 0);
typeRep[tag].is = sum$isUnit;
return;
}
typeRep[tag] = makeConstructor(fields, tagProto);
typeRep[tag].is = sum$isVariant;
typeRep[tag][TAG] = tag;
typeRep[tag][RET_TYPE] = typeName;
typeRep[tag].toString = sum$ctrToString;
});
return typeRep;
}

function sum$cata(fs) {
var tag = this[TAG];
if (!fs[tag]) {
throw new TypeError("Constructors given to cata didn't include: " + tag);
}
typeRep[tag] = makeConstructor(fields, tagProto)
typeRep[tag].is = sum$isVariant
typeRep[tag][TAG] = tag
typeRep[tag][RET_TYPE] = typeName
typeRep[tag].toString = sum$ctrToString
})
return typeRep
}

const sum$cata = function (fs) {
const tag = this[TAG]
if (!fs[tag]) {
throw new TypeError("Constructors given to cata didn't include: " + tag)
return fs[tag].apply(fs, this[VALUES]);
}

function sum$ctrToString() {
return this[RET_TYPE] + '.' + this[TAG];
}

function sum$toString() {
return this.constructor[TYPE] + '.' +
this[TAG] + arrToString(this[VALUES]);
}

function typeRepToString() {
return this[TYPE];
}

function tagged$toString() {
return this.constructor[TYPE] + arrToString(this[VALUES]);
}
return fs[tag].apply(fs, this[VALUES])
}

const sum$ctrToString = function () {
return `${this[RET_TYPE]}.${this[TAG]}`
}

const sum$toString = function () {
return `${this.constructor[TYPE]}.${this[TAG]}${arrToString(this[VALUES])}`
}

const typeRepToString = function () {
return this[TYPE]
}

const tagged$toString = function () {
return `${this.constructor[TYPE]}${arrToString(this[VALUES])}`
}

const sum$isVariant = function (val) {
return Boolean(val) &&
this[TAG] === val[TAG] &&
this[RET_TYPE] === type(val)
}

const sum$isUnit = function (val) {
return this === val || Boolean(val) &&
this[TAG] === val[TAG] &&
type(this) === type(val)
}

const isType = function (val) {
return this[TYPE] === type(val)
}

const makeValue = (fields, proto, values, argumentsLength) => {
if (argumentsLength !== fields.length) {
throw new TypeError(`Expected ${fields.length} arguments, got ${argumentsLength}`)

function sum$isVariant(val) {
return Boolean(val) &&
this[TAG] === val[TAG] &&
this[RET_TYPE] === type(val);
}

function sum$isUnit(val) {
return this === val || Boolean(val) &&
this[TAG] === val[TAG] &&
type(this) === type(val);
}
const obj = Object.create(proto)
defProp(obj, VALUES, values)
for (let idx = 0; idx < fields.length; idx++) {
obj[fields[idx]] = values[idx]

function isType(val) {
return this[TYPE] === type(val);
}
return obj
}

// adopted version of withValue from https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
const defProp = (obj, prop, val) => {
var desc = defProp.desc || (
defProp.desc = {
enumerable: false,
writable: false,
configurable: false,
value: null

function makeValue(fields, proto, values, argumentsLength) {
if (argumentsLength !== fields.length) {
throw new TypeError(
'Expected ' + fields.length + ' arguments, got ' + argumentsLength
);
}
var obj = Object.create(proto);
defProp(obj, VALUES, values);
for (var idx = 0; idx < fields.length; idx += 1) {
obj[fields[idx]] = values[idx];
}
)
desc.value = val
Object.defineProperty(obj, prop, desc)
}

// optimised version of `arr.map(toString).join(', ')`
const arrToString = (arr) => {
if (arr.length === 0) {
return ''
return obj;
}
let str = '(' + toString(arr[0])
for (var i = 1; i < arr.length; i++) {
str = str + ', ' + toString(arr[i])

// adopted version of withValue from https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
function defProp(obj, prop, val) {
var desc = defProp.desc || (
defProp.desc = {
enumerable: false,
writable: false,
configurable: false,
value: null
}
);
desc.value = val;
Object.defineProperty(obj, prop, desc);
}
return str + ')'
}

const makeConstructor = (fields, proto) => {
switch (fields.length) {
case 1: return function (a) { return makeValue(fields, proto, [a], arguments.length) }
case 2: return function (a, b) { return makeValue(fields, proto, [a, b], arguments.length) }
case 3: return function (a, b, c) { return makeValue(fields, proto, [a, b, c], arguments.length) }
case 4: return function (a, b, c, d) { return makeValue(fields, proto, [a, b, c, d], arguments.length) }
case 5: return function (a, b, c, d, e) { return makeValue(fields, proto, [a, b, c, d, e], arguments.length) }
case 6: return function (a, b, c, d, e, f) { return makeValue(fields, proto, [a, b, c, d, e, f], arguments.length) }
case 7: return function (a, b, c, d, e, f, g) { return makeValue(fields, proto, [a, b, c, d, e, f, g], arguments.length) }
case 8: return function (a, b, c, d, e, f, g, h) { return makeValue(fields, proto, [a, b, c, d, e, f, g, h], arguments.length) }
case 9: return function (a, b, c, d, e, f, g, h, i) { return makeValue(fields, proto, [a, b, c, d, e, f, g, h, i], arguments.length) }
case 10: return function (a, b, c, d, e, f, g, h, i, j) { return makeValue(fields, proto, [a, b, c, d, e, f, g, h, i, j], arguments.length) }
default: return Object.defineProperty(
function () { return makeValue(fields, proto, arguments, arguments.length) },
'length',
{ value: fields.length }
)

// optimised version of `arr.map(toString).join(', ')`
function arrToString(arr) {
if (arr.length === 0) return '';
var str = '(' + Z.toString(arr[0]);
for (var idx = 1; idx < arr.length; idx += 1) {
str = str + ', ' + Z.toString(arr[idx]);
}
return str + ')';
}

function makeConstructor(fields, proto) {
switch (fields.length) {
/* eslint-disable max-len */
case 1: return function(a) { return makeValue(fields, proto, [a], arguments.length); };
case 2: return function(a, b) { return makeValue(fields, proto, [a, b], arguments.length); };
case 3: return function(a, b, c) { return makeValue(fields, proto, [a, b, c], arguments.length); };
case 4: return function(a, b, c, d) { return makeValue(fields, proto, [a, b, c, d], arguments.length); };
case 5: return function(a, b, c, d, e) { return makeValue(fields, proto, [a, b, c, d, e], arguments.length); };
case 6: return function(a, b, c, d, e, f) { return makeValue(fields, proto, [a, b, c, d, e, f], arguments.length); };
case 7: return function(a, b, c, d, e, f, g) { return makeValue(fields, proto, [a, b, c, d, e, f, g], arguments.length); };
case 8: return function(a, b, c, d, e, f, g, h) { return makeValue(fields, proto, [a, b, c, d, e, f, g, h], arguments.length); };
case 9: return function(a, b, c, d, e, f, g, h, i) { return makeValue(fields, proto, [a, b, c, d, e, f, g, h, i], arguments.length); };
case 10: return function(a, b, c, d, e, f, g, h, i, j) { return makeValue(fields, proto, [a, b, c, d, e, f, g, h, i, j], arguments.length); };
/* eslint-enable max-len */
default: return Object.defineProperty(
function() {
return makeValue(fields, proto, arguments, arguments.length);
},
'length',
{value: fields.length}
);
}
}
}

module.exports = {
taggedSum,
tagged
}
return {tagged: tagged, taggedSum: taggedSum};

}));

0 comments on commit f62ffd9

Please sign in to comment.