05efaceab6a0861ebbbea234cdf54af8ffb42eb1
[platform/framework/web/crosswalk-tizen.git] /
1 'use strict';
2
3 var esprima;
4
5 // Browserified version does not have esprima
6 //
7 // 1. For node.js just require module as deps
8 // 2. For browser try to require mudule via external AMD system.
9 //    If not found - try to fallback to window.esprima. If not
10 //    found too - then fail to parse.
11 //
12 try {
13   esprima = require('esprima');
14 } catch (_) {
15   /*global window */
16   if (typeof window !== 'undefined') { esprima = window.esprima; }
17 }
18
19 var Type = require('../../type');
20
21 function resolveJavascriptFunction(data) {
22   if (null === data) {
23     return false;
24   }
25
26   try {
27     var source = '(' + data + ')',
28         ast    = esprima.parse(source, { range: true }),
29         params = [],
30         body;
31
32     if ('Program'             !== ast.type         ||
33         1                     !== ast.body.length  ||
34         'ExpressionStatement' !== ast.body[0].type ||
35         'FunctionExpression'  !== ast.body[0].expression.type) {
36       return false;
37     }
38
39     return true;
40   } catch (err) {
41     return false;
42   }
43 }
44
45 function constructJavascriptFunction(data) {
46   /*jslint evil:true*/
47
48   var source = '(' + data + ')',
49       ast    = esprima.parse(source, { range: true }),
50       params = [],
51       body;
52
53   if ('Program'             !== ast.type         ||
54       1                     !== ast.body.length  ||
55       'ExpressionStatement' !== ast.body[0].type ||
56       'FunctionExpression'  !== ast.body[0].expression.type) {
57     throw new Error('Failed to resolve function');
58   }
59
60   ast.body[0].expression.params.forEach(function (param) {
61     params.push(param.name);
62   });
63
64   body = ast.body[0].expression.body.range;
65
66   // Esprima's ranges include the first '{' and the last '}' characters on
67   // function expressions. So cut them out.
68   return new Function(params, source.slice(body[0]+1, body[1]-1));
69 }
70
71 function representJavascriptFunction(object /*, style*/) {
72   return object.toString();
73 }
74
75 function isFunction(object) {
76   return '[object Function]' === Object.prototype.toString.call(object);
77 }
78
79 module.exports = new Type('tag:yaml.org,2002:js/function', {
80   kind: 'scalar',
81   resolve: resolveJavascriptFunction,
82   construct: constructJavascriptFunction,
83   predicate: isFunction,
84   represent: representJavascriptFunction
85 });