babelute
Version:
Internal Domain Specific (Multi)Modeling javascript framework
244 lines (196 loc) • 8.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); // removed in production
/**
* Babelute core
*
* @author Gilles Coomans
* @licence MIT
* @copyright 2016-2017 Gilles Coomans
*/
var _lexem = require('./lexem');
var _lexem2 = _interopRequireDefault(_lexem);
var _extends = require('./utils/extends');
var _extends2 = _interopRequireDefault(_extends);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Babelute subclass(es) instances : for holding array of lexems (i.e. a sentence) written through the DSL's API.
*
* Will be the base class for all DSLs handlers.
*
* Babelute API and lexems Naming Conventions :
*
* - any "meta-language" method (aka any method that handle the sentence it self - appending new lexem, changing current lexicon, sentences translations, ...)
* must start with and underscore : e.g. _append, _lexicon, _if, _each, _eachLexem, _translate...
* - any "pragmatics output related" method should start with a '$' and should be named with followed format : e.g. .$myLexiconToMyOutputType(...)
* - any DSL lexems (so any other "api"'s method) should start with a simple alphabetic char : e.g. .myLexem(), .description(), .title(), ...
*
* @public
*/
var Babelute = function () {
/**
* construct a babelute instance
* @param {?Array} lexems array of lexems for init. (only for internal use)
*/
function Babelute() {
var lexems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
_classCallCheck(this, Babelute);
/**
* the array where lexems are stored
* @type {Array}
*/
this._lexems = lexems || [];
/**
* useful marker for fast instanceof replacement (frame/multiple-js-runtime friendly)
* @type {Boolean}
*/
this.__babelute__ = true;
}
/**
* The absolute Babelute atom method : add a lexem to babelute's array
* @public
* @param {String} lexiconName the current lexicon name
* @param {String} name the lexem's name
* @param {Array|arguments} args the lexem's arguments (either an array or maybe directly the arguments object from when lexem is called)
* @return {Babelute} the current Babelute instance
*/
_createClass(Babelute, [{
key: '_append',
value: function _append(lexiconName, name, args) {
this._lexems.push(new _lexem2.default(lexiconName, name, args));
return this;
}
/**
* conditional sentences concatenation.
*
* Apply modification at sentence writing time (aka the babelute does not contains the _if lexems. _if has immediatly been applied).
*
* @public
* @param {*} condition any value that will be casted to Boolean (!!)
* @param {Babelute} babelute which sentence to insert if !!condition === true
* @param {?Babelute} elseBabelute which sentence to insert if !!condition === false
* @return {Babelute} the current Babelute instance
*/
}, {
key: '_if',
value: function _if(condition, babelute) {
var elseBabelute = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
if (condition) this._lexems = this._lexems.concat(babelute._lexems);else if (elseBabelute) this._lexems = this._lexems.concat(elseBabelute._lexems);
return this;
}
/**
* For each item from array : execute function and concatenate returned babelute sentence to current one.
* Provided function must return a babelute.
*
* Apply modification at sentence writing time (aka the babelute does not contains the _each lexems. _each has immediatly been applied).
*
* @public
* @param {Array} array the array to iterate on
* @param {Function} func the function to handle each item. it must return a babelute.
* @return {Babelute} the current Babelute instance
*/
}, {
key: '_each',
value: function _each(array, func) {
var _this = this;
if (array) array.forEach(function (item, index) {
var b = func(item, index);
_this._lexems.push.apply(_this._lexems, b._lexems);
});
return this;
}
/**
* Use a babelute (another sentence) at this point in the current sentence
* @public
* @param {string|Babelute} babelute Either a string formatted as 'mylexicon:myMethod' (which gives the lexem's method to call), or a Babelute instance (which will be inserted in current sentence)
* @param {?...args} args the optional arguments to use when calling lexem (only if first argument is a string)
* @return {Babelute} the current Babelute instance
* @throws {Error} If lexicon not found (when first arg is string)
* @throws {Error} If method not found in lexicon (when first arg is string)
*/
/* istanbul ignore next */
}, {
key: '_use',
value: function _use(babelute) {} // eslint-disable-line no-unused-vars
// will be implemented in lexicon
/**
* Change current lexicon for next lexems
* @public
* @param {string} lexiconName the lexicon to use
* @return {Babelute} a new Babelute from lexicon (i.e. with lexicon's API)
* @throws {Error} If lexicon not found with lexiconName
*/
/* istanbul ignore next */
}, {
key: '_lexicon',
value: function _lexicon(lexiconName) {} // eslint-disable-line no-unused-vars
// will be implemented in lexicon
/**
* transform a sentence through a function. This function must return a new sentence.
* @param {Function} handler a function that receive the current sentence as argument and that return a new sentence.
* @return {Babelute} the new sentence
*/
}, {
key: '_transform',
value: function _transform(handler) {
return handler(this);
}
/**
* translate each lexems
* @param {[type]} handler [description]
* @return {[type]} [description]
*/
}, {
key: '_translateLexems',
value: function _translateLexems(handler) {
return this._transform(function (sentence) {
var b = new Babelute();
sentence._lexems.forEach(function (lexem) {
return b._use(handler(lexem));
});
return b;
});
}
/**
* translate current sentence's lexems through a Lexicon or a map of Lexicon.
*
* @param {Lexicon|Object} lexicon the Lexicon (or a map of Lexicon) to get translation from
* @param {Boolean} firstLevel true if should produce FirstLevel translation (i.e. targetLexicon.FirstLevel). False otherwise.
* @return {Babelute} a new Babelute instance with translated lexems.
*/
/* istanbul ignore next */
}, {
key: '_translateLexemsThrough',
value: function _translateLexemsThrough(lexicon) {
var firstLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
} // eslint-disable-line no-unused-vars
// will be implemented in Lexicon
// static extends(BaseClass, ...apis) {
// assert(BaseClass === Babelute || (BaseClass.prototype instanceof Babelute), 'Babelute.extends accepts only a Babelute Class (or subclass) as first argument');
// const B = function(...args) {
// BaseClass.apply(this, args);
// };
// B.prototype = Object.create(BaseClass.prototype);
// B.prototype.constructor = B;
// apis.forEach((api) => {
// for (var i in api) B.prototype[i] = api[i];
// });
// // Object.assign seems to bug when used on prototype (not investigate enough : so use plain old for-in syntax)
// // investigation gives : babel make prototype not enumerable
// return B;
// }
}]);
return Babelute;
}();
/**
* Create Babelute subclass
* @param {Babelute} BaseClass the class to be extended
* @param {?Object} api an object containing methods to add to prototype
* @return {Babelute} The subclass
* @throws {AssertionError} (only in dev mode) If BaseClass is not a Babelute Subclass (or Babelute)
*/
exports.default = Babelute;
Babelute.extends = _extends2.default;