simple-squiggle

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

snapshot.js (9711B)


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