mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-29 08:14:57 +00:00
- Python: class extending NodeExecutor + factory.py (80+ plugins) - TypeScript: class implements NodeExecutor + factory.ts (7 groups, 116 classes) - Go: struct with methods + factory.go (36 plugins) - Rust: struct impl NodeExecutor trait + factory.rs (54 plugins) - Mojo: struct + factory.mojo (11 plugins) All package.json files now include: - files array listing source files - metadata.class/struct field - metadata.entrypoint field This enables a unified plugin loading system across all languages with no import side effects (Spring-style DI pattern). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
248 lines
9.0 KiB
TypeScript
248 lines
9.0 KiB
TypeScript
/**
|
|
* Workflow plugin: String manipulation operations.
|
|
*/
|
|
|
|
import { NodeExecutor, ExecuteInputs, ExecuteResult, createTemplateContext } from '../../base';
|
|
import { interpolateTemplate } from '../../../executor/ts/utils/template-engine';
|
|
|
|
const resolve = (value: any, ctx: any): any => {
|
|
if (typeof value === 'string' && value.startsWith('{{') && value.endsWith('}}')) {
|
|
return interpolateTemplate(value, ctx);
|
|
}
|
|
return value;
|
|
};
|
|
|
|
export class StringConcat implements NodeExecutor {
|
|
readonly nodeType = 'string.concat';
|
|
readonly category = 'string';
|
|
readonly description = 'Concatenate multiple strings with an optional separator';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const values = (inputs.node.parameters.values || []).map((v: any) => resolve(v, ctx));
|
|
const separator = resolve(inputs.node.parameters.separator ?? '', ctx);
|
|
return { result: values.join(separator) };
|
|
}
|
|
}
|
|
|
|
export class StringFormat implements NodeExecutor {
|
|
readonly nodeType = 'string.format';
|
|
readonly category = 'string';
|
|
readonly description = 'Format string with variables using {key} placeholders';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const template = resolve(inputs.node.parameters.template || '', ctx);
|
|
const variables = inputs.node.parameters.variables || {};
|
|
const result = template.replace(/\{(\w+)\}/g, (_: string, key: string) =>
|
|
variables[key] !== undefined ? String(variables[key]) : `{${key}}`
|
|
);
|
|
return { result };
|
|
}
|
|
}
|
|
|
|
export class StringLength implements NodeExecutor {
|
|
readonly nodeType = 'string.length';
|
|
readonly category = 'string';
|
|
readonly description = 'Get the length of a string';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
return { result: value.length };
|
|
}
|
|
}
|
|
|
|
export class StringLower implements NodeExecutor {
|
|
readonly nodeType = 'string.lower';
|
|
readonly category = 'string';
|
|
readonly description = 'Convert string to lowercase';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
return { result: value.toLowerCase() };
|
|
}
|
|
}
|
|
|
|
export class StringUpper implements NodeExecutor {
|
|
readonly nodeType = 'string.upper';
|
|
readonly category = 'string';
|
|
readonly description = 'Convert string to uppercase';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
return { result: value.toUpperCase() };
|
|
}
|
|
}
|
|
|
|
export class StringTrim implements NodeExecutor {
|
|
readonly nodeType = 'string.trim';
|
|
readonly category = 'string';
|
|
readonly description = 'Trim whitespace from string (both ends, start only, or end only)';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const mode = inputs.node.parameters.mode || 'both';
|
|
let result: string;
|
|
switch (mode) {
|
|
case 'start': result = value.trimStart(); break;
|
|
case 'end': result = value.trimEnd(); break;
|
|
default: result = value.trim();
|
|
}
|
|
return { result };
|
|
}
|
|
}
|
|
|
|
export class StringReplace implements NodeExecutor {
|
|
readonly nodeType = 'string.replace';
|
|
readonly category = 'string';
|
|
readonly description = 'Replace substring in string (single or all occurrences)';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const search = resolve(inputs.node.parameters.search || '', ctx);
|
|
const replacement = resolve(inputs.node.parameters.replacement ?? '', ctx);
|
|
const all = inputs.node.parameters.all ?? false;
|
|
const result = all
|
|
? value.replaceAll(search, replacement)
|
|
: value.replace(search, replacement);
|
|
return { result };
|
|
}
|
|
}
|
|
|
|
export class StringSplit implements NodeExecutor {
|
|
readonly nodeType = 'string.split';
|
|
readonly category = 'string';
|
|
readonly description = 'Split string into array by separator';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const separator = resolve(inputs.node.parameters.separator ?? ',', ctx);
|
|
const limit = inputs.node.parameters.limit;
|
|
const result = limit ? value.split(separator, limit) : value.split(separator);
|
|
return { result };
|
|
}
|
|
}
|
|
|
|
export class StringJoin implements NodeExecutor {
|
|
readonly nodeType = 'string.join';
|
|
readonly category = 'string';
|
|
readonly description = 'Join array elements into string with separator';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const values = resolve(inputs.node.parameters.values || [], ctx);
|
|
const separator = resolve(inputs.node.parameters.separator ?? ',', ctx);
|
|
const result = Array.isArray(values) ? values.join(separator) : String(values);
|
|
return { result };
|
|
}
|
|
}
|
|
|
|
export class StringSubstring implements NodeExecutor {
|
|
readonly nodeType = 'string.substring';
|
|
readonly category = 'string';
|
|
readonly description = 'Extract substring from string by start and end index';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const startIdx = inputs.node.parameters.start ?? 0;
|
|
const endIdx = inputs.node.parameters.end;
|
|
const result = endIdx !== undefined ? value.substring(startIdx, endIdx) : value.substring(startIdx);
|
|
return { result };
|
|
}
|
|
}
|
|
|
|
export class StringIncludes implements NodeExecutor {
|
|
readonly nodeType = 'string.includes';
|
|
readonly category = 'string';
|
|
readonly description = 'Check if string contains a substring';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const search = String(resolve(inputs.node.parameters.search || '', ctx));
|
|
return { result: value.includes(search) };
|
|
}
|
|
}
|
|
|
|
export class StringStartsWith implements NodeExecutor {
|
|
readonly nodeType = 'string.startsWith';
|
|
readonly category = 'string';
|
|
readonly description = 'Check if string starts with a prefix';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const prefix = String(resolve(inputs.node.parameters.prefix || '', ctx));
|
|
return { result: value.startsWith(prefix) };
|
|
}
|
|
}
|
|
|
|
export class StringEndsWith implements NodeExecutor {
|
|
readonly nodeType = 'string.endsWith';
|
|
readonly category = 'string';
|
|
readonly description = 'Check if string ends with a suffix';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const suffix = String(resolve(inputs.node.parameters.suffix || '', ctx));
|
|
return { result: value.endsWith(suffix) };
|
|
}
|
|
}
|
|
|
|
export class StringPadStart implements NodeExecutor {
|
|
readonly nodeType = 'string.padStart';
|
|
readonly category = 'string';
|
|
readonly description = 'Pad string at the start to reach target length';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const length = inputs.node.parameters.length || value.length;
|
|
const fillString = resolve(inputs.node.parameters.fillString ?? ' ', ctx);
|
|
return { result: value.padStart(length, fillString) };
|
|
}
|
|
}
|
|
|
|
export class StringPadEnd implements NodeExecutor {
|
|
readonly nodeType = 'string.padEnd';
|
|
readonly category = 'string';
|
|
readonly description = 'Pad string at the end to reach target length';
|
|
|
|
execute(inputs: ExecuteInputs): ExecuteResult {
|
|
const ctx = createTemplateContext(inputs);
|
|
const value = String(resolve(inputs.node.parameters.value || '', ctx));
|
|
const length = inputs.node.parameters.length || value.length;
|
|
const fillString = resolve(inputs.node.parameters.fillString ?? ' ', ctx);
|
|
return { result: value.padEnd(length, fillString) };
|
|
}
|
|
}
|
|
|
|
// Export all string plugin classes
|
|
export const stringPluginClasses = {
|
|
'string.concat': StringConcat,
|
|
'string.format': StringFormat,
|
|
'string.length': StringLength,
|
|
'string.lower': StringLower,
|
|
'string.upper': StringUpper,
|
|
'string.trim': StringTrim,
|
|
'string.replace': StringReplace,
|
|
'string.split': StringSplit,
|
|
'string.join': StringJoin,
|
|
'string.substring': StringSubstring,
|
|
'string.includes': StringIncludes,
|
|
'string.startsWith': StringStartsWith,
|
|
'string.endsWith': StringEndsWith,
|
|
'string.padStart': StringPadStart,
|
|
'string.padEnd': StringPadEnd,
|
|
};
|
|
|
|
export default stringPluginClasses;
|