@friggframework/devtools 2.0.0-next.3 → 2.0.0-next.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frigg-cli/.eslintrc.js +141 -0
- package/frigg-cli/__tests__/jest.config.js +102 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
- package/frigg-cli/__tests__/utils/command-tester.js +170 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +286 -0
- package/frigg-cli/build-command/index.js +54 -0
- package/frigg-cli/deploy-command/index.js +36 -0
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +332 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/generate-iam-command.js +115 -0
- package/frigg-cli/index.js +47 -1
- package/frigg-cli/index.test.js +1 -4
- package/frigg-cli/init-command/backend-first-handler.js +756 -0
- package/frigg-cli/init-command/index.js +93 -0
- package/frigg-cli/init-command/template-handler.js +143 -0
- package/frigg-cli/install-command/index.js +1 -4
- package/frigg-cli/package.json +51 -0
- package/frigg-cli/start-command/index.js +24 -4
- package/frigg-cli/test/init-command.test.js +180 -0
- package/frigg-cli/test/npm-registry.test.js +319 -0
- package/frigg-cli/ui-command/index.js +154 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +16 -17
- package/frigg-cli/utils/npm-registry.js +167 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +245 -0
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +596 -0
- package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
- package/infrastructure/GENERATE-IAM-DOCS.md +253 -0
- package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
- package/infrastructure/README-TESTING.md +332 -0
- package/infrastructure/README.md +421 -0
- package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
- package/infrastructure/__tests__/helpers/test-utils.js +277 -0
- package/infrastructure/aws-discovery.js +568 -0
- package/infrastructure/aws-discovery.test.js +373 -0
- package/infrastructure/build-time-discovery.js +206 -0
- package/infrastructure/build-time-discovery.test.js +375 -0
- package/infrastructure/create-frigg-infrastructure.js +3 -5
- package/infrastructure/frigg-deployment-iam-stack.yaml +379 -0
- package/infrastructure/iam-generator.js +687 -0
- package/infrastructure/iam-generator.test.js +169 -0
- package/infrastructure/iam-policy-basic.json +212 -0
- package/infrastructure/iam-policy-full.json +282 -0
- package/infrastructure/integration.test.js +383 -0
- package/infrastructure/run-discovery.js +110 -0
- package/infrastructure/serverless-template.js +923 -113
- package/infrastructure/serverless-template.test.js +541 -0
- package/management-ui/.eslintrc.js +22 -0
- package/management-ui/README.md +203 -0
- package/management-ui/components.json +21 -0
- package/management-ui/docs/phase2-integration-guide.md +320 -0
- package/management-ui/index.html +13 -0
- package/management-ui/package-lock.json +16517 -0
- package/management-ui/package.json +76 -0
- package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
- package/management-ui/postcss.config.js +6 -0
- package/management-ui/server/api/backend.js +256 -0
- package/management-ui/server/api/cli.js +315 -0
- package/management-ui/server/api/codegen.js +663 -0
- package/management-ui/server/api/connections.js +857 -0
- package/management-ui/server/api/discovery.js +185 -0
- package/management-ui/server/api/environment/index.js +1 -0
- package/management-ui/server/api/environment/router.js +378 -0
- package/management-ui/server/api/environment.js +328 -0
- package/management-ui/server/api/integrations.js +876 -0
- package/management-ui/server/api/logs.js +248 -0
- package/management-ui/server/api/monitoring.js +282 -0
- package/management-ui/server/api/open-ide.js +31 -0
- package/management-ui/server/api/project.js +1029 -0
- package/management-ui/server/api/users/sessions.js +371 -0
- package/management-ui/server/api/users/simulation.js +254 -0
- package/management-ui/server/api/users.js +362 -0
- package/management-ui/server/api-contract.md +275 -0
- package/management-ui/server/index.js +873 -0
- package/management-ui/server/middleware/errorHandler.js +93 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +346 -0
- package/management-ui/server/services/aws-monitor.js +413 -0
- package/management-ui/server/services/npm-registry.js +347 -0
- package/management-ui/server/services/template-engine.js +538 -0
- package/management-ui/server/utils/cliIntegration.js +220 -0
- package/management-ui/server/utils/environment/auditLogger.js +471 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
- package/management-ui/server/utils/environment/encryption.js +278 -0
- package/management-ui/server/utils/environment/envFileManager.js +286 -0
- package/management-ui/server/utils/import-commonjs.js +28 -0
- package/management-ui/server/utils/response.js +83 -0
- package/management-ui/server/websocket/handler.js +325 -0
- package/management-ui/src/App.jsx +109 -0
- package/management-ui/src/assets/FriggLogo.svg +1 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +70 -0
- package/management-ui/src/components/Card.jsx +97 -0
- package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
- package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
- package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
- package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
- package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
- package/management-ui/src/components/ErrorBoundary.jsx +73 -0
- package/management-ui/src/components/IntegrationCard.jsx +481 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +336 -0
- package/management-ui/src/components/Layout.jsx +716 -0
- package/management-ui/src/components/LoadingSpinner.jsx +113 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +350 -0
- package/management-ui/src/components/StatusBadge.jsx +208 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
- package/management-ui/src/components/UserSimulation.jsx +327 -0
- package/management-ui/src/components/Welcome.jsx +434 -0
- package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
- package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
- package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
- package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
- package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
- package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
- package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
- package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
- package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
- package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
- package/management-ui/src/components/codegen/index.js +10 -0
- package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
- package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
- package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
- package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
- package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
- package/management-ui/src/components/connections/index.js +5 -0
- package/management-ui/src/components/index.js +21 -0
- package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
- package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
- package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
- package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
- package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
- package/management-ui/src/components/monitoring/index.js +6 -0
- package/management-ui/src/components/monitoring/monitoring.css +218 -0
- package/management-ui/src/components/theme-provider.jsx +52 -0
- package/management-ui/src/components/theme-toggle.jsx +39 -0
- package/management-ui/src/components/ui/badge.tsx +36 -0
- package/management-ui/src/components/ui/button.test.jsx +56 -0
- package/management-ui/src/components/ui/button.tsx +57 -0
- package/management-ui/src/components/ui/card.tsx +76 -0
- package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
- package/management-ui/src/components/ui/select.tsx +157 -0
- package/management-ui/src/components/ui/skeleton.jsx +15 -0
- package/management-ui/src/hooks/useFrigg.jsx +601 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +193 -0
- package/management-ui/src/lib/utils.ts +6 -0
- package/management-ui/src/main.jsx +10 -0
- package/management-ui/src/pages/CodeGeneration.jsx +14 -0
- package/management-ui/src/pages/Connections.jsx +252 -0
- package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
- package/management-ui/src/pages/Dashboard.jsx +311 -0
- package/management-ui/src/pages/Environment.jsx +314 -0
- package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
- package/management-ui/src/pages/IntegrationTest.jsx +742 -0
- package/management-ui/src/pages/Integrations.jsx +253 -0
- package/management-ui/src/pages/Monitoring.jsx +17 -0
- package/management-ui/src/pages/Simulation.jsx +155 -0
- package/management-ui/src/pages/Users.jsx +492 -0
- package/management-ui/src/services/api.js +41 -0
- package/management-ui/src/services/apiModuleService.js +193 -0
- package/management-ui/src/services/websocket-handlers.js +120 -0
- package/management-ui/src/test/api/project.test.js +273 -0
- package/management-ui/src/test/components/Welcome.test.jsx +378 -0
- package/management-ui/src/test/mocks/server.js +178 -0
- package/management-ui/src/test/setup.js +61 -0
- package/management-ui/src/test/utils/test-utils.jsx +134 -0
- package/management-ui/src/utils/repository.js +98 -0
- package/management-ui/src/utils/repository.test.js +118 -0
- package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
- package/management-ui/tailwind.config.js +63 -0
- package/management-ui/tsconfig.json +37 -0
- package/management-ui/tsconfig.node.json +10 -0
- package/management-ui/vite.config.js +26 -0
- package/management-ui/vitest.config.js +38 -0
- package/package.json +17 -9
- package/infrastructure/app-handler-helpers.js +0 -57
- package/infrastructure/backend-utils.js +0 -90
- package/infrastructure/routers/auth.js +0 -26
- package/infrastructure/routers/integration-defined-routers.js +0 -37
- package/infrastructure/routers/middleware/loadUser.js +0 -15
- package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
- package/infrastructure/routers/user.js +0 -41
- package/infrastructure/routers/websocket.js +0 -55
- package/infrastructure/workers/integration-defined-workers.js +0 -24
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import handlebars from 'handlebars';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Template Engine Service for Code Generation
|
|
8
|
+
* Handles template processing, file generation, and CLI integration
|
|
9
|
+
*/
|
|
10
|
+
class TemplateEngine {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.templates = new Map();
|
|
13
|
+
this.helpers = new Map();
|
|
14
|
+
this.setupDefaultHelpers();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Setup default Handlebars helpers
|
|
19
|
+
*/
|
|
20
|
+
setupDefaultHelpers() {
|
|
21
|
+
// String manipulation helpers
|
|
22
|
+
handlebars.registerHelper('capitalize', (str) => {
|
|
23
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
handlebars.registerHelper('camelCase', (str) => {
|
|
27
|
+
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
handlebars.registerHelper('pascalCase', (str) => {
|
|
31
|
+
return str.replace(/(^|-)([a-z])/g, (g) => g.replace('-', '').toUpperCase());
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
handlebars.registerHelper('kebabCase', (str) => {
|
|
35
|
+
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
handlebars.registerHelper('snakeCase', (str) => {
|
|
39
|
+
return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
handlebars.registerHelper('upperCase', (str) => {
|
|
43
|
+
return str.toUpperCase();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Array helpers
|
|
47
|
+
handlebars.registerHelper('each', handlebars.helpers.each);
|
|
48
|
+
handlebars.registerHelper('join', (array, separator) => {
|
|
49
|
+
return Array.isArray(array) ? array.join(separator || ', ') : '';
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Conditional helpers
|
|
53
|
+
handlebars.registerHelper('if', handlebars.helpers.if);
|
|
54
|
+
handlebars.registerHelper('unless', handlebars.helpers.unless);
|
|
55
|
+
handlebars.registerHelper('eq', (a, b) => a === b);
|
|
56
|
+
handlebars.registerHelper('ne', (a, b) => a !== b);
|
|
57
|
+
handlebars.registerHelper('gt', (a, b) => a > b);
|
|
58
|
+
handlebars.registerHelper('lt', (a, b) => a < b);
|
|
59
|
+
|
|
60
|
+
// JSON helpers
|
|
61
|
+
handlebars.registerHelper('json', (obj) => {
|
|
62
|
+
return JSON.stringify(obj, null, 2);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
handlebars.registerHelper('jsonInline', (obj) => {
|
|
66
|
+
return JSON.stringify(obj);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Date helpers
|
|
70
|
+
handlebars.registerHelper('now', () => {
|
|
71
|
+
return new Date().toISOString();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
handlebars.registerHelper('year', () => {
|
|
75
|
+
return new Date().getFullYear();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Code generation specific helpers
|
|
79
|
+
handlebars.registerHelper('indent', (text, spaces = 2) => {
|
|
80
|
+
const indent = ' '.repeat(spaces);
|
|
81
|
+
return text.split('\n').map(line => line.trim() ? indent + line : line).join('\n');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
handlebars.registerHelper('comment', (text, style = 'js') => {
|
|
85
|
+
switch (style) {
|
|
86
|
+
case 'js':
|
|
87
|
+
return `// ${text}`;
|
|
88
|
+
case 'block':
|
|
89
|
+
return `/*\n * ${text}\n */`;
|
|
90
|
+
case 'jsx':
|
|
91
|
+
return `{/* ${text} */}`;
|
|
92
|
+
case 'html':
|
|
93
|
+
return `<!-- ${text} -->`;
|
|
94
|
+
default:
|
|
95
|
+
return `// ${text}`;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Register a custom template
|
|
102
|
+
*/
|
|
103
|
+
registerTemplate(name, template, metadata = {}) {
|
|
104
|
+
this.templates.set(name, {
|
|
105
|
+
template: handlebars.compile(template),
|
|
106
|
+
raw: template,
|
|
107
|
+
metadata
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Register a custom helper
|
|
113
|
+
*/
|
|
114
|
+
registerHelper(name, helper) {
|
|
115
|
+
this.helpers.set(name, helper);
|
|
116
|
+
handlebars.registerHelper(name, helper);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Process template with data
|
|
121
|
+
*/
|
|
122
|
+
processTemplate(templateName, data) {
|
|
123
|
+
const template = this.templates.get(templateName);
|
|
124
|
+
if (!template) {
|
|
125
|
+
throw new Error(`Template '${templateName}' not found`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
return template.template(data);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
throw new Error(`Template processing error: ${error.message}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generate integration module
|
|
137
|
+
*/
|
|
138
|
+
generateIntegration(config) {
|
|
139
|
+
const {
|
|
140
|
+
name,
|
|
141
|
+
displayName,
|
|
142
|
+
description,
|
|
143
|
+
type,
|
|
144
|
+
baseURL,
|
|
145
|
+
authorizationURL,
|
|
146
|
+
tokenURL,
|
|
147
|
+
scope,
|
|
148
|
+
apiEndpoints = [],
|
|
149
|
+
entitySchema = []
|
|
150
|
+
} = config;
|
|
151
|
+
|
|
152
|
+
const className = this.pascalCase(name);
|
|
153
|
+
const authFields = this.getAuthFields(type);
|
|
154
|
+
const allEntityFields = [...authFields, ...entitySchema, {
|
|
155
|
+
name: 'user_id',
|
|
156
|
+
label: 'User ID',
|
|
157
|
+
type: 'string',
|
|
158
|
+
required: true
|
|
159
|
+
}];
|
|
160
|
+
|
|
161
|
+
const data = {
|
|
162
|
+
name,
|
|
163
|
+
displayName,
|
|
164
|
+
description,
|
|
165
|
+
type,
|
|
166
|
+
className,
|
|
167
|
+
baseURL,
|
|
168
|
+
authorizationURL,
|
|
169
|
+
tokenURL,
|
|
170
|
+
scope,
|
|
171
|
+
apiEndpoints,
|
|
172
|
+
entitySchema: allEntityFields,
|
|
173
|
+
authFields,
|
|
174
|
+
hasOAuth2: type === 'oauth2',
|
|
175
|
+
hasApiKey: type === 'api',
|
|
176
|
+
hasBasicAuth: type === 'basic-auth'
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const integrationCode = this.generateIntegrationCode(data);
|
|
180
|
+
const testCode = this.generateTestCode(data);
|
|
181
|
+
const packageJson = this.generatePackageJson(data);
|
|
182
|
+
const readme = this.generateReadme(data);
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
files: [
|
|
186
|
+
{ name: 'index.js', content: integrationCode },
|
|
187
|
+
{ name: '__tests__/index.test.js', content: testCode },
|
|
188
|
+
{ name: 'package.json', content: packageJson },
|
|
189
|
+
{ name: 'README.md', content: readme }
|
|
190
|
+
],
|
|
191
|
+
metadata: {
|
|
192
|
+
name,
|
|
193
|
+
className,
|
|
194
|
+
type,
|
|
195
|
+
generatedAt: new Date().toISOString()
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Generate API endpoints
|
|
202
|
+
*/
|
|
203
|
+
generateAPIEndpoints(config) {
|
|
204
|
+
const { name, description, baseURL, version, authentication, endpoints = [] } = config;
|
|
205
|
+
|
|
206
|
+
const data = {
|
|
207
|
+
name,
|
|
208
|
+
description,
|
|
209
|
+
baseURL,
|
|
210
|
+
version,
|
|
211
|
+
authentication,
|
|
212
|
+
endpoints,
|
|
213
|
+
serviceName: this.pascalCase(name) + 'Service',
|
|
214
|
+
routerName: this.camelCase(name) + 'Router'
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const routerCode = this.generateRouterCode(data);
|
|
218
|
+
const serviceCode = this.generateServiceCode(data);
|
|
219
|
+
const openApiSpec = this.generateOpenAPISpec(data);
|
|
220
|
+
const readme = this.generateAPIReadme(data);
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
files: [
|
|
224
|
+
{ name: 'router.js', content: routerCode },
|
|
225
|
+
{ name: 'service.js', content: serviceCode },
|
|
226
|
+
{ name: 'openapi.json', content: openApiSpec },
|
|
227
|
+
{ name: 'README.md', content: readme }
|
|
228
|
+
],
|
|
229
|
+
metadata: {
|
|
230
|
+
name,
|
|
231
|
+
type: 'api-endpoints',
|
|
232
|
+
endpointCount: endpoints.length,
|
|
233
|
+
generatedAt: new Date().toISOString()
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Generate project scaffold
|
|
240
|
+
*/
|
|
241
|
+
generateProjectScaffold(config) {
|
|
242
|
+
const {
|
|
243
|
+
name,
|
|
244
|
+
description,
|
|
245
|
+
template,
|
|
246
|
+
database,
|
|
247
|
+
integrations = [],
|
|
248
|
+
features = {},
|
|
249
|
+
deployment = {}
|
|
250
|
+
} = config;
|
|
251
|
+
|
|
252
|
+
const data = {
|
|
253
|
+
name,
|
|
254
|
+
description,
|
|
255
|
+
template,
|
|
256
|
+
database,
|
|
257
|
+
integrations,
|
|
258
|
+
features,
|
|
259
|
+
deployment,
|
|
260
|
+
year: new Date().getFullYear()
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const files = [];
|
|
264
|
+
|
|
265
|
+
// Generate package.json
|
|
266
|
+
files.push({
|
|
267
|
+
name: 'package.json',
|
|
268
|
+
content: this.generateScaffoldPackageJson(data)
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Generate main app file
|
|
272
|
+
files.push({
|
|
273
|
+
name: 'app.js',
|
|
274
|
+
content: this.generateAppJs(data)
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Generate README
|
|
278
|
+
files.push({
|
|
279
|
+
name: 'README.md',
|
|
280
|
+
content: this.generateScaffoldReadme(data)
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Generate environment files
|
|
284
|
+
files.push({
|
|
285
|
+
name: '.env.example',
|
|
286
|
+
content: this.generateEnvExample(data)
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Generate serverless.yml if serverless template
|
|
290
|
+
if (template === 'serverless') {
|
|
291
|
+
files.push({
|
|
292
|
+
name: 'serverless.yml',
|
|
293
|
+
content: this.generateServerlessYml(data)
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Generate Docker files if enabled
|
|
298
|
+
if (features.docker) {
|
|
299
|
+
files.push({
|
|
300
|
+
name: 'Dockerfile',
|
|
301
|
+
content: this.generateDockerfile(data)
|
|
302
|
+
});
|
|
303
|
+
files.push({
|
|
304
|
+
name: 'docker-compose.yml',
|
|
305
|
+
content: this.generateDockerCompose(data)
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Generate CI configuration if enabled
|
|
310
|
+
if (features.ci) {
|
|
311
|
+
files.push({
|
|
312
|
+
name: '.github/workflows/ci.yml',
|
|
313
|
+
content: this.generateCIConfig(data)
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
files,
|
|
319
|
+
metadata: {
|
|
320
|
+
name,
|
|
321
|
+
template,
|
|
322
|
+
type: 'project-scaffold',
|
|
323
|
+
integrationCount: integrations.length,
|
|
324
|
+
generatedAt: new Date().toISOString()
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Write generated files to filesystem
|
|
331
|
+
*/
|
|
332
|
+
async writeFiles(files, outputDir) {
|
|
333
|
+
await fs.ensureDir(outputDir);
|
|
334
|
+
const writtenFiles = [];
|
|
335
|
+
|
|
336
|
+
for (const file of files) {
|
|
337
|
+
const filePath = path.join(outputDir, file.name);
|
|
338
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
339
|
+
await fs.writeFile(filePath, file.content, 'utf8');
|
|
340
|
+
writtenFiles.push(filePath);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return writtenFiles;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Execute Frigg CLI commands
|
|
348
|
+
*/
|
|
349
|
+
async executeFriggCommand(command, args = [], cwd = process.cwd()) {
|
|
350
|
+
return new Promise((resolve, reject) => {
|
|
351
|
+
const friggCli = path.join(__dirname, '../../../frigg-cli/index.js');
|
|
352
|
+
const child = spawn('node', [friggCli, command, ...args], {
|
|
353
|
+
cwd,
|
|
354
|
+
stdio: 'pipe'
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
let stdout = '';
|
|
358
|
+
let stderr = '';
|
|
359
|
+
|
|
360
|
+
child.stdout.on('data', (data) => {
|
|
361
|
+
stdout += data.toString();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
child.stderr.on('data', (data) => {
|
|
365
|
+
stderr += data.toString();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
child.on('close', (code) => {
|
|
369
|
+
if (code === 0) {
|
|
370
|
+
resolve({ stdout, stderr, code });
|
|
371
|
+
} else {
|
|
372
|
+
reject(new Error(`Frigg CLI command failed: ${stderr || stdout}`));
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
child.on('error', reject);
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Generate and install integration using CLI
|
|
382
|
+
*/
|
|
383
|
+
async generateAndInstallIntegration(config, projectPath) {
|
|
384
|
+
try {
|
|
385
|
+
// Generate integration files
|
|
386
|
+
const result = this.generateIntegration(config);
|
|
387
|
+
|
|
388
|
+
// Create integration directory
|
|
389
|
+
const integrationDir = path.join(projectPath, 'src', 'integrations', config.name);
|
|
390
|
+
const writtenFiles = await this.writeFiles(result.files, integrationDir);
|
|
391
|
+
|
|
392
|
+
// Use CLI to install the integration
|
|
393
|
+
await this.executeFriggCommand('install', [config.name], projectPath);
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
success: true,
|
|
397
|
+
files: writtenFiles,
|
|
398
|
+
metadata: result.metadata
|
|
399
|
+
};
|
|
400
|
+
} catch (error) {
|
|
401
|
+
return {
|
|
402
|
+
success: false,
|
|
403
|
+
error: error.message
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Helper methods for code generation
|
|
409
|
+
getAuthFields(type) {
|
|
410
|
+
const authFields = {
|
|
411
|
+
api: [
|
|
412
|
+
{ name: 'api_key', label: 'API Key', type: 'string', required: true, encrypted: false }
|
|
413
|
+
],
|
|
414
|
+
oauth2: [
|
|
415
|
+
{ name: 'access_token', label: 'Access Token', type: 'string', required: true, encrypted: false },
|
|
416
|
+
{ name: 'refresh_token', label: 'Refresh Token', type: 'string', required: false, encrypted: false },
|
|
417
|
+
{ name: 'expires_at', label: 'Expires At', type: 'date', required: false, encrypted: false },
|
|
418
|
+
{ name: 'scope', label: 'Scope', type: 'string', required: false, encrypted: false }
|
|
419
|
+
],
|
|
420
|
+
'basic-auth': [
|
|
421
|
+
{ name: 'username', label: 'Username', type: 'string', required: true, encrypted: false },
|
|
422
|
+
{ name: 'password', label: 'Password', type: 'string', required: true, encrypted: true }
|
|
423
|
+
],
|
|
424
|
+
oauth1: [
|
|
425
|
+
{ name: 'oauth_token', label: 'OAuth Token', type: 'string', required: true, encrypted: false },
|
|
426
|
+
{ name: 'oauth_token_secret', label: 'OAuth Token Secret', type: 'string', required: true, encrypted: true }
|
|
427
|
+
]
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
return authFields[type] || [];
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
pascalCase(str) {
|
|
434
|
+
return str.replace(/(^|-)([a-z])/g, (g) => g.replace('-', '').toUpperCase());
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
camelCase(str) {
|
|
438
|
+
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Code generation methods (implementations would go here)
|
|
442
|
+
generateIntegrationCode(data) {
|
|
443
|
+
// Implementation for integration code generation
|
|
444
|
+
// This would use the template patterns from the CLI
|
|
445
|
+
return `// Generated integration code for ${data.name}`;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
generateTestCode(data) {
|
|
449
|
+
// Implementation for test code generation
|
|
450
|
+
return `// Generated test code for ${data.name}`;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
generatePackageJson(data) {
|
|
454
|
+
// Implementation for package.json generation
|
|
455
|
+
return JSON.stringify({
|
|
456
|
+
name: `@friggframework/${data.name}`,
|
|
457
|
+
version: '0.1.0',
|
|
458
|
+
description: data.description
|
|
459
|
+
}, null, 2);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
generateReadme(data) {
|
|
463
|
+
// Implementation for README generation
|
|
464
|
+
return `# ${data.displayName}\n\n${data.description}`;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
generateRouterCode(data) {
|
|
468
|
+
// Implementation for router code generation
|
|
469
|
+
return `// Generated router code for ${data.name}`;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
generateServiceCode(data) {
|
|
473
|
+
// Implementation for service code generation
|
|
474
|
+
return `// Generated service code for ${data.name}`;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
generateOpenAPISpec(data) {
|
|
478
|
+
// Implementation for OpenAPI spec generation
|
|
479
|
+
return JSON.stringify({
|
|
480
|
+
openapi: '3.0.0',
|
|
481
|
+
info: {
|
|
482
|
+
title: data.name,
|
|
483
|
+
version: data.version
|
|
484
|
+
}
|
|
485
|
+
}, null, 2);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
generateAPIReadme(data) {
|
|
489
|
+
// Implementation for API README generation
|
|
490
|
+
return `# ${data.name} API\n\n${data.description}`;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
generateScaffoldPackageJson(data) {
|
|
494
|
+
// Implementation for scaffold package.json generation
|
|
495
|
+
return JSON.stringify({
|
|
496
|
+
name: data.name,
|
|
497
|
+
version: '1.0.0',
|
|
498
|
+
description: data.description
|
|
499
|
+
}, null, 2);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
generateAppJs(data) {
|
|
503
|
+
// Implementation for app.js generation
|
|
504
|
+
return `// Generated app.js for ${data.name}`;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
generateScaffoldReadme(data) {
|
|
508
|
+
// Implementation for scaffold README generation
|
|
509
|
+
return `# ${data.name}\n\n${data.description}`;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
generateEnvExample(data) {
|
|
513
|
+
// Implementation for .env.example generation
|
|
514
|
+
return `# Environment variables for ${data.name}`;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
generateServerlessYml(data) {
|
|
518
|
+
// Implementation for serverless.yml generation
|
|
519
|
+
return `service: ${data.name}`;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
generateDockerfile(data) {
|
|
523
|
+
// Implementation for Dockerfile generation
|
|
524
|
+
return `FROM node:18-alpine`;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
generateDockerCompose(data) {
|
|
528
|
+
// Implementation for docker-compose.yml generation
|
|
529
|
+
return `version: '3.8'`;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
generateCIConfig(data) {
|
|
533
|
+
// Implementation for CI configuration generation
|
|
534
|
+
return `name: CI`;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export default TemplateEngine;
|