g360-cli 1.10.0 → 1.11.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/README.md +22 -1
- package/package.json +11 -2
- package/src/assets/ingestion/core/__pycache__/ingestion.cpython-312.pyc +0 -0
- package/src/assets/ingestion/core/ingestion.py +47 -0
- package/src/assets/templates/python-flet/src/core/ingestion.py +66 -0
- package/src/assets/templates/python-flet/src/test_ingestion.py +14 -0
- package/src/cli.js +44 -0
- package/src/commands/addon.test.js +37 -0
- package/src/commands/audit.test.js +32 -0
- package/src/commands/bring.test.js +37 -0
- package/src/commands/init.js +11 -0
- package/src/commands/init.test.js +19 -0
- package/src/commands/list.test.js +132 -0
- package/src/commands/set-skill.js +21 -17
- package/src/commands/set-skill.test.js +134 -0
- package/src/commands/signature.js +46 -26
- package/src/commands/update.js +14 -2
- package/src/lib/asset-validator.test.js +237 -0
- package/src/lib/manifest.test.js +173 -0
- package/src/lib/validator.test.js +115 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file manifest.test.js
|
|
3
|
+
* @description Tests para el módulo manifest
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { manifest } from '../lib/manifest.js';
|
|
10
|
+
|
|
11
|
+
// Mock de fs-extra
|
|
12
|
+
vi.mock('fs-extra', () => ({
|
|
13
|
+
default: {
|
|
14
|
+
writeJson: vi.fn(),
|
|
15
|
+
readJson: vi.fn(),
|
|
16
|
+
existsSync: vi.fn(),
|
|
17
|
+
remove: vi.fn()
|
|
18
|
+
}
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
describe('manifest module', () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('init', () => {
|
|
27
|
+
it('should create a new manifest file', async () => {
|
|
28
|
+
const projectData = {
|
|
29
|
+
name: 'test-project',
|
|
30
|
+
template: 'web-pwa',
|
|
31
|
+
version: '1.0.0'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
fs.writeJson.mockResolvedValue();
|
|
35
|
+
|
|
36
|
+
const result = await manifest.init('/test/project', projectData);
|
|
37
|
+
|
|
38
|
+
expect(fs.writeJson).toHaveBeenCalledWith(
|
|
39
|
+
path.join('/test/project', 'g360-manifest.json'),
|
|
40
|
+
expect.objectContaining({
|
|
41
|
+
name: 'test-project',
|
|
42
|
+
template: 'web-pwa',
|
|
43
|
+
version: '1.0.0',
|
|
44
|
+
createdAt: expect.any(String),
|
|
45
|
+
assets: []
|
|
46
|
+
}),
|
|
47
|
+
{ spaces: 2 }
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(result).toMatchObject({
|
|
51
|
+
name: 'test-project',
|
|
52
|
+
template: 'web-pwa',
|
|
53
|
+
version: '1.0.0'
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should include assets array in manifest', async () => {
|
|
58
|
+
const projectData = {
|
|
59
|
+
name: 'test-project',
|
|
60
|
+
template: 'web-pwa',
|
|
61
|
+
version: '1.0.0'
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
fs.writeJson.mockResolvedValue();
|
|
65
|
+
|
|
66
|
+
const result = await manifest.init('/test/project', projectData);
|
|
67
|
+
|
|
68
|
+
expect(result.assets).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('load', () => {
|
|
73
|
+
it('should load existing manifest', async () => {
|
|
74
|
+
const mockManifest = {
|
|
75
|
+
name: 'test-project',
|
|
76
|
+
template: 'web-pwa',
|
|
77
|
+
version: '1.0.0',
|
|
78
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
79
|
+
assets: []
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
fs.existsSync.mockReturnValue(true);
|
|
83
|
+
fs.readJson.mockResolvedValue(mockManifest);
|
|
84
|
+
|
|
85
|
+
const result = await manifest.load('/test/project');
|
|
86
|
+
|
|
87
|
+
expect(result).toEqual(mockManifest);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should return null for non-existing manifest', async () => {
|
|
91
|
+
fs.existsSync.mockReturnValue(false);
|
|
92
|
+
|
|
93
|
+
const result = await manifest.load('/test/project');
|
|
94
|
+
|
|
95
|
+
expect(result).toBeNull();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should return null when manifest file does not exist', async () => {
|
|
99
|
+
fs.existsSync.mockReturnValue(true);
|
|
100
|
+
fs.readJson.mockRejectedValue(new Error('File not found'));
|
|
101
|
+
|
|
102
|
+
const result = await manifest.load('/test/project');
|
|
103
|
+
|
|
104
|
+
// El código actual no maneja errores de readJson, así que debería lanzar el error
|
|
105
|
+
// Para este test, vamos a verificar que el error se maneja correctamente
|
|
106
|
+
expect(result).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('addAsset', () => {
|
|
111
|
+
it('should add asset to existing manifest', async () => {
|
|
112
|
+
const existingManifest = {
|
|
113
|
+
name: 'test-project',
|
|
114
|
+
template: 'web-pwa',
|
|
115
|
+
version: '1.0.0',
|
|
116
|
+
assets: []
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const newAsset = {
|
|
120
|
+
name: 'components',
|
|
121
|
+
type: 'directory'
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
fs.readJson.mockResolvedValue(existingManifest);
|
|
125
|
+
fs.writeJson.mockResolvedValue();
|
|
126
|
+
|
|
127
|
+
await manifest.addAsset('/test/project', newAsset);
|
|
128
|
+
|
|
129
|
+
expect(fs.writeJson).toHaveBeenCalledWith(
|
|
130
|
+
path.join('/test/project', 'g360-manifest.json'),
|
|
131
|
+
expect.objectContaining({
|
|
132
|
+
assets: expect.arrayContaining([
|
|
133
|
+
expect.objectContaining({
|
|
134
|
+
name: 'components',
|
|
135
|
+
type: 'directory',
|
|
136
|
+
addedAt: expect.any(String)
|
|
137
|
+
})
|
|
138
|
+
])
|
|
139
|
+
}),
|
|
140
|
+
{ spaces: 2 }
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should not add asset when manifest does not exist', async () => {
|
|
145
|
+
fs.readJson.mockResolvedValue(null);
|
|
146
|
+
|
|
147
|
+
await manifest.addAsset('/test/project', { name: 'test' });
|
|
148
|
+
|
|
149
|
+
expect(fs.writeJson).not.toHaveBeenCalled();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('remove', () => {
|
|
154
|
+
it('should remove manifest file', async () => {
|
|
155
|
+
fs.existsSync.mockReturnValue(true);
|
|
156
|
+
fs.remove.mockResolvedValue();
|
|
157
|
+
|
|
158
|
+
await manifest.remove('/test/project');
|
|
159
|
+
|
|
160
|
+
expect(fs.remove).toHaveBeenCalledWith(
|
|
161
|
+
path.join('/test/project', 'g360-manifest.json')
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should handle non-existing manifest gracefully', async () => {
|
|
166
|
+
fs.existsSync.mockReturnValue(false);
|
|
167
|
+
|
|
168
|
+
await manifest.remove('/test/project');
|
|
169
|
+
|
|
170
|
+
expect(fs.remove).not.toHaveBeenCalled();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file validator.test.js
|
|
3
|
+
* @description Tests para el módulo validator
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import { validator } from '../lib/validator.js';
|
|
9
|
+
|
|
10
|
+
// Mock de fs-extra
|
|
11
|
+
vi.mock('fs-extra', () => ({
|
|
12
|
+
default: {
|
|
13
|
+
existsSync: vi.fn()
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
describe('validator module', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
vi.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('isValidProjectName', () => {
|
|
23
|
+
it('should accept valid project names', () => {
|
|
24
|
+
expect(validator.isValidProjectName('my-project')).toBe(true);
|
|
25
|
+
expect(validator.isValidProjectName('project123')).toBe(true);
|
|
26
|
+
expect(validator.isValidProjectName('my-project-123')).toBe(true);
|
|
27
|
+
expect(validator.isValidProjectName('123project')).toBe(true); // Empieza con número es válido según la regex actual
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should reject invalid project names', () => {
|
|
31
|
+
expect(validator.isValidProjectName('My-Project')).toBe(false); // Mayúsculas
|
|
32
|
+
expect(validator.isValidProjectName('my_project')).toBe(false); // Guiones bajos
|
|
33
|
+
expect(validator.isValidProjectName('my project')).toBe(false); // Espacios
|
|
34
|
+
expect(validator.isValidProjectName('-project')).toBe(false); // Empieza con guion
|
|
35
|
+
expect(validator.isValidProjectName('')).toBe(false); // Vacío
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('isValidPath', () => {
|
|
40
|
+
it('should return true for existing paths', () => {
|
|
41
|
+
fs.existsSync.mockReturnValue(true);
|
|
42
|
+
expect(validator.isValidPath('/existing/path')).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should return false for non-existing paths', () => {
|
|
46
|
+
fs.existsSync.mockReturnValue(false);
|
|
47
|
+
expect(validator.isValidPath('/non/existing/path')).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle errors gracefully', () => {
|
|
51
|
+
fs.existsSync.mockImplementation(() => {
|
|
52
|
+
throw new Error('Permission denied');
|
|
53
|
+
});
|
|
54
|
+
expect(validator.isValidPath('/error/path')).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('validateProject', () => {
|
|
59
|
+
it('should validate a valid G360 project', () => {
|
|
60
|
+
fs.existsSync.mockImplementation((path) => {
|
|
61
|
+
// El directorio del proyecto existe
|
|
62
|
+
if (path === '/valid/project') return true;
|
|
63
|
+
// El manifest y el directorio g360 existen
|
|
64
|
+
if (path.includes('g360-manifest.json') || path.includes('g360')) return true;
|
|
65
|
+
return false;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const result = validator.validateProject('/valid/project');
|
|
69
|
+
|
|
70
|
+
expect(result.valid).toBe(true);
|
|
71
|
+
expect(result.errors).toHaveLength(0);
|
|
72
|
+
expect(result.warnings).toHaveLength(0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should return errors for non-existing project', () => {
|
|
76
|
+
fs.existsSync.mockReturnValue(false);
|
|
77
|
+
|
|
78
|
+
const result = validator.validateProject('/non/existing');
|
|
79
|
+
|
|
80
|
+
expect(result.valid).toBe(false);
|
|
81
|
+
expect(result.errors).toContain('Project directory does not exist');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return warnings for missing G360 files', () => {
|
|
85
|
+
fs.existsSync.mockImplementation((path) => {
|
|
86
|
+
// El directorio del proyecto existe
|
|
87
|
+
if (path === '/project/without/g360') return true;
|
|
88
|
+
// El manifest y el directorio g360 no existen
|
|
89
|
+
return false;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const result = validator.validateProject('/project/without/g360');
|
|
93
|
+
|
|
94
|
+
expect(result.valid).toBe(true);
|
|
95
|
+
expect(result.warnings).toContain('No g360-manifest.json found');
|
|
96
|
+
expect(result.warnings).toContain('No g360 directory found');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle partial G360 setup', () => {
|
|
100
|
+
fs.existsSync.mockImplementation((path) => {
|
|
101
|
+
// El directorio del proyecto existe
|
|
102
|
+
if (path === '/project/partial') return true;
|
|
103
|
+
// Solo el manifest existe
|
|
104
|
+
if (path.includes('g360-manifest.json')) return true;
|
|
105
|
+
// El directorio g360 no existe
|
|
106
|
+
return false;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const result = validator.validateProject('/project/partial');
|
|
110
|
+
|
|
111
|
+
expect(result.valid).toBe(true);
|
|
112
|
+
expect(result.warnings).toContain('No g360 directory found');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|