@angular-wave/angular.ts 0.0.54 → 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@angular-wave/angular.ts",
3
3
  "license": "MIT",
4
- "version": "0.0.54",
4
+ "version": "0.0.55",
5
5
  "type": "module",
6
6
  "main": "dist/angular-ts.esm.js",
7
7
  "browser": "dist/angular-ts.umd.js",
@@ -1,50 +1,75 @@
1
- const KEY = "$$ngAnimateParentKey";
1
+ const KEY = "$animId";
2
2
  let parentCounter = 0;
3
- let cache = Object.create(null);
3
+ const cache = new Map();
4
4
 
5
5
  export function animateCache() {
6
6
  return {
7
+ /**
8
+ * Generates a unique cache key based on the node's parent and other parameters.
9
+ * @param {HTMLElement} node - The DOM node to generate the cache key for.
10
+ * @param {string} method - The animation method being applied.
11
+ * @param {string} [addClass] - Class to add during the animation.
12
+ * @param {string} [removeClass] - Class to remove during the animation.
13
+ * @returns {string} - The generated cache key.
14
+ */
7
15
  cacheKey(node, method, addClass, removeClass) {
8
16
  const { parentNode } = node;
9
- const parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);
17
+ const parentID = parentNode[KEY] ?? (parentNode[KEY] = ++parentCounter);
10
18
  const parts = [parentID, method, node.getAttribute("class")];
11
- if (addClass) {
12
- parts.push(addClass);
13
- }
14
- if (removeClass) {
15
- parts.push(removeClass);
16
- }
19
+ if (addClass) parts.push(addClass);
20
+ if (removeClass) parts.push(removeClass);
17
21
  return parts.join(" ");
18
22
  },
19
23
 
24
+ /**
25
+ * Checks if a cached animation without a duration exists.
26
+ * @param {string} key - The cache key to check.
27
+ * @returns {boolean} - True if an invalid animation is cached, false otherwise.
28
+ */
20
29
  containsCachedAnimationWithoutDuration(key) {
21
- const entry = cache[key];
22
-
23
- // nothing cached, so go ahead and animate
24
- // otherwise it should be a valid animation
25
- return (entry && !entry.isValid) || false;
30
+ const entry = cache.get(key);
31
+ return entry ? !entry.isValid : false;
26
32
  },
27
33
 
34
+ /**
35
+ * Clears the cache.
36
+ * @returns {void}
37
+ */
28
38
  flush() {
29
- cache = Object.create(null);
39
+ cache.clear();
30
40
  },
31
41
 
42
+ /**
43
+ * Gets the count of a specific cache entry.
44
+ * @param {string} key - The cache key to count.
45
+ * @returns {number} - The count of the cache entry.
46
+ */
32
47
  count(key) {
33
- const entry = cache[key];
34
- return entry ? entry.total : 0;
48
+ return cache.get(key)?.total ?? 0;
35
49
  },
36
50
 
51
+ /**
52
+ * Retrieves a value associated with a specific cache key.
53
+ * @param {string} key - The cache key to retrieve.
54
+ * @returns {any} - The value associated with the cache key.
55
+ */
37
56
  get(key) {
38
- const entry = cache[key];
39
- return entry && entry.value;
57
+ return cache.get(key)?.value;
40
58
  },
41
59
 
60
+ /**
61
+ * Adds or updates a cache entry.
62
+ * @param {string} key - The cache key to add or update.
63
+ * @param {any} value - The value to store.
64
+ * @param {boolean} isValid - Whether the cache entry is valid.
65
+ */
42
66
  put(key, value, isValid) {
43
- if (!cache[key]) {
44
- cache[key] = { total: 1, value, isValid };
67
+ const entry = cache.get(key);
68
+ if (entry) {
69
+ entry.total++;
70
+ entry.value = value;
45
71
  } else {
46
- cache[key].total++;
47
- cache[key].value = value;
72
+ cache.set(key, { total: 1, value, isValid });
48
73
  }
49
74
  },
50
75
  };
@@ -2,6 +2,11 @@ import { isString } from "../shared/utils";
2
2
  import { NG_ANIMATE_CHILDREN_DATA } from "./shared";
3
3
 
4
4
  $$AnimateChildrenDirective.$inject = ["$interpolate"];
5
+
6
+ /**
7
+ * @param {*} $interpolate
8
+ * @returns {import("../types").Directive}
9
+ */
5
10
  export function $$AnimateChildrenDirective($interpolate) {
6
11
  return {
7
12
  link(scope, element, attrs) {
@@ -23,9 +23,16 @@ export function $$AnimateCssDriverProvider($$animationProvider) {
23
23
  "$animateCss",
24
24
  "$$AnimateRunner",
25
25
  "$rootElement",
26
+ /**
27
+ *
28
+ * @param {*} $animateCss
29
+ * @param {typeof import('../core/animate/animate-runner').AnimateRunner} $$AnimateRunner
30
+ * @param {*} $rootElement
31
+ * @returns
32
+ */
26
33
  function ($animateCss, $$AnimateRunner, $rootElement) {
27
34
  const bodyNode = document.body;
28
- const rootNode = getDomNode($rootElement);
35
+ const rootNode = $rootElement[0];
29
36
 
30
37
  const rootBodyElement = JQLite(
31
38
  // this is to avoid using something that exists outside of the body
@@ -41,24 +48,12 @@ export function $$AnimateCssDriverProvider($$animationProvider) {
41
48
  ? prepareFromToAnchorAnimation(
42
49
  animationDetails.from,
43
50
  animationDetails.to,
44
- animationDetails.classes,
45
51
  animationDetails.anchors,
46
52
  )
47
53
  : prepareRegularAnimation(animationDetails);
48
54
  };
49
55
 
50
- function filterCssClasses(classes) {
51
- // remove all the `ng-` stuff
52
- return classes.replace(/\bng-\S+\b/g, "");
53
- }
54
-
55
- function getUniqueValues(a, b) {
56
- if (isString(a)) a = a.split(" ");
57
- if (isString(b)) b = b.split(" ");
58
- return a.filter((val) => b.indexOf(val) === -1).join(" ");
59
- }
60
-
61
- function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {
56
+ function prepareAnchoredAnimation(outAnchor, inAnchor) {
62
57
  const clone = JQLite(getDomNode(outAnchor).cloneNode(true));
63
58
  const startingClasses = filterCssClasses(getClassVal(clone));
64
59
 
@@ -186,19 +181,15 @@ export function $$AnimateCssDriverProvider($$animationProvider) {
186
181
  }
187
182
  }
188
183
 
189
- function prepareFromToAnchorAnimation(from, to, classes, anchors) {
184
+ function prepareFromToAnchorAnimation(from, to, anchors) {
190
185
  const fromAnimation = prepareRegularAnimation(from);
191
186
  const toAnimation = prepareRegularAnimation(to);
192
187
 
193
188
  const anchorAnimations = [];
194
- forEach(anchors, (anchor) => {
189
+ anchors.forEach((anchor) => {
195
190
  const outElement = anchor.out;
196
191
  const inElement = anchor.in;
197
- const animator = prepareAnchoredAnimation(
198
- classes,
199
- outElement,
200
- inElement,
201
- );
192
+ const animator = prepareAnchoredAnimation(outElement, inElement);
202
193
  if (animator) {
203
194
  anchorAnimations.push(animator);
204
195
  }
@@ -236,7 +227,7 @@ export function $$AnimateCssDriverProvider($$animationProvider) {
236
227
  return runner;
237
228
 
238
229
  function endFn() {
239
- forEach(animationRunners, (runner) => {
230
+ animationRunners.forEach((runner) => {
240
231
  runner.end();
241
232
  });
242
233
  }
@@ -245,7 +236,6 @@ export function $$AnimateCssDriverProvider($$animationProvider) {
245
236
  }
246
237
 
247
238
  function prepareRegularAnimation(animationDetails) {
248
- const { element } = animationDetails;
249
239
  const options = animationDetails.options || {};
250
240
 
251
241
  if (animationDetails.structural) {
@@ -271,14 +261,26 @@ export function $$AnimateCssDriverProvider($$animationProvider) {
271
261
  );
272
262
  }
273
263
 
274
- const animator = $animateCss(element, options);
264
+ const animator = $animateCss(animationDetails.element, options);
275
265
 
276
266
  // the driver lookup code inside of $$animation attempts to spawn a
277
267
  // driver one by one until a driver returns a.$$willAnimate animator object.
278
268
  // $animateCss will always return an object, however, it will pass in
279
269
  // a flag as a hint as to whether an animation was detected or not
270
+
280
271
  return animator.$$willAnimate ? animator : null;
281
272
  }
282
273
  },
283
274
  ];
284
275
  }
276
+
277
+ function filterCssClasses(classes) {
278
+ // remove all the `ng-` stuff
279
+ return classes.replace(/\bng-\S+\b/g, "");
280
+ }
281
+
282
+ function getUniqueValues(a, b) {
283
+ if (isString(a)) a = a.split(" ");
284
+ if (isString(b)) b = b.split(" ");
285
+ return a.filter((val) => b.indexOf(val) === -1).join(" ");
286
+ }
@@ -0,0 +1,40 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>AngularTS Test Runner</title>
6
+
7
+ <link rel="shortcut icon" type="image/png" href="/images/favicon.ico" />
8
+
9
+ <!--
10
+ <script src="https://cdn.jsdelivr.net/npm/angular@1.8.3/angular.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/angular-animate@1.8.3/angular-animate.js"></script>
12
+ <script>window.angular.module("test", ["ngAnimate"])</script> -->
13
+
14
+ <script type="module" src="/src/index.js"></script>
15
+ <script>
16
+ document.addEventListener("DOMContentLoaded", () => {
17
+ window.angular.module("test", ["ngAnimate"]);
18
+ });
19
+ </script>
20
+
21
+ <style>
22
+ /* The starting CSS styles for the enter animation */
23
+ .fade.ng-enter {
24
+ transition: 0.5s linear all;
25
+ opacity: 0;
26
+ }
27
+
28
+ /* The finishing CSS styles for the enter animation */
29
+ .fade.ng-enter.ng-enter-active {
30
+ opacity: 1;
31
+ background-color: red;
32
+ }
33
+ </style>
34
+ </head>
35
+ <body ng-app="test">
36
+ <div ng-if="bool" class="fade">Fade me in out</div>
37
+ <button ng-click="bool=true">Fade In!</button>
38
+ <button ng-click="bool=false">Fade Out!</button>
39
+ </body>
40
+ </html>
@@ -155,7 +155,6 @@ export function $AnimateCssProvider() {
155
155
 
156
156
  function computeCachedCssStyles(
157
157
  node,
158
- className,
159
158
  cacheKey,
160
159
  allowNoDuration,
161
160
  properties,
@@ -247,10 +246,9 @@ export function $AnimateCssProvider() {
247
246
  });
248
247
  }
249
248
 
250
- function computeTimings(node, className, cacheKey, allowNoDuration) {
249
+ function computeTimings(node, cacheKey, allowNoDuration) {
251
250
  const timings = computeCachedCssStyles(
252
251
  node,
253
- className,
254
252
  cacheKey,
255
253
  allowNoDuration,
256
254
  DETECT_CSS_PROPERTIES,
@@ -343,7 +341,6 @@ export function $AnimateCssProvider() {
343
341
  let preparationClasses = [structuralClassName, addRemoveClassName]
344
342
  .join(" ")
345
343
  .trim();
346
- let fullClassName = `${classes} ${preparationClasses}`;
347
344
  const hasToStyles = styles.to && Object.keys(styles.to).length > 0;
348
345
  const containsKeyframeAnimation =
349
346
  (options.keyframeStyle || "").length > 0;
@@ -405,6 +402,7 @@ export function $AnimateCssProvider() {
405
402
 
406
403
  // we set the duration so that it will be picked up by getComputedStyle later
407
404
  applyInlineStyle(node, durationStyle);
405
+
408
406
  temporaryStyles.push(durationStyle);
409
407
  }
410
408
 
@@ -432,12 +430,7 @@ export function $AnimateCssProvider() {
432
430
  blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
433
431
  }
434
432
 
435
- let timings = computeTimings(
436
- node,
437
- fullClassName,
438
- cacheKey,
439
- !isStructural,
440
- );
433
+ let timings = computeTimings(node, cacheKey, !isStructural);
441
434
  let relativeDelay = timings.maxDelay;
442
435
  maxDelay = Math.max(relativeDelay, 0);
443
436
  maxDuration = timings.maxDuration;
@@ -485,7 +478,7 @@ export function $AnimateCssProvider() {
485
478
  return closeAndReturnNoopAnimator();
486
479
  }
487
480
 
488
- const activeClasses = pendClasses(
481
+ var activeClasses = pendClasses(
489
482
  preparationClasses,
490
483
  ACTIVE_CLASS_SUFFIX,
491
484
  );
@@ -585,15 +578,15 @@ export function $AnimateCssProvider() {
585
578
  animationPaused = false;
586
579
 
587
580
  if (preparationClasses && !options.$$skipPreparationClasses) {
588
- preparationClasses
589
- .split(" ")
590
- .forEach((cls) => element.classList.remove(cls));
581
+ preparationClasses.split(" ").forEach(function (cls) {
582
+ element[0].classList.remove(cls);
583
+ });
591
584
  }
592
-
585
+ activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);
593
586
  if (activeClasses) {
594
- activeClasses
595
- .split(" ")
596
- .forEach((cls) => element.classList.remove(cls));
587
+ activeClasses.split(" ").forEach(function (cls) {
588
+ element[0].classList.remove(cls);
589
+ });
597
590
  }
598
591
 
599
592
  blockKeyframeAnimations(node, false);
@@ -782,7 +775,8 @@ export function $AnimateCssProvider() {
782
775
  });
783
776
 
784
777
  applyAnimationClasses(element, options);
785
- element.className += ` ${activeClasses}`;
778
+
779
+ element[0].classList.add(activeClasses);
786
780
  if (flags.recalculateTimingStyles) {
787
781
  fullClassName = `${node.getAttribute("class")} ${preparationClasses}`;
788
782
  cacheKey = $$animateCache.cacheKey(
@@ -792,7 +786,7 @@ export function $AnimateCssProvider() {
792
786
  options.removeClass,
793
787
  );
794
788
 
795
- timings = computeTimings(node, fullClassName, cacheKey, false);
789
+ timings = computeTimings(node, cacheKey, false);
796
790
  relativeDelay = timings.maxDelay;
797
791
  maxDelay = Math.max(relativeDelay, 0);
798
792
  maxDuration = timings.maxDuration;
@@ -391,7 +391,7 @@ export function $$AnimateQueueProvider($animateProvider) {
391
391
  // we always make a copy of the options since
392
392
  // there should never be any side effects on
393
393
  // the input data when running `$animateCss`.
394
- let options = structuredClone(initialOptions);
394
+ let options = initialOptions;
395
395
 
396
396
  let element = stripCommentsFromElement(originalElement);
397
397
  const node = getDomNode(element);
@@ -196,7 +196,7 @@ export function $$AnimationProvider() {
196
196
 
197
197
  $rootScope.$$postDigest(() => {
198
198
  const animations = [];
199
- forEach(animationQueue, (entry) => {
199
+ animationQueue.forEach((entry) => {
200
200
  // the element was destroyed early on which removed the runner
201
201
  // form its storage. This means we can't animate this element
202
202
  // at all and it already has been closed due to destruction.
@@ -213,7 +213,7 @@ export function $$AnimationProvider() {
213
213
  const groupedAnimations = groupAnimations(animations);
214
214
  const toBeSortedAnimations = [];
215
215
 
216
- forEach(groupedAnimations, (animationEntry) => {
216
+ groupedAnimations.forEach((animationEntry) => {
217
217
  const element = animationEntry.from
218
218
  ? animationEntry.from.element
219
219
  : animationEntry.element;
@@ -342,7 +342,7 @@ export function $$AnimationProvider() {
342
342
  if (anchorNodes.length) {
343
343
  const direction = enterOrMove ? "to" : "from";
344
344
 
345
- forEach(anchorNodes, (anchor) => {
345
+ anchorNodes.forEach((anchor) => {
346
346
  const key = anchor.getAttribute(NG_ANIMATE_REF_ATTR);
347
347
  refLookup[key] = refLookup[key] || {};
348
348
  refLookup[key][direction] = {
@@ -303,6 +303,11 @@ export function resolveElementClasses(existing, toAdd, toRemove) {
303
303
  return classes;
304
304
  }
305
305
 
306
+ /**
307
+ *
308
+ * @param {JQLite|Element} element
309
+ * @returns {Element}
310
+ */
306
311
  export function getDomNode(element) {
307
312
  return element instanceof JQLite ? element[0] : element;
308
313
  }
@@ -50,7 +50,7 @@ export function AnimateRunnerFactoryProvider() {
50
50
  ];
51
51
  }
52
52
 
53
- class AnimateRunner {
53
+ export class AnimateRunner {
54
54
  static chain(chain, callback) {
55
55
  let index = 0;
56
56
 
@@ -483,7 +483,6 @@ describe("$animate", () => {
483
483
 
484
484
  element = JQLite('<svg><g class="test-class4"></g></svg>');
485
485
  const target = element.children().eq(0);
486
- debugger;
487
486
  $animate.addClass(target, "test-class1");
488
487
  $animate.removeClass(target, "test-class1");
489
488
  $animate.addClass(target, "test-class2");
package/src/loader.js CHANGED
@@ -183,7 +183,6 @@ export class Angular {
183
183
  };
184
184
 
185
185
  this.doBootstrap = function () {
186
- // @ts-ignore
187
186
  element = JQLite(element);
188
187
 
189
188
  if (element.injector()) {
@@ -51,7 +51,6 @@ export class ParamType {
51
51
  }
52
52
  /** @inheritdoc */
53
53
  equals(a, b) {
54
- // tslint:disable-next-line:triple-equals
55
54
  return a == b;
56
55
  }
57
56
  $subPattern() {
@@ -87,7 +87,7 @@ function initDefaultTypes() {
87
87
  decode: valToString,
88
88
  is: is(String),
89
89
  pattern: /.*/,
90
- // tslint:disable-next-line:triple-equals
90
+
91
91
  equals: (a, b) => a == b, // allow coersion for null/undefined/""
92
92
  };
93
93
  return Object.assign({}, defaultTypeBase, def);
@@ -4,10 +4,12 @@ import { isInjectable } from "../../shared/predicates";
4
4
  import { isDefined, isUndefined, isString } from "../../shared/utils";
5
5
  import { services } from "../common/coreservices";
6
6
  import { ParamType } from "./param-type";
7
- const hasOwn = Object.prototype.hasOwnProperty;
7
+
8
8
  const isShorthand = (cfg) =>
9
- ["value", "type", "squash", "array", "dynamic"].filter(hasOwn.bind(cfg || {}))
10
- .length === 0;
9
+ ["value", "type", "squash", "array", "dynamic"].filter(
10
+ Object.prototype.hasOwnProperty.bind(cfg || {}),
11
+ ).length === 0;
12
+
11
13
  var DefType;
12
14
  (function (DefType) {
13
15
  DefType[(DefType["PATH"] = 0)] = "PATH";
@@ -15,6 +17,7 @@ var DefType;
15
17
  DefType[(DefType["CONFIG"] = 2)] = "CONFIG";
16
18
  })(DefType || (DefType = {}));
17
19
  export { DefType };
20
+
18
21
  function getParamDeclaration(paramName, location, state) {
19
22
  const noReloadOnSearch =
20
23
  (state.reloadOnSearch === false && location === DefType.SEARCH) ||
@@ -21,7 +21,6 @@ export let resolvePolicies = {
21
21
  const whens = resolvePolicies.when;
22
22
  const ALL_WHENS = [whens.EAGER, whens.LAZY];
23
23
  const EAGER_WHENS = [whens.EAGER];
24
- // tslint:disable-next-line:no-inferrable-types
25
24
  export const NATIVE_INJECTOR_TOKEN = "Native Injector";
26
25
  /**
27
26
  * Encapsulates Dependency Injection for a path of nodes
@@ -431,15 +431,12 @@ describe("$state", () => {
431
431
  $stateProvider.state(childNoParam);
432
432
 
433
433
  $transitions.onEnter({}, function (trans, state) {
434
- console.log("enter");
435
434
  dynlog += "enter:" + state.name + ";";
436
435
  });
437
436
  $transitions.onExit({}, function (trans, state) {
438
- console.log("exit");
439
437
  dynlog += "exit:" + state.name + ";";
440
438
  });
441
439
  $transitions.onSuccess({}, function () {
442
- console.log("success");
443
440
  dynlog += "success;";
444
441
  });
445
442
 
@@ -4,7 +4,6 @@ import { TransitionHook } from "./transition-hook";
4
4
  * Plugins can define custom hook types, such as sticky states does for `onInactive`.
5
5
  */
6
6
  export class TransitionEventType {
7
- /* tslint:disable:no-inferrable-types */
8
7
  constructor(
9
8
  name,
10
9
  hookPhase,
@@ -455,7 +455,6 @@ export class Transition {
455
455
  redirect(targetState) {
456
456
  let redirects = 1,
457
457
  trans = this;
458
- // tslint:disable-next-line:no-conditional-assignment
459
458
  while ((trans = trans.redirectedFrom()) != null) {
460
459
  if (++redirects > 20)
461
460
  throw new Error(`Too many consecutive Transition redirects (20+)`);
@@ -249,7 +249,6 @@ export class UrlMatcher {
249
249
  };
250
250
  let details;
251
251
  let segment;
252
- // tslint:disable-next-line:no-conditional-assignment
253
252
  while ((matchArray = placeholder.exec(pattern))) {
254
253
  details = matchDetails(matchArray, false);
255
254
  if (details.segment.indexOf("?") >= 0) break; // we're into the search part
@@ -269,7 +268,6 @@ export class UrlMatcher {
269
268
  segment = segment.substring(0, i);
270
269
  if (search.length > 0) {
271
270
  last = 0;
272
- // tslint:disable-next-line:no-conditional-assignment
273
271
  while ((matchArray = searchPlaceholder.exec(search))) {
274
272
  details = matchDetails(matchArray, true);
275
273
  checkParamErrors(details.id);
@@ -1,16 +1,6 @@
1
- /**
2
- * Random utility functions used in the ng-router code
3
- *
4
- * These functions are exported, but are subject to change without notice.
5
- *
6
- */
7
1
  import { isDate, isFunction, isRegExp, isString } from "./utils";
8
2
  import { all, any, prop, curry, not } from "./hof";
9
3
  import { services } from "../router/common/coreservices";
10
- export const root =
11
- (typeof self === "object" && self.self === self && self) ||
12
- (typeof global === "object" && global.global === global && global) ||
13
- this;
14
4
  export const fromJson = JSON.parse.bind(JSON);
15
5
  export const toJson = JSON.stringify.bind(JSON);
16
6
  export const forEach = _forEach;
@@ -158,7 +148,6 @@ export const mergeR = (memo, item) => Object.assign(memo, item);
158
148
  */
159
149
  export function ancestors(first, second) {
160
150
  const path = [];
161
- // tslint:disable-next-line:forin
162
151
  for (const n in first.path) {
163
152
  if (first.path[n] !== second.path[n]) break;
164
153
  path.push(first.path[n]);
@@ -476,7 +465,7 @@ function _equals(o1, o2) {
476
465
  if (predicates.map(any).reduce((b, fn) => b || !!fn(tup), false))
477
466
  return false;
478
467
  const keys = {};
479
- // tslint:disable-next-line:forin
468
+
480
469
  for (const key in o1) {
481
470
  if (!_equals(o1[key], o2[key])) return false;
482
471
  keys[key] = true;
package/src/shared/hof.js CHANGED
@@ -133,7 +133,6 @@ export function or(fn1, fn2) {
133
133
  * @returns a function which takes an array and returns true if `fn1` is true for all elements of the array
134
134
  */
135
135
  export const all = (fn1) => (arr) => arr.reduce((b, x) => b && !!fn1(x), true);
136
- // tslint:disable-next-line:variable-name
137
136
  export const any = (fn1) => (arr) => arr.reduce((b, x) => b || !!fn1(x), false);
138
137
  /** Given a class, returns a Predicate function that returns true if the object is of that class */
139
138
  export const is = (ctor) => (obj) =>