UNPKG

@tensorify.io/sdk

Version:

TypeScript SDK for developing Tensorify plugins with comprehensive validation, frontend enforcement, and publishing tools

482 lines (472 loc) 15.1 kB
"use strict"; /** * 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