@futurebrand/dev-tools 2.5.2 → 2.5.4
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/dist/commands/ai/add.js +36 -12
- package/dist/commands/ai/generate.js +36 -14
- package/dist/commands/ai/modules/figma/api.js +1 -1
- package/dist/commands/ai/modules/figma/index.js +7 -18
- package/dist/commands/ai/modules/file-manager/index.d.ts +22 -0
- package/dist/commands/ai/modules/file-manager/index.js +156 -0
- package/dist/commands/ai/modules/file-manager/types.d.ts +4 -0
- package/dist/commands/ai/modules/file-manager/types.js +2 -0
- package/dist/commands/ai/modules/generator/index.d.ts +7 -4
- package/dist/commands/ai/modules/generator/index.js +36 -37
- package/dist/commands/ai/modules/generator/types.d.ts +17 -0
- package/dist/commands/ai/modules/generator/types.js +2 -0
- package/dist/commands/ai/modules/project-adder/index.d.ts +2 -3
- package/dist/commands/ai/modules/project-adder/index.js +6 -59
- package/dist/commands/ai/modules/state/index.d.ts +2 -0
- package/dist/commands/ai/modules/state/index.js +9 -0
- package/package.json +1 -1
package/dist/commands/ai/add.js
CHANGED
|
@@ -19,28 +19,52 @@ const addCommand = new commander_1.Command('add')
|
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
const isAll = options.all === true;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
const projects = state
|
|
23
|
+
.getData()
|
|
24
|
+
.projects.filter((p) => p.type === 'strapi' || p.type === 'next.js');
|
|
25
|
+
const userQuery = await inquirer_1.default.prompt([
|
|
26
|
+
{
|
|
27
|
+
type: 'select',
|
|
28
|
+
name: 'project',
|
|
29
|
+
message: 'Select the project to generate',
|
|
30
|
+
choices: projects.map((p) => ({
|
|
31
|
+
name: `${p.name} (${p.type})`,
|
|
32
|
+
value: p.name,
|
|
33
|
+
})),
|
|
34
|
+
},
|
|
31
35
|
{
|
|
32
36
|
type: 'select',
|
|
33
37
|
name: 'block',
|
|
34
38
|
message: 'Select the block to add',
|
|
35
|
-
choices
|
|
39
|
+
choices: async ({ project }) => {
|
|
40
|
+
const projectData = projects.find((p) => p.name === project);
|
|
41
|
+
if (!projectData) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const allBlocks = state.getAvailableBlocks({
|
|
45
|
+
hidden: false,
|
|
46
|
+
});
|
|
47
|
+
const toGenerateBlocks = isAll
|
|
48
|
+
? allBlocks
|
|
49
|
+
: await state.file.getAvailableBlocksToAdd(allBlocks, projectData);
|
|
50
|
+
if (!toGenerateBlocks.length) {
|
|
51
|
+
throw new Error('No blocks available to generate');
|
|
52
|
+
}
|
|
53
|
+
return toGenerateBlocks.map((block) => block.name).sort();
|
|
54
|
+
},
|
|
36
55
|
},
|
|
37
56
|
]);
|
|
38
|
-
const blocksToAdd =
|
|
57
|
+
const blocksToAdd = userQuery.block;
|
|
39
58
|
if (!blocksToAdd) {
|
|
40
59
|
console.error('No blocks selected');
|
|
41
60
|
return;
|
|
42
61
|
}
|
|
62
|
+
const project = projects.find((p) => p.name === userQuery.project);
|
|
63
|
+
if (!project) {
|
|
64
|
+
console.error('No project selected');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
43
67
|
const projectAdder = new project_adder_1.default(state);
|
|
44
|
-
await projectAdder.addBlock(blocksToAdd);
|
|
68
|
+
await projectAdder.addBlock(blocksToAdd, project);
|
|
45
69
|
});
|
|
46
70
|
exports.default = addCommand;
|
|
@@ -18,31 +18,53 @@ const generateCommand = new commander_1.Command('generate')
|
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
20
|
const isAll = options.all === true;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
const projects = state
|
|
22
|
+
.getData()
|
|
23
|
+
.projects.filter((p) => p.type === 'strapi' || p.type === 'next.js');
|
|
24
|
+
const userQuery = await inquirer_1.default.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'select',
|
|
27
|
+
name: 'project',
|
|
28
|
+
message: 'Select the project to generate',
|
|
29
|
+
choices: projects.map((p) => ({
|
|
30
|
+
name: `${p.name} (${p.type})`,
|
|
31
|
+
value: p.name,
|
|
32
|
+
})),
|
|
33
|
+
},
|
|
32
34
|
{
|
|
33
35
|
type: 'checkbox',
|
|
34
36
|
name: 'blocks',
|
|
35
37
|
message: 'Select the blocks to generate',
|
|
36
|
-
choices
|
|
38
|
+
choices: async ({ project }) => {
|
|
39
|
+
const projectData = projects.find((p) => p.name === project);
|
|
40
|
+
if (!projectData) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const allBlocks = state.getAvailableBlocks({
|
|
44
|
+
hidden: false,
|
|
45
|
+
});
|
|
46
|
+
const toGenerateBlocks = isAll
|
|
47
|
+
? allBlocks
|
|
48
|
+
: await state.file.getAvailableBlocksToGenerate(allBlocks, projectData);
|
|
49
|
+
if (!toGenerateBlocks.length) {
|
|
50
|
+
throw new Error('No blocks available to generate');
|
|
51
|
+
}
|
|
52
|
+
return toGenerateBlocks.map((block) => block.name).sort();
|
|
53
|
+
},
|
|
37
54
|
},
|
|
38
55
|
]);
|
|
39
|
-
const blocksToGenerate =
|
|
56
|
+
const blocksToGenerate = userQuery.blocks;
|
|
40
57
|
if (!blocksToGenerate.length) {
|
|
41
58
|
console.error('No blocks selected');
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
61
|
+
const project = projects.find((p) => p.name === userQuery.project);
|
|
62
|
+
if (!project) {
|
|
63
|
+
console.error('No project selected');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
44
66
|
const generator = new generator_1.Generator(state);
|
|
45
|
-
await generator.generateBlocks(blocksToGenerate);
|
|
67
|
+
await generator.generateBlocks(blocksToGenerate, project);
|
|
46
68
|
});
|
|
47
69
|
const generateStyleCommand = new commander_1.Command('styles')
|
|
48
70
|
.alias('style')
|
|
@@ -11,7 +11,7 @@ class FigmaAPI {
|
|
|
11
11
|
return id;
|
|
12
12
|
}
|
|
13
13
|
async getVariables(pageId) {
|
|
14
|
-
const { variables } = await this.state.fetchApi(`/figma/${pageId}/
|
|
14
|
+
const { variables } = await this.state.fetchApi(`/figma/${pageId}/variables`);
|
|
15
15
|
return variables;
|
|
16
16
|
}
|
|
17
17
|
async getBlocks(pageId, canvasId) {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const path = require("node:path");
|
|
4
|
-
const files_1 = require("../../../../utils/files");
|
|
5
3
|
const inquirer_1 = require("inquirer");
|
|
6
|
-
const generator_1 = require("../generator");
|
|
7
4
|
const api_1 = require("./api");
|
|
8
5
|
class FigmaModule {
|
|
9
6
|
state;
|
|
@@ -25,24 +22,16 @@ class FigmaModule {
|
|
|
25
22
|
async getDefaultCheckedBlocks(blocks) {
|
|
26
23
|
const data = this.state.getData();
|
|
27
24
|
const defaultBlocks = [];
|
|
28
|
-
const currentBlocks = data.blocks;
|
|
29
25
|
const nextProject = data.projects.find((project) => project.type === 'next.js');
|
|
30
26
|
for (const block of blocks) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
const tempFolder = await (0, files_1.getTempFilePath)(generator_1.GENERATOR_FOLDER_NAME, block.name);
|
|
38
|
-
if (await (0, files_1.verifyPath)(tempFolder)) {
|
|
39
|
-
block.generated = true;
|
|
27
|
+
if (nextProject) {
|
|
28
|
+
const alreadyGenerated = await this.state.file.verifyBlockAlreadyGenerated(block.name, nextProject);
|
|
29
|
+
if (alreadyGenerated) {
|
|
30
|
+
continue;
|
|
40
31
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
block.hidden = true;
|
|
45
|
-
}
|
|
32
|
+
const alreadyExist = await this.state.file.verifyBlockAlreadyExists(nextProject, block.name);
|
|
33
|
+
if (alreadyExist) {
|
|
34
|
+
continue;
|
|
46
35
|
}
|
|
47
36
|
}
|
|
48
37
|
if (!block.hidden) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IProject } from '../../../../types/project';
|
|
2
|
+
import type { IBlockData } from '../state/types';
|
|
3
|
+
export declare const GENERATOR_FOLDER_NAME = "generated-blocks";
|
|
4
|
+
export declare const GENERATOR_STRAPI_FILE_NAME = "strapi.json";
|
|
5
|
+
export declare const GENERATOR_NEXTJS_FILE_NAME = "nextjs.tsx";
|
|
6
|
+
declare class FileManager {
|
|
7
|
+
private getBlockTempPath;
|
|
8
|
+
private getBlockTempFilePath;
|
|
9
|
+
private getStrapiFolders;
|
|
10
|
+
private getNextjsBlockFolder;
|
|
11
|
+
private getBlockPath;
|
|
12
|
+
verifyBlockAlreadyGenerated(blockName: string, project: IProject): Promise<boolean>;
|
|
13
|
+
verifyBlockAlreadyExists(project: IProject, blockName: string): Promise<boolean>;
|
|
14
|
+
getAvailableBlocksToGenerate(blocks: IBlockData[], project: IProject): Promise<IBlockData[]>;
|
|
15
|
+
getAvailableBlocksToAdd(blocks: IBlockData[], project: IProject): Promise<IBlockData[]>;
|
|
16
|
+
createBlockTempFolder(blockName: string): Promise<void>;
|
|
17
|
+
saveGeneratedBlock(blockName: string, project: IProject, content: any): Promise<void>;
|
|
18
|
+
loadGeneratedBlock(blockName: string, project: IProject): Promise<string>;
|
|
19
|
+
addNextBlockToProject(blockName: string, project: IProject): Promise<void>;
|
|
20
|
+
addStrapiBlockToProject(blockName: string, project: IProject): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export default FileManager;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GENERATOR_NEXTJS_FILE_NAME = exports.GENERATOR_STRAPI_FILE_NAME = exports.GENERATOR_FOLDER_NAME = void 0;
|
|
4
|
+
const fs = require("node:fs/promises");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const files_1 = require("../../../../utils/files");
|
|
7
|
+
exports.GENERATOR_FOLDER_NAME = 'generated-blocks';
|
|
8
|
+
exports.GENERATOR_STRAPI_FILE_NAME = 'strapi.json';
|
|
9
|
+
exports.GENERATOR_NEXTJS_FILE_NAME = 'nextjs.tsx';
|
|
10
|
+
class FileManager {
|
|
11
|
+
async getBlockTempPath(blockName) {
|
|
12
|
+
const tempFolder = await (0, files_1.getTempFilePath)(exports.GENERATOR_FOLDER_NAME, blockName);
|
|
13
|
+
await (0, files_1.verifyAndCreateFolder)(tempFolder);
|
|
14
|
+
return tempFolder;
|
|
15
|
+
}
|
|
16
|
+
async getBlockTempFilePath(project, blockName) {
|
|
17
|
+
const tempFolder = await this.getBlockTempPath(blockName);
|
|
18
|
+
const projectType = typeof project === 'string' ? project : project.type;
|
|
19
|
+
if (projectType === 'strapi') {
|
|
20
|
+
return path.join(tempFolder, exports.GENERATOR_STRAPI_FILE_NAME);
|
|
21
|
+
}
|
|
22
|
+
if (projectType === 'next.js') {
|
|
23
|
+
return path.join(tempFolder, exports.GENERATOR_NEXTJS_FILE_NAME);
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Unsupported project type: ${projectType}`);
|
|
26
|
+
}
|
|
27
|
+
getStrapiFolders(project) {
|
|
28
|
+
if (project.type !== 'strapi') {
|
|
29
|
+
throw new Error('Project is not a Strapi project');
|
|
30
|
+
}
|
|
31
|
+
const srcPath = project.srcPath || path.join(project.path, 'src');
|
|
32
|
+
const componentsFolder = path.join(srcPath, 'components');
|
|
33
|
+
const blocksFolder = path.join(componentsFolder, 'blocks');
|
|
34
|
+
const blocksAssetsFolder = path.join(componentsFolder, 'blocks-assets');
|
|
35
|
+
return {
|
|
36
|
+
blocks: blocksFolder,
|
|
37
|
+
assets: blocksAssetsFolder,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
getNextjsBlockFolder(project, blockName) {
|
|
41
|
+
if (project.type !== 'next.js') {
|
|
42
|
+
throw new Error('Project is not a Next.js project');
|
|
43
|
+
}
|
|
44
|
+
const blockFolder = path.join(project.srcPath || project.path, 'layouts', 'blocks', blockName);
|
|
45
|
+
return blockFolder;
|
|
46
|
+
}
|
|
47
|
+
getBlockPath(project, blockName) {
|
|
48
|
+
if (project.type === 'strapi') {
|
|
49
|
+
const folders = this.getStrapiFolders(project);
|
|
50
|
+
const jsonName = blockName.replace('block-', '');
|
|
51
|
+
return path.join(folders.blocks, `${jsonName}.json`);
|
|
52
|
+
}
|
|
53
|
+
if (project.type === 'next.js') {
|
|
54
|
+
const blockFolder = this.getNextjsBlockFolder(project, blockName);
|
|
55
|
+
return path.join(blockFolder, `${blockName}.tsx`);
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`Unsupported project type: ${project.type}`);
|
|
58
|
+
}
|
|
59
|
+
async verifyBlockAlreadyGenerated(blockName, project) {
|
|
60
|
+
const blockPath = await this.getBlockTempFilePath(project, blockName);
|
|
61
|
+
return await (0, files_1.verifyPath)(blockPath);
|
|
62
|
+
}
|
|
63
|
+
async verifyBlockAlreadyExists(project, blockName) {
|
|
64
|
+
const blockPath = this.getBlockPath(project, blockName);
|
|
65
|
+
return await (0, files_1.verifyPath)(blockPath);
|
|
66
|
+
}
|
|
67
|
+
async getAvailableBlocksToGenerate(blocks, project) {
|
|
68
|
+
const toGenerateBlocks = [];
|
|
69
|
+
for (const block of blocks) {
|
|
70
|
+
const alreadyExists = await this.verifyBlockAlreadyExists(project, block.name);
|
|
71
|
+
if (alreadyExists) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const alreadyGenerated = await this.verifyBlockAlreadyGenerated(block.name, project);
|
|
75
|
+
if (alreadyGenerated) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
toGenerateBlocks.push(block);
|
|
79
|
+
}
|
|
80
|
+
return toGenerateBlocks;
|
|
81
|
+
}
|
|
82
|
+
async getAvailableBlocksToAdd(blocks, project) {
|
|
83
|
+
const toAddBlocks = [];
|
|
84
|
+
for (const block of blocks) {
|
|
85
|
+
const alreadyExists = await this.verifyBlockAlreadyExists(project, block.name);
|
|
86
|
+
if (alreadyExists) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const alreadyGenerated = await this.verifyBlockAlreadyGenerated(block.name, project);
|
|
90
|
+
if (alreadyGenerated) {
|
|
91
|
+
toAddBlocks.push(block);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return toAddBlocks;
|
|
95
|
+
}
|
|
96
|
+
async createBlockTempFolder(blockName) {
|
|
97
|
+
const tempFolder = await this.getBlockTempPath(blockName);
|
|
98
|
+
await (0, files_1.verifyAndCreateFolder)(tempFolder);
|
|
99
|
+
}
|
|
100
|
+
async saveGeneratedBlock(blockName, project, content) {
|
|
101
|
+
const blockPath = await this.getBlockTempFilePath(project, blockName);
|
|
102
|
+
const stringContent = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
|
|
103
|
+
await fs.writeFile(blockPath, stringContent);
|
|
104
|
+
}
|
|
105
|
+
async loadGeneratedBlock(blockName, project) {
|
|
106
|
+
const blockPath = await this.getBlockTempFilePath(project, blockName);
|
|
107
|
+
if (!(await (0, files_1.verifyPath)(blockPath))) {
|
|
108
|
+
throw new Error(`Generated block not found: ${blockPath}`);
|
|
109
|
+
}
|
|
110
|
+
return (0, files_1.loadFile)(blockPath);
|
|
111
|
+
}
|
|
112
|
+
async addNextBlockToProject(blockName, project) {
|
|
113
|
+
if (project.type !== 'next.js') {
|
|
114
|
+
throw new Error('Project is not a Next.js project');
|
|
115
|
+
}
|
|
116
|
+
const generatedPath = await this.getBlockTempFilePath(project, blockName);
|
|
117
|
+
if (!(await (0, files_1.verifyPath)(generatedPath))) {
|
|
118
|
+
throw new Error(`Generated block not found: ${generatedPath}`);
|
|
119
|
+
}
|
|
120
|
+
const content = await (0, files_1.loadFile)(generatedPath);
|
|
121
|
+
const blockFolder = this.getNextjsBlockFolder(project, blockName);
|
|
122
|
+
await (0, files_1.verifyAndCreateFolder)(blockFolder);
|
|
123
|
+
const mainFilePath = path.join(blockFolder, `${blockName}.tsx`);
|
|
124
|
+
const indexFilePath = path.join(blockFolder, 'index.ts');
|
|
125
|
+
const indexContent = `export { default } from './${blockName}'
|
|
126
|
+
`;
|
|
127
|
+
await fs.writeFile(mainFilePath, content);
|
|
128
|
+
await fs.writeFile(indexFilePath, indexContent);
|
|
129
|
+
}
|
|
130
|
+
async addStrapiBlockToProject(blockName, project) {
|
|
131
|
+
if (project.type !== 'strapi') {
|
|
132
|
+
throw new Error('Project is not a Strapi project');
|
|
133
|
+
}
|
|
134
|
+
const generatedPath = await this.getBlockTempFilePath(project, blockName);
|
|
135
|
+
if (!(await (0, files_1.verifyPath)(generatedPath))) {
|
|
136
|
+
throw new Error(`Generated block not found: ${generatedPath}`);
|
|
137
|
+
}
|
|
138
|
+
const content = await (0, files_1.loadFile)(generatedPath);
|
|
139
|
+
const blockData = JSON.parse(content);
|
|
140
|
+
const folders = this.getStrapiFolders(project);
|
|
141
|
+
await (0, files_1.verifyAndCreateFolder)(folders.blocks);
|
|
142
|
+
await (0, files_1.verifyAndCreateFolder)(folders.assets);
|
|
143
|
+
const blockNameClean = blockName.replace('block-', '');
|
|
144
|
+
const blockFilePath = path.join(folders.blocks, `${blockNameClean}.json`);
|
|
145
|
+
await fs.writeFile(blockFilePath, JSON.stringify(blockData.block, null, 2));
|
|
146
|
+
for (const asset of blockData.assets || []) {
|
|
147
|
+
const name = asset.info?.name;
|
|
148
|
+
if (!name) {
|
|
149
|
+
throw new Error(`Asset name is missing for block: ${blockName}`);
|
|
150
|
+
}
|
|
151
|
+
const assetFilePath = path.join(folders.assets, `${name}.json`);
|
|
152
|
+
await fs.writeFile(assetFilePath, JSON.stringify(asset, null, 2));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.default = FileManager;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IProject } from '../../../../types/project';
|
|
2
2
|
import type AIState from '../state';
|
|
3
|
+
import type { IStrapiGenerateResponse } from './types';
|
|
3
4
|
export declare const GENERATOR_FOLDER_NAME = "generated-blocks";
|
|
4
5
|
export declare const GENERATOR_STRAPI_FILE_NAME = "strapi.json";
|
|
5
6
|
export declare const GENERATOR_NEXTJS_FILE_NAME = "nextjs.tsx";
|
|
@@ -7,11 +8,13 @@ export declare class Generator {
|
|
|
7
8
|
private state;
|
|
8
9
|
constructor(state: AIState);
|
|
9
10
|
private get data();
|
|
10
|
-
private
|
|
11
|
-
private
|
|
11
|
+
private fetchNextBlock;
|
|
12
|
+
private fetchStrapiBlock;
|
|
12
13
|
loadProjectCSS(nextProject?: IProject): Promise<string | null>;
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
private generateStrapiBlock;
|
|
15
|
+
private generateNextBlock;
|
|
16
|
+
generateBlock(blockName: string, project: IProject): Promise<IStrapiGenerateResponse | undefined>;
|
|
17
|
+
generateBlocks(blockNames: string[], project: IProject): Promise<void>;
|
|
15
18
|
generateStyles(): Promise<void>;
|
|
16
19
|
generateChecklist(): Promise<void>;
|
|
17
20
|
}
|
|
@@ -16,7 +16,7 @@ class Generator {
|
|
|
16
16
|
get data() {
|
|
17
17
|
return this.state.getData();
|
|
18
18
|
}
|
|
19
|
-
async
|
|
19
|
+
async fetchNextBlock(blockName, blockVariants, variables, styles, strapiComponent) {
|
|
20
20
|
const requestBody = {
|
|
21
21
|
name: blockName.replace('block-', ''),
|
|
22
22
|
variants: blockVariants,
|
|
@@ -34,10 +34,9 @@ class Generator {
|
|
|
34
34
|
if (!data.result?.block) {
|
|
35
35
|
throw new Error('Next.js block generation failed');
|
|
36
36
|
}
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
38
37
|
return data.result.block;
|
|
39
38
|
}
|
|
40
|
-
async
|
|
39
|
+
async fetchStrapiBlock(blockName, blockVariants) {
|
|
41
40
|
const requestBody = {
|
|
42
41
|
name: blockName.replace('block-', ''),
|
|
43
42
|
variants: blockVariants,
|
|
@@ -52,14 +51,13 @@ class Generator {
|
|
|
52
51
|
if (!data.result) {
|
|
53
52
|
throw new Error('Strapi block generation failed');
|
|
54
53
|
}
|
|
55
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
56
54
|
return data.result;
|
|
57
55
|
}
|
|
58
56
|
async loadProjectCSS(nextProject) {
|
|
59
57
|
if (!nextProject) {
|
|
60
58
|
return null;
|
|
61
59
|
}
|
|
62
|
-
const cssFile = path.join(nextProject.
|
|
60
|
+
const cssFile = path.join(nextProject.srcPath, 'styles', 'index.css');
|
|
63
61
|
try {
|
|
64
62
|
const css = await fs.readFile(cssFile, 'utf-8');
|
|
65
63
|
if (!css) {
|
|
@@ -72,52 +70,53 @@ class Generator {
|
|
|
72
70
|
return null;
|
|
73
71
|
}
|
|
74
72
|
}
|
|
75
|
-
async
|
|
73
|
+
async generateStrapiBlock(blockName, project, blockVariants) {
|
|
74
|
+
const isAlreadyGenerated = await this.state.file.verifyBlockAlreadyGenerated(blockName, project);
|
|
75
|
+
if (isAlreadyGenerated) {
|
|
76
|
+
const content = await this.state.file.loadGeneratedBlock(blockName, project);
|
|
77
|
+
return JSON.parse(content);
|
|
78
|
+
}
|
|
79
|
+
const response = await this.fetchStrapiBlock(blockName, blockVariants);
|
|
80
|
+
await this.state.file.saveGeneratedBlock(blockName, project, response);
|
|
81
|
+
return response;
|
|
82
|
+
}
|
|
83
|
+
async generateNextBlock(blockName, project, blockVariants) {
|
|
84
|
+
const strapiProject = this.data.projects.find((p) => p.type === 'strapi');
|
|
85
|
+
const strapiBlock = strapiProject
|
|
86
|
+
? await this.generateStrapiBlock(blockName, strapiProject, blockVariants)
|
|
87
|
+
: undefined;
|
|
88
|
+
const styles = await this.loadProjectCSS(project);
|
|
89
|
+
const nextResponse = await this.fetchNextBlock(blockName, blockVariants, this.data.variables, styles, strapiBlock);
|
|
90
|
+
await this.state.file.saveGeneratedBlock(blockName, project, nextResponse);
|
|
91
|
+
}
|
|
92
|
+
async generateBlock(blockName, project) {
|
|
76
93
|
try {
|
|
77
94
|
const blockVariants = this.state.getBlockVariants(blockName);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (strapiProject) {
|
|
82
|
-
strapiResponse = await this.generateStrapiBlock(blockName, blockVariants);
|
|
83
|
-
onGenerateCallback();
|
|
84
|
-
const cachePath = path.join(tempFolder, exports.GENERATOR_STRAPI_FILE_NAME);
|
|
85
|
-
await fs.writeFile(cachePath, JSON.stringify(strapiResponse, null, 2));
|
|
95
|
+
await this.state.file.createBlockTempFolder(blockName);
|
|
96
|
+
if (project.type === 'strapi') {
|
|
97
|
+
return this.generateStrapiBlock(blockName, project, blockVariants);
|
|
86
98
|
}
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
onGenerateCallback();
|
|
90
|
-
const cachePath = path.join(tempFolder, exports.GENERATOR_NEXTJS_FILE_NAME);
|
|
91
|
-
await fs.writeFile(cachePath, nextResponse);
|
|
99
|
+
if (project.type === 'next.js') {
|
|
100
|
+
await this.generateNextBlock(blockName, project, blockVariants);
|
|
92
101
|
}
|
|
93
|
-
this.state.setBlockGenerated(blockName);
|
|
94
102
|
}
|
|
95
103
|
catch (error) {
|
|
96
104
|
console.error(error);
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
|
-
async generateBlocks(blockNames) {
|
|
107
|
+
async generateBlocks(blockNames, project) {
|
|
100
108
|
if (!blockNames.length) {
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
throw new Error('No blocks to generate');
|
|
110
|
+
}
|
|
111
|
+
if (project.type !== 'strapi' && project.type !== 'next.js') {
|
|
112
|
+
throw new Error('Project type not supported');
|
|
103
113
|
}
|
|
104
114
|
console.log('- Generating Blocks... Please wait');
|
|
105
|
-
const strapiProject = this.data.projects.find((project) => project.type === 'strapi');
|
|
106
|
-
const nextProject = this.data.projects.find((project) => project.type === 'next.js');
|
|
107
|
-
const styles = await this.loadProjectCSS(nextProject);
|
|
108
115
|
const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.legacy);
|
|
109
|
-
|
|
110
|
-
if (strapiProject) {
|
|
111
|
-
length += blockNames.length;
|
|
112
|
-
}
|
|
113
|
-
if (nextProject) {
|
|
114
|
-
length += blockNames.length;
|
|
115
|
-
}
|
|
116
|
-
progressBar.start(length, 0);
|
|
116
|
+
progressBar.start(blockNames.length, 0);
|
|
117
117
|
for (const block of blockNames) {
|
|
118
|
-
await this.generateBlock(block,
|
|
119
|
-
|
|
120
|
-
});
|
|
118
|
+
await this.generateBlock(block, project);
|
|
119
|
+
progressBar.increment();
|
|
121
120
|
}
|
|
122
121
|
progressBar.stop();
|
|
123
122
|
await this.state.save();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface IStrapiComponent {
|
|
2
|
+
collectionName: string;
|
|
3
|
+
info: {
|
|
4
|
+
name: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
description: string;
|
|
7
|
+
};
|
|
8
|
+
options: Record<string, unknown>;
|
|
9
|
+
attributes: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export interface IStrapiGenerateResponse {
|
|
12
|
+
block: IStrapiComponent;
|
|
13
|
+
assets: IStrapiComponent[];
|
|
14
|
+
}
|
|
15
|
+
export interface INextjsGenerateResponse {
|
|
16
|
+
block: string;
|
|
17
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import type { IProject } from '../../../../types/project';
|
|
1
2
|
import type AIState from '../state';
|
|
2
3
|
declare class ProjectAdder {
|
|
3
4
|
private state;
|
|
4
5
|
constructor(state: AIState);
|
|
5
6
|
private get data();
|
|
6
|
-
|
|
7
|
-
private createNextjsFiles;
|
|
8
|
-
addBlock(blockName: string): Promise<void>;
|
|
7
|
+
addBlock(blockName: string, project: IProject): Promise<void>;
|
|
9
8
|
}
|
|
10
9
|
export default ProjectAdder;
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const fs = require("node:fs/promises");
|
|
4
|
-
const path = require("node:path");
|
|
5
|
-
const files_1 = require("../../../../utils/files");
|
|
6
|
-
const generator_1 = require("../generator");
|
|
7
3
|
class ProjectAdder {
|
|
8
4
|
state;
|
|
9
5
|
constructor(state) {
|
|
@@ -12,67 +8,18 @@ class ProjectAdder {
|
|
|
12
8
|
get data() {
|
|
13
9
|
return this.state.getData();
|
|
14
10
|
}
|
|
15
|
-
async
|
|
16
|
-
const strapiProject = this.data.projects.find((project) => project.type === 'strapi');
|
|
17
|
-
if (!strapiProject) {
|
|
18
|
-
throw new Error('Strapi project not found');
|
|
19
|
-
// return
|
|
20
|
-
}
|
|
21
|
-
const srcPath = strapiProject.srcPath || path.join(strapiProject.path, 'src');
|
|
22
|
-
const componentsFolder = path.join(srcPath, 'components');
|
|
23
|
-
const blocksFolder = path.join(componentsFolder, 'blocks');
|
|
24
|
-
const blocksAssetsFolder = path.join(componentsFolder, 'blocks-assets');
|
|
25
|
-
const strapiResult = await (0, files_1.loadJSONFile)(filePath);
|
|
26
|
-
const blockData = strapiResult.block;
|
|
27
|
-
const assets = strapiResult.assets;
|
|
28
|
-
await (0, files_1.verifyAndCreateFolder)(blocksFolder);
|
|
29
|
-
await (0, files_1.verifyAndCreateFolder)(blocksAssetsFolder);
|
|
30
|
-
for (const asset of assets) {
|
|
31
|
-
const name = asset.info?.name;
|
|
32
|
-
if (!name) {
|
|
33
|
-
console.warn('Asset name is missing, skipping asset creation');
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
await fs.writeFile(path.join(blocksAssetsFolder, `${name}.json`), JSON.stringify(asset, null, 2));
|
|
37
|
-
}
|
|
38
|
-
const blockName = block.name.replace('block-', '');
|
|
39
|
-
await fs.writeFile(path.join(blocksFolder, `${blockName}.json`), JSON.stringify(blockData, null, 2));
|
|
40
|
-
}
|
|
41
|
-
async createNextjsFiles(filePath, block) {
|
|
42
|
-
const project = this.data.projects.find((project) => project.type === 'next.js');
|
|
43
|
-
if (!project) {
|
|
44
|
-
throw new Error('Nextjs project not found');
|
|
45
|
-
// return
|
|
46
|
-
}
|
|
47
|
-
const blockFolder = path.join(project.srcPath || project.path, 'layouts', 'blocks', block.name);
|
|
48
|
-
await (0, files_1.verifyAndCreateFolder)(blockFolder);
|
|
49
|
-
const nextjsResult = await (0, files_1.loadFile)(filePath);
|
|
50
|
-
await fs.writeFile(path.join(blockFolder, `${block.name}.tsx`), nextjsResult);
|
|
51
|
-
const indexContent = `export { default } from './${block.name}'`;
|
|
52
|
-
await fs.writeFile(path.join(blockFolder, 'index.ts'), indexContent);
|
|
53
|
-
}
|
|
54
|
-
async addBlock(blockName) {
|
|
11
|
+
async addBlock(blockName, project) {
|
|
55
12
|
const block = this.data.blocks.find((block) => block.name === blockName);
|
|
56
|
-
if (!block
|
|
13
|
+
if (!block) {
|
|
57
14
|
console.error(`Block ${blockName} not found`);
|
|
58
15
|
return;
|
|
59
16
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (await (0, files_1.verifyPath)(strapiTempFilePath)) {
|
|
63
|
-
await this.createStrapiFiles(strapiTempFilePath, block);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
console.warn(`Strapi file for block ${blockName} not found in ${strapiTempFilePath}`);
|
|
67
|
-
}
|
|
68
|
-
if (await (0, files_1.verifyPath)(nextTempFilePath)) {
|
|
69
|
-
await this.createNextjsFiles(nextTempFilePath, block);
|
|
17
|
+
if (project.type === 'strapi') {
|
|
18
|
+
await this.state.file.addStrapiBlockToProject(block.name, project);
|
|
70
19
|
}
|
|
71
|
-
else {
|
|
72
|
-
|
|
20
|
+
else if (project.type === 'next.js') {
|
|
21
|
+
await this.state.file.addNextBlockToProject(block.name, project);
|
|
73
22
|
}
|
|
74
|
-
this.state.setBlockHidden(blockName, true);
|
|
75
|
-
await this.state.save();
|
|
76
23
|
console.log(`Block ${blockName} added successfully`);
|
|
77
24
|
}
|
|
78
25
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import FileManager from '../file-manager';
|
|
1
2
|
import type { IAIFileState, IAvailableFilters } from './types';
|
|
2
3
|
declare class AIState {
|
|
3
4
|
private filePath;
|
|
4
5
|
private data;
|
|
5
6
|
private server;
|
|
7
|
+
file: FileManager;
|
|
6
8
|
constructor();
|
|
7
9
|
private createOptions;
|
|
8
10
|
create(): Promise<void>;
|
|
@@ -4,13 +4,16 @@ const ai_server_module_1 = require("../../../../modules/ai-server-module");
|
|
|
4
4
|
const project_1 = require("../../../../utils/project");
|
|
5
5
|
const inquirer_1 = require("inquirer");
|
|
6
6
|
const files_1 = require("../../../../utils/files");
|
|
7
|
+
const file_manager_1 = require("../file-manager");
|
|
7
8
|
const FILE_NAME = 'ai-state.json';
|
|
8
9
|
class AIState {
|
|
9
10
|
filePath = '';
|
|
10
11
|
data = null;
|
|
11
12
|
server;
|
|
13
|
+
file;
|
|
12
14
|
constructor() {
|
|
13
15
|
this.server = new ai_server_module_1.default();
|
|
16
|
+
this.file = new file_manager_1.default();
|
|
14
17
|
}
|
|
15
18
|
async createOptions() {
|
|
16
19
|
const query = await inquirer_1.default.prompt([
|
|
@@ -94,9 +97,15 @@ class AIState {
|
|
|
94
97
|
this.data.blocks = blocks;
|
|
95
98
|
}
|
|
96
99
|
setVariables(variables) {
|
|
100
|
+
if (!this.data) {
|
|
101
|
+
throw new Error('AI State not initialized');
|
|
102
|
+
}
|
|
97
103
|
this.data.variables = variables;
|
|
98
104
|
}
|
|
99
105
|
setColors(colors) {
|
|
106
|
+
if (!this.data) {
|
|
107
|
+
throw new Error('AI State not initialized');
|
|
108
|
+
}
|
|
100
109
|
this.data.colors = colors;
|
|
101
110
|
}
|
|
102
111
|
setBlockGenerated(blockName, generated = true) {
|