miaoda-game-devkit 0.2.10 → 0.2.12

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.
@@ -2,11 +2,99 @@
2
2
  import { resolve as resolve4 } from "path";
3
3
  import { describe, expect, it } from "vitest";
4
4
 
5
+ // src/react/manual-game-clock.ts
6
+ var ManualGameClock = class {
7
+ time = 0;
8
+ nextId = 1;
9
+ frames = /* @__PURE__ */ new Map();
10
+ timers = /* @__PURE__ */ new Map();
11
+ now() {
12
+ return this.time;
13
+ }
14
+ requestFrame(callback) {
15
+ const id = this.nextId++;
16
+ this.frames.set(id, callback);
17
+ return id;
18
+ }
19
+ cancelFrame(id) {
20
+ this.frames.delete(id);
21
+ }
22
+ setTimeout(callback, delayMs) {
23
+ const id = this.nextId++;
24
+ this.timers.set(id, { callback, dueAt: this.time + delayMs });
25
+ return id;
26
+ }
27
+ clearTimeout(id) {
28
+ this.timers.delete(id);
29
+ }
30
+ advanceBy(deltaMs) {
31
+ if (!Number.isFinite(deltaMs) || deltaMs < 0) {
32
+ throw new RangeError("deltaMs must be a non-negative finite number");
33
+ }
34
+ this.time += deltaMs;
35
+ const dueTimers = [...this.timers.entries()].filter(([, timer]) => timer.dueAt <= this.time).sort((left, right) => left[1].dueAt - right[1].dueAt);
36
+ for (const [id, timer] of dueTimers) {
37
+ if (timer.dueAt <= this.time && this.timers.delete(id)) timer.callback();
38
+ }
39
+ }
40
+ stepFrame(deltaMs = 16) {
41
+ this.advanceBy(deltaMs);
42
+ const callbacks = [...this.frames.values()];
43
+ this.frames.clear();
44
+ for (const callback of callbacks) callback(this.time);
45
+ }
46
+ stepFrames(count, deltaMs = 16) {
47
+ if (!Number.isInteger(count) || count < 0) {
48
+ throw new RangeError("count must be a non-negative integer");
49
+ }
50
+ for (let index = 0; index < count; index += 1) this.stepFrame(deltaMs);
51
+ }
52
+ pendingFrameCount() {
53
+ return this.frames.size;
54
+ }
55
+ pendingTimerCount() {
56
+ return this.timers.size;
57
+ }
58
+ };
59
+
60
+ // src/react-vitest-config.ts
61
+ import { resolve } from "path";
62
+ import { defineConfig } from "vitest/config";
63
+ function defineReactGameVitestConfig(options) {
64
+ return defineConfig({
65
+ resolve: {
66
+ alias: { ...options.aliases, "@": resolve(options.projectRoot, "src") }
67
+ },
68
+ test: {
69
+ include: [
70
+ "src/**/*.{test,spec}.{ts,tsx}",
71
+ "tests/**/*.{test,spec}.{ts,tsx}"
72
+ ],
73
+ environment: "jsdom",
74
+ environmentOptions: {
75
+ jsdom: { url: "http://localhost/", pretendToBeVisual: true }
76
+ },
77
+ setupFiles: [
78
+ "miaoda-game-devkit/react/vitest-setup",
79
+ ...options.additionalSetupFiles ?? []
80
+ ],
81
+ reporters: ["minimal"],
82
+ restoreMocks: true,
83
+ clearMocks: true,
84
+ testTimeout: options.testTimeout,
85
+ hookTimeout: options.hookTimeout
86
+ }
87
+ });
88
+ }
89
+
5
90
  // src/vite.ts
6
91
  import { existsSync } from "fs";
7
92
  import { createRequire } from "module";
8
- import { dirname, join, normalize, resolve, sep } from "path";
93
+ import { dirname, join, normalize, resolve as resolve2, sep } from "path";
9
94
  var PHASER_MODULE_ID = "phaser";
95
+ var REXUI_OPTIMIZE_ENTRIES = [
96
+ "phaser4-rex-plugins/templates/ui/ui-plugin.js"
97
+ ];
10
98
  function isPromiseLike(value) {
11
99
  return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
12
100
  }
@@ -27,14 +115,14 @@ function isInsideDirectory(filePath, directory) {
27
115
  return normalizedFile.startsWith(normalizedDirectory);
28
116
  }
