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
@@ -16,7 +16,11 @@ export function nodeSignature(project: Project, assetId: string, nodeId: string)
|
||||
const node = asset.graph.nodes.find((n) => n.id === nodeId);
|
||||
if (!node) return 'missing';
|
||||
const def = nodeDef(node.type);
|
||||
const connected = def ? inlineInputs(def).filter((p) => edgesInto(asset.graph, node.id, p.key).length > 0).map((p) => p.key) : [];
|
||||
const connected = def
|
||||
? inlineInputs(def)
|
||||
.filter((p) => edgesInto(asset.graph, node.id, p.key).length > 0)
|
||||
.map((p) => p.key)
|
||||
: [];
|
||||
return `${node.type}|${connected.join(',')}|${asset.variables.map((v) => v.key).join(',')}`;
|
||||
}
|
||||
|
||||
@@ -35,7 +39,11 @@ export function buildNodeSection(host: InspectorHost, assetId: string, nodeId: s
|
||||
if (def.params.length > 0) addTitle(host, 'SETTINGS');
|
||||
for (const param of def.params) {
|
||||
const effective = resolveParamDef(host.state.project, param, asset);
|
||||
const row = createFieldRow(effective, node.params[param.key] ?? effective.default, paramHandlers(host, assetId, nodeId, param.key));
|
||||
const row = createFieldRow(
|
||||
effective,
|
||||
node.params[param.key] ?? effective.default,
|
||||
paramHandlers(host, assetId, nodeId, param.key),
|
||||
);
|
||||
host.fields.set(`param:${param.key}`, row);
|
||||
host.body.add(row.row);
|
||||
}
|
||||
@@ -44,13 +52,22 @@ export function buildNodeSection(host: InspectorHost, assetId: string, nodeId: s
|
||||
if (free.length > 0) addTitle(host, 'INPUTS (unconnected)');
|
||||
for (const port of free) {
|
||||
const inline = inlineInputDef(port);
|
||||
const row = createFieldRow(inline, node.params[port.key] ?? inline.default, paramHandlers(host, assetId, nodeId, port.key));
|
||||
const row = createFieldRow(
|
||||
inline,
|
||||
node.params[port.key] ?? inline.default,
|
||||
paramHandlers(host, assetId, nodeId, port.key),
|
||||
);
|
||||
host.fields.set(`input:${port.key}`, row);
|
||||
host.body.add(row.row);
|
||||
}
|
||||
|
||||
addGap(host);
|
||||
host.body.add(new Button('Delete node', { variant: 'danger', onClick: () => host.state.execute(new RemoveNodeCommand(assetId, nodeId)) }));
|
||||
host.body.add(
|
||||
new Button('Delete node', {
|
||||
variant: 'danger',
|
||||
onClick: () => host.state.execute(new RemoveNodeCommand(assetId, nodeId)),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/** Pushes the node's current params into the rows. False when the node is gone (rebuild). */
|
||||
@@ -60,7 +77,10 @@ export function refreshNodeSection(host: InspectorHost, assetId: string, nodeId:
|
||||
if (!node || !def) return false;
|
||||
for (const [key, row] of host.fields) {
|
||||
const [scope, name] = key.split(':') as ['param' | 'input', string];
|
||||
const fallback = scope === 'param' ? def.params.find((p) => p.key === name)?.default : inlineInputDef(def.inputs.find((p) => p.key === name)!).default;
|
||||
const fallback =
|
||||
scope === 'param'
|
||||
? def.params.find((p) => p.key === name)?.default
|
||||
: inlineInputDef(def.inputs.find((p) => p.key === name)!).default;
|
||||
row.setValue(node.params[name] ?? fallback ?? '');
|
||||
}
|
||||
return true;
|
||||
@@ -76,7 +96,12 @@ function resolveParamDef(project: Project, param: PropertyDef, asset: Asset): Pr
|
||||
return { ...param, options: asset.variables.map((v) => ({ value: v.key, label: v.key })) };
|
||||
}
|
||||
if (param.key === 'asset') {
|
||||
return { ...param, options: project.assets.filter((a) => isPlaceableType(a.type)).map((a) => ({ value: a.id, label: `${a.name} (${a.type})` })) };
|
||||
return {
|
||||
...param,
|
||||
options: project.assets
|
||||
.filter((a) => isPlaceableType(a.type))
|
||||
.map((a) => ({ value: a.id, label: `${a.name} (${a.type})` })),
|
||||
};
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user