@kensio/smartass 1.0.2 → 1.1.0

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/README.md CHANGED
@@ -51,6 +51,7 @@ npm install @kensio/smartass
51
51
  - [assertNonNullable](src/assert/non-nullable/non-nullable.assert.ts)
52
52
  - [assertNumberBetween](src/assert/number-between/number-between.assert.ts)
53
53
  - [assertNumberToNearest](src/assert/number-to-nearest/number-to-nearest.assert.ts)
54
+ - [assertObjectEquals](src/assert/object-equals/object-equals.assert.ts)
54
55
  - [assertObjectMatches](src/assert/object-matches/object-matches.assert.ts)
55
56
  - [assertOneOf](src/assert/one-of/one-of.assert.ts)
56
57
  - [assertStringEndsWith](src/assert/string-ends-with/string-ends-with.assert.ts)
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Assert that two objects have the same own keys and deeply equal values, with
3
+ * type narrowing.
4
+ *
5
+ * Plain objects are compared recursively by value. Arrays are compared by length
6
+ * and by recursively comparing each element in order. Primitive values and
7
+ * non-plain objects are compared using Object.is.
8
+ */
9
+ export declare function assertObjectEquals<const TExpected extends Record<PropertyKey, unknown>>(actual: unknown, expected: TExpected, message?: string): asserts actual is TExpected;
10
+ //# sourceMappingURL=object-equals.assert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-equals.assert.d.ts","sourceRoot":"","sources":["../../../src/assert/object-equals/object-equals.assert.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,CAAC,SAAS,SAAS,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,EAEpD,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,IAAI,SAAS,CAc7B"}
@@ -0,0 +1,22 @@
1
+ import { AssertionError } from "../../assertion-error.js";
2
+ import { desc, repr } from "../../describe/describe.js";
3
+ import { findObjectComparisonMismatch } from "../../compare/object-comparison.js";
4
+ /**
5
+ * Assert that two objects have the same own keys and deeply equal values, with
6
+ * type narrowing.
7
+ *
8
+ * Plain objects are compared recursively by value. Arrays are compared by length
9
+ * and by recursively comparing each element in order. Primitive values and
10
+ * non-plain objects are compared using Object.is.
11
+ */
12
+ export function assertObjectEquals(actual, expected, message) {
13
+ const mismatch = findObjectComparisonMismatch(actual, expected, {
14
+ exactObjectKeys: true,
15
+ plainActualObjectsOnly: true,
16
+ });
17
+ if (mismatch !== undefined) {
18
+ throw new AssertionError(message ??
19
+ `Expected ${desc(actual)} to equal ${desc(expected)}. Mismatch at ${mismatch.path}: expected ${repr(mismatch.expected)}, got ${repr(mismatch.actual)}.`, actual, expected);
20
+ }
21
+ }
22
+ //# sourceMappingURL=object-equals.assert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-equals.assert.js","sourceRoot":"","sources":["../../../src/assert/object-equals/object-equals.assert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AAElF;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAGhC,MAAe,EACf,QAAmB,EACnB,OAAgB;IAEhB,MAAM,QAAQ,GAAG,4BAA4B,CAAC,MAAM,EAAE,QAAQ,EAAE;QAC9D,eAAe,EAAE,IAAI;QACrB,sBAAsB,EAAE,IAAI;KAC7B,CAAC,CAAC;IAEH,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,cAAc,CACtB,OAAO;YACL,YAAY,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,QAAQ,CAAC,iBAAiB,QAAQ,CAAC,IAAI,cAAc,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EACzJ,MAAM,EACN,QAAQ,CACT,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"object-matches.assert.d.ts","sourceRoot":"","sources":["../../../src/assert/object-matches/object-matches.assert.ts"],"names":[],"mappings":"AAGA,KAAK,YAAY,GAAG,CAAC,GAAG,UAAU,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC;AAExD,KAAK,eAAe,GAChB,YAAY,GACZ,IAAI,GACJ,MAAM,GACN,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,GACrB,GAAG,CAAC,OAAO,CAAC,GACZ,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GACxB,OAAO,CAAC,MAAM,CAAC,GACf,OAAO,CAAC,OAAO,CAAC,CAAC;AAErB,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,eAAe,GAC/C,CAAC,GACD,CAAC,SAAS,SAAS,OAAO,EAAE,GAC1B;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAClD,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GACzC,CAAC,CAAC;AAEV;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EACP,KAAK,CAAC,SAAS,SAAS,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,EAEpD,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,IAAI,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC,CAWxD"}
1
+ {"version":3,"file":"object-matches.assert.d.ts","sourceRoot":"","sources":["../../../src/assert/object-matches/object-matches.assert.ts"],"names":[],"mappings":"AAIA,KAAK,YAAY,GAAG,CAAC,GAAG,UAAU,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC;AAExD,KAAK,eAAe,GAChB,YAAY,GACZ,IAAI,GACJ,MAAM,GACN,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,GACrB,GAAG,CAAC,OAAO,CAAC,GACZ,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GACxB,OAAO,CAAC,MAAM,CAAC,GACf,OAAO,CAAC,OAAO,CAAC,CAAC;AAErB,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,eAAe,GAC/C,CAAC,GACD,CAAC,SAAS,SAAS,OAAO,EAAE,GAC1B;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAClD,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GACzC,CAAC,CAAC;AAEV;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EACP,KAAK,CAAC,SAAS,SAAS,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,EAEpD,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,IAAI,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC,CAcxD"}
@@ -1,5 +1,6 @@
1
1
  import { AssertionError } from "../../assertion-error.js";
