UNPKG

prprompts-flutter-generator

Version:

AI-powered Flutter development with full automation + official extension support - Generate 32 security-audited guides & auto-implement in 2-3 hours. NEW v5.1: Official Claude Code plugin with hooks, Gemini TOML commands, Qwen MCP settings. Features: Comp

358 lines (323 loc) 9.95 kB
/** * ComponentModel.js * Represents a parsed React component with all its properties and metadata * * This model captures the complete structure of a React/React Native component * to facilitate conversion to Flutter widgets. */ /** * Component types supported * @enum {string} */ const ComponentType = { PAGE: 'page', WIDGET: 'widget', HOOK: 'hook', CONTEXT: 'context', HOC: 'hoc', // Higher-Order Component }; /** * State management patterns * @enum {string} */ const StateManagementPattern = { REDUX: 'redux', ZUSTAND: 'zustand', CONTEXT: 'context', USE_STATE: 'useState', MOBX: 'mobx', RECOIL: 'recoil', }; /** * Represents a component property/prop */ class ComponentProp { /** * @param {Object} options * @param {string} options.name - Property name * @param {string} options.type - Property type * @param {boolean} [options.isRequired=false] - Whether the prop is required * @param {string} [options.defaultValue] - Default value if any */ constructor({ name, type, isRequired = false, defaultValue = null }) { this._validate({ name, type }); this.name = name; this.type = type; this.isRequired = isRequired; this.defaultValue = defaultValue; } _validate({ name, type }) { if (!name || typeof name !== 'string') { throw new Error('ComponentProp: name is required and must be a string'); } if (!type || typeof type !== 'string') { throw new Error('ComponentProp: type is required and must be a string'); } } toJSON() { return { name: this.name, type: this.type, isRequired: this.isRequired, defaultValue: this.defaultValue, }; } static fromJSON(json) { return new ComponentProp(json); } } /** * Represents a state variable */ class StateVariable { /** * @param {Object} options * @param {string} options.name - Variable name * @param {string} options.type - Variable type * @param {string} [options.initialValue] - Initial value */ constructor({ name, type, initialValue = null }) { this._validate({ name, type }); this.name = name; this.type = type; this.initialValue = initialValue; } _validate({ name, type }) { if (!name || typeof name !== 'string') { throw new Error('StateVariable: name is required and must be a string'); } if (!type || typeof type !== 'string') { throw new Error('StateVariable: type is required and must be a string'); } } toJSON() { return { name: this.name, type: this.type, initialValue: this.initialValue, }; } static fromJSON(json) { return new StateVariable(json); } } /** * Represents an API endpoint */ class ApiEndpoint { /** * @param {Object} options * @param {string} options.method - HTTP method (GET, POST, PUT, DELETE, etc.) * @param {string} options.path - API endpoint path * @param {string} [options.description] - Endpoint description * @param {string[]} [options.parameters=[]] - Parameters used */ constructor({ method, path, description = null, parameters = [] }) { this._validate({ method, path }); this.method = method.toUpperCase(); this.path = path; this.description = description; this.parameters = parameters; } _validate({ method, path }) { if (!method || typeof method !== 'string') { throw new Error('ApiEndpoint: method is required and must be a string'); } if (!path || typeof path !== 'string') { throw new Error('ApiEndpoint: path is required and must be a string'); } const validMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']; if (!validMethods.includes(method.toUpperCase())) { throw new Error(`ApiEndpoint: method must be one of ${validMethods.join(', ')}`); } } toJSON() { return { method: this.method, path: this.path, description: this.description, parameters: this.parameters, }; } static fromJSON(json) { return new ApiEndpoint(json); } } /** * Represents a parsed React component */ class ComponentModel { /** * @param {Object} options * @param {string} options.filePath - Component file path * @param {string} options.name - Component name * @param {string} options.type - Component type (from ComponentType enum) * @param {ComponentProp[]} [options.props=[]] - Component props * @param {StateVariable[]} [options.state=[]] - State variables * @param {string[]} [options.hooks=[]] - React hooks used * @param {Object[]} [options.methods=[]] - Component methods * @param {string[]} [options.children=[]] - Child components * @param {Object[]} [options.imports=[]] - Import statements * @param {Object[]} [options.exports=[]] - Export statements * @param {Object} [options.styling={}] - Styling information * @param {string} [options.stateManagement] - State management pattern * @param {string} [options.feature] - Feature category * @param {string[]} [options.apiEndpoints=[]] - API endpoints used * @param {boolean} [options.isResponsive=false] - Whether component is responsive * @param {string} [options.description] - Component description */ constructor({ filePath, name, type, props = [], state = [], hooks = [], methods = [], children = [], imports = [], exports = [], styling = {}, stateManagement = null, feature = null, apiEndpoints = [], isResponsive = false, description = null, }) { this._validate({ filePath, name, type }); this.filePath = filePath; this.name = name; this.type = type; this.props = props.map(p => p instanceof ComponentProp ? p : new ComponentProp(p)); this.state = state.map(s => s instanceof StateVariable ? s : new StateVariable(s)); this.hooks = hooks; this.methods = methods; this.children = children; this.imports = imports; this.exports = exports; this.styling = styling; this.stateManagement = stateManagement; this.feature = feature; this.apiEndpoints = apiEndpoints.map(e => e instanceof ApiEndpoint ? e : new ApiEndpoint(e)); this.isResponsive = isResponsive; this.description = description; } _validate({ filePath, name, type }) { if (!filePath || typeof filePath !== 'string') { throw new Error('ComponentModel: filePath is required and must be a string'); } if (!name || typeof name !== 'string') { throw new Error('ComponentModel: name is required and must be a string'); } if (!type || typeof type !== 'string') { throw new Error('ComponentModel: type is required and must be a string'); } if (!Object.values(ComponentType).includes(type)) { throw new Error(`ComponentModel: type must be one of ${Object.values(ComponentType).join(', ')}`); } } /** * Get all required props * @returns {ComponentProp[]} */ getRequiredProps() { return this.props.filter(p => p.isRequired); } /** * Get all optional props * @returns {ComponentProp[]} */ getOptionalProps() { return this.props.filter(p => !p.isRequired); } /** * Check if component uses async operations * @returns {boolean} */ hasAsyncOperations() { return this.apiEndpoints.length > 0 || this.hooks.some(h => h.includes('useEffect') || h.includes('useAsync')); } /** * Get complexity score (0-10) * @returns {number} */ getComplexityScore() { let score = 0; // Base complexity score += this.props.length * 0.5; score += this.state.length * 1; score += this.methods.length * 1; score += this.apiEndpoints.length * 2; score += this.children.length * 0.5; // State management adds complexity if (this.stateManagement === StateManagementPattern.REDUX) score += 2; if (this.stateManagement === StateManagementPattern.MOBX) score += 2; return Math.min(Math.round(score), 10); } /** * Determine if component should use BLoC or Cubit in Flutter * @returns {string} 'bloc' or 'cubit' */ recommendedFlutterStateManagement() { const complexity = this.getComplexityScore(); const hasAsync = this.hasAsyncOperations(); if (complexity > 5 || hasAsync) { return 'bloc'; } return 'cubit'; } /** * Convert to JSON * @returns {Object} */ toJSON() { return { filePath: this.filePath, name: this.name, type: this.type, props: this.props.map(p => p.toJSON()), state: this.state.map(s => s.toJSON()), hooks: this.hooks, methods: this.methods, children: this.children, imports: this.imports, exports: this.exports, styling: this.styling, stateManagement: this.stateManagement, feature: this.feature, apiEndpoints: this.apiEndpoints.map(e => e.toJSON()), isResponsive: this.isResponsive, description: this.description, }; } /** * Create from JSON * @param {Object} json * @returns {ComponentModel} */ static fromJSON(json) { return new ComponentModel(json); } /** * Create a minimal component for testing * @param {Object} overrides * @returns {ComponentModel} */ static createMinimal(overrides = {}) { return new ComponentModel({ filePath: 'test/Component.tsx', name: 'TestComponent', type: ComponentType.WIDGET, ...overrides, }); } } module.exports = { ComponentModel, ComponentProp, StateVariable, ApiEndpoint, ComponentType, StateManagementPattern, };