@futurebrand/dev-tools 2.1.2 → 2.4.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/dist/bin.js +11 -0
- package/dist/commands/ai/add.d.ts +3 -0
- package/dist/commands/ai/add.js +46 -0
- package/dist/commands/ai/generate.d.ts +3 -0
- package/dist/commands/ai/generate.js +75 -0
- package/dist/commands/ai/index.d.ts +3 -0
- package/dist/commands/ai/index.js +43 -0
- package/dist/commands/ai/modules/figma/api.d.ts +8 -0
- package/dist/commands/ai/modules/figma/api.js +22 -0
- package/dist/commands/ai/modules/figma/index.d.ts +10 -0
- package/dist/commands/ai/modules/figma/index.js +95 -0
- package/dist/commands/ai/modules/figma/types.d.ts +40 -0
- package/dist/commands/ai/modules/generator/index.d.ts +17 -0
- package/dist/commands/ai/modules/generator/index.js +184 -0
- package/dist/commands/ai/modules/project-adder/index.d.ts +10 -0
- package/dist/commands/ai/modules/project-adder/index.js +78 -0
- package/dist/commands/ai/modules/state/index.d.ts +23 -0
- package/dist/commands/ai/modules/state/index.js +133 -0
- package/dist/commands/ai/modules/state/types.d.ts +29 -0
- package/dist/commands/ai/modules/state/types.js +2 -0
- package/dist/commands/ai/remove.d.ts +3 -0
- package/dist/commands/ai/remove.js +42 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +21 -0
- package/dist/{bin/commands → commands}/project-setup/configs.d.ts +1 -1
- package/dist/{bin/commands → commands}/project-setup/configs.js +1 -0
- package/dist/commands/project-setup/index.js +22 -0
- package/dist/commands/project-setup/utils/files.d.ts +2 -0
- package/dist/commands/project-setup/utils/files.js +21 -0
- package/dist/commands/project-setup/utils/lint.d.ts +3 -0
- package/dist/commands/project-setup/utils/lint.js +22 -0
- package/dist/commands/project-setup/utils/packages.d.ts +5 -0
- package/dist/{bin/commands/project-setup/modules → commands/project-setup/utils}/packages.js +17 -8
- package/dist/modules/parallel/index.d.ts +16 -0
- package/dist/modules/parallel/index.js +50 -0
- package/dist/plugins/eslint/configs/configs.d.mts +1 -1
- package/dist/plugins/eslint/configs/configs.mjs +1 -1
- package/dist/plugins/eslint/node.mjs +1 -1
- package/dist/plugins/prettier/prettier.d.mts +7 -5
- package/dist/types/project.d.ts +20 -0
- package/dist/types/project.js +2 -0
- package/dist/utils/files.d.ts +10 -0
- package/dist/utils/files.js +84 -0
- package/dist/utils/package-manager.d.ts +4 -0
- package/dist/utils/package-manager.js +40 -0
- package/dist/utils/project-type.d.ts +2 -0
- package/dist/utils/project-type.js +66 -0
- package/dist/utils/project.d.ts +2 -0
- package/dist/utils/project.js +43 -0
- package/dist/utils/sleep.d.ts +1 -0
- package/dist/utils/sleep.js +6 -0
- package/package.json +25 -22
- package/dist/bin/commands/index.d.ts +0 -2
- package/dist/bin/commands/index.js +0 -7
- package/dist/bin/commands/project-setup/index.js +0 -22
- package/dist/bin/commands/project-setup/modules/files.d.ts +0 -2
- package/dist/bin/commands/project-setup/modules/files.js +0 -29
- package/dist/bin/commands/project-setup/modules/packages.d.ts +0 -3
- package/dist/bin/index.js +0 -20
- package/dist/bin/modules/files.d.ts +0 -6
- package/dist/bin/modules/files.js +0 -68
- package/dist/bin/modules/package-manager.d.ts +0 -1
- package/dist/bin/modules/package-manager.js +0 -15
- package/dist/bin/modules/project-type.d.ts +0 -2
- package/dist/bin/modules/project-type.js +0 -36
- package/dist/bin/types.d.ts +0 -8
- /package/dist/{bin/index.d.ts → bin.d.ts} +0 -0
- /package/dist/{bin → commands/ai/modules/figma}/types.js +0 -0
- /package/dist/{bin/commands → commands}/project-setup/index.d.ts +0 -0
package/dist/bin.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const package_json_1 = require("../package.json");
|
|
6
|
+
const commands_1 = require("./commands");
|
|
7
|
+
(0, commands_1.addCommands)(commander_1.program, {
|
|
8
|
+
version: package_json_1.version,
|
|
9
|
+
description: package_json_1.description,
|
|
10
|
+
});
|
|
11
|
+
commander_1.program.parse(process.argv);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const inquirer_1 = require("inquirer");
|
|
5
|
+
const project_adder_1 = require("./modules/project-adder");
|
|
6
|
+
const state_1 = require("./modules/state");
|
|
7
|
+
const addCommand = new commander_1.Command('add')
|
|
8
|
+
.alias('a')
|
|
9
|
+
.alias('copy')
|
|
10
|
+
.alias('move')
|
|
11
|
+
.alias('import')
|
|
12
|
+
.option('-a, --all', 'Show all hidden blocks')
|
|
13
|
+
.description('Ai Add Command')
|
|
14
|
+
.action(async (options) => {
|
|
15
|
+
const state = await state_1.default.init();
|
|
16
|
+
if (!state.isReady) {
|
|
17
|
+
console.error('AI State not initialized');
|
|
18
|
+
console.error('Run "fub ai --init" first');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const isAll = options.all === true;
|
|
22
|
+
const choices = state.getAvailableBlocksNames({
|
|
23
|
+
hidden: isAll ? undefined : false,
|
|
24
|
+
generated: true,
|
|
25
|
+
});
|
|
26
|
+
if (!choices.length) {
|
|
27
|
+
console.error('No blocks available to add');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const blockQuery = await inquirer_1.default.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: 'select',
|
|
33
|
+
name: 'block',
|
|
34
|
+
message: 'Select the block to add',
|
|
35
|
+
choices,
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
const blocksToAdd = blockQuery.block;
|
|
39
|
+
if (!blocksToAdd) {
|
|
40
|
+
console.error('No blocks selected');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const projectAdder = new project_adder_1.default(state);
|
|
44
|
+
await projectAdder.addBlock(blocksToAdd);
|
|
45
|
+
});
|
|
46
|
+
exports.default = addCommand;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const inquirer_1 = require("inquirer");
|
|
5
|
+
const generator_1 = require("./modules/generator");
|
|
6
|
+
const state_1 = require("./modules/state");
|
|
7
|
+
const generateCommand = new commander_1.Command('generate')
|
|
8
|
+
.alias('g')
|
|
9
|
+
.alias('create')
|
|
10
|
+
.option('-a, --all', 'Show all generated and hidden blocks')
|
|
11
|
+
.description('Ai Generate Command')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
const state = await state_1.default.init();
|
|
14
|
+
if (!state.isReady) {
|
|
15
|
+
console.error('AI State not initialized');
|
|
16
|
+
console.error('Run "fub ai --init" first');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const isAll = options.all === true;
|
|
20
|
+
const choices = state.getAvailableBlocksNames(isAll
|
|
21
|
+
? {}
|
|
22
|
+
: {
|
|
23
|
+
hidden: false,
|
|
24
|
+
generated: false,
|
|
25
|
+
});
|
|
26
|
+
if (!choices.length) {
|
|
27
|
+
console.error('No blocks available to generate');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const blockQuery = await inquirer_1.default.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: 'checkbox',
|
|
33
|
+
name: 'blocks',
|
|
34
|
+
message: 'Select the blocks to generate',
|
|
35
|
+
choices,
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
const blocksToGenerate = blockQuery.blocks;
|
|
39
|
+
if (!blocksToGenerate.length) {
|
|
40
|
+
console.error('No blocks selected');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const generator = new generator_1.Generator(state);
|
|
44
|
+
await generator.generateBlocks(blocksToGenerate);
|
|
45
|
+
});
|
|
46
|
+
const generateStyleCommand = new commander_1.Command('styles')
|
|
47
|
+
.alias('style')
|
|
48
|
+
.alias('css')
|
|
49
|
+
.description('Ai Generate Style Command')
|
|
50
|
+
.action(async () => {
|
|
51
|
+
const state = await state_1.default.init();
|
|
52
|
+
if (!state.isReady) {
|
|
53
|
+
console.error('AI State not initialized');
|
|
54
|
+
console.error('Run "fub ai --init" first');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const generator = new generator_1.Generator(state);
|
|
58
|
+
await generator.generateStyles();
|
|
59
|
+
});
|
|
60
|
+
const generateChecklistCommand = new commander_1.Command('checklist')
|
|
61
|
+
.alias('ckl')
|
|
62
|
+
.description('Ai Generate Checklist File Command')
|
|
63
|
+
.action(async () => {
|
|
64
|
+
const state = await state_1.default.init();
|
|
65
|
+
if (!state.isReady) {
|
|
66
|
+
console.error('AI State not initialized');
|
|
67
|
+
console.error('Run "fub ai --init" first');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const generator = new generator_1.Generator(state);
|
|
71
|
+
await generator.generateChecklist();
|
|
72
|
+
});
|
|
73
|
+
generateCommand.addCommand(generateStyleCommand);
|
|
74
|
+
generateCommand.addCommand(generateChecklistCommand);
|
|
75
|
+
exports.default = generateCommand;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const add_1 = require("./add");
|
|
5
|
+
const generate_1 = require("./generate");
|
|
6
|
+
const figma_1 = require("./modules/figma");
|
|
7
|
+
const state_1 = require("./modules/state");
|
|
8
|
+
const remove_1 = require("./remove");
|
|
9
|
+
const fubAICommand = new commander_1.Command('ai')
|
|
10
|
+
.description('Ai Commands')
|
|
11
|
+
// Init flag
|
|
12
|
+
.option('-i, --init', 'Init AI State')
|
|
13
|
+
.option('-r, --reset', 'Reset AI State')
|
|
14
|
+
.option('-l, --load', 'Load AI Data')
|
|
15
|
+
.action(async (options) => {
|
|
16
|
+
const isInit = options.init === true;
|
|
17
|
+
const isReset = options.reset === true;
|
|
18
|
+
const isLoad = options.load === true;
|
|
19
|
+
if (!isInit && !isReset && !isLoad) {
|
|
20
|
+
console.error('No action specified');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const state = await state_1.default.init();
|
|
25
|
+
if (isInit && state.isReady) {
|
|
26
|
+
console.error('AI State already initialized, use --reset to recreate it or --load to load blocks again');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (isReset || isInit || (isLoad && !state.isReady)) {
|
|
30
|
+
await state.create();
|
|
31
|
+
}
|
|
32
|
+
const figma = new figma_1.default(state);
|
|
33
|
+
await figma.loadBlocks();
|
|
34
|
+
await state.save();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(error);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
fubAICommand.addCommand(generate_1.default);
|
|
41
|
+
fubAICommand.addCommand(add_1.default);
|
|
42
|
+
fubAICommand.addCommand(remove_1.default);
|
|
43
|
+
exports.default = fubAICommand;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type AIState from '../state';
|
|
2
|
+
export declare class FigmaAPI {
|
|
3
|
+
private state;
|
|
4
|
+
constructor(state: AIState);
|
|
5
|
+
getBlockCanvas(pageId: string): Promise<string>;
|
|
6
|
+
getVariables(pageId: string): Promise<Record<string, any>>;
|
|
7
|
+
getBlocks(pageId: string, canvasId: string): Promise<Record<string, import("./types").IFigmaNode[]>>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FigmaAPI = void 0;
|
|
4
|
+
class FigmaAPI {
|
|
5
|
+
state;
|
|
6
|
+
constructor(state) {
|
|
7
|
+
this.state = state;
|
|
8
|
+
}
|
|
9
|
+
async getBlockCanvas(pageId) {
|
|
10
|
+
const { id } = await this.state.fetchApi(`/figma/${pageId}/blocks`);
|
|
11
|
+
return id;
|
|
12
|
+
}
|
|
13
|
+
async getVariables(pageId) {
|
|
14
|
+
const { variables } = await this.state.fetchApi(`/figma/${pageId}/blocks`);
|
|
15
|
+
return variables;
|
|
16
|
+
}
|
|
17
|
+
async getBlocks(pageId, canvasId) {
|
|
18
|
+
const { blocks } = await this.state.fetchApi(`/figma/${pageId}/blocks/${canvasId}`);
|
|
19
|
+
return blocks;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.FigmaAPI = FigmaAPI;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const inquirer_1 = require("inquirer");
|
|
4
|
+
const api_1 = require("./api");
|
|
5
|
+
// Limit of same variant of the same block
|
|
6
|
+
class FigmaModule {
|
|
7
|
+
state;
|
|
8
|
+
api;
|
|
9
|
+
constructor(state) {
|
|
10
|
+
this.state = state;
|
|
11
|
+
this.api = new api_1.FigmaAPI(state);
|
|
12
|
+
}
|
|
13
|
+
addVariantsToBlock(data, variants) {
|
|
14
|
+
// Add only unique instances
|
|
15
|
+
for (const variant of variants) {
|
|
16
|
+
const existIndex = data.variants.findIndex((v) => v.id === variant.id);
|
|
17
|
+
if (existIndex !== -1) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
data.variants.push(variant);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
getDefaultCheckedBlocks(blocks, added) {
|
|
24
|
+
// const data = this.state.getData()
|
|
25
|
+
const defaultBlocks = [];
|
|
26
|
+
// const strapiProject = data.projects.find(
|
|
27
|
+
// (project) => project.type === 'strapi'
|
|
28
|
+
// )
|
|
29
|
+
// const nextProject = data.projects.find(
|
|
30
|
+
// (project) => project.type === 'next.js'
|
|
31
|
+
// )
|
|
32
|
+
for (const block of blocks) {
|
|
33
|
+
if (added.includes(block.name)) {
|
|
34
|
+
//
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (!block.hidden && !block.generated) {
|
|
38
|
+
defaultBlocks.push(block.name);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return defaultBlocks;
|
|
42
|
+
}
|
|
43
|
+
async loadBlocks() {
|
|
44
|
+
console.log('- Finding figma blocks canvas... Please wait');
|
|
45
|
+
const data = this.state.getData();
|
|
46
|
+
const figmaPageID = data.configs.figma;
|
|
47
|
+
const canvas = await this.api.getBlockCanvas(figmaPageID);
|
|
48
|
+
console.log('- Loading pages blocks');
|
|
49
|
+
const blocksData = data.blocks;
|
|
50
|
+
const newBlocks = [];
|
|
51
|
+
const [blocks, variables] = await Promise.all([
|
|
52
|
+
this.api.getBlocks(figmaPageID, canvas),
|
|
53
|
+
this.api.getVariables(figmaPageID),
|
|
54
|
+
]);
|
|
55
|
+
Object.keys(blocks).forEach((blockName) => {
|
|
56
|
+
let block = blocksData.find((block) => block.name === blockName);
|
|
57
|
+
if (!block) {
|
|
58
|
+
block = {
|
|
59
|
+
name: blockName,
|
|
60
|
+
variants: [],
|
|
61
|
+
hidden: false,
|
|
62
|
+
generated: false,
|
|
63
|
+
};
|
|
64
|
+
newBlocks.push(blockName);
|
|
65
|
+
blocksData.push(block);
|
|
66
|
+
}
|
|
67
|
+
this.addVariantsToBlock(block, blocks[blockName]);
|
|
68
|
+
});
|
|
69
|
+
console.log(`- Loaded ${blocksData.length} blocks from Figma (${newBlocks.length} new)`);
|
|
70
|
+
const blockNames = blocksData.map((block) => block.name);
|
|
71
|
+
const defaultCheckedBlocks = this.getDefaultCheckedBlocks(blocksData, newBlocks);
|
|
72
|
+
if (newBlocks.length) {
|
|
73
|
+
const query = await inquirer_1.default.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: 'checkbox',
|
|
76
|
+
name: 'blocks',
|
|
77
|
+
message: 'What blocks do you want to use?',
|
|
78
|
+
choices: blockNames,
|
|
79
|
+
default: defaultCheckedBlocks,
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
for (const blockName of blockNames) {
|
|
83
|
+
const block = blocksData.find((b) => b.name === blockName);
|
|
84
|
+
if (block) {
|
|
85
|
+
const isNotHidden = query.blocks.includes(blockName);
|
|
86
|
+
block.hidden = !isNotHidden;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.state.setBlocks(blocksData);
|
|
91
|
+
this.state.setVariables(variables);
|
|
92
|
+
console.log('- Figma blocks loaded successfully');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.default = FigmaModule;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface IDocumentResponse {
|
|
2
|
+
id: string;
|
|
3
|
+
}
|
|
4
|
+
export interface IVariablesResponse {
|
|
5
|
+
variables: Record<string, any>;
|
|
6
|
+
}
|
|
7
|
+
interface IFigmaProperties {
|
|
8
|
+
value: string;
|
|
9
|
+
type: string;
|
|
10
|
+
}
|
|
11
|
+
export interface IFigmaNode {
|
|
12
|
+
id: string;
|
|
13
|
+
type: string;
|
|
14
|
+
name: string;
|
|
15
|
+
visible: boolean;
|
|
16
|
+
children: IFigmaNode[];
|
|
17
|
+
scrollBehavior: string;
|
|
18
|
+
componentId: string;
|
|
19
|
+
componentProperties: Record<string, IFigmaProperties>;
|
|
20
|
+
overrides: {
|
|
21
|
+
id: string;
|
|
22
|
+
overriddenFields: string[];
|
|
23
|
+
}[];
|
|
24
|
+
absoluteBoundingBox: {
|
|
25
|
+
x: number;
|
|
26
|
+
y: number;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
absoluteRenderBounds: {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface IListBlocksResponse {
|
|
38
|
+
blocks: Record<string, IFigmaNode[]>;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IProject } from '../../../../types/project';
|
|
2
|
+
import type AIState from '../state';
|
|
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
|
+
export declare class Generator {
|
|
7
|
+
private state;
|
|
8
|
+
constructor(state: AIState);
|
|
9
|
+
private get data();
|
|
10
|
+
private generateNextBlock;
|
|
11
|
+
private generateStrapiBlock;
|
|
12
|
+
loadProjectCSS(nextProject?: IProject): Promise<string | null>;
|
|
13
|
+
generateBlock(blockName: string, strapiProject: IProject | null | undefined, nextProject: IProject | null | undefined, styles: string | null | undefined, onGenerateCallback: () => void): Promise<void>;
|
|
14
|
+
generateBlocks(blockNames: string[]): Promise<void>;
|
|
15
|
+
generateStyles(): Promise<void>;
|
|
16
|
+
generateChecklist(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Generator = 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
|
+
const cliProgress = require("cli-progress");
|
|
8
|
+
exports.GENERATOR_FOLDER_NAME = 'generated-blocks';
|
|
9
|
+
exports.GENERATOR_STRAPI_FILE_NAME = 'strapi.json';
|
|
10
|
+
exports.GENERATOR_NEXTJS_FILE_NAME = 'nextjs.tsx';
|
|
11
|
+
class Generator {
|
|
12
|
+
state;
|
|
13
|
+
constructor(state) {
|
|
14
|
+
this.state = state;
|
|
15
|
+
}
|
|
16
|
+
get data() {
|
|
17
|
+
return this.state.getData();
|
|
18
|
+
}
|
|
19
|
+
async generateNextBlock(blockName, blockVariants, variables, styles, strapiComponent) {
|
|
20
|
+
const requestBody = {
|
|
21
|
+
name: blockName.replace('block-', ''),
|
|
22
|
+
variants: blockVariants,
|
|
23
|
+
variables,
|
|
24
|
+
styles,
|
|
25
|
+
strapiComponent,
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
const data = await this.state.fetchApi('/generate/nextjs/block', {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify(requestBody),
|
|
34
|
+
});
|
|
35
|
+
if (data.result?.block) {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
37
|
+
return data.result.block;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error(error);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async generateStrapiBlock(blockName, blockVariants) {
|
|
47
|
+
const requestBody = {
|
|
48
|
+
name: blockName.replace('block-', ''),
|
|
49
|
+
variants: blockVariants,
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
const data = await this.state.fetchApi('/generate/strapi/block', {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify(requestBody),
|
|
58
|
+
});
|
|
59
|
+
if (data.result) {
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
61
|
+
return data.result;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.error(error);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async loadProjectCSS(nextProject) {
|
|
71
|
+
if (!nextProject) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const cssFile = path.join(nextProject.path, 'styles', 'index.css');
|
|
75
|
+
try {
|
|
76
|
+
const css = await fs.readFile(cssFile, 'utf-8');
|
|
77
|
+
if (!css) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return css;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error(error);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async generateBlock(blockName, strapiProject, nextProject, styles, onGenerateCallback) {
|
|
88
|
+
try {
|
|
89
|
+
const blockVariants = this.state.getBlockVariants(blockName);
|
|
90
|
+
const tempFolder = await (0, files_1.getTempFilePath)(exports.GENERATOR_FOLDER_NAME, blockName);
|
|
91
|
+
await (0, files_1.verifyAndCreateFolder)(tempFolder);
|
|
92
|
+
let strapiResponse = null;
|
|
93
|
+
if (strapiProject) {
|
|
94
|
+
strapiResponse = await this.generateStrapiBlock(blockName, blockVariants);
|
|
95
|
+
onGenerateCallback();
|
|
96
|
+
if (strapiResponse) {
|
|
97
|
+
const cachePath = path.join(tempFolder, exports.GENERATOR_STRAPI_FILE_NAME);
|
|
98
|
+
await fs.writeFile(cachePath, JSON.stringify(strapiResponse, null, 2));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (nextProject) {
|
|
102
|
+
const nextResponse = await this.generateNextBlock(blockName, blockVariants, this.data.variables, styles, strapiResponse);
|
|
103
|
+
onGenerateCallback();
|
|
104
|
+
if (nextResponse) {
|
|
105
|
+
const cachePath = path.join(tempFolder, exports.GENERATOR_NEXTJS_FILE_NAME);
|
|
106
|
+
await fs.writeFile(cachePath, nextResponse);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
this.state.setBlockGenerated(blockName);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error(error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async generateBlocks(blockNames) {
|
|
116
|
+
if (!blockNames.length) {
|
|
117
|
+
console.error('No blocks selected');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
console.log('- Generating Blocks... Please wait');
|
|
121
|
+
const strapiProject = this.data.projects.find((project) => project.type === 'strapi');
|
|
122
|
+
const nextProject = this.data.projects.find((project) => project.type === 'next.js');
|
|
123
|
+
const styles = await this.loadProjectCSS(nextProject);
|
|
124
|
+
const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.legacy);
|
|
125
|
+
let length = 0;
|
|
126
|
+
if (strapiProject) {
|
|
127
|
+
length += blockNames.length;
|
|
128
|
+
}
|
|
129
|
+
if (nextProject) {
|
|
130
|
+
length += blockNames.length;
|
|
131
|
+
}
|
|
132
|
+
progressBar.start(length, 0);
|
|
133
|
+
for (const block of blockNames) {
|
|
134
|
+
await this.generateBlock(block, strapiProject, nextProject, styles, () => {
|
|
135
|
+
progressBar.increment();
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
progressBar.stop();
|
|
139
|
+
await this.state.save();
|
|
140
|
+
console.log('- All Blocks generated');
|
|
141
|
+
}
|
|
142
|
+
async generateStyles() {
|
|
143
|
+
console.log('- Generating Styles... Please wait');
|
|
144
|
+
const variables = this.data.variables;
|
|
145
|
+
const data = await this.state.fetchApi('/generate/styles', {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: {
|
|
148
|
+
'Content-Type': 'application/json',
|
|
149
|
+
},
|
|
150
|
+
body: JSON.stringify({ variables }),
|
|
151
|
+
});
|
|
152
|
+
const colors = (data.result?.colors || []);
|
|
153
|
+
this.state.setColors(colors);
|
|
154
|
+
const lines = ['@theme {'];
|
|
155
|
+
for (const color of colors) {
|
|
156
|
+
lines.push(` /* ${color.description} */`);
|
|
157
|
+
lines.push(` --color-${color.name}: ${color.value};`);
|
|
158
|
+
}
|
|
159
|
+
lines.push('}');
|
|
160
|
+
await this.state.save();
|
|
161
|
+
const cssText = lines.join('\n');
|
|
162
|
+
const tempPath = await (0, files_1.getTempFilePath)('styles.css');
|
|
163
|
+
await fs.writeFile(tempPath, cssText);
|
|
164
|
+
console.log(`- Styles generated and saved to ${tempPath}`);
|
|
165
|
+
}
|
|
166
|
+
async generateChecklist() {
|
|
167
|
+
console.log('- Generating Checklist... Please wait');
|
|
168
|
+
const lines = ['# Checklist', ''];
|
|
169
|
+
const blocks = this.state.getData().blocks;
|
|
170
|
+
for (const block of blocks) {
|
|
171
|
+
const name = block.name
|
|
172
|
+
.replace('block-', '')
|
|
173
|
+
.split('-')
|
|
174
|
+
.map((word) => word.length > 1 ? word.charAt(0).toUpperCase() + word.slice(1) : word)
|
|
175
|
+
.join(' ');
|
|
176
|
+
lines.push(`- [${block.generated || block.hidden ? 'x' : ' '}] Block | ${name} (\`${block.name}\`)`);
|
|
177
|
+
}
|
|
178
|
+
const listText = lines.join('\n');
|
|
179
|
+
const tempPath = await (0, files_1.getTempFilePath)('checklist.md');
|
|
180
|
+
await fs.writeFile(tempPath, listText);
|
|
181
|
+
console.log(`- Checklist generated and saved to ${tempPath}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
exports.Generator = Generator;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type AIState from '../state';
|
|
2
|
+
declare class ProjectAdder {
|
|
3
|
+
private state;
|
|
4
|
+
constructor(state: AIState);
|
|
5
|
+
private get data();
|
|
6
|
+
private createStrapiFiles;
|
|
7
|
+
private createNextjsFiles;
|
|
8
|
+
addBlock(blockName: string): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export default ProjectAdder;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
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
|
+
class ProjectAdder {
|
|
8
|
+
state;
|
|
9
|
+
constructor(state) {
|
|
10
|
+
this.state = state;
|
|
11
|
+
}
|
|
12
|
+
get data() {
|
|
13
|
+
return this.state.getData();
|
|
14
|
+
}
|
|
15
|
+
async createStrapiFiles(filePath, block) {
|
|
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 componentsFolder = path.join(strapiProject.path, 'src', 'components');
|
|
22
|
+
const blocksFolder = path.join(componentsFolder, 'blocks');
|
|
23
|
+
const blocksAssetsFolder = path.join(componentsFolder, 'blocks-assets');
|
|
24
|
+
const strapiResult = await (0, files_1.loadJSONFile)(filePath);
|
|
25
|
+
const blockData = strapiResult.block;
|
|
26
|
+
const assets = strapiResult.assets;
|
|
27
|
+
await (0, files_1.verifyAndCreateFolder)(blocksFolder);
|
|
28
|
+
await (0, files_1.verifyAndCreateFolder)(blocksAssetsFolder);
|
|
29
|
+
for (const asset of assets) {
|
|
30
|
+
const name = asset.info?.name;
|
|
31
|
+
if (!name) {
|
|
32
|
+
console.warn('Asset name is missing, skipping asset creation');
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
await fs.writeFile(path.join(blocksAssetsFolder, `${name}.json`), JSON.stringify(asset, null, 2));
|
|
36
|
+
}
|
|
37
|
+
const blockName = block.name.replace('block-', '');
|
|
38
|
+
await fs.writeFile(path.join(blocksFolder, `${blockName}.json`), JSON.stringify(blockData, null, 2));
|
|
39
|
+
}
|
|
40
|
+
async createNextjsFiles(filePath, block) {
|
|
41
|
+
const project = this.data.projects.find((project) => project.type === 'next.js');
|
|
42
|
+
if (!project) {
|
|
43
|
+
throw new Error('Strapi project not found');
|
|
44
|
+
// return
|
|
45
|
+
}
|
|
46
|
+
const blockFolder = path.join(project.path, 'layouts', 'blocks', block.name);
|
|
47
|
+
await (0, files_1.verifyAndCreateFolder)(blockFolder);
|
|
48
|
+
const nextjsResult = await (0, files_1.loadFile)(filePath);
|
|
49
|
+
await fs.writeFile(path.join(blockFolder, `${block.name}.tsx`), nextjsResult);
|
|
50
|
+
const indexContent = `export { default } from './${block.name}'`;
|
|
51
|
+
await fs.writeFile(path.join(blockFolder, 'index.ts'), indexContent);
|
|
52
|
+
}
|
|
53
|
+
async addBlock(blockName) {
|
|
54
|
+
const block = this.data.blocks.find((block) => block.name === blockName);
|
|
55
|
+
if (!block || !block.generated) {
|
|
56
|
+
console.error(`Block ${blockName} not found`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const strapiTempFilePath = await (0, files_1.getTempFilePath)(generator_1.GENERATOR_FOLDER_NAME, blockName, generator_1.GENERATOR_STRAPI_FILE_NAME);
|
|
60
|
+
const nextTempFilePath = await (0, files_1.getTempFilePath)(generator_1.GENERATOR_FOLDER_NAME, blockName, generator_1.GENERATOR_NEXTJS_FILE_NAME);
|
|
61
|
+
if (await (0, files_1.verifyPath)(strapiTempFilePath)) {
|
|
62
|
+
await this.createStrapiFiles(strapiTempFilePath, block);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.warn(`Strapi file for block ${blockName} not found in ${strapiTempFilePath}`);
|
|
66
|
+
}
|
|
67
|
+
if (await (0, files_1.verifyPath)(nextTempFilePath)) {
|
|
68
|
+
await this.createNextjsFiles(nextTempFilePath, block);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.warn(`Next.js file for block ${blockName} not found in ${nextTempFilePath}`);
|
|
72
|
+
}
|
|
73
|
+
this.state.setBlockHidden(blockName, true);
|
|
74
|
+
await this.state.save();
|
|
75
|
+
console.log(`Block ${blockName} added successfully`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.default = ProjectAdder;
|