create-fluxstack 1.18.0 → 1.19.0
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/CHANGELOG.md +132 -0
- package/app/client/src/App.tsx +7 -7
- package/app/client/src/components/AppLayout.tsx +60 -23
- package/app/client/src/components/ColorWheel.tsx +195 -0
- package/app/client/src/components/DemoPage.tsx +5 -3
- package/app/client/src/components/LiveUploadWidget.tsx +1 -1
- package/app/client/src/components/ThemePicker.tsx +307 -0
- package/app/client/src/config/theme.config.ts +127 -0
- package/app/client/src/hooks/useThemeClock.ts +66 -0
- package/app/client/src/index.css +193 -0
- package/app/client/src/lib/theme-clock.ts +201 -0
- package/app/client/src/live/AuthDemo.tsx +9 -9
- package/app/client/src/live/CounterDemo.tsx +10 -10
- package/app/client/src/live/FormDemo.tsx +8 -8
- package/app/client/src/live/PingPongDemo.tsx +10 -10
- package/app/client/src/live/RoomChatDemo.tsx +10 -10
- package/app/client/src/live/SharedCounterDemo.tsx +5 -5
- package/app/client/src/pages/ApiTestPage.tsx +5 -5
- package/app/client/src/pages/HomePage.tsx +12 -12
- package/app/server/index.ts +8 -0
- package/app/server/live/auto-generated-components.ts +1 -1
- package/app/server/live/rooms/ChatRoom.ts +13 -8
- package/app/server/routes/index.ts +20 -10
- package/core/build/index.ts +1 -1
- package/core/cli/command-registry.ts +1 -1
- package/core/cli/commands/build.ts +25 -6
- package/core/cli/commands/plugin-deps.ts +1 -2
- package/core/cli/generators/plugin.ts +433 -581
- package/core/framework/server.ts +34 -8
- package/core/index.ts +6 -5
- package/core/plugins/index.ts +71 -199
- package/core/plugins/types.ts +76 -461
- package/core/server/index.ts +1 -1
- package/core/utils/logger/startup-banner.ts +26 -4
- package/core/utils/version.ts +6 -6
- package/create-fluxstack.ts +216 -107
- package/package.json +108 -107
- package/tsconfig.json +2 -1
- package/app/client/.live-stubs/LiveAdminPanel.js +0 -15
- package/app/client/.live-stubs/LiveCounter.js +0 -9
- package/app/client/.live-stubs/LiveForm.js +0 -11
- package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
- package/app/client/.live-stubs/LivePingPong.js +0 -10
- package/app/client/.live-stubs/LiveRoomChat.js +0 -11
- package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
- package/app/client/.live-stubs/LiveUpload.js +0 -15
- package/core/plugins/config.ts +0 -356
- package/core/plugins/dependency-manager.ts +0 -481
- package/core/plugins/discovery.ts +0 -379
- package/core/plugins/executor.ts +0 -353
- package/core/plugins/manager.ts +0 -645
- package/core/plugins/module-resolver.ts +0 -227
- package/core/plugins/registry.ts +0 -913
- package/vitest.config.live.ts +0 -69
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gerenciador de Dependências de Plugins
|
|
3
|
-
* Resolve e instala dependências de plugins automaticamente
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
7
|
-
import { join, resolve } from 'path'
|
|
8
|
-
import { execSync } from 'child_process'
|
|
9
|
-
import type { Logger } from '@core/utils/logger'
|
|
10
|
-
|
|
11
|
-
export interface PluginDependency {
|
|
12
|
-
name: string
|
|
13
|
-
version: string
|
|
14
|
-
type: 'dependency' | 'devDependency' | 'peerDependency'
|
|
15
|
-
optional?: boolean
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface DependencyResolution {
|
|
19
|
-
plugin: string
|
|
20
|
-
dependencies: PluginDependency[]
|
|
21
|
-
conflicts: DependencyConflict[]
|
|
22
|
-
resolved: boolean
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface DependencyConflict {
|
|
26
|
-
package: string
|
|
27
|
-
versions: Array<{
|
|
28
|
-
plugin: string
|
|
29
|
-
version: string
|
|
30
|
-
}>
|
|
31
|
-
resolution?: string
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface DependencyManagerConfig {
|
|
35
|
-
logger?: Logger
|
|
36
|
-
autoInstall?: boolean
|
|
37
|
-
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun'
|
|
38
|
-
workspaceRoot?: string
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export class PluginDependencyManager {
|
|
42
|
-
private logger?: Logger
|
|
43
|
-
private config: DependencyManagerConfig
|
|
44
|
-
private installedDependencies: Map<string, string> = new Map()
|
|
45
|
-
private pluginDependencies: Map<string, PluginDependency[]> = new Map()
|
|
46
|
-
|
|
47
|
-
constructor(config: DependencyManagerConfig = {}) {
|
|
48
|
-
this.config = {
|
|
49
|
-
autoInstall: true,
|
|
50
|
-
packageManager: 'bun',
|
|
51
|
-
workspaceRoot: process.cwd(),
|
|
52
|
-
...config
|
|
53
|
-
}
|
|
54
|
-
this.logger = config.logger
|
|
55
|
-
|
|
56
|
-
this.loadInstalledDependencies()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Registrar dependências de um plugin
|
|
61
|
-
*/
|
|
62
|
-
registerPluginDependencies(pluginName: string, dependencies: PluginDependency[]): void {
|
|
63
|
-
this.pluginDependencies.set(pluginName, dependencies)
|
|
64
|
-
this.logger?.debug(`Dependências registradas para plugin '${pluginName}'`, {
|
|
65
|
-
plugin: pluginName,
|
|
66
|
-
dependencies: dependencies.length
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Resolver dependências de um plugin a partir do package.json
|
|
72
|
-
*/
|
|
73
|
-
async resolvePluginDependencies(pluginPath: string): Promise<DependencyResolution> {
|
|
74
|
-
const pluginName = this.getPluginNameFromPath(pluginPath)
|
|
75
|
-
const packageJsonPath = join(pluginPath, 'package.json')
|
|
76
|
-
|
|
77
|
-
if (!existsSync(packageJsonPath)) {
|
|
78
|
-
return {
|
|
79
|
-
plugin: pluginName,
|
|
80
|
-
dependencies: [],
|
|
81
|
-
conflicts: [],
|
|
82
|
-
resolved: true
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
88
|
-
const dependencies: PluginDependency[] = []
|
|
89
|
-
|
|
90
|
-
// Processar dependencies
|
|
91
|
-
if (packageJson.dependencies) {
|
|
92
|
-
for (const [name, version] of Object.entries(packageJson.dependencies)) {
|
|
93
|
-
dependencies.push({
|
|
94
|
-
name,
|
|
95
|
-
version: version as string,
|
|
96
|
-
type: 'dependency'
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Processar peerDependencies
|
|
102
|
-
if (packageJson.peerDependencies) {
|
|
103
|
-
for (const [name, version] of Object.entries(packageJson.peerDependencies)) {
|
|
104
|
-
const isOptional = packageJson.peerDependenciesMeta?.[name]?.optional || false
|
|
105
|
-
dependencies.push({
|
|
106
|
-
name,
|
|
107
|
-
version: version as string,
|
|
108
|
-
type: 'peerDependency',
|
|
109
|
-
optional: isOptional
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Registrar dependências
|
|
115
|
-
this.registerPluginDependencies(pluginName, dependencies)
|
|
116
|
-
|
|
117
|
-
// Detectar conflitos
|
|
118
|
-
const conflicts = this.detectConflicts(pluginName, dependencies)
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
plugin: pluginName,
|
|
122
|
-
dependencies,
|
|
123
|
-
conflicts,
|
|
124
|
-
resolved: conflicts.length === 0
|
|
125
|
-
}
|
|
126
|
-
} catch (error) {
|
|
127
|
-
this.logger?.error(`Erro ao resolver dependências do plugin '${pluginName}'`, { error })
|
|
128
|
-
return {
|
|
129
|
-
plugin: pluginName,
|
|
130
|
-
dependencies: [],
|
|
131
|
-
conflicts: [],
|
|
132
|
-
resolved: false
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Instalar dependências de plugins
|
|
139
|
-
* NOVA ESTRATÉGIA: Instala no node_modules local do plugin primeiro,
|
|
140
|
-
* com fallback para o projeto principal
|
|
141
|
-
*/
|
|
142
|
-
async installPluginDependencies(resolutions: DependencyResolution[]): Promise<void> {
|
|
143
|
-
if (!this.config.autoInstall) {
|
|
144
|
-
this.logger?.debug('Auto-instalação desabilitada, pulando instalação de dependências')
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Instalar dependências para cada plugin individualmente
|
|
149
|
-
for (const resolution of resolutions) {
|
|
150
|
-
if (resolution.dependencies.length === 0) continue
|
|
151
|
-
|
|
152
|
-
const pluginPath = this.findPluginDirectory(resolution.plugin)
|
|
153
|
-
if (!pluginPath) {
|
|
154
|
-
this.logger?.warn(`Não foi possível encontrar diretório do plugin '${resolution.plugin}'`)
|
|
155
|
-
continue
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
this.logger?.debug(`📦 Instalando dependências localmente para plugin '${resolution.plugin}'`, {
|
|
159
|
-
plugin: resolution.plugin,
|
|
160
|
-
path: pluginPath,
|
|
161
|
-
dependencies: resolution.dependencies.length
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
// Instalar APENAS no node_modules local do plugin
|
|
166
|
-
await this.installPluginDependenciesLocally(pluginPath, resolution.dependencies)
|
|
167
|
-
|
|
168
|
-
this.logger?.debug(`✅ Dependências do plugin '${resolution.plugin}' instaladas localmente`)
|
|
169
|
-
} catch (error) {
|
|
170
|
-
this.logger?.error(`❌ Erro ao instalar dependências do plugin '${resolution.plugin}'`, { error })
|
|
171
|
-
// Continuar com outros plugins
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Instalar dependências no diretório local do plugin
|
|
178
|
-
*/
|
|
179
|
-
async installPluginDependenciesLocally(pluginPath: string, dependencies: PluginDependency[]): Promise<void> {
|
|
180
|
-
if (dependencies.length === 0) return
|
|
181
|
-
|
|
182
|
-
const regularDeps = dependencies.filter(d => d.type === 'dependency')
|
|
183
|
-
const peerDeps = dependencies.filter(d => d.type === 'peerDependency' && !d.optional)
|
|
184
|
-
|
|
185
|
-
const allDeps = [...regularDeps, ...peerDeps]
|
|
186
|
-
if (allDeps.length === 0) return
|
|
187
|
-
|
|
188
|
-
// Verificar quais dependências já estão instaladas localmente
|
|
189
|
-
const toInstall = allDeps.filter(dep => {
|
|
190
|
-
const depPath = join(pluginPath, 'node_modules', dep.name, 'package.json')
|
|
191
|
-
if (!existsSync(depPath)) {
|
|
192
|
-
return true // Precisa instalar
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
const installedPkg = JSON.parse(readFileSync(depPath, 'utf-8'))
|
|
197
|
-
const installedVersion = installedPkg.version
|
|
198
|
-
|
|
199
|
-
// Verificar se a versão é compatível
|
|
200
|
-
if (!this.isVersionCompatible(installedVersion, dep.version)) {
|
|
201
|
-
this.logger?.debug(`📦 Dependência '${dep.name}' está desatualizada (${installedVersion} → ${dep.version})`)
|
|
202
|
-
return true // Precisa atualizar
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return false // Já está instalado corretamente
|
|
206
|
-
} catch (error) {
|
|
207
|
-
return true // Erro ao ler, melhor reinstalar
|
|
208
|
-
}
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
if (toInstall.length === 0) {
|
|
212
|
-
this.logger?.debug(`✅ Todas as dependências do plugin já estão instaladas`)
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const packages = toInstall.map(d => `${d.name}@${d.version}`).join(' ')
|
|
217
|
-
const command = this.getInstallCommand(packages, false)
|
|
218
|
-
|
|
219
|
-
this.logger?.debug(`🔧 Instalando ${toInstall.length} dependência(s): ${command}`, { cwd: pluginPath })
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
execSync(command, {
|
|
223
|
-
cwd: pluginPath,
|
|
224
|
-
stdio: 'inherit'
|
|
225
|
-
})
|
|
226
|
-
this.logger?.debug(`✅ Pacotes instalados localmente em ${pluginPath}`)
|
|
227
|
-
} catch (error) {
|
|
228
|
-
this.logger?.error(`❌ Falha ao instalar dependências localmente`, { error, pluginPath })
|
|
229
|
-
throw error
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Instalar dependências diretamente em um path específico
|
|
235
|
-
*/
|
|
236
|
-
async installDependenciesInPath(pluginPath: string, dependencies: Record<string, string>): Promise<void> {
|
|
237
|
-
if (!this.config.autoInstall) {
|
|
238
|
-
this.logger?.debug('Auto-instalação desabilitada')
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (Object.keys(dependencies).length === 0) {
|
|
243
|
-
return
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const pluginDeps: PluginDependency[] = Object.entries(dependencies).map(([name, version]) => ({
|
|
247
|
-
name,
|
|
248
|
-
version,
|
|
249
|
-
type: 'dependency'
|
|
250
|
-
}))
|
|
251
|
-
|
|
252
|
-
this.logger?.debug(`📦 Instalando ${pluginDeps.length} dependência(s) em ${pluginPath}`)
|
|
253
|
-
|
|
254
|
-
try {
|
|
255
|
-
await this.installPluginDependenciesLocally(pluginPath, pluginDeps)
|
|
256
|
-
this.logger?.debug(`✅ Dependências instaladas com sucesso em ${pluginPath}`)
|
|
257
|
-
} catch (error) {
|
|
258
|
-
this.logger?.error(`❌ Erro ao instalar dependências em ${pluginPath}`, { error })
|
|
259
|
-
throw error
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Encontrar diretório de um plugin pelo nome
|
|
265
|
-
*/
|
|
266
|
-
private findPluginDirectory(pluginName: string): string | null {
|
|
267
|
-
const possiblePaths = [
|
|
268
|
-
`plugins/${pluginName}`,
|
|
269
|
-
`core/plugins/built-in/${pluginName}`
|
|
270
|
-
]
|
|
271
|
-
|
|
272
|
-
for (const path of possiblePaths) {
|
|
273
|
-
if (existsSync(path)) {
|
|
274
|
-
return resolve(path)
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return null
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Detectar conflitos de versão
|
|
283
|
-
*/
|
|
284
|
-
private detectConflicts(pluginName: string, dependencies: PluginDependency[]): DependencyConflict[] {
|
|
285
|
-
const conflicts: DependencyConflict[] = []
|
|
286
|
-
|
|
287
|
-
for (const dep of dependencies) {
|
|
288
|
-
const existingVersions: Array<{ plugin: string; version: string }> = []
|
|
289
|
-
|
|
290
|
-
// Verificar se outros plugins já declararam esta dependência
|
|
291
|
-
for (const [otherPlugin, otherDeps] of this.pluginDependencies.entries()) {
|
|
292
|
-
if (otherPlugin === pluginName) continue
|
|
293
|
-
|
|
294
|
-
const conflictingDep = otherDeps.find(d => d.name === dep.name)
|
|
295
|
-
if (conflictingDep && !this.isVersionCompatible(conflictingDep.version, dep.version)) {
|
|
296
|
-
existingVersions.push({
|
|
297
|
-
plugin: otherPlugin,
|
|
298
|
-
version: conflictingDep.version
|
|
299
|
-
})
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (existingVersions.length > 0) {
|
|
304
|
-
existingVersions.push({
|
|
305
|
-
plugin: pluginName,
|
|
306
|
-
version: dep.version
|
|
307
|
-
})
|
|
308
|
-
|
|
309
|
-
conflicts.push({
|
|
310
|
-
package: dep.name,
|
|
311
|
-
versions: existingVersions
|
|
312
|
-
})
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return conflicts
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Resolver conflitos de dependências
|
|
321
|
-
*/
|
|
322
|
-
private async resolveConflicts(conflicts: DependencyConflict[]): Promise<void> {
|
|
323
|
-
this.logger?.warn(`Detectados ${conflicts.length} conflitos de dependências`, {
|
|
324
|
-
conflicts: conflicts.map(c => ({
|
|
325
|
-
package: c.package,
|
|
326
|
-
versions: c.versions.length
|
|
327
|
-
}))
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
for (const conflict of conflicts) {
|
|
331
|
-
// Estratégia simples: usar a versão mais alta
|
|
332
|
-
const sortedVersions = conflict.versions.sort((a, b) => {
|
|
333
|
-
return this.compareVersions(b.version, a.version)
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
const resolution = sortedVersions[0].version
|
|
337
|
-
conflict.resolution = resolution
|
|
338
|
-
|
|
339
|
-
this.logger?.debug(`Conflito resolvido para '${conflict.package}': usando versão ${resolution}`, {
|
|
340
|
-
package: conflict.package,
|
|
341
|
-
resolution,
|
|
342
|
-
conflictingVersions: conflict.versions
|
|
343
|
-
})
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Instalar dependências usando o package manager configurado
|
|
349
|
-
*/
|
|
350
|
-
private async installDependencies(dependencies: PluginDependency[]): Promise<void> {
|
|
351
|
-
const regularDeps = dependencies.filter(d => d.type === 'dependency')
|
|
352
|
-
const peerDeps = dependencies.filter(d => d.type === 'peerDependency' && !d.optional)
|
|
353
|
-
|
|
354
|
-
if (regularDeps.length > 0) {
|
|
355
|
-
const packages = regularDeps.map(d => `${d.name}@${d.version}`).join(' ')
|
|
356
|
-
const command = this.getInstallCommand(packages, false)
|
|
357
|
-
|
|
358
|
-
this.logger?.debug(`Executando: ${command}`)
|
|
359
|
-
execSync(command, {
|
|
360
|
-
cwd: this.config.workspaceRoot,
|
|
361
|
-
stdio: 'inherit'
|
|
362
|
-
})
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (peerDeps.length > 0) {
|
|
366
|
-
const packages = peerDeps.map(d => `${d.name}@${d.version}`).join(' ')
|
|
367
|
-
const command = this.getInstallCommand(packages, false) // Peer deps como regulares
|
|
368
|
-
|
|
369
|
-
this.logger?.debug(`Executando: ${command}`)
|
|
370
|
-
execSync(command, {
|
|
371
|
-
cwd: this.config.workspaceRoot,
|
|
372
|
-
stdio: 'inherit'
|
|
373
|
-
})
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Recarregar dependências instaladas
|
|
377
|
-
this.loadInstalledDependencies()
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Obter comando de instalação baseado no package manager
|
|
382
|
-
*/
|
|
383
|
-
private getInstallCommand(packages: string, dev: boolean): string {
|
|
384
|
-
const devFlag = dev ? '--save-dev' : ''
|
|
385
|
-
|
|
386
|
-
switch (this.config.packageManager) {
|
|
387
|
-
case 'npm':
|
|
388
|
-
return `npm install ${devFlag} ${packages}`
|
|
389
|
-
case 'yarn':
|
|
390
|
-
return `yarn add ${dev ? '--dev' : ''} ${packages}`
|
|
391
|
-
case 'pnpm':
|
|
392
|
-
return `pnpm add ${devFlag} ${packages}`
|
|
393
|
-
case 'bun':
|
|
394
|
-
return `bun add ${devFlag} ${packages}`
|
|
395
|
-
default:
|
|
396
|
-
return `npm install ${devFlag} ${packages}`
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Carregar dependências já instaladas
|
|
402
|
-
*/
|
|
403
|
-
private loadInstalledDependencies(): void {
|
|
404
|
-
const packageJsonPath = join(this.config.workspaceRoot!, 'package.json')
|
|
405
|
-
|
|
406
|
-
if (!existsSync(packageJsonPath)) {
|
|
407
|
-
return
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
try {
|
|
411
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
412
|
-
|
|
413
|
-
// Carregar dependencies
|
|
414
|
-
if (packageJson.dependencies) {
|
|
415
|
-
for (const [name, version] of Object.entries(packageJson.dependencies)) {
|
|
416
|
-
this.installedDependencies.set(name, version as string)
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Carregar devDependencies
|
|
421
|
-
if (packageJson.devDependencies) {
|
|
422
|
-
for (const [name, version] of Object.entries(packageJson.devDependencies)) {
|
|
423
|
-
this.installedDependencies.set(name, version as string)
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
} catch (error) {
|
|
427
|
-
this.logger?.warn('Erro ao carregar package.json principal', { error })
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Verificar se versões são compatíveis
|
|
433
|
-
*/
|
|
434
|
-
private isVersionCompatible(installed: string, required: string): boolean {
|
|
435
|
-
// Implementação simples - em produção usaria semver
|
|
436
|
-
if (required.startsWith('^') || required.startsWith('~')) {
|
|
437
|
-
const requiredVersion = required.slice(1)
|
|
438
|
-
return this.compareVersions(installed, requiredVersion) >= 0
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
return installed === required
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Comparar versões (implementação simples)
|
|
446
|
-
*/
|
|
447
|
-
private compareVersions(a: string, b: string): number {
|
|
448
|
-
const aParts = a.replace(/[^\d.]/g, '').split('.').map(Number)
|
|
449
|
-
const bParts = b.replace(/[^\d.]/g, '').split('.').map(Number)
|
|
450
|
-
|
|
451
|
-
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
|
|
452
|
-
const aPart = aParts[i] || 0
|
|
453
|
-
const bPart = bParts[i] || 0
|
|
454
|
-
|
|
455
|
-
if (aPart > bPart) return 1
|
|
456
|
-
if (aPart < bPart) return -1
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
return 0
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Extrair nome do plugin do caminho
|
|
464
|
-
*/
|
|
465
|
-
private getPluginNameFromPath(pluginPath: string): string {
|
|
466
|
-
return pluginPath.split('/').pop() || 'unknown'
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Obter estatísticas de dependências
|
|
471
|
-
*/
|
|
472
|
-
getStats() {
|
|
473
|
-
return {
|
|
474
|
-
totalPlugins: this.pluginDependencies.size,
|
|
475
|
-
totalDependencies: Array.from(this.pluginDependencies.values())
|
|
476
|
-
.reduce((sum, deps) => sum + deps.length, 0),
|
|
477
|
-
installedDependencies: this.installedDependencies.size,
|
|
478
|
-
packageManager: this.config.packageManager
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|