aboutsummaryrefslogtreecommitdiff
path: root/node_modules/espurify/lib/clone-ast.js
blob: f6804e716b99ff5c7bee87da98e363456af71993 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
'use strict';

var isArray = require('core-js/library/fn/array/is-array');
var objectKeys = require('core-js/library/fn/object/keys');
var indexOf = require('core-js/library/fn/array/index-of');
var Map = require('core-js/library/fn/map');
var reduce = require('core-js/library/fn/array/reduce');

module.exports = function cloneWithWhitelist (astWhiteList) {
  var whitelist = reduce(objectKeys(astWhiteList), function (props, key) {
    var propNames = astWhiteList[key];
    var prepend = (indexOf(propNames, 'type') === -1) ? ['type'] : [];
    props[key] = prepend.concat(propNames || []);
    return props;
  }, {});

  function cloneNodeOrObject (obj, seen) {
    var props = obj.type ? whitelist[obj.type] : null;
    if (props) {
      return cloneNode(obj, props, seen);
    } else {
      return cloneObject(obj, seen);
    }
  }

  function cloneArray (ary, seen) {
    var i = ary.length;
    var clone = [];
    while (i--) {
      clone[i] = cloneOf(ary[i], seen);
    }
    return clone;
  }

  function cloneNode (node, props, seen) {
    var i, len, key;
    var clone = {};
    for (i = 0, len = props.length; i < len; i += 1) {
      key = props[i];
      if (node.hasOwnProperty(key)) {
        clone[key] = cloneOf(node[key], seen);
      }
    }
    return clone;
  }

  function cloneObject (obj, seen) {
    var props = objectKeys(obj);
    var i, len, key, value;
    var clone = {};
    for (i = 0, len = props.length; i < len; i += 1) {
      key = props[i];
      value = obj[key];
      if (seen.has(value)) {
        continue;
      }
      clone[key] = cloneOf(value, seen);
    }
    return clone;
  }

  function cloneOf (val, seen) {
    if (typeof val === 'object' && val !== null) {
      seen.set(val, true);
      if (val instanceof RegExp) {
        return new RegExp(val);
      } else if (isArray(val)) {
        return cloneArray(val, seen);
      } else {
        return cloneNodeOrObject(val, seen);
      }
    } else {
      return val;
    }
  }

  function cloneRoot (obj) {
    var seen = new Map();
    seen.set(obj, true);
    return cloneNodeOrObject(obj, seen);
  }

  return cloneRoot;
};