@caperjs/core 0.1.1 → 0.2.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 +1 -1
- package/{config → build}/assetpack.mjs +103 -45
- package/build/defaults.mjs +157 -0
- package/build/index.mjs +96 -0
- package/build/internal/ast.mjs +255 -0
- package/build/internal/buildFlags.mjs +50 -0
- package/build/internal/discovery.mjs +402 -0
- package/build/internal/manifest.mjs +38 -0
- package/build/internal/schema.mjs +65 -0
- package/build/internal/util.mjs +30 -0
- package/build/internal/validate.mjs +186 -0
- package/build/plugins/assetTypes.mjs +460 -0
- package/build/plugins/caperConfig.mjs +489 -0
- package/build/plugins/devHelper.mjs +31 -0
- package/build/plugins/lists.mjs +286 -0
- package/build/plugins/pruneFallbacks.mjs +150 -0
- package/build/plugins/pwa.mjs +240 -0
- package/build/plugins/runtime.mjs +129 -0
- package/cli.mjs +9 -6
- package/extras/llms.txt +23 -17
- package/lib/{CaptionsPlugin-Dc8fIrjy.js → CaptionsPlugin-DKhbmJvH.js} +15 -15
- package/lib/{CaptionsPlugin-Dc8fIrjy.js.map → CaptionsPlugin-DKhbmJvH.js.map} +1 -1
- package/lib/{DataAdapter-BY2114sp.js → DataAdapter-BZFTkFQ4.js} +4 -4
- package/lib/{DataAdapter-BY2114sp.js.map → DataAdapter-BZFTkFQ4.js.map} +1 -1
- package/lib/{DebugRenderer-BJMLILqI.js → DebugRenderer-C7X-nlXE.js} +2 -2
- package/lib/{DebugRenderer-BJMLILqI.js.map → DebugRenderer-C7X-nlXE.js.map} +1 -1
- package/lib/{DevToolsPlugin-wQ5rOkn0.js → DevToolsPlugin-P-atJ-5U.js} +2 -2
- package/lib/{DevToolsPlugin-wQ5rOkn0.js.map → DevToolsPlugin-P-atJ-5U.js.map} +1 -1
- package/lib/{GSAPPlugin-DHhSZKv8.js → GSAPPlugin-CeH9275z.js} +2 -2
- package/lib/{GSAPPlugin-DHhSZKv8.js.map → GSAPPlugin-CeH9275z.js.map} +1 -1
- package/lib/{LayoutPlugin-B-DF9SYM.js → LayoutPlugin-iZ3k6RsK.js} +4 -4
- package/lib/{LayoutPlugin-B-DF9SYM.js.map → LayoutPlugin-iZ3k6RsK.js.map} +1 -1
- package/lib/{SpinePlugin-Dz_3dljz.js → SpinePlugin-BWiavCpO.js} +2 -2
- package/lib/{SpinePlugin-Dz_3dljz.js.map → SpinePlugin-BWiavCpO.js.map} +1 -1
- package/lib/{StatsPlugin-Cg82JMBD.js → StatsPlugin-CBpzDJL0.js} +4 -4
- package/lib/{StatsPlugin-Cg82JMBD.js.map → StatsPlugin-CBpzDJL0.js.map} +1 -1
- package/lib/{VoiceOverPlugin-BR3ImT8C.js → VoiceOverPlugin-YaiKJtJ6.js} +26 -26
- package/lib/{VoiceOverPlugin-BR3ImT8C.js.map → VoiceOverPlugin-YaiKJtJ6.js.map} +1 -1
- package/lib/caper.mjs +95 -95
- package/lib/caper.mjs.map +1 -1
- package/lib/core/Application.d.ts +1 -1
- package/lib/core/Application.d.ts.map +1 -1
- package/lib/core/interfaces/IApplicationOptions.d.ts +2 -1
- package/lib/core/interfaces/IApplicationOptions.d.ts.map +1 -1
- package/lib/core/interfaces/ICoreSignals.d.ts +5 -1
- package/lib/core/interfaces/ICoreSignals.d.ts.map +1 -1
- package/lib/display/Container.d.ts +1 -1
- package/lib/display/Container.d.ts.map +1 -1
- package/lib/display/ParticleContainer.d.ts +1 -1
- package/lib/display/ParticleContainer.d.ts.map +1 -1
- package/lib/plugins/Plugin.d.ts +1 -1
- package/lib/plugins/Plugin.d.ts.map +1 -1
- package/lib/plugins/defaults.d.ts.map +1 -1
- package/lib/plugins/gesture/GesturePlugin.d.ts +58 -0
- package/lib/plugins/gesture/GesturePlugin.d.ts.map +1 -0
- package/lib/plugins/gesture/gestureMath.d.ts +32 -0
- package/lib/plugins/gesture/gestureMath.d.ts.map +1 -0
- package/lib/plugins/gesture/gestureMath.test.d.ts +2 -0
- package/lib/plugins/gesture/gestureMath.test.d.ts.map +1 -0
- package/lib/plugins/gesture/index.d.ts +3 -0
- package/lib/plugins/gesture/index.d.ts.map +1 -0
- package/lib/plugins/gesture/types.d.ts +45 -0
- package/lib/plugins/gesture/types.d.ts.map +1 -0
- package/lib/plugins/index.d.ts +1 -0
- package/lib/plugins/index.d.ts.map +1 -1
- package/lib/plugins/input/Controls.d.ts +5 -2
- package/lib/plugins/input/Controls.d.ts.map +1 -1
- package/lib/plugins/input/InputPlugin.d.ts +9 -2
- package/lib/plugins/input/InputPlugin.d.ts.map +1 -1
- package/lib/plugins/input/interfaces.d.ts +5 -3
- package/lib/plugins/input/interfaces.d.ts.map +1 -1
- package/lib/plugins/input/touch/{TouchControls.d.ts → VirtualControls.d.ts} +5 -4
- package/lib/plugins/input/touch/VirtualControls.d.ts.map +1 -0
- package/lib/plugins/input/touch/index.d.ts +1 -1
- package/lib/plugins/input/touch/index.d.ts.map +1 -1
- package/lib/{registries-CYCaYKZI.js → registries-qQmLeN0b.js} +505 -354
- package/lib/registries-qQmLeN0b.js.map +1 -0
- package/lib/types/caper-app.d.ts +1 -0
- package/lib/utils/bind.test.d.ts +2 -0
- package/lib/utils/bind.test.d.ts.map +1 -0
- package/package.json +33 -33
- package/src/core/Application.ts +1 -1
- package/src/core/interfaces/IApplicationOptions.ts +2 -0
- package/src/core/interfaces/ICoreSignals.ts +9 -0
- package/src/display/Container.ts +1 -1
- package/src/display/ParticleContainer.ts +1 -1
- package/src/plugins/Plugin.ts +1 -1
- package/src/plugins/defaults.ts +6 -0
- package/src/plugins/gesture/GesturePlugin.ts +215 -0
- package/src/plugins/gesture/gestureMath.test.ts +75 -0
- package/src/plugins/gesture/gestureMath.ts +59 -0
- package/src/plugins/gesture/index.ts +2 -0
- package/src/plugins/gesture/types.ts +54 -0
- package/src/plugins/index.ts +1 -0
- package/src/plugins/input/Controls.ts +9 -3
- package/src/plugins/input/InputPlugin.ts +61 -14
- package/src/plugins/input/interfaces.ts +5 -3
- package/src/plugins/input/touch/{TouchControls.ts → VirtualControls.ts} +4 -1
- package/src/plugins/input/touch/index.ts +1 -1
- package/src/types/caper-app.d.ts +1 -0
- package/src/utils/bind.test.ts +99 -0
- package/src/version.ts +1 -1
- package/templates/app/default/package.template.json +8 -4
- package/templates/app/default/vite.config.ts +15 -0
- package/LICENSE +0 -22
- package/cli/vite.mjs +0 -55
- package/config/vite.mjs +0 -2464
- package/lib/plugins/input/touch/TouchControls.d.ts.map +0 -1
- package/lib/registries-CYCaYKZI.js.map +0 -1
|
@@ -4,11 +4,12 @@ import { bindAllMethods } from '../../utils';
|
|
|
4
4
|
import { Action } from '../actions';
|
|
5
5
|
import { IControls, UserControls } from './interfaces';
|
|
6
6
|
import { KeyboardControls } from './keyboard';
|
|
7
|
-
import {
|
|
7
|
+
import { VirtualControls } from './touch';
|
|
8
8
|
|
|
9
9
|
export class Controls implements IControls {
|
|
10
10
|
keyboard: KeyboardControls;
|
|
11
|
-
|
|
11
|
+
/** @deprecated Use {@link Controls.virtual} instead. */
|
|
12
|
+
touch: VirtualControls;
|
|
12
13
|
|
|
13
14
|
constructor() {
|
|
14
15
|
bindAllMethods(this);
|
|
@@ -18,6 +19,11 @@ export class Controls implements IControls {
|
|
|
18
19
|
return Application.getInstance();
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/** Virtual on-screen buttons (joystick/buttons) — the same instance as {@link Controls.touch}. */
|
|
23
|
+
get virtual(): VirtualControls {
|
|
24
|
+
return this.touch;
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
destroy() {
|
|
22
28
|
if (this.keyboard) {
|
|
23
29
|
this.keyboard.destroy();
|
|
@@ -39,7 +45,7 @@ export class Controls implements IControls {
|
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
if (scheme.touch) {
|
|
42
|
-
this.touch = new
|
|
48
|
+
this.touch = new VirtualControls();
|
|
43
49
|
this.touch.initialize(scheme.touch);
|
|
44
50
|
}
|
|
45
51
|
}
|
|
@@ -16,6 +16,7 @@ export type InputManagerOptions = {
|
|
|
16
16
|
|
|
17
17
|
export interface IInputPlugin extends IPlugin<InputManagerOptions> {
|
|
18
18
|
readonly controls: Controls;
|
|
19
|
+
readonly lastUsedController: InputController | null;
|
|
19
20
|
activeGamepads: Map<string, Gamepad>;
|
|
20
21
|
activeControllers: Set<string>;
|
|
21
22
|
options: InputManagerOptions;
|
|
@@ -23,6 +24,7 @@ export interface IInputPlugin extends IPlugin<InputManagerOptions> {
|
|
|
23
24
|
onGamepadDisconnected: Signal<(gamepad: Gamepad) => void>;
|
|
24
25
|
onControllerActivated: Signal<(controller: string) => void>;
|
|
25
26
|
onControllerDeactivated: Signal<(controller: string) => void>;
|
|
27
|
+
onControllerChanged: Signal<(controller: InputController) => void>;
|
|
26
28
|
|
|
27
29
|
isControllerActive(controller: InputController): boolean;
|
|
28
30
|
|
|
@@ -44,11 +46,20 @@ export class InputPlugin extends Plugin<InputManagerOptions> implements IInputPl
|
|
|
44
46
|
// properties
|
|
45
47
|
public activeGamepads = new Map<string, Gamepad>();
|
|
46
48
|
public activeControllers = new Set<string>([]);
|
|
49
|
+
private _lastUsedController: InputController | null = null;
|
|
50
|
+
private _canvas: HTMLCanvasElement | null = null;
|
|
47
51
|
// signals
|
|
48
52
|
public onGamepadConnected: Signal<(gamepad: Gamepad) => void> = new Signal<(gamepad: Gamepad) => void>();
|
|
49
53
|
public onGamepadDisconnected: Signal<(gamepad: Gamepad) => void> = new Signal<(gamepad: Gamepad) => void>();
|
|
50
54
|
public onControllerActivated: Signal<(controller: string) => void> = new Signal<(controller: string) => void>();
|
|
51
55
|
public onControllerDeactivated: Signal<(controller: string) => void> = new Signal<(controller: string) => void>();
|
|
56
|
+
public onControllerChanged: Signal<(controller: InputController) => void> = new Signal<
|
|
57
|
+
(controller: InputController) => void
|
|
58
|
+
>();
|
|
59
|
+
|
|
60
|
+
get lastUsedController(): InputController | null {
|
|
61
|
+
return this._lastUsedController;
|
|
62
|
+
}
|
|
52
63
|
|
|
53
64
|
isActionActive(action: Action): boolean {
|
|
54
65
|
return this.controls.isActionActive(action);
|
|
@@ -58,8 +69,9 @@ export class InputPlugin extends Plugin<InputManagerOptions> implements IInputPl
|
|
|
58
69
|
this._options = { ...defaultOptions, ...options };
|
|
59
70
|
|
|
60
71
|
app.stage.eventMode = 'static';
|
|
61
|
-
app.
|
|
62
|
-
|
|
72
|
+
this._canvas = app.canvas as HTMLCanvasElement;
|
|
73
|
+
this._canvas.addEventListener('pointerdown', this._onPointerDown);
|
|
74
|
+
this._canvas.addEventListener('pointermove', this._onPointerMove);
|
|
63
75
|
window.addEventListener('keydown', this._onKeyDown);
|
|
64
76
|
window.addEventListener('gamepadconnected', this._onGamepadConnected);
|
|
65
77
|
window.addEventListener('gamepaddisconnected', this._onGamepadDisconnected);
|
|
@@ -77,12 +89,23 @@ export class InputPlugin extends Plugin<InputManagerOptions> implements IInputPl
|
|
|
77
89
|
|
|
78
90
|
destroy(): void {
|
|
79
91
|
// unregister all event listeners
|
|
80
|
-
|
|
81
|
-
|
|
92
|
+
if (this._canvas) {
|
|
93
|
+
this._canvas.removeEventListener('pointerdown', this._onPointerDown);
|
|
94
|
+
this._canvas.removeEventListener('pointermove', this._onPointerMove);
|
|
95
|
+
this._canvas = null;
|
|
96
|
+
}
|
|
82
97
|
window.removeEventListener('keydown', this._onKeyDown);
|
|
83
98
|
window.removeEventListener('gamepadconnected', this._onGamepadConnected);
|
|
84
99
|
window.removeEventListener('gamepaddisconnected', this._onGamepadDisconnected);
|
|
85
100
|
|
|
101
|
+
this.controls.destroy();
|
|
102
|
+
|
|
103
|
+
this.onGamepadConnected.disconnectAll();
|
|
104
|
+
this.onGamepadDisconnected.disconnectAll();
|
|
105
|
+
this.onControllerActivated.disconnectAll();
|
|
106
|
+
this.onControllerDeactivated.disconnectAll();
|
|
107
|
+
this.onControllerChanged.disconnectAll();
|
|
108
|
+
|
|
86
109
|
super.destroy();
|
|
87
110
|
}
|
|
88
111
|
|
|
@@ -95,16 +118,36 @@ export class InputPlugin extends Plugin<InputManagerOptions> implements IInputPl
|
|
|
95
118
|
}
|
|
96
119
|
|
|
97
120
|
protected getCoreSignals(): string[] {
|
|
98
|
-
return [
|
|
121
|
+
return [
|
|
122
|
+
'onGamepadConnected',
|
|
123
|
+
'onGamepadDisconnected',
|
|
124
|
+
'onControllerActivated',
|
|
125
|
+
'onControllerDeactivated',
|
|
126
|
+
'onControllerChanged',
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private _isInputControllerType(value: string): value is InputController {
|
|
131
|
+
return (Object.values(InputControllerTypes) as string[]).includes(value);
|
|
99
132
|
}
|
|
100
133
|
|
|
101
134
|
private _activateController(inputController: string): void {
|
|
102
|
-
|
|
103
|
-
|
|
135
|
+
const isNewController = !this.activeControllers.has(inputController);
|
|
136
|
+
if (isNewController) {
|
|
137
|
+
this.activeControllers.add(inputController);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// only the four InputControllerTypes values are valid "last used" values —
|
|
141
|
+
// a raw gamepad device id (see _onGamepadConnected) must never land here
|
|
142
|
+
if (this._isInputControllerType(inputController) && inputController !== this._lastUsedController) {
|
|
143
|
+
this._lastUsedController = inputController;
|
|
144
|
+
this.onControllerChanged.emit(inputController);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (isNewController) {
|
|
148
|
+
// emit the controller activated signal
|
|
149
|
+
this.onControllerActivated.emit(inputController);
|
|
104
150
|
}
|
|
105
|
-
this.activeControllers.add(inputController);
|
|
106
|
-
// emit the controller activated signal
|
|
107
|
-
this.onControllerActivated.emit(inputController);
|
|
108
151
|
}
|
|
109
152
|
|
|
110
153
|
private _deactivateController(inputController: InputController): void {
|
|
@@ -125,12 +168,16 @@ export class InputPlugin extends Plugin<InputManagerOptions> implements IInputPl
|
|
|
125
168
|
this.activeGamepads.delete(gamepadId);
|
|
126
169
|
}
|
|
127
170
|
|
|
128
|
-
private
|
|
129
|
-
|
|
171
|
+
private _onPointerDown(event: PointerEvent): void {
|
|
172
|
+
if (event.pointerType === 'touch') {
|
|
173
|
+
this._activateController(InputControllerTypes.Touch);
|
|
174
|
+
}
|
|
130
175
|
}
|
|
131
176
|
|
|
132
|
-
private
|
|
133
|
-
|
|
177
|
+
private _onPointerMove(event: PointerEvent): void {
|
|
178
|
+
if (event.pointerType === 'mouse') {
|
|
179
|
+
this._activateController(InputControllerTypes.Mouse);
|
|
180
|
+
}
|
|
134
181
|
}
|
|
135
182
|
|
|
136
183
|
private _onKeyDown(): void {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ActionContext, ActionMap, UserActions, UserButtons } from '../actions';
|
|
2
2
|
import { IKeyboardControlScheme, KeyboardControls } from './keyboard';
|
|
3
|
-
import { ITouchControlScheme,
|
|
3
|
+
import { ITouchControlScheme, VirtualControls } from './touch';
|
|
4
4
|
import { AbstractControlScheme, ControlsActionMap, KeyboardControlsMap, TouchControlsMap } from './types';
|
|
5
5
|
|
|
6
6
|
export interface ControlsAction {
|
|
@@ -17,12 +17,13 @@ export interface IGamepadControlScheme extends AbstractControlScheme<'buttonDown
|
|
|
17
17
|
export interface ControlScheme {
|
|
18
18
|
keyboard?: IKeyboardControlScheme;
|
|
19
19
|
touch?: ITouchControlScheme;
|
|
20
|
-
gamepad?: IGamepadControlScheme;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
export interface IControls {
|
|
24
23
|
readonly keyboard: KeyboardControls;
|
|
25
|
-
|
|
24
|
+
/** @deprecated Use {@link IControls.virtual} instead. */
|
|
25
|
+
readonly touch: VirtualControls;
|
|
26
|
+
readonly virtual: VirtualControls;
|
|
26
27
|
|
|
27
28
|
isActionActive(action: string): boolean;
|
|
28
29
|
|
|
@@ -33,5 +34,6 @@ export interface IControls {
|
|
|
33
34
|
|
|
34
35
|
export interface UserControls<U extends UserActions = UserActions, B extends UserButtons = UserButtons> {
|
|
35
36
|
keyboard: Partial<KeyboardControlsMap<U>>;
|
|
37
|
+
/** Virtual on-screen buttons (joystick/buttons) — despite the key name, this is not touchscreen input. */
|
|
36
38
|
touch: Partial<TouchControlsMap<U, B>>;
|
|
37
39
|
}
|
|
@@ -8,7 +8,7 @@ import { type IButton, type IJoystick } from '../../../ui';
|
|
|
8
8
|
import type { Action } from '../../actions';
|
|
9
9
|
import { AbstractControls } from '../AbstractControls';
|
|
10
10
|
|
|
11
|
-
export class
|
|
11
|
+
export class VirtualControls extends WithSignals(AbstractControls) {
|
|
12
12
|
protected scheme: Partial<TouchControlsMap>;
|
|
13
13
|
private _buttons: Set<IButton> = new Set();
|
|
14
14
|
private _joystickMap: Partial<JoystickControlsScheme>;
|
|
@@ -235,3 +235,6 @@ export class TouchControls extends WithSignals(AbstractControls) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
|
+
|
|
239
|
+
/** @deprecated Use {@link VirtualControls} instead. */
|
|
240
|
+
export { VirtualControls as TouchControls };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* caper.config.ts not found, skipping augmentation. */
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { bindAllMethods } from './bind';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `bindAllMethods` walks up the prototype chain binding every method, and stops
|
|
6
|
+
* at the first class marked with `__caper_method_binding_root`. The marker MUST
|
|
7
|
+
* be `static`: the walk tests it with
|
|
8
|
+
* `hasOwnProperty(prototype.constructor, ...)`, and an instance field never
|
|
9
|
+
* lands on the constructor — so declaring it non-static silently disables the
|
|
10
|
+
* guard and the walk runs all the way to `Object.prototype`, binding (and
|
|
11
|
+
* copying onto every instance) every method of the base class. For a caper
|
|
12
|
+
* `Container` that base is PixiJS's `Container`: ~70 extra bound closures and
|
|
13
|
+
* own properties per display object.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Stands in for the foreign base we must NOT bind into (i.e. PixiJS). */
|
|
17
|
+
class Foreign {
|
|
18
|
+
foreignMethod(): unknown {
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class Root extends Foreign {
|
|
24
|
+
private static readonly __caper_method_binding_root = true;
|
|
25
|
+
|
|
26
|
+
rootMethod(): unknown {
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class Leaf extends Root {
|
|
32
|
+
constructor() {
|
|
33
|
+
super();
|
|
34
|
+
bindAllMethods(this);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
leafMethod(): unknown {
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The pre-fix declaration: an instance field, which the guard cannot see. */
|
|
43
|
+
class BrokenRoot extends Foreign {
|
|
44
|
+
private readonly __caper_method_binding_root = true;
|
|
45
|
+
|
|
46
|
+
rootMethod(): unknown {
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
class BrokenLeaf extends BrokenRoot {
|
|
52
|
+
constructor() {
|
|
53
|
+
super();
|
|
54
|
+
bindAllMethods(this);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('bindAllMethods', () => {
|
|
59
|
+
it('binds methods declared at and below the leaf', () => {
|
|
60
|
+
const leaf = new Leaf();
|
|
61
|
+
const { leafMethod, rootMethod } = leaf;
|
|
62
|
+
|
|
63
|
+
expect(leafMethod()).toBe(leaf);
|
|
64
|
+
expect(rootMethod()).toBe(leaf);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('stops at the static root marker, leaving the foreign base unbound', () => {
|
|
68
|
+
const leaf = new Leaf();
|
|
69
|
+
const { foreignMethod } = leaf;
|
|
70
|
+
|
|
71
|
+
// Detached and never bound — strict-mode `this` is undefined.
|
|
72
|
+
expect(foreignMethod()).toBeUndefined();
|
|
73
|
+
expect(Object.prototype.hasOwnProperty.call(leaf, 'foreignMethod')).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('does not copy the foreign base onto the instance', () => {
|
|
77
|
+
const leaf = new Leaf();
|
|
78
|
+
const own = Object.getOwnPropertyNames(leaf).filter((k) => typeof (leaf as never)[k] === 'function');
|
|
79
|
+
|
|
80
|
+
expect(own).toContain('leafMethod');
|
|
81
|
+
expect(own).toContain('rootMethod');
|
|
82
|
+
expect(own).not.toContain('foreignMethod');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('a NON-static marker fails to stop the walk (the bug this guards)', () => {
|
|
86
|
+
const broken = new BrokenLeaf();
|
|
87
|
+
|
|
88
|
+
// The guard never fires, so the foreign base gets bound and copied on.
|
|
89
|
+
expect(Object.prototype.hasOwnProperty.call(broken, 'foreignMethod')).toBe(true);
|
|
90
|
+
expect(broken.foreignMethod()).toBe(broken);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('subclasses do not re-trigger the guard via an inherited static', () => {
|
|
94
|
+
// `hasOwnProperty` is own-only, so `Leaf` inheriting Root's static does not
|
|
95
|
+
// stop the walk before Leaf's own methods are collected.
|
|
96
|
+
expect(Object.prototype.hasOwnProperty.call(Leaf, '__caper_method_binding_root')).toBe(false);
|
|
97
|
+
expect(Object.prototype.hasOwnProperty.call(Root, '__caper_method_binding_root')).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
});
|
package/src/version.ts
CHANGED
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
"main": "index.html",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"clean": "rimraf .assetpack .cache dist",
|
|
8
|
-
"start": "~PACKAGE_MANAGER~ clean &&
|
|
9
|
-
"dev": "~PACKAGE_MANAGER~ clean &&
|
|
10
|
-
"preview": "~PACKAGE_MANAGER~ clean &&
|
|
11
|
-
"build": "~PACKAGE_MANAGER~ clean &&
|
|
8
|
+
"start": "~PACKAGE_MANAGER~ clean && vite",
|
|
9
|
+
"dev": "~PACKAGE_MANAGER~ clean && vite",
|
|
10
|
+
"preview": "~PACKAGE_MANAGER~ clean && vite build && vite preview",
|
|
11
|
+
"build": "~PACKAGE_MANAGER~ clean && vite build",
|
|
12
12
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@caperjs/core": "latest"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"vite": "^8.1.3",
|
|
19
|
+
"workbox-window": "^7.4.0"
|
|
16
20
|
}
|
|
17
21
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { caper } from '@caperjs/core/vite';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Caper contributes its plugins and its config defaults through `caper()`, and
|
|
6
|
+
* only fills in what this file leaves unset — so anything you set here wins.
|
|
7
|
+
*
|
|
8
|
+
* Options:
|
|
9
|
+
* caper({ assets: { ... } }) AssetPack overrides, merged over caper's defaults
|
|
10
|
+
* (`assets: false` turns the asset pipeline off)
|
|
11
|
+
* caper({ pwa: { manifest } }) makes the game installable, service worker included
|
|
12
|
+
*/
|
|
13
|
+
export default defineConfig({
|
|
14
|
+
plugins: [caper()],
|
|
15
|
+
});
|
package/LICENSE
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) Relish Interactive
|
|
4
|
-
Copyright (c) 2026 Anthony Sapp
|
|
5
|
-
|
|
6
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
-
in the Software without restriction, including without limitation the rights
|
|
9
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
furnished to do so, subject to the following conditions:
|
|
12
|
-
|
|
13
|
-
The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
copies or substantial portions of the Software.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
SOFTWARE.
|
package/cli/vite.mjs
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { build, createServer, loadConfigFromFile, mergeConfig, preview } from 'vite';
|
|
2
|
-
import { defaultConfig } from '../config/vite.mjs';
|
|
3
|
-
|
|
4
|
-
async function getMergedViteConfig(command, mode) {
|
|
5
|
-
// Load user's vite.config.js file if it exists
|
|
6
|
-
const userConfig = await loadConfigFromFile({
|
|
7
|
-
command,
|
|
8
|
-
mode,
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
// Merge user config with default config
|
|
12
|
-
const mergedConfig = mergeConfig(defaultConfig, userConfig?.config || {});
|
|
13
|
-
|
|
14
|
-
// Remove duplicate plugins by name, preferring user's config over default, while preserving order.
|
|
15
|
-
if (mergedConfig.plugins) {
|
|
16
|
-
const seen = new Set();
|
|
17
|
-
mergedConfig.plugins = mergedConfig.plugins
|
|
18
|
-
.flat()
|
|
19
|
-
.reverse()
|
|
20
|
-
.filter((plugin) => {
|
|
21
|
-
if (!plugin || !plugin.name) {
|
|
22
|
-
// Keep plugins without a name (e.g., some Vite internal plugins)
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
if (seen.has(plugin.name)) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
seen.add(plugin.name);
|
|
29
|
-
return true;
|
|
30
|
-
})
|
|
31
|
-
.reverse();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return mergedConfig;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function startDevServer() {
|
|
38
|
-
const config = await getMergedViteConfig('serve', 'development');
|
|
39
|
-
const server = await createServer(config);
|
|
40
|
-
await server.listen();
|
|
41
|
-
|
|
42
|
-
server.printUrls();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export async function runBuild() {
|
|
46
|
-
const config = await getMergedViteConfig('build', 'production');
|
|
47
|
-
await build(config);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export async function runPreview() {
|
|
51
|
-
const config = await getMergedViteConfig('build', 'production');
|
|
52
|
-
await build(config);
|
|
53
|
-
const server = await preview(config);
|
|
54
|
-
server.printUrls();
|
|
55
|
-
}
|