tstyche 1.0.0-beta.5 → 1.0.0-beta.6

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/CHANGELOG.md CHANGED
@@ -1,19 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.0-beta.6] - 2023-12-03
4
+
5
+ ### Added
6
+
7
+ - **New!** Add `.toHaveProperty()` matcher ([#36](https://github.com/tstyche/tstyche/pull/36))
8
+
9
+ ### Fixed
10
+
11
+ - Accept template literals as arguments of the `.toRaiseError()` matcher ([#38](https://github.com/tstyche/tstyche/pull/38))
12
+
3
13
  ## [1.0.0-beta.5] - 2023-11-27
4
14
 
5
15
  ### Changed
6
16
 
7
- - **Breaking:** Move retry logic to the `Lock` class ([#31](https://github.com/tstyche/tstyche/pull/31))
17
+ - **Breaking!** Move retry logic to the `Lock` class ([#31](https://github.com/tstyche/tstyche/pull/31))
8
18
  - Bring back support for Node.js 16 ([#28](https://github.com/tstyche/tstyche/pull/28), [#27](https://github.com/tstyche/tstyche/pull/27))
9
19
 
10
20
  ### Added
11
21
 
12
- - Add support for the `current` target tag ([#33](https://github.com/tstyche/tstyche/pull/33))
22
+ - **New!** Add support for the `current` target tag ([#33](https://github.com/tstyche/tstyche/pull/33))
13
23
 
14
24
  ### Fixed
15
25
 
16
- - Allow `.raiseError()` to take template literals as arguments. ([#35](https://github.com/tstyche/tstyche/pull/35))
26
+ - Allow `.raiseError()` to take template literals as arguments ([#35](https://github.com/tstyche/tstyche/pull/35))
17
27
 
18
28
  ## [1.0.0-beta.4] - 2023-11-24
19
29
 
@@ -23,9 +33,9 @@
23
33
 
24
34
  ### Removed
25
35
 
26
- - **Breaking:** Remove the `context()` helper ([#24](https://github.com/tstyche/tstyche/pull/24))
27
- - **Breaking:** Drop support for Node.js 16 ([#22](https://github.com/tstyche/tstyche/pull/22))
28
- - **Breaking:** Rename methods of the `StoreService` class ([`5d74201`](https://github.com/tstyche/tstyche/commit/5d74201))
36
+ - **Breaking!** Remove the `context()` helper ([#24](https://github.com/tstyche/tstyche/pull/24))
37
+ - **Breaking!** Drop support for Node.js 16 ([#22](https://github.com/tstyche/tstyche/pull/22))
38
+ - **Breaking!** Rename methods of the `StoreService` class ([`5d74201`](https://github.com/tstyche/tstyche/commit/5d74201))
29
39
 
30
40
  ### Fixed
31
41
 
@@ -55,6 +65,7 @@
55
65
 
56
66
  _First pre-release._
57
67
 
68
+ [1.0.0-beta.6]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.6
58
69
  [1.0.0-beta.5]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.5
59
70
  [1.0.0-beta.4]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.4
60
71
  [1.0.0-beta.3]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.3
package/README.md CHANGED
@@ -56,9 +56,10 @@ test("handles numbers", () => {
56
56
 
57
57
  Here is the list of all matchers:
58
58
 
59
- - `.toBeAssignable()`, `.toEqual()`, `.toMatch()` compares types or types of expression;
60
- - `.toRaiseError()` captures the error message or code;
61
- - `.toBeString()`, `.toBeNumber()`, `.toBeVoid()` and 9 more checks for primitive types.
59
+ - `.toBeAssignable()`, `.toEqual()`, `.toMatch()` compares types or types of expression,
60
+ - `.toHaveProperty()` looks up keys on an object type,
61
+ - `.toRaiseError()` captures the type error message or code,
62
+ - `.toBeString()`, `.toBeNumber()`, `.toBeVoid()` and 9 more shorthand checks for primitive types.
62
63
 
63
64
  ## Runner
64
65
 
package/build/index.d.cts CHANGED
@@ -133,6 +133,10 @@ interface Matchers {
133
133
  */
134
134
  (target: unknown): void;
135
135
  };
136
+ /**
137
+ * Checks if a property key exists on the source type.
138
+ */
139
+ toHaveProperty: (key: string | number | symbol) => void;
136
140
  /**
137
141
  * Checks if the target type is a subtype the source type.
138
142
  */
package/build/index.d.ts CHANGED
@@ -133,6 +133,10 @@ interface Matchers {
133
133
  */
134
134
  (target: unknown): void;
135
135
  };
136
+ /**
137
+ * Checks if a property key exists on the source type.
138
+ */
139
+ toHaveProperty: (key: string | number | symbol) => void;
136
140
  /**
137
141
  * Checks if the target type is a subtype the source type.
138
142
  */
package/build/tstyche.js CHANGED
@@ -1511,6 +1511,7 @@ class CollectService {
1511
1511
  "toBeUnknown",
1512
1512
  "toBeVoid",
1513
1513
  "toEqual",
1514
+ "toHaveProperty",
1514
1515
  "toMatch",
1515
1516
  "toRaiseError",
1516
1517
  ];
@@ -1682,10 +1683,12 @@ class Checker {
1682
1683
  #assertNonNullishTypeChecker(assertion) {
1683
1684
  this.#assertNonNullish(assertion.typeChecker, "The 'typeChecker' was not provided.");
1684
1685
  }
1686
+ #assertStringsOrNumber(expression) {
1687
+ return (expression != null &&
1688
+ (this.compiler.isStringLiteralLike(expression) || this.compiler.isNumericLiteral(expression)));
1689
+ }
1685
1690
  #assertStringsOrNumbers(nodes) {
1686
- return nodes.every((expression) => this.compiler.isStringLiteral(expression) ||
1687
- this.compiler.isNumericLiteral(expression) ||
1688
- this.compiler.isNoSubstitutionTemplateLiteral(expression));
1691
+ return nodes.every((expression) => this.#assertStringsOrNumber(expression));
1689
1692
  }
1690
1693
  explain(assertion) {
1691
1694
  this.#assertNonNullishTypeChecker(assertion);
@@ -1743,6 +1746,26 @@ class Checker {
1743
1746
  : `Type '${targetTypeText}' is not identical to type '${sourceTypeText}'.`, origin),
1744
1747
  ];
1745
1748
  }
1749
+ case "toHaveProperty": {
1750
+ this.#assertNonNullishSourceType(assertion);
1751
+ this.#assertNonNullishTargetType(assertion);
1752
+ const sourceText = assertion.typeChecker.typeToString(assertion.sourceType.type);
1753
+ let targetArgumentText;
1754
+ if (assertion.targetType.type.flags & this.compiler.TypeFlags.StringOrNumberLiteral) {
1755
+ targetArgumentText = String(assertion.targetType.type.value);
1756
+ }
1757
+ else if (assertion.targetType.type.flags & this.compiler.TypeFlags.UniqueESSymbol) {
1758
+ targetArgumentText = `[${this.compiler.unescapeLeadingUnderscores(assertion.targetType.type.symbol.escapedName)}]`;
1759
+ }
1760
+ else {
1761
+ throw new Error("An argument for 'key' must be of type 'string | number | symbol'.");
1762
+ }
1763
+ return [
1764
+ Diagnostic.error(assertion.isNot
1765
+ ? `Property '${targetArgumentText}' exists on type '${sourceText}'.`
1766
+ : `Property '${targetArgumentText}' does not exist on type '${sourceText}'.`, origin),
1767
+ ];
1768
+ }
1746
1769
  case "toMatch": {
1747
1770
  this.#assertNonNullishSourceType(assertion);
1748
1771
  this.#assertNonNullishTargetType(assertion);
@@ -1796,7 +1819,7 @@ class Checker {
1796
1819
  }
1797
1820
  const isMatch = this.#matchExpectedError(diagnostic, argument);
1798
1821
  if (!assertion.isNot && !isMatch) {
1799
- const expectedText = this.compiler.isStringLiteral(argument)
1822
+ const expectedText = this.compiler.isStringLiteralLike(argument)
1800
1823
  ? `matching substring '${argument.text}'`
1801
1824
  : `with code ${argument.text}`;
1802
1825
  const related = [
@@ -1806,7 +1829,7 @@ class Checker {
1806
1829
  diagnostics.push(Diagnostic.error(`${sourceText} did not raise a type error ${expectedText}.`, origin).add({ related }));
1807
1830
  }
1808
1831
  if (assertion.isNot && isMatch) {
1809
- const expectedText = this.compiler.isStringLiteral(argument)
1832
+ const expectedText = this.compiler.isStringLiteralLike(argument)
1810
1833
  ? `matching substring '${argument.text}'`
1811
1834
  : `with code ${argument.text}`;
1812
1835
  const related = [
@@ -1892,6 +1915,27 @@ class Checker {
1892
1915
  this.#assertNonNullish(assertion.typeChecker?.isTypeIdenticalTo, "The 'isTypeIdenticalTo' method is missing in the provided type checker.");
1893
1916
  return assertion.typeChecker.isTypeIdenticalTo(assertion.sourceType.type, assertion.targetType.type);
1894
1917
  }
1918
+ case "toHaveProperty": {
1919
+ this.#assertNonNullishSourceType(assertion);
1920
+ this.#assertNonNullishTargetType(assertion);
1921
+ if (!(assertion.sourceType.type.flags & this.compiler.TypeFlags.StructuredType)) {
1922
+ const receivedText = assertion.typeChecker?.typeToString(assertion.sourceType.type);
1923
+ throw new Error(`An argument for 'source' must be of object type, received: '${receivedText}'.`);
1924
+ }
1925
+ let targetArgumentText;
1926
+ if (assertion.targetType.type.flags & this.compiler.TypeFlags.StringOrNumberLiteral) {
1927
+ targetArgumentText = String(assertion.targetType.type.value);
1928
+ }
1929
+ else if (assertion.targetType.type.flags & this.compiler.TypeFlags.UniqueESSymbol) {
1930
+ targetArgumentText = this.compiler.unescapeLeadingUnderscores(assertion.targetType.type.escapedName);
1931
+ }
1932
+ else {
1933
+ throw new Error("An argument for 'key' must be of type 'string | number | symbol'.");
1934
+ }
1935
+ return assertion.sourceType.type.getProperties().some((property) => {
1936
+ return this.compiler.unescapeLeadingUnderscores(property.escapedName) === targetArgumentText;
1937
+ });
1938
+ }
1895
1939
  case "toMatch": {
1896
1940
  this.#assertNonNullishSourceType(assertion);
1897
1941
  this.#assertNonNullishTargetType(assertion);
@@ -1909,7 +1953,7 @@ class Checker {
1909
1953
  return false;
1910
1954
  }
1911
1955
  return assertion.targetArguments.every((expectedArgument, index) => {
1912
- if (this.compiler.isStringLiteral(expectedArgument)) {
1956
+ if (this.compiler.isStringLiteralLike(expectedArgument)) {
1913
1957
  return this.compiler
1914
1958
  .flattenDiagnosticMessageText(assertion.diagnostics[index]?.messageText, " ", 0)
1915
1959
  .includes(expectedArgument.text);
@@ -1925,7 +1969,7 @@ class Checker {
1925
1969
  }
1926
1970
  }
1927
1971
  #matchExpectedError(diagnostic, argument) {
1928
- if (this.compiler.isStringLiteral(argument)) {
1972
+ if (this.compiler.isStringLiteralLike(argument)) {
1929
1973
  return this.compiler.flattenDiagnosticMessageText(diagnostic.messageText, " ", 0).includes(argument.text);
1930
1974
  }
1931
1975
  if (this.compiler.isNumericLiteral(argument)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tstyche",
3
- "version": "1.0.0-beta.5",
3
+ "version": "1.0.0-beta.6",
4
4
  "description": "The Essential Type Testing Tool.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -57,14 +57,14 @@
57
57
  "devDependencies": {
58
58
  "@jest/globals": "29.7.0",
59
59
  "@rollup/plugin-typescript": "11.1.5",
60
- "@types/node": "20.10.0",
61
- "@typescript-eslint/eslint-plugin": "6.12.0",
62
- "@typescript-eslint/parser": "6.12.0",
60
+ "@types/node": "20.10.2",
61
+ "@typescript-eslint/eslint-plugin": "6.13.1",
62
+ "@typescript-eslint/parser": "6.13.1",
63
63
  "ajv": "8.12.0",
64
64
  "c8": "8.0.1",
65
- "cspell": "8.0.0",
66
- "eslint": "8.54.0",
67
- "eslint-config-prettier": "9.0.0",
65
+ "cspell": "8.1.0",
66
+ "eslint": "8.55.0",
67
+ "eslint-config-prettier": "9.1.0",
68
68
  "eslint-import-resolver-typescript": "3.6.1",
69
69
  "eslint-plugin-import": "2.29.0",
70
70
  "eslint-plugin-jest": "27.6.0",
@@ -76,7 +76,7 @@
76
76
  "jest-serializer-ansi-escapes": "2.0.1",
77
77
  "magic-string": "0.30.5",
78
78
  "prettier": "3.1.0",
79
- "rollup": "4.6.0",
79
+ "rollup": "4.6.1",
80
80
  "rollup-plugin-dts": "6.1.0",
81
81
  "rollup-plugin-tsconfig-paths": "1.5.2",
82
82
  "ts-node": "10.9.1",