@woosh/meep-engine 2.48.6 → 2.48.8

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
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.48.6",
8
+ "version": "2.48.8",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -1,5 +1,6 @@
1
1
  import { isArrayEqualStrict } from "./collection/array/isArrayEqualStrict.js";
2
2
  import { isTypedArray } from "./collection/array/typed/isTypedArray.js";
3
+ import { InMemoryDescriptor } from "./debug/InMemoryDescriptor.js";
3
4
 
4
5
  function equal(a, b, m) {
5
6
  assert(a === b, m) // eslint-disable-line eqeqeq
@@ -385,6 +386,30 @@ assert.isFiniteNumber = function (value, name = "value") {
385
386
  }
386
387
  };
387
388
 
389
+ /**
390
+ * @template T
391
+ * @param {T} value
392
+ * @param {string} name
393
+ * @param {Matcher<T>} matcher
394
+ */
395
+ assert.that = function (value, name, matcher) {
396
+ if (matcher.matches(value)) {
397
+ return;
398
+ }
399
+
400
+ const mismatch_description = new InMemoryDescriptor();
401
+
402
+ mismatch_description.appendText(`Expected ${name} to be `);
403
+
404
+ matcher.describeTo(mismatch_description);
405
+
406
+ mismatch_description.appendText(" instead ");
407
+
408
+ matcher.describeMismatch(value, mismatch_description);
409
+
410
+ throw new Error(mismatch_description.value);
411
+ }
412
+
388
413
  export {
389
414
  assert
390
415
  };
