askeroo
Version:
A modern CLI prompt library with flow control, history navigation, and conditional prompts
216 lines • 7.99 kB
JavaScript
// Completed fields store using the store factory pattern
// Uses createStore for automatic reactive updates
import { createStore } from "../../core/store.js";
// Create the completed fields store
export const completedFieldsStore = createStore({
fieldState: {
values: {},
visited: new Set(),
completed: new Set(),
properties: new Map(),
messages: {},
groupNames: {},
groupIds: {},
},
promptOrderState: {
rootFieldHistory: [],
groupFieldHistory: new Map(),
},
treeManager: null,
revision: 0,
});
// Set the tree manager (called from PromptApp)
export function setTreeManager(manager) {
completedFieldsStore.update((state) => {
state.treeManager = manager;
});
}
// Notify that tree has changed (called from PromptApp after tree updates)
export function notifyTreeChanged() {
completedFieldsStore.update((state) => {
state.revision += 1;
});
}
// Get current completed fields state (legacy support)
export function getCompletedFieldsState() {
const store = completedFieldsStore.get();
return {
fieldState: store.fieldState,
promptOrderState: store.promptOrderState,
treeManager: store.treeManager,
revision: store.revision,
};
}
// Helper functions for formatting values and extracting field messages
function formatValue(value, fieldProperties) {
// Handle empty arrays
if (Array.isArray(value)) {
if (value.length === 0) {
return "None";
}
// For multi-select fields, get the labels from the options
if (fieldProperties &&
fieldProperties.options &&
Array.isArray(fieldProperties.options)) {
const selectedLabels = value
.map((val) => {
const option = fieldProperties.options.find((opt) => opt.value === val);
return option ? option.label : val;
})
.filter(Boolean);
return selectedLabels.join(", ");
}
return value.join(", ");
}
if (typeof value === "boolean") {
// For confirm fields, try to get the label from options
if (fieldProperties &&
fieldProperties.options &&
Array.isArray(fieldProperties.options)) {
const option = fieldProperties.options.find((opt) => opt.value === value);
return option ? option.label : value.toString();
}
return value ? "Yes" : "No";
}
// Handle falsey values (null, undefined, empty string, 0, false)
if (!value && value !== 0 && value !== false) {
if (value === null)
return "None";
if (value === undefined)
return "Not set";
if (value === "")
return "Empty";
return "None";
}
// For radio fields, get the label from options
if (fieldProperties &&
fieldProperties.options &&
Array.isArray(fieldProperties.options)) {
const option = fieldProperties.options.find((opt) => opt.value === value);
if (option) {
return option.label;
}
}
return String(value);
}
// Get completed fields as formatted objects
export function getCompletedFields() {
const fields = [];
const { fieldState, promptOrderState } = completedFieldsStore.get();
// Helper function to create field object
const createField = (fieldId, index) => {
if (!fieldState.completed.has(fieldId) ||
fieldState.values[fieldId] === undefined) {
return null;
}
const value = fieldState.values[fieldId];
const groupName = fieldState.groupNames[fieldId];
const groupId = fieldState.groupIds[fieldId];
// Get the original field properties
const originalProperties = fieldState.properties.get(fieldId) || {};
// Use the original field's label and shortLabel properties
const label = originalProperties.label ||
originalProperties.message ||
fieldState.messages[fieldId] ||
fieldId;
const shortLabel = originalProperties.shortLabel;
// Format the value using the original field properties
const formattedValue = formatValue(value, originalProperties);
return {
id: fieldId,
groupName,
groupId,
label,
shortLabel,
value: String(value),
formattedValue,
timestamp: index, // Use index as ordering timestamp
meta: originalProperties.meta, // Include meta from original field properties
};
};
// Use ordering information if available
if (promptOrderState?.rootFieldHistory &&
promptOrderState?.groupFieldHistory) {
// Create a combined chronological list
const allFieldsInOrder = [];
// Add root fields with their position markers
promptOrderState.rootFieldHistory.forEach((fieldInfo) => {
allFieldsInOrder.push({ id: fieldInfo.id, type: "root" });
});
// Add group fields with their position markers
for (const [groupId, groupFields,] of promptOrderState.groupFieldHistory) {
groupFields.forEach((fieldInfo) => {
allFieldsInOrder.push({
id: fieldInfo.id,
type: "group",
groupId,
});
});
}
// Sort by completion timestamp (when they were actually completed)
allFieldsInOrder.sort((a, b) => {
// Get the completion order from the Set iteration order
const aCompleted = Array.from(fieldState.completed).indexOf(a.id);
const bCompleted = Array.from(fieldState.completed).indexOf(b.id);
return aCompleted - bCompleted;
});
// Create fields in the correct chronological order
allFieldsInOrder.forEach((fieldInfo, index) => {
const field = createField(fieldInfo.id, index);
if (field) {
fields.push(field);
}
});
}
else {
// Fallback to old behavior if ordering info is not available
let index = 0;
for (const fieldId of fieldState.completed) {
const field = createField(fieldId, index++);
if (field) {
fields.push(field);
}
}
}
return fields;
}
// NEW TREE-BASED APPROACH: Get completed fields directly from tree
export function getCompletedFieldsData() {
const treeManager = completedFieldsStore.get().treeManager;
if (!treeManager) {
// Fallback to legacy approach if tree manager not set yet
return getCompletedFields();
}
const completedFields = [];
treeManager.traverseDepthFirst((node) => {
if (node.type === "field" &&
node.completed &&
!node.excludeFromCompleted &&
!node.hideOnCompletion &&
node.value !== undefined) {
const fieldProperties = node.properties || {};
const label = fieldProperties.label ||
fieldProperties.message ||
node.label ||
`${node.fieldType} field`;
const shortLabel = fieldProperties.shortLabel;
completedFields.push({
id: node.id,
label,
shortLabel,
value: node.value,
formattedValue: formatValue(node.value, fieldProperties),
groupLabel: node.parent?.type === "group"
? node.parent.label
: undefined,
meta: fieldProperties.meta,
});
}
});
return completedFields;
}
// Clear all completed fields data (for testing/reset)
export function clearCompletedFieldsStore() {
completedFieldsStore.reset();
}
//# sourceMappingURL=completed-fields-store.js.map