fix: code validator false positives and null property removal (#294, #293, #611) (#637)

- Fix $() node reference triggering "Invalid $ usage" warning by adding ( and _ to regex lookahead
- Fix helper function primitive returns triggering "Cannot return primitive values" error
- Fix null values in diff engine causing Zod validation errors — null now deletes properties
- Update property removal docs from undefined to null

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Romuald Członkowski
2026-03-15 11:26:44 +01:00
committed by GitHub
parent 599bc664d0
commit 65ab94deb2
16 changed files with 339 additions and 89 deletions

View File

@@ -1374,8 +1374,11 @@ export class NodeSpecificValidators {
});
}
// Check for primitive return
if (/return\s+(true|false|null|undefined|\d+|['"`])/m.test(code)) {
// Skip primitive return check when helper functions are present,
// since we can't distinguish top-level vs nested returns without AST.
// Matches: function name(), const/let/var name = [async] function/arrow
const hasHelperFunctions = /(?:function\s+\w+\s*\(|(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>|\w+\s*=>))/.test(code);
if (!hasHelperFunctions && /return\s+(true|false|null|undefined|\d+|['"`])/m.test(code)) {
errors.push({
type: 'invalid_value',
property: 'jsCode',
@@ -1487,7 +1490,7 @@ export class NodeSpecificValidators {
// Check for common variable mistakes
if (language === 'javaScript') {
// Using $ without proper variable
if (/\$(?![a-zA-Z])/.test(code) && !code.includes('${')) {
if (/\$(?![a-zA-Z_(])/.test(code) && !code.includes('${')) {
warnings.push({
type: 'best_practice',
message: 'Invalid $ usage detected',

View File

@@ -1237,15 +1237,21 @@ export class WorkflowDiffEngine {
private setNestedProperty(obj: any, path: string, value: any): void {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object') {
if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
if (value === null) return; // parent path doesn't exist, nothing to delete
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
const finalKey = keys[keys.length - 1];
if (value === null) {
delete current[finalKey];
} else {
current[finalKey] = value;
}
}
}