@@ -0,0 +1,85 @@
1
+ import { Description } from "./Description.js";
2
+ import { SelfDescribingValueIterator } from "./SelfDescribingValueIterator.js";
3
+
4
+
5
+ function descriptionOf(value) {
6
+ try {
7
+ return String(value);
8
+ } catch (e) {
9
+ return 'VALUE@0';
10
+ }
11
+ }
12
+
13
+ /**
14
+ *
15
+ * @param {number} value
16
+ * @return {string}
17
+ */
18
+ function formatNumber(value) {
19
+ return String(value);
20
+ }
21
+
22
+
23
+ export class BaseDescription extends Description {
24
+ appendDescriptionOf(value) {
25
+ value.describeTo(this);
26
+ return this;
27
+ }
28
+
29
+ #toJavaScriptSyntax(unformatted) {
30
+ this.appendText('"');
31
+
32
+ // TODO escape string
33
+ this.appendText(unformatted);
34
+
35
+ this.appendText('"');
36
+ }
37
+
38
+ appendValue(value) {
39
+ if (value == null) {
40
+ this.appendText("null");
41
+ } else if (value === undefined) {
42
+ this.appendText("undefined");
43
+ } else if (typeof value === "string") {
44
+ this.#toJavaScriptSyntax(value);
45
+ } else if (typeof value === "number") {
46
+ this.appendText(formatNumber(value));
47
+ } else if (Array.isArray(value)) {
48
+ this.appendValueList("[", ", ", "]", value);
49
+ } else {
50
+ this.appendText('<');
51
+ this.appendText(descriptionOf(value));
52
+ this.appendText('>');
53
+ }
54
+ return this;
55
+ }
56
+
57
+ appendValueList(start, separator, end, values) {
58
+ this.appendList(start, separator, end, new SelfDescribingValueIterator(values));
59
+ return this;
60
+ }
61
+
62
+ appendList(start, separator, end, values) {
63
+ let separate = false;
64
+
65
+ this.appendText(start);
66
+
67
+ /**
68
+ *
69
+ */
70
+ const iterator = values[Symbol.iterator]();
71
+
72
+ for (let i = iterator.next(); i.done !== true; i = iterator.next()) {
73
+ if (separate) {
74
+ this.appendText(separator);
75
+ }
76
+
77
+ this.appendDescriptionOf(i.value);
78
+ separate = true;
79
+ }
80
+
81
+ this.appendText(end);
82
+
83
+ return this;
84
+ }
85
+ }
@@ -0,0 +1,7 @@
1
+ import { Matcher } from "./Matcher.js";
2
+
3
+ export class BaseMatcher extends Matcher {
4
+ describeMismatch(item, mismatch_description) {
5
+ mismatch_description.appendText("was ").appendValue(item);
6
+ }
7
+ }
@@ -0,0 +1,53 @@
1
+ export class Description {
2
+ /**
3
+ *
4
+ * @param {SelfDescribing} value
5
+ * @returns {this}
6
+ */
7
+ appendDescriptionOf(value) {
8
+ throw new Error('Not Implemented');
9
+ }
10
+
11
+ /**
12
+ * @param {string} start
13
+ * @param {string} separator
14
+ * @param {string} end
15
+ * @param {Iterable<SelfDescribing>} values
16
+ * @returns {this}
17
+ */
18
+ appendList(start, separator, end, values) {
19
+ throw new Error('Not Implemented');
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @param {string} text
25
+ * @returns {this}
26
+ */
27
+ appendText(text) {
28
+ throw new Error('Not Implemented');
29
+ }
30
+
31
+ /**
32
+ * @template T
33
+ * @param {T} value
34
+ * @returns {this}
35
+ */
36
+ appendValue(value) {
37
+ throw new Error('Not Implemented');
38
+ }
39
+
40
+ /**
41
+ *
42
+ * @template T
43
+ * @param {string} start
44
+ * @param {string} separator
45
+ * @param {string} end
46
+ * @param {Iterable<T>} values
47
+ * @returns {this}
48
+ */
49
+ appendValueList(start, separator, end, values) {
50
+ throw new Error('Not Implemented');
51
+ }
52
+
53
+ }
@@ -0,0 +1,11 @@
1
+ import { BaseDescription } from "./BaseDescription.js";
2
+
3
+ export class InMemoryDescriptor extends BaseDescription {
4
+ value = ""
5
+
6
+ appendText(text) {
7
+ this.value += text;
8
+
9
+ return this;
10
+ }
11
+ }
@@ -0,0 +1,35 @@
1
+ import { SelfDescribing } from "./SelfDescribing.js";
2
+ import { NullDescription } from "./NullDescription.js";
3
+
4
+ /**
5
+ * Heavily influenced by Hamcrest, pretty much a straight port
6
+ * @template T
7
+ */
8
+ export class Matcher extends SelfDescribing {
9
+
10
+ /**
11
+ *
12
+ * @param {T} item
13
+ * @param {Description} [mismatch_description]
14
+ * @returns {boolean}
15
+ */
16
+ matches(item, mismatch_description = NullDescription.INSTANCE) {
17
+ throw new Error('Not Implemented');
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param {T} item
23
+ * @param {Description} mismatch_description
24
+ * @returns {void}
25
+ */
26
+ describeMismatch(item, mismatch_description) {
27
+ throw new Error('Not Implemented');
28
+ }
29
+ }
30
+
31
+ /**
32
+ * @readonly
33
+ * @type {boolean}
34
+ */
35
+ Matcher.prototype.isMatcher = true;
@@ -0,0 +1,28 @@
1
+ import { Description } from "./Description.js";
2
+
3
+ /**
4
+ * Special description that doesn't record anything
5
+ */
6
+ export class NullDescription extends Description {
7
+ appendText(text) {
8
+ return this;
9
+ }
10
+
11
+ appendList(start, separator, end, values) {
12
+ return this;
13
+ }
14
+
15
+ appendValueList(start, separator, end, values) {
16
+ return this;
17
+ }
18
+
19
+ appendValue(value) {
20
+ return this;
21
+ }
22
+
23
+ appendDescriptionOf(value) {
24
+ return this;
25
+ }
26
+ }
27
+
28
+ NullDescription.INSTANCE = new NullDescription();
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The ability of an object to describe itself.
3
+ */
4
+ export class SelfDescribing {
5
+ /**
6
+ * Generates a description of the object. The description may be part of a
7
+ * description of a larger object of which this is just a component, so it
8
+ * should be worded appropriately.
9
+ * @param {Description} description The description to be built or appended to
10
+ * @returns {void}
11
+ */
12
+ describeTo(description) {
13
+ throw new Error('Not Implemented');
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ import { SelfDescribing } from "./SelfDescribing.js";
2
+
3
+ export class SelfDescribingValue extends SelfDescribing{
4
+ value;
5
+
6
+ constructor(value) {
7
+ super();
8
+
9
+ this.value = value;
10
+ }
11
+
12
+ describeTo(description) {
13
+ description.appendValue(this.value);
14
+ }
15
+ }
@@ -0,0 +1,27 @@
1
+ import { SelfDescribingValue } from "./SelfDescribingValue.js";
2
+
3
+ /**
4
+ * @template T
5
+ * @extends Iterable<SelfDescribing>
6
+ */
7
+ export class SelfDescribingValueIterator {
8
+ #iterable;
9
+
10
+ /**
11
+ *
12
+ * @param {Iterable<T>} iterable
13
+ */
14
+ constructor(iterable) {
15
+ this.#iterable = iterable;
16
+ }
17
+
18
+ * [Symbol.iterator]() {
19
+
20
+ for (const el of this.#iterable) {
21
+
22
+ yield new SelfDescribingValue(el);
23
+
24
+ }
25
+
26
+ }
27
+ }
@@ -0,0 +1,38 @@
1
+ import { Matcher } from "../Matcher.js";
2
+ import { NullDescription } from "../NullDescription.js";
3
+ import { BaseMatcher } from "../BaseMatcher.js";
4
+
5
+ export class AllOf extends BaseMatcher {
6
+ /**
7
+ * @type {Matcher[]}
8
+ */
9
+ #matchers;
10
+
11
+ /**
12
+ *
13
+ * @param {Matcher[]} matchers
14
+ */
15
+ constructor(matchers) {
16
+ super();
17
+
18
+ this.#matchers = matchers;
19
+ }
20
+
21
+ matches(item, mismatch_description) {
22
+ for (const matcher of this.#matchers) {
23
+ if (!matcher.matches(item, NullDescription.INSTANCE)) {
24
+
25
+ mismatch_description.appendDescriptionOf(matcher).appendText(" ");
26
+ matcher.describeMismatch(item, mismatch_description);
27
+
28
+ return false;
29
+ }
30
+ }
31
+
32
+ return true;
33
+ }
34
+
35
+ describeTo(description) {
36
+ description.appendList("(", ' and ', ")", this.#matchers);
37
+ }
38
+ }
@@ -0,0 +1,35 @@
1
+ import { Matcher } from "../Matcher.js";
2
+ import { NullDescription } from "../NullDescription.js";
3
+ import { BaseMatcher } from "../BaseMatcher.js";
4
+
5
+ export class AnyOf extends BaseMatcher {
6
+ /**
7
+ * @type {Matcher[]}
8
+ */
9
+ #matchers;
10
+
11
+ /**
12
+ *
13
+ * @param {Matcher[]} matchers
14
+ */
15
+ constructor(matchers) {
16
+ super();
17
+
18
+ this.#matchers = matchers;
19
+ }
20
+
21
+ matches(item, mismatch_description) {
22
+ for (const matcher of this.#matchers) {
23
+ if (!matcher.matches(item, NullDescription.INSTANCE)) {
24
+
25
+ return true;
26
+ }
27
+ }
28
+
29
+ return false;
30
+ }
31
+
32
+ describeTo(description) {
33
+ description.appendList("(", " or ", ")", this.#matchers);
34
+ }
35
+ }
@@ -0,0 +1,53 @@
1
+ import { BaseMatcher } from "../BaseMatcher.js";
2
+ import { NullDescription } from "../NullDescription.js";
3
+ import { AllOf } from "./AllOf.js";
4
+ import { AnyOf } from "./AnyOf.js";
5
+
6
+ export class CombinableMatcher extends BaseMatcher {
7
+
8
+ /**
9
+ * @type {Matcher}
10
+ */
11
+ #matcher
12
+
13
+ /**
14
+ *
15
+ * @param {Matcher} matcher
16
+ */
17
+ constructor(matcher) {
18
+ super();
19
+ this.#matcher = matcher;
20
+ }
21
+
22
+
23
+ matches(item, mismatch_description) {
24
+ if (!this.#matcher.matches(item, NullDescription.INSTANCE)) {
25
+ this.#matcher.describeMismatch(item, mismatch_description);
26
+ return false;
27
+ }
28
+
29
+ return true;
30
+ }
31
+
32
+ describeTo(description) {
33
+ description.appendDescriptionOf(this.#matcher);
34
+ }
35
+
36
+ /**
37
+ *
38
+ * @param {Matcher} other
39
+ * @return {CombinableMatcher}
40
+ */
41
+ and(other) {
42
+ return new CombinableMatcher(new AllOf([this.#matcher, other]))
43
+ }
44
+
45
+ /**
46
+ *
47
+ * @param {Matcher} other
48
+ * @return {CombinableMatcher}
49
+ */
50
+ or(other) {
51
+ return new CombinableMatcher(new AnyOf([this.#matcher, other]));
52
+ }
53
+ }
@@ -0,0 +1,44 @@
1
+ import { BaseMatcher } from "../BaseMatcher.js";
2
+ import { isArrayEqualStrict } from "../../collection/array/isArrayEqualStrict.js";
3
+
4
+ export class IsEqual extends BaseMatcher {
5
+ #expected;
6
+
7
+ constructor(expected) {
8
+ super();
9
+ this.#expected = expected;
10
+ }
11
+
12
+ matches(item, mismatch_description) {
13
+ return this.areEqual(item, this.#expected);
14
+ }
15
+
16
+ describeTo(description) {
17
+ description.appendValue(this.#expected);
18
+ }
19
+
20
+
21
+ areEqual(actual, expected) {
22
+ if (expected === actual) {
23
+ return true;
24
+ }
25
+
26
+ if (actual === null || actual === undefined) {
27
+ return false;
28
+ }
29
+
30
+ if (expected !== null && Array.isArray(actual)) {
31
+ return Array.isArray(expected) && isArrayEqualStrict(actual, expected);
32
+ }
33
+
34
+ if (typeof actual === "object" && typeof expected === "object" && typeof actual.equals === "function") {
35
+
36
+ return actual.equals(expected);
37
+
38
+ }
39
+
40
+ return false;
41
+ }
42
+
43
+
44
+ }
@@ -0,0 +1,74 @@
1
+ import { BaseMatcher } from "../BaseMatcher.js";
2
+ import { NullDescription } from "../NullDescription.js";
3
+
4
+ export class IsIterableContaining extends BaseMatcher {
5
+ /**
6
+ * @type {Matcher}
7
+ */
8
+ #element_matcher
9
+
10
+ /**
11
+ *
12
+ * @param {Matcher} matcher
13
+ */
14
+ constructor(matcher) {
15
+ super();
16
+
17
+ this.#element_matcher = matcher;
18
+ }
19
+
20
+ matches(item, mismatch_description) {
21
+ if (this.#isEmpty(item)) {
22
+ mismatch_description.appendText("was empty");
23
+ return false;
24
+ }
25
+
26
+ for (const itemElement of item) {
27
+ if (this.#element_matcher.matches(itemElement, NullDescription.INSTANCE)) {
28
+ return true;
29
+ }
30
+ }
31
+
32
+ mismatch_description.appendText("mismatches were: [");
33
+
34
+ let is_past_first = false;
35
+
36
+ for (const itemElement of item) {
37
+ if (is_past_first) {
38
+ mismatch_description.appendText(", ");
39
+ }
40
+
41
+ this.#element_matcher.describeMismatch(item, mismatch_description);
42
+
43
+ is_past_first = true;
44
+ }
45
+
46
+
47
+ mismatch_description.appendText("]");
48
+
49
+ return false;
50
+
51
+ }
52
+
53
+ /**
54
+ *
55
+ * @param {Iterable} iterable
56
+ * @return {boolean}
57
+ */
58
+ #isEmpty(iterable) {
59
+ const iterator = iterable[Symbol.iterator]();
60
+
61
+ const el = iterator.next();
62
+
63
+ return el.done === true;
64
+ }
65
+
66
+
67
+ describeTo(description) {
68
+
69
+ description
70
+ .appendText("a collection containing ")
71
+ .appendDescriptionOf(this.#element_matcher);
72
+
73
+ }
74
+ }
@@ -0,0 +1,26 @@
1
+ import { Matcher } from "../Matcher.js";
2
+ import { BaseMatcher } from "../BaseMatcher.js";
3
+
4
+ export class IsNot extends BaseMatcher {
5
+ /**
6
+ * @type {Matcher}
7
+ */
8
+ #matcher
9
+
10
+ /**
11
+ *
12
+ * @param {Matcher} matcher
13
+ */
14
+ constructor(matcher) {
15
+ super();
16
+ this.#matcher = matcher;
17
+ }
18
+
19
+ matches(item, mismatch_description) {
20
+ return !this.#matcher.matches(item, mismatch_description);
21
+ }
22
+
23
+ describeTo(description) {
24
+ description.appendText('not ').appendDescriptionOf(this.#matcher);
25
+ }
26
+ }
@@ -0,0 +1,11 @@
1
+ import { BaseMatcher } from "../BaseMatcher.js";
2
+
3
+ export class IsNull extends BaseMatcher {
4
+ matches(item, mismatch_description) {
5
+ return item === null;
6
+ }
7
+
8
+ describeTo(description) {
9
+ description.appendText("null");
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import { BaseMatcher } from "../BaseMatcher.js";
2
+
3
+ export class IsUndefined extends BaseMatcher {
4
+ matches(item, mismatch_description) {
5
+ return item === undefined;
6
+ }
7
+
8
+ describeTo(description) {
9
+ description.appendText("undefined");
10
+ }
11
+ }
@@ -0,0 +1,50 @@
1
+ import { AnyOf } from "./AnyOf.js";
2
+ import { AllOf } from "./AllOf.js";
3
+ import { IsNot } from "./IsNot.js";
4
+ import { IsEqual } from "./IsEqual.js";
5
+ import { IsNull } from "./IsNull.js";
6
+ import { IsIterableContaining } from "./IsIterableContaining.js";
7
+ import { Matcher } from "../Matcher.js";
8
+
9
+ export function anyOf(...matchers) {
10
+ return new AnyOf(matchers);
11
+ }
12
+
13
+ export function allOf(...matchers) {
14
+ return new AllOf(matchers);
15
+ }
16
+
17
+ export function not(matcher) {
18
+ return new IsNot(matcher);
19
+ }
20
+
21
+ export function equalTo(thing) {
22
+ return new IsEqual(thing);
23
+ }
24
+
25
+ export function notEqualTo(thing) {
26
+ return not(equalTo(thing));
27
+ }
28
+
29
+ export function isNull() {
30
+ return new IsNull();
31
+ }
32
+
33
+ export function isNotNull() {
34
+ return not(isNull());
35
+ }
36
+
37
+ /**
38
+ * @template
39
+ * @param {Matcher|T} value
40
+ * @return {Matcher}
41
+ */
42
+ export function hasItem(value) {
43
+ if (value instanceof Matcher) {
44
+ return new IsIterableContaining(value);
45
+ } else {
46
+ return new IsIterableContaining(equalTo(value));
47
+ }
48
+
49
+ }
50
+
@@ -64,6 +64,26 @@ export class NodeInstancePortReference {
64
64
  return this.connections.length > 0;
65
65
  }
66
66
 
67
+ /**
68
+ * Checks if a connection exists from this endpoint to a specific node instance
69
+ * @param {number} node_instance_id
70
+ * @returns {boolean}
71
+ */
72
+ isConnectedToNode(node_instance_id) {
73
+ const connections = this.connections;
74
+ const connection_count = connections.length;
75
+
76
+ for (let i = 0; i < connection_count; i++) {
77
+ const connection = connections[i];
78
+
79
+ if (connection.isAttachedToNode(node_instance_id)) {
80
+ return true;
81
+ }
82
+ }
83
+
84
+ return false;
85
+ }
86
+
67
87
 
68
88
  /**
69
89
  *