miaoda-game-devkit 0.6.2 → 0.6.3

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.
@@ -5,6 +5,87 @@ var import_vitest = require("@testing-library/jest-dom/vitest");
5
5
  var import_react = require("@testing-library/react");
6
6
  var import_vitest2 = require("vitest");
7
7
 
8
+ // src/react/react-error-diagnostics.ts
9
+ var MAX_DIAGNOSTIC_LENGTH = 1e3;
10
+ function truncate(value) {
11
+ const trimmed = value.trim();
12
+ if (trimmed.length <= MAX_DIAGNOSTIC_LENGTH) return trimmed;
13
+ return `${trimmed.slice(0, MAX_DIAGNOSTIC_LENGTH - 1)}\u2026`;
14
+ }
15
+ function safeJson(value) {
16
+ const seen = /* @__PURE__ */ new WeakSet();
17
+ try {
18
+ return JSON.stringify(value, (_key, nested) => {
19
+ if (typeof nested === "bigint") return `${nested}n`;
20
+ if (typeof nested === "function") {
21
+ return `Function<${nested.name || "anonymous"}>`;
22
+ }
23
+ if (typeof nested === "symbol") return nested.toString();
24
+ if (nested && typeof nested === "object") {
25
+ if (seen.has(nested)) return "[Circular]";
26
+ seen.add(nested);
27
+ }
28
+ return nested;
29
+ });
30
+ } catch {
31
+ return void 0;
32
+ }
33
+ }
34
+ function collectEntries(value, fallbackCode, seen) {
35
+ if (typeof value === "string") {
36
+ return value.trim() ? [{ code: fallbackCode, message: truncate(value) }] : [];
37
+ }
38
+ if (value === null || value === void 0 || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") {
39
+ return [{ code: fallbackCode, message: String(value) }];
40
+ }
41
+ if (typeof value === "function") {
42
+ return [
43
+ { code: fallbackCode, message: `Function<${value.name || "anonymous"}>` }
44
+ ];
45
+ }
46
+ if (seen.has(value)) return [];
47
+ seen.add(value);
48
+ if (Array.isArray(value)) {
49
+ return value.flatMap((item) => collectEntries(item, fallbackCode, seen));
50
+ }
51
+ const record = value;
52
+ const code = typeof record.code === "string" && record.code.trim() ? record.code.trim() : fallbackCode;
53
+ const entries = [];
54
+ if (typeof record.message === "string" && record.message.trim()) {
55
+ entries.push({ code, message: truncate(record.message) });
56
+ }
57
+ if (record.cause !== void 0) {
58
+ entries.push(...collectEntries(record.cause, fallbackCode, seen));
59
+ }
60
+ if (Array.isArray(record.errors)) {
61
+ entries.push(...collectEntries(record.errors, fallbackCode, seen));
62
+ }
63
+ if (entries.length > 0) return entries;
64
+ if (typeof record.stack === "string" && record.stack.trim()) {
65
+ return [{ code, message: truncate(record.stack) }];
66
+ }
67
+ const json = safeJson(value);
68
+ return json && json !== "{}" ? [{ code, message: truncate(json) }] : [];
69
+ }
70
+ function extractFailureEntries(value, fallbackCode = "TEST_FAILURE") {
71
+ const entries = collectEntries(value, fallbackCode, /* @__PURE__ */ new WeakSet());
72
+ const keys = /* @__PURE__ */ new Set();
73
+ return entries.filter((entry) => {
74
+ const key = `${entry.code}\0${entry.message}`;
75
+ if (keys.has(key)) return false;
76
+ keys.add(key);
77
+ return true;
78
+ });
79
+ }
80
+ function runtimeFailureError(code, value) {
81
+ const entries = extractFailureEntries(value, code);
82
+ const error = new Error(
83
+ entries.map((entry) => entry.message).join(" | ") || "No readable runtime error value"
84
+ );
85
+ error.code = code;
86
+ return error;
87
+ }
88
+
8
89
  // src/testing/jsdom-canvas.ts
9
90
  var contexts = /* @__PURE__ */ new WeakMap();