2
2
  import { desc, repr } from "../../describe/describe.js";
3
+ import { findObjectComparisonMismatch } from "../../compare/object-comparison.js";
3
4
  /**
4
5
  * Assert that an object matches a partial deep object structure, with
5
6
  * type-narrowing.
@@ -9,89 +10,13 @@ import { desc, repr } from "../../describe/describe.js";
9
10
  * non-plain objects are compared using Object.is.
10
11
  */
11
12
  export function assertObjectMatches(actual, expected, message) {
12
- const mismatch = findMismatch(actual, expected, "$");
13
+ const mismatch = findObjectComparisonMismatch(actual, expected, {
14
+ exactObjectKeys: false,
15
+ plainActualObjectsOnly: false,
16
+ });
13
17
  if (mismatch !== undefined) {
14
18
  throw new AssertionError(message ??
15
19
  `Expected ${desc(actual)} to match ${desc(expected)}. Mismatch at ${mismatch.path}: expected ${repr(mismatch.expected)}, got ${repr(mismatch.actual)}.`, actual, expected);
16
20
  }
17
21
  }
18
- function findMismatch(actual, expected, path) {
19
- if (Array.isArray(expected)) {
20
- return findArrayMismatch(actual, expected, path);
21
- }
22
- if (isPlainObject(expected)) {
23
- return findObjectMismatch(actual, expected, path);
24
- }
25
- if (!Object.is(actual, expected)) {
26
- return {
27
- path,
28
- actual,
29
- expected,
30
- };
31
- }
32
- return undefined;
33
- }
34
- function findArrayMismatch(actual, expected, path) {
35
- if (!Array.isArray(actual)) {
36
- return {
37
- path,
38
- actual,
39
- expected,
40
- };
41
- }
42
- if (actual.length !== expected.length) {
43
- return {
44
- path: `${path}.length`,
45
- actual: actual.length,
46
- expected: expected.length,
47
- };
48
- }
49
- for (const [index, expectedElement] of expected.entries()) {
50
- const mismatch = findMismatch(actual[index], expectedElement, `${path}[${String(index)}]`);
51
- if (mismatch !== undefined) {
52
- return mismatch;
53
- }
54
- }
55
- return undefined;
56
- }
57
- function findObjectMismatch(actual, expected, path) {
58
- if (actual === null || typeof actual !== "object" || Array.isArray(actual)) {
59
- return {
60
- path,
61
- actual,
62
- expected,
63
- };
64
- }
65
- const actualObject = actual;
66
- for (const key of Reflect.ownKeys(expected)) {
67
- if (!Object.hasOwn(actualObject, key)) {
68
- return {
69
- path: formatPath(path, key),
70
- actual: undefined,
71
- expected: expected[key],
72
- };
73
- }
74
- const mismatch = findMismatch(actualObject[key], expected[key], formatPath(path, key));
75
- if (mismatch !== undefined) {
76
- return mismatch;
77
- }
78
- }
79
- return undefined;
80
- }
81
- function isPlainObject(value) {
82
- if (value === null || typeof value !== "object") {
83
- return false;
84
- }
85
- const prototype = Object.getPrototypeOf(value);
86
- return prototype === Object.prototype || prototype === null;
87
- }
88
- function formatPath(parent, key) {
89
- if (typeof key === "string" && /^[$A-Z_a-z][\w$]*$/.test(key)) {
90
- return `${parent}.${key}`;
91
- }
92
- if (typeof key === "symbol") {
93
- return `${parent}[${key.toString()}]`;
94
- }
95
- return `${parent}[${repr(key)}]`;
96
- }
97
22
  //# sourceMappingURL=object-matches.assert.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"object-matches.assert.js","sourceRoot":"","sources":["../../../src/assert/object-matches/object-matches.assert.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"object-matches.assert.js","sourceRoot":"","sources":["../../../src/assert/object-matches/object-matches.assert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AAsBlF;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAIjC,MAAe,EACf,QAAmB,EACnB,OAAgB;IAEhB,MAAM,QAAQ,GAAG,4BAA4B,CAAC,MAAM,EAAE,QAAQ,EAAE;QAC9D,eAAe,EAAE,KAAK;QACtB,sBAAsB,EAAE,KAAK;KAC9B,CAAC,CAAC;IAEH,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,cAAc,CACtB,OAAO;YACL,YAAY,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,QAAQ,CAAC,iBAAiB,QAAQ,CAAC,IAAI,cAAc,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EACzJ,MAAM,EACN,QAAQ,CACT,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface ObjectComparisonMismatch {
