@memberjunction/react-runtime
Version:
Platform-agnostic React component runtime for MemberJunction. Provides core compilation, registry, and execution capabilities for React components in any JavaScript environment.
203 lines • 7.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractPropPaths = exports.wrapCallbacksWithLogging = exports.createPropsTransformer = exports.mergeProps = exports.validateComponentProps = exports.normalizeStyles = exports.normalizeCallbacks = exports.buildComponentProps = void 0;
const core_1 = require("@memberjunction/core");
function buildComponentProps(data = {}, userState = {}, utilities = {}, callbacks = {
OpenEntityRecord: () => { },
RegisterMethod: () => { },
CreateSimpleNotification: () => { }
}, components = {}, styles, options = {}, onStateChanged) {
const { validate = true, transformData, transformState, debounceUpdateUserState = 3000 } = options;
const transformedData = transformData ? transformData(data) : data;
const transformedState = transformState ? transformState(userState) : userState;
const props = {
data: transformedData,
userState: transformedState,
utilities,
callbacks: normalizeCallbacks(callbacks, debounceUpdateUserState),
components,
styles: normalizeStyles(styles),
onStateChanged
};
if (validate) {
validateComponentProps(props);
}
return props;
}
exports.buildComponentProps = buildComponentProps;
const updateUserStateSubjects = new WeakMap();
const updateUserStateSubscriptions = new WeakMap();
const loopDetectionStates = new WeakMap();
function deepEqual(obj1, obj2) {
if (obj1 === obj2)
return true;
if (!obj1 || !obj2)
return false;
if (typeof obj1 !== 'object' || typeof obj2 !== 'object')
return false;
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length)
return false;
for (const key of keys1) {
if (!keys2.includes(key))
return false;
if (!deepEqual(obj1[key], obj2[key]))
return false;
}
return true;
}
function normalizeCallbacks(callbacks, debounceMs = 3000) {
const normalized = {
OpenEntityRecord: callbacks?.OpenEntityRecord || (() => { }),
RegisterMethod: callbacks?.RegisterMethod || (() => { }),
CreateSimpleNotification: callbacks?.CreateSimpleNotification || (() => { })
};
if (callbacks) {
Object.keys(callbacks).forEach(key => {
if (typeof callbacks[key] === 'function' && !normalized.hasOwnProperty(key)) {
normalized[key] = callbacks[key];
}
});
}
return normalized;
}
exports.normalizeCallbacks = normalizeCallbacks;
function normalizeStyles(styles) {
return styles;
}
exports.normalizeStyles = normalizeStyles;
function validateComponentProps(props) {
if (props.data === null || props.data === undefined) {
throw new Error('Component props.data cannot be null or undefined');
}
if (props.userState === null) {
throw new Error('Component props.userState cannot be null');
}
if (props.utilities === null) {
throw new Error('Component props.utilities cannot be null');
}
if (!props.callbacks || typeof props.callbacks !== 'object') {
throw new Error('Component props.callbacks must be an object');
}
for (const [key, value] of Object.entries(props.callbacks)) {
if (value !== undefined && typeof value !== 'function') {
throw new Error(`Component callback "${key}" must be a function`);
}
}
}
exports.validateComponentProps = validateComponentProps;
function mergeProps(...propsList) {
const merged = {
data: {},
userState: {},
utilities: {},
callbacks: {},
components: {},
styles: {}
};
for (const props of propsList) {
if (props.data) {
merged.data = { ...merged.data, ...props.data };
}
if (props.userState) {
merged.userState = { ...merged.userState, ...props.userState };
}
if (props.utilities) {
merged.utilities = { ...merged.utilities, ...props.utilities };
}
if (props.callbacks) {
merged.callbacks = { ...merged.callbacks, ...props.callbacks };
}
if (props.components) {
merged.components = { ...merged.components, ...props.components };
}
if (props.styles) {
merged.styles = { ...merged.styles, ...props.styles };
}
}
return merged;
}
exports.mergeProps = mergeProps;
function createPropsTransformer(transformations) {
return (props) => {
const transformed = { ...props };
for (const [path, transformer] of Object.entries(transformations)) {
const pathParts = path.split('.');
let current = transformed;
for (let i = 0; i < pathParts.length - 1; i++) {
if (!current[pathParts[i]]) {
current[pathParts[i]] = {};
}
current = current[pathParts[i]];
}
const lastPart = pathParts[pathParts.length - 1];
if (current[lastPart] !== undefined) {
current[lastPart] = transformer(current[lastPart]);
}
}
return transformed;
};
}
exports.createPropsTransformer = createPropsTransformer;
function wrapCallbacksWithLogging(callbacks, componentName) {
const wrapped = {
OpenEntityRecord: callbacks?.OpenEntityRecord || (() => { }),
RegisterMethod: callbacks?.RegisterMethod || (() => { }),
CreateSimpleNotification: callbacks?.CreateSimpleNotification || (() => { })
};
Object.keys(callbacks).forEach(key => {
if (key !== 'OpenEntityRecord' && key !== 'RegisterMethod' && key !== 'CreateSimpleNotification' && typeof callbacks[key] === 'function') {
wrapped[key] = (...args) => {
if (!(0, core_1.GetProductionStatus)()) {
(0, core_1.LogStatus)(`[${componentName}] ${key} called with args:`, undefined, args);
}
return callbacks[key](...args);
};
}
});
if (callbacks.OpenEntityRecord) {
wrapped.OpenEntityRecord = (entityName, key) => {
if (!(0, core_1.GetProductionStatus)()) {
(0, core_1.LogStatus)(`[${componentName}] OpenEntityRecord called:`, undefined, { entityName, key });
}
callbacks.OpenEntityRecord(entityName, key);
};
}
if (callbacks.RegisterMethod) {
wrapped.RegisterMethod = (methodName, handler) => {
if (!(0, core_1.GetProductionStatus)()) {
(0, core_1.LogStatus)(`[${componentName}] RegisterMethod called for:`, undefined, methodName);
}
callbacks.RegisterMethod(methodName, handler);
};
}
if (callbacks.CreateSimpleNotification) {
wrapped.CreateSimpleNotification = (message, style, hideAfter) => {
if (!(0, core_1.GetProductionStatus)()) {
(0, core_1.LogStatus)(`[${componentName}] CreateSimpleNotification called:`, undefined, { message, style, hideAfter });
}
callbacks.CreateSimpleNotification(message, style, hideAfter);
};
}
return wrapped;
}
exports.wrapCallbacksWithLogging = wrapCallbacksWithLogging;
function extractPropPaths(componentCode) {
const paths = [];
const patterns = [
/props\.data\.(\w+)/g,
/props\.userState\.(\w+)/g,
/props\.utilities\.(\w+)/g,
/props\.callbacks\.(\w+)/g
];
for (const pattern of patterns) {
let match;
while ((match = pattern.exec(componentCode)) !== null) {
paths.push(match[0]);
}
}
return [...new Set(paths)];
}
exports.extractPropPaths = extractPropPaths;
//# sourceMappingURL=prop-builder.js.map