29
117
  function phaserRexUIScenePlugin(projectRoot2) {
30
- let scenesRoot = projectRoot2 ? resolve(projectRoot2, "src/scenes") : void 0;
118
+ let scenesRoot = projectRoot2 ? resolve2(projectRoot2, "src/scenes") : void 0;
31
119
  let phaserFacade = projectRoot2 ? resolvePhaserFacade(projectRoot2) : void 0;
32
120
  return {
33
121
  name: "miaoda-phaser-rexui-scene",
34
122
  enforce: "pre",
35
123
  configResolved(config) {
36
124
  const resolvedProjectRoot = projectRoot2 ?? config.root;
37
- scenesRoot ??= resolve(resolvedProjectRoot, "src/scenes");
125
+ scenesRoot ??= resolve2(resolvedProjectRoot, "src/scenes");
38
126
  phaserFacade ??= resolvePhaserFacade(resolvedProjectRoot);
39
127
  },
40
128
  /** 查询参数属于构建工具元数据,去除后才能稳定判断真实源码位置。 */
@@ -48,8 +136,18 @@ function phaserRexUIScenePlugin(projectRoot2) {
48
136
  };
49
137
  }
50
138
  function withGameDefaults(config) {
139
+ const optimizeDeps = config.optimizeDeps ?? {};
51
140
  return {
52
141
  ...config,
142
+ optimizeDeps: {
143
+ ...optimizeDeps,
144
+ include: [
145
+ .../* @__PURE__ */ new Set([
146
+ ...optimizeDeps.include ?? [],
147
+ ...REXUI_OPTIMIZE_ENTRIES
148
+ ])
149
+ ]
150
+ },
53
151
  plugins: [
54
152
  phaserRexUIScenePlugin(),
55
153
  ...config.plugins ?? []
@@ -67,8 +165,8 @@ function defineGameViteConfig(config) {
67
165
  }
68
166
 
69
167
  // src/vitest-config.ts
70
- import { resolve as resolve2 } from "path";
71
- import { defineConfig } from "vitest/config";
168
+ import { resolve as resolve3 } from "path";
169
+ import { defineConfig as defineConfig2 } from "vitest/config";
72
170
 
73
171
  // src/gameplay-audit.ts
74
172
  import { readdirSync, readFileSync, statSync } from "fs";
@@ -672,6 +770,8 @@ GAMEPLAY_AUDIT: ALL CONTRACTS PASSED (${tests.filter((test) => test.metadata).le
672
770
  };
673
771
 
674
772
  // src/vitest-config.ts
773
+ var PHASER_FACADE_DEPENDENCY = /miaoda-game-devkit[\\/]dist[\\/]phaser-facade\.mjs$/;
774
+ var REXUI_DEPENDENCY = /phaser4-rex-plugins/;
675
775
  function defineGameVitestConfig(options) {
676
776
  const auditIssues = validateGameplayAuditOptions(options.gameplayAudit, options.projectRoot);
677
777
  if (auditIssues.length > 0) {
@@ -680,12 +780,12 @@ function defineGameVitestConfig(options) {
680
780
  - ${auditIssues.join("\n- ")}`
681
781
  );
682
782
  }
683
- return defineConfig({
783
+ return defineConfig2({
684
784
  plugins: [phaserRexUIScenePlugin(options.projectRoot)],
685
785
  resolve: {
686
786
  alias: {
687
787
  ...options.aliases,
688
- "@": resolve2(options.projectRoot, "src")
788
+ "@": resolve3(options.projectRoot, "src")
689
789
  }
690
790
  },
691
791
  // devkit 作为 external ESM 加载时,应用测试也必须 externalize Phaser,
@@ -703,7 +803,11 @@ function defineGameVitestConfig(options) {
703
803
  // 如果强制内联,Vite 会把这些模块按浏览器模块转换,
704
804
  // 最终触发 "No such built-in module: node:"。
705
805
  external: [/miaoda-game-devkit/],
706
- inline: options.inlineDependencies
806
+ inline: [
807
+ PHASER_FACADE_DEPENDENCY,
808
+ REXUI_DEPENDENCY,
809
+ ...options.inlineDependencies ?? []
810
+ ]
707
811
  }
708
812
  },
709
813
  environment: "jsdom",
@@ -745,91 +849,6 @@ function defineGameVitestConfig(options) {
745
849
  });
746
850
  }
747
851
 
748
- // src/react-vitest-config.ts
749
- import { resolve as resolve3 } from "path";
750
- import { defineConfig as defineConfig2 } from "vitest/config";
751
- function defineReactGameVitestConfig(options) {
752
- return defineConfig2({
753
- resolve: {
754
- alias: { ...options.aliases, "@": resolve3(options.projectRoot, "src") }
755
- },
756
- test: {
757
- include: [
758
- "src/**/*.{test,spec}.{ts,tsx}",
759
- "tests/**/*.{test,spec}.{ts,tsx}"
760
- ],
761
- environment: "jsdom",
762
- environmentOptions: {
763
- jsdom: { url: "http://localhost/", pretendToBeVisual: true }
764
- },
765
- setupFiles: [
766
- "miaoda-game-devkit/react/vitest-setup",
767
- ...options.additionalSetupFiles ?? []
768
- ],
769
- reporters: ["minimal"],
770
- restoreMocks: true,
771
- clearMocks: true,
772
- testTimeout: options.testTimeout,
773
- hookTimeout: options.hookTimeout
774
- }
775
- });
776
- }
777
-
778
- // src/react/manual-game-clock.ts
779
- var ManualGameClock = class {
780
- time = 0;
781
- nextId = 1;
782
- frames = /* @__PURE__ */ new Map();
783
- timers = /* @__PURE__ */ new Map();
784
- now() {
785
- return this.time;
786
- }
787
- requestFrame(callback) {
788
- const id = this.nextId++;
789
- this.frames.set(id, callback);
790
- return id;
791
- }
792
- cancelFrame(id) {
793
- this.frames.delete(id);
794
- }
795
- setTimeout(callback, delayMs) {
796
- const id = this.nextId++;
797
- this.timers.set(id, { callback, dueAt: this.time + delayMs });
798
- return id;
799
- }
800
- clearTimeout(id) {
801
- this.timers.delete(id);
802
- }
803
- advanceBy(deltaMs) {
804
- if (!Number.isFinite(deltaMs) || deltaMs < 0) {
805
- throw new RangeError("deltaMs must be a non-negative finite number");
806
- }
807
- this.time += deltaMs;
808
- const dueTimers = [...this.timers.entries()].filter(([, timer]) => timer.dueAt <= this.time).sort((left, right) => left[1].dueAt - right[1].dueAt);
809
- for (const [id, timer] of dueTimers) {
810
- if (timer.dueAt <= this.time && this.timers.delete(id)) timer.callback();
811
- }
812
- }
813
- stepFrame(deltaMs = 16) {
814
- this.advanceBy(deltaMs);
815
- const callbacks = [...this.frames.values()];
816
- this.frames.clear();
817
- for (const callback of callbacks) callback(this.time);
818
- }
819
- stepFrames(count, deltaMs = 16) {
820
- if (!Number.isInteger(count) || count < 0) {
821
- throw new RangeError("count must be a non-negative integer");
822
- }
823
- for (let index = 0; index < count; index += 1) this.stepFrame(deltaMs);
824
- }
825
- pendingFrameCount() {
826
- return this.frames.size;
827
- }
828
- pendingTimerCount() {
829
- return this.timers.size;
830
- }
831
- };
832
-
833
852
  // src/lint/vitest-config.test.ts
834
853
  var projectRoot = resolve4(import.meta.dirname, "../..");
835
854
  var gameplayAudit = {
@@ -862,6 +881,21 @@ describe("defineGameVitestConfig", () => {
862
881
  name: "miaoda-phaser-rexui-scene"
863
882
  });
864
883
  });
884
+ it("defineGameViteConfig \u9884\u6784\u5EFA\u52A8\u6001 RexUI \u5165\u53E3\u5E76\u4FDD\u7559\u9879\u76EE\u914D\u7F6E", () => {
885
+ const config = defineGameViteConfig({
886
+ optimizeDeps: {
887
+ include: ["application-dependency"],
888
+ exclude: ["excluded-dependency"]
889
+ }
890
+ });
891
+ expect(config.optimizeDeps).toEqual({
892
+ include: [
893
+ "application-dependency",
894
+ "phaser4-rex-plugins/templates/ui/ui-plugin.js"
895
+ ],
896
+ exclude: ["excluded-dependency"]
897
+ });
898
+ });
865
899
  it("\u63D0\u4F9B Phaser \u8FD0\u884C\u65F6\u6D4B\u8BD5\u9700\u8981\u7684\u56FA\u5B9A\u57FA\u7EBF", () => {
866
900
  const config = defineGameVitestConfig({ projectRoot, gameplayAudit });
867
901
  expect(config.resolve?.alias).toMatchObject({
@@ -877,7 +911,10 @@ describe("defineGameVitestConfig", () => {
877
911
  server: {
878
912
  deps: {
879
913
  external: [/miaoda-game-devkit/],
880
- inline: void 0
914
+ inline: [
915
+ /miaoda-game-devkit[\\/]dist[\\/]phaser-facade\.mjs$/,
916
+ /phaser4-rex-plugins/
917
+ ]
881
918
  }
882
919
  },
883
920
  environment: "jsdom",
@@ -907,7 +944,7 @@ describe("defineGameVitestConfig", () => {
907
944
  const config = defineGameVitestConfig({
908
945
  projectRoot,
909
946
  gameplayAudit,
910
- inlineDependencies: [/phaser4-rex-plugins/],
947
+ inlineDependencies: [/project-specific-inline-dependency/],
911
948
  additionalSetupFiles: ["tests/custom-setup.ts"],
912
949
  testTimeout: 5e3,
913
950
  hookTimeout: 2e3
@@ -915,6 +952,15 @@ describe("defineGameVitestConfig", () => {
915
952
  expect(config.test).toMatchObject({
916
953
  include: ["tests/**/*.test.ts"],
917
954
  setupFiles: ["miaoda-game-devkit/vitest-setup", "tests/custom-setup.ts"],
955
+ server: {
956
+ deps: {
957
+ inline: [
958
+ /miaoda-game-devkit[\\/]dist[\\/]phaser-facade\.mjs$/,
959
+ /phaser4-rex-plugins/,
960
+ /project-specific-inline-dependency/
961
+ ]
962
+ }
963
+ },
918
964
  testTimeout: 5e3,
919
965
  hookTimeout: 2e3
920
966
  });
package/dist/vite.js CHANGED
@@ -28,6 +28,9 @@ var import_node_fs = require("fs");
28
28
  var import_node_module = require("module");
29
29
  var import_node_path = require("path");
30
30
  var PHASER_MODULE_ID = "phaser";
31
+ var REXUI_OPTIMIZE_ENTRIES = [
32
+ "phaser4-rex-plugins/templates/ui/ui-plugin.js"
33
+ ];
31
34
  function isPromiseLike(value) {
32
35
  return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
33
36
  }
@@ -69,8 +72,18 @@ function phaserRexUIScenePlugin(projectRoot) {
69
72
  };
70
73
  }
71
74
  function withGameDefaults(config) {
75
+ const optimizeDeps = config.optimizeDeps ?? {};
72
76
  return {
73
77
  ...config,
78
+ optimizeDeps: {
79
+ ...optimizeDeps,
80
+ include: [
81
+ .../* @__PURE__ */ new Set([
82
+ ...optimizeDeps.include ?? [],
83
+ ...REXUI_OPTIMIZE_ENTRIES
84
+ ])
85
+ ]
86
+ },
74
87
  plugins: [
75
88
  phaserRexUIScenePlugin(),
76
89
  ...config.plugins ?? []
package/dist/vite.mjs CHANGED
@@ -3,6 +3,9 @@ import { existsSync } from "fs";
3
3
  import { createRequire } from "module";
4
4
  import { dirname, join, normalize, resolve, sep } from "path";
5
5
  var PHASER_MODULE_ID = "phaser";
6
+ var REXUI_OPTIMIZE_ENTRIES = [
7
+ "phaser4-rex-plugins/templates/ui/ui-plugin.js"
8
+ ];
6
9
  function isPromiseLike(value) {
7
10
  return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
8
11
  }
@@ -44,8 +47,18 @@ function phaserRexUIScenePlugin(projectRoot) {
44
47
  };
45
48
  }
46
49
  function withGameDefaults(config) {
50
+ const optimizeDeps = config.optimizeDeps ?? {};
47
51
  return {
48
52
  ...config,
53
+ optimizeDeps: {
54
+ ...optimizeDeps,
55
+ include: [
56
+ .../* @__PURE__ */ new Set([
57
+ ...optimizeDeps.include ?? [],
58
+ ...REXUI_OPTIMIZE_ENTRIES
59
+ ])
60
+ ]
61
+ },
49
62
  plugins: [
50
63
  phaserRexUIScenePlugin(),
51
64
  ...config.plugins ?? []
@@ -1,5 +1,5 @@
1
1
  import { ViteUserConfig } from 'vitest/config';
2
- import { G as GameplayAuditOptions } from './gameplay-audit-BwAobjIX.mjs';
2
+ import { G as GameplayAuditOptions } from './gameplay-audit-DmbBA0M_.mjs';
3
3
  import 'phaser';
4
4
 
5
5
  interface GameVitestConfigOptions {
@@ -11,7 +11,7 @@ interface GameVitestConfigOptions {
11
11
  aliases?: Record<string, string>;
12
12
  /** 在 devkit 基础 setup 之后执行的项目级 setup 文件。 */
13
13
  additionalSetupFiles?: string[];
14
- /** 需要由 Vite 转换的项目依赖,例如包含无扩展名 import 的插件。 */
14
+ /** devkit 内置 Phaser/RexUI 边界外,还需要由 Vite 转换的项目依赖。 */
15
15
  inlineDependencies?: RegExp[];
16
16
  /** 单个游戏运行时测试的超时时间。 */
17
17
  testTimeout?: number;
@@ -1,5 +1,5 @@
1
1
  import { ViteUserConfig } from 'vitest/config';
2
- import { G as GameplayAuditOptions } from './gameplay-audit-BwAobjIX.js';
2
+ import { G as GameplayAuditOptions } from './gameplay-audit-DmbBA0M_.js';
3
3
  import 'phaser';
4
4
 
5
5
  interface GameVitestConfigOptions {
@@ -11,7 +11,7 @@ interface GameVitestConfigOptions {
11
11
  aliases?: Record<string, string>;
12
12
  /** 在 devkit 基础 setup 之后执行的项目级 setup 文件。 */
13
13
  additionalSetupFiles?: string[];
14
- /** 需要由 Vite 转换的项目依赖,例如包含无扩展名 import 的插件。 */
14
+ /** devkit 内置 Phaser/RexUI 边界外,还需要由 Vite 转换的项目依赖。 */
15
15
  inlineDependencies?: RegExp[];
16
16
  /** 单个游戏运行时测试的超时时间。 */
17
17
  testTimeout?: number;
@@ -671,6 +671,8 @@ function phaserRexUIScenePlugin(projectRoot) {
671
671
  }
672
672
 
673
673
  // src/vitest-config.ts
674
+ var PHASER_FACADE_DEPENDENCY = /miaoda-game-devkit[\\/]dist[\\/]phaser-facade\.mjs$/;
675
+ var REXUI_DEPENDENCY = /phaser4-rex-plugins/;
674
676
  function defineGameVitestConfig(options) {
675
677
  const auditIssues = validateGameplayAuditOptions(options.gameplayAudit, options.projectRoot);
676
678
  if (auditIssues.length > 0) {
@@ -702,7 +704,11 @@ function defineGameVitestConfig(options) {
702
704
  // 如果强制内联,Vite 会把这些模块按浏览器模块转换,
703
705
  // 最终触发 "No such built-in module: node:"。
704
706
  external: [/miaoda-game-devkit/],
705
- inline: options.inlineDependencies
707
+ inline: [
708
+ PHASER_FACADE_DEPENDENCY,
709
+ REXUI_DEPENDENCY,
710
+ ...options.inlineDependencies ?? []
711
+ ]
706
712
  }
707
713
  },
708
714
  environment: "jsdom",
@@ -647,6 +647,8 @@ function phaserRexUIScenePlugin(projectRoot) {
647
647
  }
648
648
 
649
649
  // src/vitest-config.ts
650
+ var PHASER_FACADE_DEPENDENCY = /miaoda-game-devkit[\\/]dist[\\/]phaser-facade\.mjs$/;
651
+ var REXUI_DEPENDENCY = /phaser4-rex-plugins/;
650
652
  function defineGameVitestConfig(options) {
651
653
  const auditIssues = validateGameplayAuditOptions(options.gameplayAudit, options.projectRoot);
652
654
  if (auditIssues.length > 0) {
@@ -678,7 +680,11 @@ function defineGameVitestConfig(options) {
678
680
  // 如果强制内联,Vite 会把这些模块按浏览器模块转换,
679
681
  // 最终触发 "No such built-in module: node:"。
680
682
  external: [/miaoda-game-devkit/],
681
- inline: options.inlineDependencies
683
+ inline: [
684
+ PHASER_FACADE_DEPENDENCY,
685
+ REXUI_DEPENDENCY,
686
+ ...options.inlineDependencies ?? []
687
+ ]
682
688
  }
683
689
  },
684
690
  environment: "jsdom",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-game-devkit",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "Shared lint and deterministic Phaser HEADLESS testing tools for Miaoda games",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",