Add ESLint and Prettier, and close the node test gaps
Tooling: - Prettier as the single formatting authority (110 columns, single quotes, measured against the existing style); Markdown excluded because table-cell padding turns the README glossary into 1000-character lines. - Type-aware ESLint ending in eslint-config-prettier, so a rule always means "this is a bug", never "this looks different". - .editorconfig and an `npm run check` that runs typecheck, lint, format and tests in one go. Findings fixed on the first run: three more duplicate imports, four String(unknown) calls (parameter types narrowed instead of casts), two dead initialisers, two redundant casts, a console.log for a real error. Two warnings were false here and are disabled with a reason in place. Tests 132 -> 269: - node-catalog.test.ts covers every node with a run(), with a guard that fails when a new node has no row. - behavior-events.test.ts covers the ten event nodes through a running World, checking timing rather than existence. - Input's state machine (press/release/releaseAll) is reachable without DOM events now; the DOM handlers are thin adapters. Compare fell back to == without a configured operator although the schema default is <; aligned. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f140c2fd77
commit
d54a620ebd
113 files changed
+5049
-666
No files matched your search
@@ -10,7 +10,14 @@ export const Move: NodeDef = {
|
||||
"Moves an object by (dx, dy) × scale × dt. Connect dt to an event's dt for per-second movement; " +
|
||||
'leave it at 1 for per-frame. With "Collide with solids" on, the object\'s solid colliders stop at ' +
|
||||
'other solid colliders and slide along them; blocked x/y tell which axes hit.',
|
||||
inputs: [exec(), obj('object'), num('dx'), num('dy'), withDefault(num('scale'), 1), withDefault(num('dt'), 1)],
|
||||
inputs: [
|
||||
exec(),
|
||||
obj('object'),
|
||||
num('dx'),
|
||||
num('dy'),
|
||||
withDefault(num('scale'), 1),
|
||||
withDefault(num('dt'), 1),
|
||||
],
|
||||
outputs: [exec(), bool('blockedX', 'blocked x'), bool('blockedY', 'blocked y')],
|
||||
params: [{ key: 'collide', label: 'Collide with solids', kind: 'boolean', default: false }],
|
||||
run: (ctx, inputs, params) => {
|
||||
|
||||
@@ -5,7 +5,8 @@ export const RestartGame: NodeDef = {
|
||||
type: 'RestartGame',
|
||||
label: 'Restart game',
|
||||
category: 'action',
|
||||
description: 'Starts the scene over from its saved state – everything spawned, moved or destroyed is reset.',
|
||||
description:
|
||||
'Starts the scene over from its saved state – everything spawned, moved or destroyed is reset.',
|
||||
inputs: [exec()],
|
||||
outputs: [],
|
||||
params: [],
|
||||
|
||||
@@ -28,7 +28,9 @@ export const Compare: NodeDef = {
|
||||
},
|
||||
],
|
||||
run: (_ctx, inputs, params) => {
|
||||
const compare = OPERATORS[String(params.op)] ?? OPERATORS['==']!;
|
||||
// The fallback matches the param's declared default, so a node whose setting is missing
|
||||
// (an old document, a hand-written graph) behaves like a freshly created one.
|
||||
const compare = OPERATORS[String(params.op)] ?? OPERATORS['<']!;
|
||||
return { outputs: { result: compare(asNumber(inputs.a), asNumber(inputs.b)) } };
|
||||
},
|
||||
};
|
||||
@@ -73,23 +73,80 @@ import { SetVariable } from './variable/SetVariable';
|
||||
*/
|
||||
export const BUILT_IN_NODES: readonly NodeDef[] = [
|
||||
// events
|
||||
OnStart, OnUpdate, OnKeyDown, OnKeyUp, OnKeyHeld, OnTimer,
|
||||
OnCollisionEnter, OnCollisionStay, OnCollisionExit, OnClick,
|
||||
OnStart,
|
||||
OnUpdate,
|
||||
OnKeyDown,
|
||||
OnKeyUp,
|
||||
OnKeyHeld,
|
||||
OnTimer,
|
||||
OnCollisionEnter,
|
||||
OnCollisionStay,
|
||||
OnCollisionExit,
|
||||
OnClick,
|
||||
// flow
|
||||
Branch, Sequence,
|
||||
Branch,
|
||||
Sequence,
|
||||
// variables
|
||||
GetVariable, SetVariable,
|
||||
GetVariable,
|
||||
SetVariable,
|
||||
// data: references and properties
|
||||
Self, Owner, Parent, ObjectByName, NameOf, IsAsset, IsEnabled, GetProperty, GetPosition,
|
||||
Self,
|
||||
Owner,
|
||||
Parent,
|
||||
ObjectByName,
|
||||
NameOf,
|
||||
IsAsset,
|
||||
IsEnabled,
|
||||
GetProperty,
|
||||
GetPosition,
|
||||
// data: literals and math
|
||||
NumberLiteral, BooleanLiteral, StringLiteral,
|
||||
Add, Subtract, Multiply, Divide, Min, Max, Abs, Sqrt, Clamp, Floor, Ceil, Round, Modulo, Random, Time,
|
||||
NumberLiteral,
|
||||
BooleanLiteral,
|
||||
StringLiteral,
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Min,
|
||||
Max,
|
||||
Abs,
|
||||
Sqrt,
|
||||
Clamp,
|
||||
Floor,
|
||||
Ceil,
|
||||
Round,
|
||||
Modulo,
|
||||
Random,
|
||||
Time,
|
||||
// data: text and comparison
|
||||
ToText, Join, Equals, Compare, And, Or, Not,
|
||||
ToText,
|
||||
Join,
|
||||
Equals,
|
||||
Compare,
|
||||
And,
|
||||
Or,
|
||||
Not,
|
||||
// data: vectors and input
|
||||
Length, Distance, Normalize, AxisInput, KeyIsDown, MousePosition, MouseButton, IsHovered, IsTouching,
|
||||
Length,
|
||||
Distance,
|
||||
Normalize,
|
||||
AxisInput,
|
||||
KeyIsDown,
|
||||
MousePosition,
|
||||
MouseButton,
|
||||
IsHovered,
|
||||
IsTouching,
|
||||
// actions
|
||||
Move, SetPosition, SetProperty, SetEnabled, SetText, Spawn, Destroy, Log, StopGame, RestartGame,
|
||||
Move,
|
||||
SetPosition,
|
||||
SetProperty,
|
||||
SetEnabled,
|
||||
SetText,
|
||||
Spawn,
|
||||
Destroy,
|
||||
Log,
|
||||
StopGame,
|
||||
RestartGame,
|
||||
];
|
||||
|
||||
for (const def of BUILT_IN_NODES) registerNode(def);
|
||||
@@ -16,17 +16,34 @@ export const any = (key: string, label = key): PortDef => ({ key, label, type: '
|
||||
export const withDefault = (port: PortDef, value: PropertyValue): PortDef => ({ ...port, default: value });
|
||||
|
||||
/** Outputs of the three collision events: the other body, its collider and the own collider. */
|
||||
export const collisionOutputs = (): PortDef[] => [exec(), obj('other'), obj('otherCollider', 'other collider'), obj('collider')];
|
||||
export const collisionOutputs = (): PortDef[] => [
|
||||
exec(),
|
||||
obj('other'),
|
||||
obj('otherCollider', 'other collider'),
|
||||
obj('collider'),
|
||||
];
|
||||
|
||||
// --- params ----------------------------------------------------------------------------------
|
||||
|
||||
export const keyParam: PropertyDef = { key: 'key', label: 'Key', kind: 'key', default: 'ArrowRight' };
|
||||
|
||||
/** Options are empty on purpose: the graph inspector fills in the behavior's variables. */
|
||||
export const variableParam: PropertyDef = { key: 'variable', label: 'Variable', kind: 'enum', default: '', options: [] };
|
||||
export const variableParam: PropertyDef = {
|
||||
key: 'variable',
|
||||
label: 'Variable',
|
||||
kind: 'enum',
|
||||
default: '',
|
||||
options: [],
|
||||
};
|
||||
|
||||
/** Options are empty on purpose: the graph inspector fills in the project's placeable assets. */
|
||||
export const assetParam: PropertyDef = { key: 'asset', label: 'Asset', kind: 'enum', default: '', options: [] };
|
||||
export const assetParam: PropertyDef = {
|
||||
key: 'asset',
|
||||
label: 'Asset',
|
||||
kind: 'enum',
|
||||
default: '',
|
||||
options: [],
|
||||
};
|
||||
|
||||
// --- node factories --------------------------------------------------------------------------
|
||||
|
||||
@@ -59,7 +76,11 @@ export function unaryMath(type: string, description: string, fn: (value: number)
|
||||
}
|
||||
|
||||
/** A data node combining the booleans `a` and `b`. */
|
||||
export function binaryLogic(type: string, description: string, fn: (a: boolean, b: boolean) => boolean): NodeDef {
|
||||
export function binaryLogic(
|
||||
type: string,
|
||||
description: string,
|
||||
fn: (a: boolean, b: boolean) => boolean,
|
||||
): NodeDef {
|
||||
return {
|
||||
type,
|
||||
label: type,
|
||||
|
||||
@@ -9,5 +9,7 @@ export const GetVariable: NodeDef = {
|
||||
inputs: [],
|
||||
outputs: [any('value')],
|
||||
params: [variableParam],
|
||||
run: (ctx, _inputs, params) => ({ outputs: { value: ctx.variables[String(params.variable ?? '')] ?? null } }),
|
||||
run: (ctx, _inputs, params) => ({
|
||||
outputs: { value: ctx.variables[String(params.variable ?? '')] ?? null },
|
||||
}),
|
||||
};
|
||||
Reference in new issue
Block a user