@tensorify.io/sdk
Version:
TypeScript SDK for developing Tensorify plugins with V2-Alpha definition/execution pattern and legacy compatibility
482 lines (472 loc) • 15.1 kB
JavaScript
;
/**
* Utility functions for plugin development and CLI integration
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generatePluginManifest = generatePluginManifest;
exports.readPackageJson = readPackageJson;
exports.writeManifestFile = writeManifestFile;
exports.buildPluginManifest = buildPluginManifest;
exports.validatePlugin = validatePlugin;
exports.validatePluginSettings = validatePluginSettings;
exports.createDefaultSettings = createDefaultSettings;
exports.mergeSettingsWithDefaults = mergeSettingsWithDefaults;
exports.processDynamicLabelTemplate = processDynamicLabelTemplate;
exports.generateVariableName = generateVariableName;
exports.sanitizeVariableName = sanitizeVariableName;
exports.indentCode = indentCode;
exports.autoDetectEntrypointClassName = autoDetectEntrypointClassName;
exports.isValidPluginDirectory = isValidPluginDirectory;
exports.createPluginTemplate = createPluginTemplate;
exports.getPluginMetadata = getPluginMetadata;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const core_1 = require("../types/core");
const settings_1 = require("../types/settings");
// ========================================
// MANIFEST GENERATION UTILITIES
// ========================================
/**
* Generate a plugin manifest from a plugin instance and package.json
*
* @param plugin Plugin instance
* @param packageJsonPath Path to package.json file
* @param entrypointClassName Name of the plugin class
* @returns Generated manifest
*/
function generatePluginManifest(plugin, packageJsonPath, entrypointClassName) {
const packageInfo = readPackageJson(packageJsonPath);
return plugin.generateManifest(packageInfo, entrypointClassName);
}
/**
* Read and parse package.json file
*
* @param packageJsonPath Path to package.json
* @returns Parsed package.json information
*/
function readPackageJson(packageJsonPath) {
try {
const content = fs.readFileSync(packageJsonPath, "utf-8");
const packageJson = JSON.parse(content);
return {
name: packageJson.name,
version: packageJson.version,
description: packageJson.description,
author: packageJson.author,
main: packageJson.main,
keywords: packageJson.keywords,
dependencies: packageJson.dependencies,
peerDependencies: packageJson.peerDependencies,
repository: packageJson.repository,
tensorify: packageJson.tensorify,
};
}
catch (error) {
throw new Error(`Failed to read package.json: ${error}`);
}
}
/**
* Write manifest to file
*
* @param manifest Plugin manifest to write
* @param outputPath Output file path
*/
function writeManifestFile(manifest, outputPath) {
try {
const manifestJson = JSON.stringify(manifest, null, 2);
const dir = path.dirname(outputPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(outputPath, manifestJson, "utf-8");
}
catch (error) {
throw new Error(`Failed to write manifest file: ${error}`);
}
}
/**
* Complete build workflow: generate manifest and write to file
*
* @param plugin Plugin instance
* @param packageJsonPath Path to package.json
* @param entrypointClassName Plugin class name
* @param outputPath Output manifest file path
* @returns Generated manifest
*/
function buildPluginManifest(plugin, packageJsonPath, entrypointClassName, outputPath) {
const manifest = generatePluginManifest(plugin, packageJsonPath, entrypointClassName);
writeManifestFile(manifest, outputPath);
return manifest;
}
// ========================================
// PLUGIN VALIDATION UTILITIES
// ========================================
/**
* Validate a plugin instance comprehensively
*
* @param plugin Plugin instance to validate
* @returns Validation result
*/
function validatePlugin(plugin) {
// Create default settings for validation
const defaultSettings = plugin.createDefaultSettings();
// Validate the settings
return plugin.validateSettings(defaultSettings);
}
/**
* Validate plugin settings against field definitions
*
* @param plugin Plugin instance
* @param settings Settings to validate
* @returns Validation result with detailed feedback
*/
function validatePluginSettings(plugin, settings) {
const result = plugin.validateSettings(settings);
if (result.isValid) {
return {
isValid: true,
message: "All settings are valid",
};
}
const details = result.errors.map((error) => `${error.path}: ${error.message}`);
return {
isValid: false,
message: `Validation failed with ${result.errors.length} error(s)`,
details,
};
}
// ========================================
// SETTINGS UTILITIES
// ========================================
/**
* Create default settings object from field definitions
*
* @param settingsFields Array of settings field definitions
* @returns Default settings object
*/
function createDefaultSettings(settingsFields) {
const settings = {
variableName: `plugin_${Date.now()}`,
labelName: "Plugin",
};
for (const field of settingsFields) {
if (field.defaultValue !== undefined) {
settings[field.key] = field.defaultValue;
}
else {
// Use data type default
settings[field.key] = settings_1.DEFAULT_VALUES[field.dataType];
}
}
return settings;
}
/**
* Merge user settings with defaults
*
* @param userSettings User-provided settings
* @param settingsFields Settings field definitions
* @returns Merged settings with defaults applied
*/
function mergeSettingsWithDefaults(userSettings, settingsFields) {
const defaults = createDefaultSettings(settingsFields);
return { ...defaults, ...userSettings };
}
/**
* Generate dynamic label from template and settings
*
* @param template Template string with {placeholders}
* @param settings Settings object
* @returns Processed label string
*/
function processDynamicLabelTemplate(template, settings) {
if (!template)
return "";
let result = template;
for (const [key, value] of Object.entries(settings)) {
const placeholder = `{${key}}`;
result = result.replace(new RegExp(placeholder, "g"), String(value));
}
return result;
}
// ========================================
// CODE GENERATION UTILITIES
// ========================================
/**
* Generate a unique variable name with prefix
*
* @param prefix Variable name prefix
* @returns Unique variable name
*/
function generateVariableName(prefix = "var") {
const timestamp = Date.now();
const random = Math.floor(Math.random() * 1000);
return `${prefix}_${timestamp}_${random}`;
}
/**
* Sanitize a string to be a valid variable name
*
* @param name Input string
* @returns Sanitized variable name
*/
function sanitizeVariableName(name) {
return name
.replace(/[^a-zA-Z0-9_]/g, "_")
.replace(/^[0-9]/, "_$&")
.replace(/_+/g, "_")
.toLowerCase();
}
/**
* Indent code by specified levels
*
* @param code Code string to indent
* @param levels Number of indentation levels
* @param indentString String to use for each level (default: 2 spaces)
* @returns Indented code
*/
function indentCode(code, levels, indentString = " ") {
if (levels <= 0)
return code;
const indent = indentString.repeat(levels);
return code
.split("\n")
.map((line) => (line.trim() ? indent + line : line))
.join("\n");
}
// ========================================
// FILE SYSTEM UTILITIES
// ========================================
/**
* Auto-detect the entrypoint class name from source files
*
* @param sourceDir Source directory to search
* @returns Detected class name or null
*/
function autoDetectEntrypointClassName(sourceDir) {
try {
const indexPath = path.join(sourceDir, "index.ts");
if (!fs.existsSync(indexPath))
return null;
const content = fs.readFileSync(indexPath, "utf-8");
// Look for default export class
const defaultExportMatch = content.match(/export\s+default\s+class\s+(\w+)/);
if (defaultExportMatch) {
return defaultExportMatch[1];
}
// Look for named export class that extends TensorifyPlugin
const namedExportMatch = content.match(/export\s+class\s+(\w+)\s+extends\s+TensorifyPlugin/);
if (namedExportMatch) {
return namedExportMatch[1];
}
return null;
}
catch (error) {
return null;
}
}
/**
* Check if a directory contains a valid plugin structure
*
* @param directory Directory to check
* @returns True if valid plugin structure
*/
function isValidPluginDirectory(directory) {
const requiredFiles = ["package.json", "tsconfig.json"];
const requiredDirs = ["src"];
for (const file of requiredFiles) {
if (!fs.existsSync(path.join(directory, file))) {
return false;
}
}
for (const dir of requiredDirs) {
if (!fs.existsSync(path.join(directory, dir))) {
return false;
}
}
// Check for index.ts in src
if (!fs.existsSync(path.join(directory, "src", "index.ts"))) {
return false;
}
return true;
}
// ========================================
// DEVELOPMENT UTILITIES
// ========================================
/**
* Create a minimal plugin template
*
* @param pluginName Human-readable plugin name
* @param pluginId Unique plugin identifier
* @param nodeType Plugin category
* @returns Plugin template code
*/
function createPluginTemplate(pluginName, pluginId, nodeType = core_1.NodeType.CUSTOM) {
return `import {
TensorifyPlugin,
IPluginDefinition,
PluginSettings,
PluginCodeGenerationContext,
NodeType,
PluginCapability,
HandleViewType,
HandlePosition,
EdgeType,
NodeViewContainerType,
IconType,
SettingsUIType,
SettingsDataType
} from '@tensorify.io/sdk';
export default class ${pluginName.replace(/[^a-zA-Z0-9]/g, "")}Plugin extends TensorifyPlugin {
constructor() {
const definition: IPluginDefinition = {
// Core Metadata (id, name, description, version, nodeType are derived from package.json)
// nodeType is derived from package.json tensorify.pluginType field
// Visual Configuration
visual: {
containerType: NodeViewContainerType.DEFAULT,
size: {
width: 200,
height: 120
},
padding: {
inner: 16,
outer: 8,
extraPadding: false
},
styling: {
borderRadius: 8,
borderWidth: 2,
shadowLevel: 1,
theme: "auto"
},
icons: {
primary: {
type: IconType.LUCIDE,
value: "box"
},
secondary: [],
showIconBackground: true,
iconSize: "medium"
},
labels: {
title: "${pluginName}",
showLabels: true,
labelPosition: "top"
}
},
// Handle Configuration
inputHandles: [
{
id: "input",
position: HandlePosition.LEFT,
viewType: HandleViewType.DEFAULT,
required: false,
label: "Input",
edgeType: EdgeType.DEFAULT,
dataType: "any"
}
],
outputHandles: [
{
id: "output",
position: HandlePosition.RIGHT,
viewType: HandleViewType.DEFAULT,
label: "Output",
edgeType: EdgeType.DEFAULT,
dataType: "any"
}
],
// Settings Configuration
settingsFields: [
{
key: "message",
label: "Message",
type: SettingsUIType.INPUT_TEXT,
dataType: SettingsDataType.STRING,
defaultValue: "Hello World!",
required: false,
description: "Message to display in generated code"
}
],
// Plugin Metadata
capabilities: [PluginCapability.CODE_GENERATION],
requirements: {
minSdkVersion: "1.0.0",
dependencies: []
}
};
super(definition);
}
public getTranslationCode(
settings: PluginSettings,
children?: any,
context?: PluginCodeGenerationContext
): string {
// Validate settings
const validation = this.validateSettings(settings);
if (!validation.isValid) {
throw new Error(\`Settings validation failed: \${validation.errors.map(e => e.message).join(', ')}\`);
}
// Generate code
const message = settings.message || "Hello World!";
const variableName = settings.variableName;
return \`# ${pluginName} Plugin
\${variableName} = "\${message}"
print(\${variableName})\`;
}
}`;
}
/**
* Get plugin metadata summary
*
* @param plugin Plugin instance
* @returns Metadata summary object
*/
function getPluginMetadata(plugin) {
const definition = plugin.getDefinition();
return {
id: definition.id,
name: definition.name,
version: definition.version,
nodeType: definition.nodeType,
inputHandles: definition.inputHandles.length,
outputHandles: definition.outputHandles.length,
settingsFields: definition.settingsFields.length,
capabilities: definition.capabilities,
hasVisualConfig: !!definition.visual,
hasDynamicLabel: !!definition.visual.labels.dynamicLabelTemplate,
};
}
//# sourceMappingURL=plugin-utils.js.map