'use strict';
var esprima;
// Browserified version does not have esprima // // 1. For node.js just require module as deps // 2. For browser try to require mudule via external AMD system. // If not found - try to fallback to window.esprima. If not // found too - then fail to parse. // try {
// workaround to exclude package from browserify list. var _require = require; esprima = _require('esprima');
} catch (_) {
/*global window */ if (typeof window !== 'undefined') esprima = window.esprima;
}
var Type = require('../../type');
function resolveJavascriptFunction(data) {
if (data === null) return false; try { var source = '(' + data + ')', ast = esprima.parse(source, { range: true }); if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || (ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression')) { return false; } return true; } catch (err) { return false; }
}
function constructJavascriptFunction(data) {
/*jslint evil:true*/ var source = '(' + data + ')', ast = esprima.parse(source, { range: true }), params = [], body; if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || (ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression')) { throw new Error('Failed to resolve function'); } ast.body[0].expression.params.forEach(function (param) { params.push(param.name); }); body = ast.body[0].expression.body.range; // Esprima's ranges include the first '{' and the last '}' characters on // function expressions. So cut them out. if (ast.body[0].expression.body.type === 'BlockStatement') { /*eslint-disable no-new-func*/ return new Function(params, source.slice(body[0] + 1, body[1] - 1)); } // ES6 arrow functions can omit the BlockStatement. In that case, just return // the body. /*eslint-disable no-new-func*/ return new Function(params, 'return ' + source.slice(body[0], body[1]));
}
function representJavascriptFunction(object /*, style*/) {
return object.toString();
}
function isFunction(object) {
return Object.prototype.toString.call(object) === '[object Function]';
}
module.exports = new Type('tag:yaml.org,2002:js/function', {
kind: 'scalar', resolve: resolveJavascriptFunction, construct: constructJavascriptFunction, predicate: isFunction, represent: representJavascriptFunction
});