simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

snapshot.js (11509B)


      1 "use strict";
      2 
      3 var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
      4 
      5 var _typeof3 = require("@babel/runtime/helpers/typeof");
      6 
      7 Object.defineProperty(exports, "__esModule", {
      8   value: true
      9 });
     10 exports.createSnapshotFromFactories = createSnapshotFromFactories;
     11 exports.validateBundle = validateBundle;
     12 exports.validateTypeOf = validateTypeOf;
     13 
     14 var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
     15 
     16 var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
     17 
     18 var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
     19 
     20 var _assert = _interopRequireDefault(require("assert"));
     21 
     22 var allIsFunctions = _interopRequireWildcard(require("./is.js"));
     23 
     24 var _create = require("../core/create.js");
     25 
     26 var _string = require("./string.js");
     27 
     28 function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
     29 
     30 function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof3(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
     31 
     32 function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
     33 
     34 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
     35 
     36 function validateBundle(expectedBundleStructure, bundle) {
     37   var originalWarn = console.warn;
     38 
     39   console.warn = function () {
     40     for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
     41       args[_key] = arguments[_key];
     42     }
     43 
     44     if (args.join(' ').indexOf('is moved to') !== -1 && args.join(' ').indexOf('Please use the new location instead') !== -1) {
     45       // Ignore warnings like:
     46       // Warning: math.type.isNumber is moved to math.isNumber in v6.0.0. Please use the new location instead.
     47       return;
     48     }
     49 
     50     originalWarn.apply(console, args);
     51   };
     52 
     53   try {
     54     var issues = []; // see whether all expected functions and objects are there
     55 
     56     traverse(expectedBundleStructure, function (expectedType, path) {
     57       var actualValue = get(bundle, path);
     58       var actualType = validateTypeOf(actualValue);
     59       var message = actualType === 'undefined' ? 'Missing entry in bundle. ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType) : 'Unexpected entry type in bundle. ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType);
     60 
     61       if (actualType !== expectedType) {
     62         issues.push({
     63           actualType: actualType,
     64           expectedType: expectedType,
     65           message: message
     66         });
     67         console.warn(message);
     68       }
     69     }); // see whether there are any functions or objects that shouldn't be there
     70 
     71     traverse(bundle, function (actualValue, path) {
     72       var actualType = validateTypeOf(actualValue);
     73       var expectedType = get(expectedBundleStructure, path) || 'undefined'; // FIXME: ugly to have these special cases
     74 
     75       if (path.join('.').indexOf('docs.') !== -1) {
     76         // ignore the contents of docs
     77         return;
     78       }
     79 
     80       if (path.join('.').indexOf('all.') !== -1) {
     81         // ignore the contents of all dependencies
     82         return;
     83       }
     84 
     85       var message = expectedType === 'undefined' ? 'Unknown entry in bundle. ' + 'Is there a new function added which is missing in this snapshot test? ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType) : 'Unexpected entry type in bundle. ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType);
     86 
     87       if (actualType !== expectedType) {
     88         issues.push({
     89           actualType: actualType,
     90           expectedType: expectedType,
     91           message: message
     92         });
     93         console.warn(message);
     94       }
     95     }); // assert on the first issue (if any)
     96 
     97     if (issues.length > 0) {
     98       var _issues$ = issues[0],
     99           actualType = _issues$.actualType,
    100           expectedType = _issues$.expectedType,
    101           message = _issues$.message;
    102       console.warn("".concat(issues.length, " bundle issues found"));
    103 
    104       _assert.default.strictEqual(actualType, expectedType, message);
    105     }
    106   } finally {
    107     console.warn = originalWarn;
    108   }
    109 }
    110 /**
    111  * Based on an object with factory functions, create the expected
    112  * structures for ES6 export and a mathjs instance.
    113  * @param {Object} factories
    114  * @return {{expectedInstanceStructure: Object, expectedES6Structure: Object}}
    115  */
    116 
    117 
    118 function createSnapshotFromFactories(factories) {
    119   var math = (0, _create.create)(factories);
    120   var allFactoryFunctions = {};
    121   var allFunctionsConstantsClasses = {};
    122   var allFunctionsConstants = {};
    123   var allTransformFunctions = {};
    124   var allDependencyCollections = {};
    125   var allClasses = {};
    126   var allNodeClasses = {};
    127   Object.keys(factories).forEach(function (factoryName) {
    128     var factory = factories[factoryName];
    129     var name = factory.fn;
    130     var isTransformFunction = factory.meta && factory.meta.isTransformFunction;
    131     var isClass = !isLowerCase(name[0]) && validateTypeOf(math[name]) === 'Function';
    132     var dependenciesName = factory.fn + (isTransformFunction ? 'Transform' : '') + 'Dependencies';
    133     allFactoryFunctions[factoryName] = 'Function';
    134     allFunctionsConstantsClasses[name] = validateTypeOf(math[name]);
    135     allDependencyCollections[dependenciesName] = 'Object';
    136 
    137     if (isTransformFunction) {
    138       allTransformFunctions[name] = 'Function';
    139     }
    140 
    141     if (isClass) {
    142       if ((0, _string.endsWith)(name, 'Node')) {
    143         allNodeClasses[name] = 'Function';
    144       } else {
    145         allClasses[name] = 'Function';
    146       }
    147     } else {
    148       allFunctionsConstants[name] = validateTypeOf(math[name]);
    149     }
    150   });
    151   var embeddedDocs = {};
    152   Object.keys(factories).forEach(function (factoryName) {
    153     var factory = factories[factoryName];
    154     var name = factory.fn;
    155 
    156     if (isLowerCase(factory.fn[0])) {
    157       // ignore class names starting with upper case
    158       embeddedDocs[name] = 'Object';
    159     }
    160   });
    161   embeddedDocs = exclude(embeddedDocs, ['equalScalar', 'apply', 'addScalar', 'multiplyScalar', 'print', 'divideScalar', 'parse', 'compile', 'parser', 'chain', 'reviver', 'replacer']);
    162   var allTypeChecks = {};
    163   Object.keys(allIsFunctions).forEach(function (name) {
    164     if (name.indexOf('is') === 0) {
    165       allTypeChecks[name] = 'Function';
    166     }
    167   });
    168   var allErrorClasses = {
    169     ArgumentsError: 'Function',
    170     DimensionError: 'Function',
    171     IndexError: 'Function'
    172   };
    173 
    174   var expectedInstanceStructure = _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, allFunctionsConstantsClasses), {}, {
    175     on: 'Function',
    176     off: 'Function',
    177     once: 'Function',
    178     emit: 'Function',
    179     import: 'Function',
    180     config: 'Function',
    181     create: 'Function',
    182     factory: 'Function'
    183   }, allTypeChecks), allErrorClasses), {}, {
    184     expression: {
    185       transform: _objectSpread({}, allTransformFunctions),
    186       mathWithTransform: _objectSpread(_objectSpread({}, exclude(allFunctionsConstants, ['chain'])), {}, {
    187         config: 'Function'
    188       })
    189     }
    190   });
    191 
    192   var expectedES6Structure = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, exclude(allFunctionsConstantsClasses, ['E', 'false', 'Infinity', 'NaN', 'null', 'PI', 'true'])), {}, {
    193     create: 'Function',
    194     config: 'Function',
    195     factory: 'Function',
    196     _true: 'boolean',
    197     _false: 'boolean',
    198     _null: 'null',
    199     _Infinity: 'number',
    200     _NaN: 'number'
    201   }, allTypeChecks), allErrorClasses), allDependencyCollections), allFactoryFunctions), {}, {
    202     docs: embeddedDocs
    203   });
    204 
    205   return {
    206     expectedInstanceStructure: expectedInstanceStructure,
    207     expectedES6Structure: expectedES6Structure
    208   };
    209 }
    210 
    211 function validateTypeOf(x) {
    212   if (x && x.type === 'Unit') {
    213     return 'Unit';
    214   }
    215 
    216   if (x && x.type === 'Complex') {
    217     return 'Complex';
    218   }
    219 
    220   if (Array.isArray(x)) {
    221     return 'Array';
    222   }
    223 
    224   if (x === null) {
    225     return 'null';
    226   }
    227 
    228   if (typeof x === 'function') {
    229     return 'Function';
    230   }
    231 
    232   if ((0, _typeof2.default)(x) === 'object') {
    233     return 'Object';
    234   }
    235 
    236   return (0, _typeof2.default)(x);
    237 }
    238 
    239 function traverse(obj) {
    240   var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (value, path) {};
    241   var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
    242 
    243   // FIXME: ugly to have these special cases
    244   if (path.length > 0 && path[0].indexOf('Dependencies') !== -1) {
    245     // special case for objects holding a collection of dependencies
    246     callback(obj, path);
    247   } else if (validateTypeOf(obj) === 'Array') {
    248     obj.map(function (item, index) {
    249       return traverse(item, callback, path.concat(index));
    250     });
    251   } else if (validateTypeOf(obj) === 'Object') {
    252     Object.keys(obj).forEach(function (key) {
    253       // FIXME: ugly to have these special cases
    254       // ignore special case of deprecated docs
    255       if (key === 'docs' && path.join('.') === 'expression') {
    256         return;
    257       }
    258 
    259       traverse(obj[key], callback, path.concat(key));
    260     });
    261   } else {
    262     callback(obj, path);
    263   }
    264 }
    265 
    266 function get(object, path) {
    267   var child = object;
    268 
    269   for (var i = 0; i < path.length; i++) {
    270     var key = path[i];
    271     child = child ? child[key] : undefined;
    272   }
    273 
    274   return child;
    275 }
    276 /**
    277  * Create a copy of the provided `object` and delete
    278  * all properties listed in `excludedProperties`
    279  * @param {Object} object
    280  * @param {string[]} excludedProperties
    281  * @return {Object}
    282  */
    283 
    284 
    285 function exclude(object, excludedProperties) {
    286   var strippedObject = (0, _extends2.default)({}, object);
    287   excludedProperties.forEach(function (excludedProperty) {
    288     delete strippedObject[excludedProperty];
    289   });
    290   return strippedObject;
    291 }
    292 
    293 function isLowerCase(text) {
    294   return typeof text === 'string' && text.toLowerCase() === text;
    295 }