2
+ path: string;
3
+ actual: unknown;
4
+ expected: unknown;
5
+ }
6
+ interface ObjectComparisonOptions {
7
+ exactObjectKeys: boolean;
8
+ plainActualObjectsOnly: boolean;
9
+ }
10
+ /**
11
+ * Find a mismatch between two objects, if any.
12
+ */
13
+ export declare function findObjectComparisonMismatch(actual: unknown, expected: unknown, options: ObjectComparisonOptions, path?: string): ObjectComparisonMismatch | undefined;
14
+ export {};
15
+ //# sourceMappingURL=object-comparison.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-comparison.d.ts","sourceRoot":"","sources":["../../src/compare/object-comparison.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,uBAAuB;IAC/B,eAAe,EAAE,OAAO,CAAC;IACzB,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,uBAAuB,EAChC,IAAI,SAAM,GACT,wBAAwB,GAAG,SAAS,CAkBtC"}
@@ -0,0 +1,99 @@
1
+ import { repr } from "../describe/describe.js";
2
+ /**
3
+ * Find a mismatch between two objects, if any.
4
+ */
5
+ export function findObjectComparisonMismatch(actual, expected, options, path = "$") {
6
+ if (Array.isArray(expected)) {
7
+ return findArrayMismatch(actual, expected, options, path);
8
+ }
9
+ if (isPlainObject(expected)) {
10
+ return findObjectMismatch(actual, expected, options, path);
11
+ }
12
+ if (!Object.is(actual, expected)) {
13
+ return {
14
+ path,
15
+ actual,
16
+ expected,
17
+ };
18
+ }
19
+ return undefined;
20
+ }
21
+ function findArrayMismatch(actual, expected, options, path) {
22
+ if (!Array.isArray(actual)) {
23
+ return {
24
+ path,
25
+ actual,
26
+ expected,
27
+ };
28
+ }
29
+ if (actual.length !== expected.length) {
30
+ return {
31
+ path: `${path}.length`,
32
+ actual: actual.length,
33
+ expected: expected.length,
34
+ };
35
+ }
36
+ for (const [index, expectedElement] of expected.entries()) {
37
+ const mismatch = findObjectComparisonMismatch(actual[index], expectedElement, options, `${path}[${String(index)}]`);
38
+ if (mismatch !== undefined) {
39
+ return mismatch;
40
+ }
41
+ }
42
+ return undefined;
43
+ }
44
+ function findObjectMismatch(actual, expected, options, path) {
45
+ if (!isComparableObject(actual, options)) {
46
+ return {
47
+ path,
48
+ actual,
49
+ expected,
50
+ };
51
+ }
52
+ const actualObject = actual;
53
+ const expectedKeys = Reflect.ownKeys(expected);
54
+ if (options.exactObjectKeys &&
55
+ Reflect.ownKeys(actualObject).length !== expectedKeys.length) {
56
+ return {
57
+ path,
58
+ actual,
59
+ expected,
60
+ };
61
+ }
62
+ for (const key of expectedKeys) {
63
+ if (!Object.hasOwn(actualObject, key)) {
64
+ return {
65
+ path: formatPath(path, key),
66
+ actual: undefined,
67
+ expected: expected[key],
68
+ };
69
+ }
70
+ const mismatch = findObjectComparisonMismatch(actualObject[key], expected[key], options, formatPath(path, key));
71
+ if (mismatch !== undefined) {
72
+ return mismatch;
73
+ }
74
+ }
75
+ return undefined;
76
+ }
77
+ function isComparableObject(value, options) {
78
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
79
+ return false;
80
+ }
81
+ return !options.plainActualObjectsOnly || isPlainObject(value);
82
+ }
83
+ function isPlainObject(value) {
84
+ if (value === null || typeof value !== "object") {
85
+ return false;
86
+ }
87
+ const prototype = Object.getPrototypeOf(value);
88
+ return prototype === Object.prototype || prototype === null;
89
+ }
90
+ function formatPath(parent, key) {
91
+ if (typeof key === "string" && /^[$A-Z_a-z][\w$]*$/.test(key)) {
92
+ return `${parent}.${key}`;
93
+ }
94
+ if (typeof key === "symbol") {
95
+ return `${parent}[${key.toString()}]`;
96
+ }
97
+ return `${parent}[${repr(key)}]`;
98
+ }
99
+ //# sourceMappingURL=object-comparison.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-comparison.js","sourceRoot":"","sources":["../../src/compare/object-comparison.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export * from "./assert/instance-of/instance-of.assert.js";
11
11
  export * from "./assert/non-nullable/non-nullable.assert.js";
