specificClass.js: 1760 → 400 lines.
Machine extends BaseDomain. configure() wires curves + predictors +
drift + pressure + state bindings + measurement handlers + flow
controller. ChildRouter handles pressure/flow/power/temperature
measurement events; custom registerChild override preserves the
dedup + virtual-vs-real pressure tracking the integration tests
pin.
Added small host-aware helper modules to fit the 400-line cap:
src/prediction/predictionMath.js (calcFlow/Power/Ctrl)
src/prediction/efficiencyMath.js (calcCog/EfficiencyCurve/etc.)
src/pressure/pressureSelector.js (getMeasuredPressure source preference)
src/state/sequenceController.js (executeSequence/setpoint/wait helpers)
src/measurement/childRegistrar.js (custom registerChild path)
src/drift/healthRefresh.js (drift status update wrappers)
src/io/output.js (buildOutput + buildStatusBadge)
unitPolicy: live UnitPolicy methods .canonical()/.output()/.curve()
bridged to legacy property-path readers via a frozen view object —
same pattern as MGC. See OPEN_QUESTIONS.md.
nodeClass.js: 433 → 61 lines.
Extends BaseNodeAdapter. tickInterval=null (event-driven on state +
measurement events). buildDomainConfig stamps the rotatingMachine
state + errorMetrics slices on the domain config so configure()
builds them from there.
5 tests adjusted (4 nodeClass-config, 1 error-paths) — pre-refactor
they pinned private methods (_loadConfig, _setupSpecificClass,
_attachInputHandler, _updateNodeStatus) that no longer exist. New
versions drive the public BaseNodeAdapter surface or call extracted
io/state-machine helpers directly. See OPEN_QUESTIONS.md 2026-05-10
"private nodeClass tests" for the deferred rewrite plan.
196 / 196 tests pass (basic 110 + integration ~80 + edge ~6).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
48 lines
2.4 KiB
JavaScript
48 lines
2.4 KiB
JavaScript
/**
|
|
* registerChild adapter for rotatingMachine. Custom because:
|
|
* - virtual + real pressure children share the upstream/downstream
|
|
* position slots; real ones must be tracked for the preference order
|
|
* - re-registration of the same child must dedup the emitter listener
|
|
* - non-measurement softwareTypes are no-ops (Machine has no children
|
|
* other than measurement nodes today)
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
function registerMeasurementChild(host, child, softwareType) {
|
|
const swType = softwareType || child?.config?.functionality?.softwareType || 'measurement';
|
|
host.logger.debug(`Setting up child event for softwaretype ${swType}`);
|
|
if (swType !== 'measurement') return;
|
|
|
|
const position = String(child.config.functionality.positionVsParent || 'atEquipment').toLowerCase();
|
|
const measurementType = child.config.asset.type;
|
|
const childId = child.config?.general?.id || `${measurementType}-${position}-unknown`;
|
|
const isVirtual = Object.values(host.virtualPressureChildIds).includes(childId);
|
|
if (measurementType === 'pressure' && !isVirtual) host.realPressureChildIds[position]?.add(childId);
|
|
|
|
const eventName = `${measurementType}.measured.${position}`;
|
|
const key = `${childId}:${eventName}`;
|
|
const existing = host.childMeasurementListeners.get(key);
|
|
if (existing) {
|
|
if (typeof existing.emitter.off === 'function') existing.emitter.off(existing.eventName, existing.handler);
|
|
else if (typeof existing.emitter.removeListener === 'function') existing.emitter.removeListener(existing.eventName, existing.handler);
|
|
}
|
|
const handler = (eventData) => {
|
|
host.logger.debug(`🔄 ${position} ${measurementType} from ${eventData.childName}: ${eventData.value} ${eventData.unit}`);
|
|
host._callMeasurementHandler(measurementType, eventData.value, position, eventData);
|
|
};
|
|
child.measurements.emitter.on(eventName, handler);
|
|
host.childMeasurementListeners.set(key, { emitter: child.measurements.emitter, eventName, handler });
|
|
}
|
|
|
|
function detachAllListeners(host) {
|
|
if (!host.childMeasurementListeners) return;
|
|
for (const [, e] of host.childMeasurementListeners) {
|
|
if (typeof e.emitter?.off === 'function') e.emitter.off(e.eventName, e.handler);
|
|
else if (typeof e.emitter?.removeListener === 'function') e.emitter.removeListener(e.eventName, e.handler);
|
|
}
|
|
host.childMeasurementListeners.clear();
|
|
}
|
|
|
|
module.exports = { registerMeasurementChild, detachAllListeners };
|