10
91
  function createCanvasContext(canvas) {
@@ -73,21 +154,23 @@ function clearJSDOMStorage() {
73
154
  installJSDOMCanvasContext();
74
155
  var failures = [];
75
156
  var consoleError;
76
- var onError = (event) => failures.push(event.error ?? event.message);
77
- var onRejection = (event) => failures.push(event.reason);
157
+ var onError = (event) => failures.push(
158
+ runtimeFailureError("WINDOW_ERROR", event.error ?? event.message)
159
+ );
160
+ var onRejection = (event) => failures.push(runtimeFailureError("UNHANDLED_REJECTION", event.reason));
78
161
  (0, import_vitest2.beforeEach)(() => {
79
162
  failures = [];
80
163
  window.addEventListener("error", onError);
81
164
  window.addEventListener("unhandledrejection", onRejection);
82
165
  consoleError = import_vitest2.vi.spyOn(console, "error").mockImplementation((...args) => {
83
- failures.push(args);
166
+ failures.push(runtimeFailureError("CONSOLE_ERROR", args));
84
167
  });
85
168
  });
86
169
  (0, import_vitest2.afterEach)(() => {
87
170
  try {
88
171
  (0, import_react.cleanup)();
89
172
  } catch (error) {
90
- failures.push(error);
173
+ failures.push(runtimeFailureError("CLEANUP_ERROR", error));
91
174
  } finally {
92
175
  clearJSDOMStorage();
93
176
  window.removeEventListener("error", onError);
@@ -3,6 +3,87 @@ import "@testing-library/jest-dom/vitest";
3
3
  import { cleanup } from "@testing-library/react";
4
4
  import { afterEach, beforeEach, vi } from "vitest";
5
5
 
6
+ // src/react/react-error-diagnostics.ts
7
+ var MAX_DIAGNOSTIC_LENGTH = 1e3;
8
+ function truncate(value) {
9
+ const trimmed = value.trim();
10
+ if (trimmed.length <= MAX_DIAGNOSTIC_LENGTH) return trimmed;
11
+ return `${trimmed.slice(0, MAX_DIAGNOSTIC_LENGTH - 1)}\u2026`;
12
+ }
13
+ function safeJson(value) {
14
+ const seen = /* @__PURE__ */ new WeakSet();
15
+ try {
16
+ return JSON.stringify(value, (_key, nested) => {
17
+ if (typeof nested === "bigint") return `${nested}n`;
18
+ if (typeof nested === "function") {
19
+ return `Function<${nested.name || "anonymous"}>`;
20
+ }
21
+ if (typeof nested === "symbol") return nested.toString();
22
+ if (nested && typeof nested === "object") {
23
+ if (seen.has(nested)) return "[Circular]";
24
+ seen.add(nested);
25
+ }
26
+ return nested;
27
+ });
28
+ } catch {
29
+ return void 0;
30
+ }
31
+ }
32
+ function collectEntries(value, fallbackCode, seen) {
33
+ if (typeof value === "string") {
34
+ return value.trim() ? [{ code: fallbackCode, message: truncate(value) }] : [];
35
+ }
36
+ if (value === null || value === void 0 || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") {
37
+ return [{ code: fallbackCode, message: String(value) }];
38
+ }
39
+ if (typeof value === "function") {
40
+ return [
41
+ { code: fallbackCode, message: `Function<${value.name || "anonymous"}>` }
42
+ ];
43
+ }
44
+ if (seen.has(value)) return [];
45
+ seen.add(value);
46
+ if (Array.isArray(value)) {
47
+ return value.flatMap((item) => collectEntries(item, fallbackCode, seen));
48
+ }
49
+ const record = value;
50
+ const code = typeof record.code === "string" && record.code.trim() ? record.code.trim() : fallbackCode;
51
+ const entries = [];
52
+ if (typeof record.message === "string" && record.message.trim()) {
53
+ entries.push({ code, message: truncate(record.message) });
54
+ }
55
+ if (record.cause !== void 0) {
56
+ entries.push(...collectEntries(record.cause, fallbackCode, seen));
57
+ }
58
+ if (Array.isArray(record.errors)) {
59
+ entries.push(...collectEntries(record.errors, fallbackCode, seen));
60
+ }
61
+ if (entries.length > 0) return entries;
62
+ if (typeof record.stack === "string" && record.stack.trim()) {
63
+ return [{ code, message: truncate(record.stack) }];
64
+ }
65
+ const json = safeJson(value);
66
+ return json && json !== "{}" ? [{ code, message: truncate(json) }] : [];
67
+ }
68
+ function extractFailureEntries(value, fallbackCode = "TEST_FAILURE") {
69
+ const entries = collectEntries(value, fallbackCode, /* @__PURE__ */ new WeakSet());
70
+ const keys = /* @__PURE__ */ new Set();
71
+ return entries.filter((entry) => {
72
+ const key = `${entry.code}\0${entry.message}`;
73
+ if (keys.has(key)) return false;
74
+ keys.add(key);
75
+ return true;
76
+ });
77
+ }
78
+ function runtimeFailureError(code, value) {
79
+ const entries = extractFailureEntries(value, code);
80
+ const error = new Error(
81
+ entries.map((entry) => entry.message).join(" | ") || "No readable runtime error value"
82
+ );
83
+ error.code = code;
84
+ return error;
85
+ }
86
+
6
87
  // src/testing/jsdom-canvas.ts
7
88
  var contexts = /* @__PURE__ */ new WeakMap();
8
89
  function createCanvasContext(canvas) {
@@ -71,21 +152,23 @@ function clearJSDOMStorage() {
71
152
  installJSDOMCanvasContext();
72
153
  var failures = [];
73
154
  var consoleError;
74
- var onError = (event) => failures.push(event.error ?? event.message);
75
- var onRejection = (event) => failures.push(event.reason);
155
+ var onError = (event) => failures.push(
156
+ runtimeFailureError("WINDOW_ERROR", event.error ?? event.message)
157
+ );
158
+ var onRejection = (event) => failures.push(runtimeFailureError("UNHANDLED_REJECTION", event.reason));
76
159
  beforeEach(() => {
77
160
  failures = [];
78
161
  window.addEventListener("error", onError);
79
162
  window.addEventListener("unhandledrejection", onRejection);
80
163
  consoleError = vi.spyOn(console, "error").mockImplementation((...args) => {
81
- failures.push(args);
164
+ failures.push(runtimeFailureError("CONSOLE_ERROR", args));
82
165
  });
83
166
  });
84
167
  afterEach(() => {
85
168
  try {
86
169
  cleanup();
87
170
  } catch (error) {
88
- failures.push(error);
171
+ failures.push(runtimeFailureError("CLEANUP_ERROR", error));
89
172
  } finally {
90
173
  clearJSDOMStorage();
91
174
  window.removeEventListener("error", onError);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-game-devkit",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Shared React and Phaser game lint plus deterministic testing tools for Miaoda games",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",