12
12
  export * from "./assert/number-between/number-between.assert.js";
13
13
  export * from "./assert/number-to-nearest/number-to-nearest.assert.js";
14
+ export * from "./assert/object-equals/object-equals.assert.js";
14
15
  export * from "./assert/object-matches/object-matches.assert.js";
15
16
  export * from "./assert/one-of/one-of.assert.js";
16
17
  export * from "./assert/string-ends-with/string-ends-with.assert.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,kDAAkD,CAAC;AACjE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AACvD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,kDAAkD,CAAC;AACjE,cAAc,wDAAwD,CAAC;AACvE,cAAc,kDAAkD,CAAC;AACjE,cAAc,kCAAkC,CAAC;AACjD,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,0DAA0D,CAAC;AACzE,cAAc,0DAA0D,CAAC;AACzE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,sDAAsD,CAAC;AACrE,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,kDAAkD,CAAC;AACjE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AACvD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,kDAAkD,CAAC;AACjE,cAAc,wDAAwD,CAAC;AACvE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,kDAAkD,CAAC;AACjE,cAAc,kCAAkC,CAAC;AACjD,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,0DAA0D,CAAC;AACzE,cAAc,0DAA0D,CAAC;AACzE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,sDAAsD,CAAC;AACrE,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC"}
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ export * from "./assert/instance-of/instance-of.assert.js";
11
11
  export * from "./assert/non-nullable/non-nullable.assert.js";
12
12
  export * from "./assert/number-between/number-between.assert.js";
13
13
  export * from "./assert/number-to-nearest/number-to-nearest.assert.js";
14
+ export * from "./assert/object-equals/object-equals.assert.js";
14
15
  export * from "./assert/object-matches/object-matches.assert.js";
15
16
  export * from "./assert/one-of/one-of.assert.js";
16
17
  export * from "./assert/string-ends-with/string-ends-with.assert.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,kDAAkD,CAAC;AACjE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AACvD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,kDAAkD,CAAC;AACjE,cAAc,wDAAwD,CAAC;AACvE,cAAc,kDAAkD,CAAC;AACjE,cAAc,kCAAkC,CAAC;AACjD,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,0DAA0D,CAAC;AACzE,cAAc,0DAA0D,CAAC;AACzE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,sDAAsD,CAAC;AACrE,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,kDAAkD,CAAC;AACjE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AACvD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,kDAAkD,CAAC;AACjE,cAAc,wDAAwD,CAAC;AACvE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,kDAAkD,CAAC;AACjE,cAAc,kCAAkC,CAAC;AACjD,cAAc,sDAAsD,CAAC;AACrE,cAAc,oDAAoD,CAAC;AACnE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,0DAA0D,CAAC;AACzE,cAAc,0DAA0D,CAAC;AACzE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,4CAA4C,CAAC;AAC3D,cAAc,sDAAsD,CAAC;AACrE,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "author": "Kensio Software",
5
5
  "repository": "https://github.com/KensioSoftware/smartass",
6
6
  "license": "AGPL-3.0",
7
- "version": "1.0.2",
7
+ "version": "1.1.0",
8
8
  "type": "module",
9
9
  "main": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",