mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 12:05:54 +00:00
164 lines
5.6 KiB
Python
164 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare YAML node definitions with frontend node-configs."""
|
|
|
|
import yaml
|
|
import os
|
|
import re
|
|
import json
|
|
|
|
# 1. Parse YAML files
|
|
yaml_dir = 'src/langbot/templates/metadata/nodes'
|
|
yaml_nodes = {}
|
|
|
|
for filename in sorted(os.listdir(yaml_dir)):
|
|
if filename.endswith('.yaml'):
|
|
filepath = os.path.join(yaml_dir, filename)
|
|
with open(filepath, 'r') as f:
|
|
data = yaml.safe_load(f)
|
|
node_name = data.get('name', filename.replace('.yaml', ''))
|
|
yaml_nodes[node_name] = {
|
|
'category': data.get('category', ''),
|
|
'inputs': [i['name'] for i in data.get('inputs', [])],
|
|
'outputs': [o['name'] for o in data.get('outputs', [])],
|
|
'config': [c['name'] for c in data.get('config', [])]
|
|
}
|
|
|
|
# 2. Parse frontend node-configs TypeScript files
|
|
node_configs_dir = 'web/src/app/home/workflows/components/workflow-editor/node-configs'
|
|
|
|
frontend_nodes = {}
|
|
|
|
def parse_ts_file(filepath):
|
|
"""Parse a TypeScript file to extract node configurations."""
|
|
with open(filepath, 'r') as f:
|
|
content = f.read()
|
|
|
|
# Find all node type definitions
|
|
# Pattern: nodeType: 'xxx'
|
|
node_type_pattern = r"nodeType:\s*'([^']+)'"
|
|
node_types = re.findall(node_type_pattern, content)
|
|
|
|
# For each node type, extract inputs, outputs, and config
|
|
for node_type in node_types:
|
|
# Find the config object for this node type
|
|
# Look for the section between this nodeType and the next one or end of object
|
|
pattern = rf"nodeType:\s*'({re.escape(node_type)})'.*?(?=nodeType:|export\s+(const|function)|$)"
|
|
match = re.search(pattern, content, re.DOTALL)
|
|
|
|
if match:
|
|
section = match.group(0)
|
|
|
|
# Extract inputs
|
|
inputs = re.findall(r"createInput\('([^']+)'", section)
|
|
|
|
# Extract outputs
|
|
outputs = re.findall(r"createOutput\('([^']+)'", section)
|
|
|
|
# Extract config names
|
|
config_names = re.findall(r"name:\s*'([^']+)'", section)
|
|
# Remove duplicates while preserving order
|
|
seen = set()
|
|
unique_config = []
|
|
for c in config_names:
|
|
if c not in seen:
|
|
seen.add(c)
|
|
unique_config.append(c)
|
|
|
|
frontend_nodes[node_type] = {
|
|
'inputs': inputs,
|
|
'outputs': outputs,
|
|
'config': unique_config
|
|
}
|
|
|
|
# Parse all config files
|
|
for filename in os.listdir(node_configs_dir):
|
|
if filename.endswith('.ts') and filename != 'types.ts' and filename != 'index.ts':
|
|
filepath = os.path.join(node_configs_dir, filename)
|
|
parse_ts_file(filepath)
|
|
|
|
# 3. Compare and report differences
|
|
print("=" * 80)
|
|
print("WORKFLOW NODE COMPARISON REPORT: YAML vs Frontend")
|
|
print("=" * 80)
|
|
|
|
all_node_types = sorted(set(list(yaml_nodes.keys()) + list(frontend_nodes.keys())))
|
|
|
|
discrepancies = []
|
|
|
|
for node_type in all_node_types:
|
|
yaml_def = yaml_nodes.get(node_type)
|
|
frontend_def = frontend_nodes.get(node_type)
|
|
|
|
node_discrepancies = []
|
|
|
|
if not yaml_def:
|
|
print(f"\n⚠️ {node_type}: ONLY in frontend (not in YAML)")
|
|
continue
|
|
if not frontend_def:
|
|
print(f"\n⚠️ {node_type}: ONLY in YAML (not in frontend)")
|
|
continue
|
|
|
|
# Compare inputs
|
|
yaml_inputs = set(yaml_def['inputs'])
|
|
frontend_inputs = set(frontend_def['inputs'])
|
|
if yaml_inputs != frontend_inputs:
|
|
only_yaml = yaml_inputs - frontend_inputs
|
|
only_frontend = frontend_inputs - yaml_inputs
|
|
node_discrepancies.append({
|
|
'type': 'inputs',
|
|
'only_yaml': list(only_yaml),
|
|
'only_frontend': list(only_frontend)
|
|
})
|
|
|
|
# Compare outputs
|
|
yaml_outputs = set(yaml_def['outputs'])
|
|
frontend_outputs = set(frontend_def['outputs'])
|
|
if yaml_outputs != frontend_outputs:
|
|
only_yaml = yaml_outputs - frontend_outputs
|
|
only_frontend = frontend_outputs - yaml_outputs
|
|
node_discrepancies.append({
|
|
'type': 'outputs',
|
|
'only_yaml': list(only_yaml),
|
|
'only_frontend': list(only_frontend)
|
|
})
|
|
|
|
# Compare config
|
|
yaml_config = set(yaml_def['config'])
|
|
frontend_config = set(frontend_def['config'])
|
|
if yaml_config != frontend_config:
|
|
only_yaml = yaml_config - frontend_config
|
|
only_frontend = frontend_config - yaml_config
|
|
node_discrepancies.append({
|
|
'type': 'config',
|
|
'only_yaml': list(only_yaml),
|
|
'only_frontend': list(only_frontend)
|
|
})
|
|
|
|
if node_discrepancies:
|
|
print(f"\n❌ {node_type} ({yaml_def['category']}): HAS DISCREPANCIES")
|
|
for d in node_discrepancies:
|
|
print(f" {d['type']}:")
|
|
if d['only_yaml']:
|
|
print(f" Only in YAML: {d['only_yaml']}")
|
|
if d['only_frontend']:
|
|
print(f" Only in Frontend: {d['only_frontend']}")
|
|
discrepancies.append((node_type, node_discrepancies))
|
|
else:
|
|
print(f"\n✅ {node_type} ({yaml_def['category']}): OK")
|
|
|
|
print(f"\n{'=' * 80}")
|
|
print(f"SUMMARY: {len(discrepancies)} nodes with discrepancies out of {len(all_node_types)} total")
|
|
print(f"{'=' * 80}")
|
|
|
|
# Output as JSON for further processing
|
|
output = {
|
|
'yaml_nodes': {k: v for k, v in yaml_nodes.items()},
|
|
'frontend_nodes': {k: v for k, v in frontend_nodes.items()},
|
|
'discrepancies': {k: v for k, v in discrepancies}
|
|
}
|
|
|
|
with open('node_comparison.json', 'w') as f:
|
|
json.dump(output, f, indent=2)
|
|
|
|
print(f"\nDetailed comparison saved to node_comparison.json")
|