optikit 1.1.1 → 1.2.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 +23 -2
- package/CLAUDE.md +239 -0
- package/CODE_QUALITY.md +398 -0
- package/ENHANCEMENTS.md +310 -0
- package/FEATURE_ENHANCEMENTS.md +435 -0
- package/README.md +46 -13
- package/SAFETY_FEATURES.md +396 -0
- package/USAGE.md +225 -41
- package/VERSION_MANAGEMENT.md +438 -0
- package/dist/cli.js +116 -7
- package/dist/commands/build/releases.js +57 -0
- package/dist/commands/buildReleases.js +48 -74
- package/dist/commands/clean/flutter.js +51 -0
- package/dist/commands/clean/ios.js +109 -0
- package/dist/commands/cleanProject.js +34 -4
- package/dist/commands/cleanProjectIos.js +17 -7
- package/dist/commands/config/init.js +54 -0
- package/dist/commands/config/rollback.js +161 -0
- package/dist/commands/generateModule.js +39 -11
- package/dist/commands/init.js +54 -0
- package/dist/commands/openProject.js +17 -0
- package/dist/commands/project/devices.js +188 -0
- package/dist/commands/project/generate.js +143 -0
- package/dist/commands/project/open.js +63 -0
- package/dist/commands/project/setup.js +46 -0
- package/dist/commands/rollback.js +161 -0
- package/dist/commands/setupVSCode.js +27 -21
- package/dist/commands/updateVersions.js +13 -1
- package/dist/commands/version/bump.js +161 -0
- package/dist/commands/version/update.js +91 -0
- package/dist/commands/version.js +161 -0
- package/dist/constants.js +131 -0
- package/dist/utils/backupHelpers.js +88 -0
- package/dist/utils/buildHelpers.js +55 -0
- package/dist/utils/commandHelpers.js +51 -0
- package/dist/utils/configHelpers.js +80 -0
- package/dist/utils/dryRunHelpers.js +103 -0
- package/dist/utils/fileHelpers.js +2 -1
- package/dist/utils/helpers/build.js +55 -0
- package/dist/utils/helpers/dryRun.js +103 -0
- package/dist/utils/helpers/file.js +24 -0
- package/dist/utils/helpers/string.js +3 -0
- package/dist/utils/helpers/version.js +80 -0
- package/dist/utils/services/backup.js +88 -0
- package/dist/utils/services/command.js +51 -0
- package/dist/utils/services/config.js +80 -0
- package/dist/utils/services/exec.js +132 -0
- package/dist/utils/services/logger.js +15 -0
- package/dist/utils/validationHelpers.js +101 -0
- package/dist/utils/validators/validation.js +101 -0
- package/dist/utils/versionHelpers.js +80 -0
- package/package.json +1 -1
- package/src/cli.ts +165 -7
- package/src/commands/build/releases.ts +79 -0
- package/src/commands/clean/flutter.ts +58 -0
- package/src/commands/{cleanProjectIos.ts → clean/ios.ts} +19 -10
- package/src/commands/config/init.ts +63 -0
- package/src/commands/config/rollback.ts +200 -0
- package/src/commands/project/devices.ts +246 -0
- package/src/commands/{generateModule.ts → project/generate.ts} +47 -17
- package/src/commands/{openProject.ts → project/open.ts} +26 -5
- package/src/commands/project/setup.ts +50 -0
- package/src/commands/version/bump.ts +202 -0
- package/src/commands/{updateVersions.ts → version/update.ts} +22 -6
- package/src/constants.ts +144 -0
- package/src/utils/helpers/build.ts +80 -0
- package/src/utils/helpers/dryRun.ts +124 -0
- package/src/utils/{fileHelpers.ts → helpers/file.ts} +3 -2
- package/src/utils/helpers/version.ts +109 -0
- package/src/utils/services/backup.ts +109 -0
- package/src/utils/services/command.ts +76 -0
- package/src/utils/services/config.ts +106 -0
- package/src/utils/{execHelpers.ts → services/exec.ts} +1 -1
- package/src/utils/validators/validation.ts +122 -0
- package/src/commands/buildReleases.ts +0 -102
- package/src/commands/cleanProject.ts +0 -25
- package/src/commands/setupVSCode.ts +0 -44
- /package/src/utils/{stringHelpers.ts → helpers/string.ts} +0 -0
- /package/src/utils/{loggerHelpers.ts → services/logger.ts} +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { LoggerHelpers } from "../utils/loggerHelpers.js";
|
|
4
|
+
import { saveConfig } from "../utils/configHelpers.js";
|
|
5
|
+
export { initializeProject };
|
|
6
|
+
/**
|
|
7
|
+
* Initializes OptiKit in the current project
|
|
8
|
+
* Creates .optikitrc configuration file with defaults
|
|
9
|
+
*/
|
|
10
|
+
async function initializeProject() {
|
|
11
|
+
try {
|
|
12
|
+
LoggerHelpers.info("Initializing OptiKit in this project...");
|
|
13
|
+
const configPath = path.join(process.cwd(), ".optikitrc.json");
|
|
14
|
+
// Check if config already exists
|
|
15
|
+
if (fs.existsSync(configPath)) {
|
|
16
|
+
LoggerHelpers.warning("OptiKit configuration already exists.");
|
|
17
|
+
LoggerHelpers.info("To reconfigure, delete .optikitrc.json and run init again.");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Create default configuration
|
|
21
|
+
const defaultConfig = {
|
|
22
|
+
backupRetentionCount: 5,
|
|
23
|
+
useFvmByDefault: false,
|
|
24
|
+
autoBackup: true,
|
|
25
|
+
verbose: false,
|
|
26
|
+
};
|
|
27
|
+
// Save configuration
|
|
28
|
+
const success = saveConfig(defaultConfig);
|
|
29
|
+
if (success) {
|
|
30
|
+
LoggerHelpers.success("OptiKit initialized successfully!");
|
|
31
|
+
console.log("\nDefault configuration:");
|
|
32
|
+
console.log(JSON.stringify(defaultConfig, null, 2));
|
|
33
|
+
console.log("\nYou can modify .optikitrc.json to customize these settings.\n");
|
|
34
|
+
// Create .gitignore entry for backups if .gitignore exists
|
|
35
|
+
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
36
|
+
if (fs.existsSync(gitignorePath)) {
|
|
37
|
+
const gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
|
|
38
|
+
if (!gitignoreContent.includes(".optikit-backup")) {
|
|
39
|
+
fs.appendFileSync(gitignorePath, "\n# OptiKit backup files\n.optikit-backup/\n");
|
|
40
|
+
LoggerHelpers.success("Added .optikit-backup/ to .gitignore");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof Error) {
|
|
47
|
+
LoggerHelpers.error(`Error initializing project: ${error.message}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
LoggerHelpers.error(`Error initializing project: ${error}`);
|
|
51
|
+
}
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { LoggerHelpers } from "../utils/loggerHelpers.js";
|
|
2
2
|
import { execCommand } from "../utils/execHelpers.js";
|
|
3
3
|
import { platform } from "os";
|
|
4
|
+
import { validateFlutterProject, validateIosProject, validateAndroidProject } from "../utils/validationHelpers.js";
|
|
4
5
|
export { openIos, openAndroid };
|
|
5
6
|
async function openIos() {
|
|
6
7
|
LoggerHelpers.info("Opening the iOS project in Xcode...");
|
|
8
|
+
// Pre-flight validation
|
|
9
|
+
if (!validateFlutterProject()) {
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
if (!validateIosProject()) {
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
7
15
|
const command = "open ios/Runner.xcworkspace";
|
|
8
16
|
try {
|
|
9
17
|
await execCommand(command);
|
|
@@ -16,10 +24,18 @@ async function openIos() {
|
|
|
16
24
|
else {
|
|
17
25
|
LoggerHelpers.error(`Error while opening Xcode: ${error}`);
|
|
18
26
|
}
|
|
27
|
+
process.exit(1);
|
|
19
28
|
}
|
|
20
29
|
}
|
|
21
30
|
async function openAndroid() {
|
|
22
31
|
LoggerHelpers.info("Opening the Android project in Android Studio...");
|
|
32
|
+
// Pre-flight validation
|
|
33
|
+
if (!validateFlutterProject()) {
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (!validateAndroidProject()) {
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
23
39
|
const osPlatform = platform();
|
|
24
40
|
let command;
|
|
25
41
|
if (osPlatform === "win32") {
|
|
@@ -42,5 +58,6 @@ async function openAndroid() {
|
|
|
42
58
|
else {
|
|
43
59
|
LoggerHelpers.error(`Error while opening Android Studio: ${error}`);
|
|
44
60
|
}
|
|
61
|
+
process.exit(1);
|
|
45
62
|
}
|
|
46
63
|
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { exec } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import { execCommand } from "../../utils/services/exec.js";
|
|
4
|
+
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
5
|
+
import { validateFlutterProject, validateFlutterSdk } from "../../utils/validators/validation.js";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
export { listDevices, runApp, getDevicesList, runAppInteractive };
|
|
9
|
+
;
|
|
10
|
+
/**
|
|
11
|
+
* Gets a parsed list of devices
|
|
12
|
+
*/
|
|
13
|
+
async function getDevicesList(useFvm = false) {
|
|
14
|
+
const flutterCommand = useFvm ? "fvm flutter" : "flutter";
|
|
15
|
+
try {
|
|
16
|
+
const { stdout } = await execAsync(`${flutterCommand} devices --machine`);
|
|
17
|
+
const devices = JSON.parse(stdout);
|
|
18
|
+
return devices.map(device => ({
|
|
19
|
+
id: device.id,
|
|
20
|
+
name: device.name,
|
|
21
|
+
platform: device.platform,
|
|
22
|
+
isEmulator: device.emulator
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
// Fallback to empty array if parsing fails
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Lists all connected devices with numbered list
|
|
32
|
+
*/
|
|
33
|
+
async function listDevices(useFvm = false) {
|
|
34
|
+
// Pre-flight validation
|
|
35
|
+
if (!validateFlutterProject()) {
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
if (!(await validateFlutterSdk(!useFvm))) {
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
LoggerHelpers.info("Fetching connected devices...\n");
|
|
43
|
+
const devices = await getDevicesList(useFvm);
|
|
44
|
+
if (devices.length === 0) {
|
|
45
|
+
LoggerHelpers.warning("No devices found.");
|
|
46
|
+
console.log(chalk.gray("\nMake sure you have:"));
|
|
47
|
+
console.log(chalk.gray(" - A device connected via USB"));
|
|
48
|
+
console.log(chalk.gray(" - An emulator/simulator running"));
|
|
49
|
+
console.log(chalk.gray(" - Chrome browser for web development\n"));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
console.log(chalk.bold("\n📱 Connected Devices:\n"));
|
|
53
|
+
devices.forEach((device, index) => {
|
|
54
|
+
const number = chalk.cyan(`[${index + 1}]`);
|
|
55
|
+
const name = chalk.white.bold(device.name);
|
|
56
|
+
const platform = chalk.gray(`(${device.platform})`);
|
|
57
|
+
const type = device.isEmulator ? chalk.yellow(" [Emulator]") : chalk.green(" [Physical]");
|
|
58
|
+
const id = chalk.gray(`ID: ${device.id}`);
|
|
59
|
+
console.log(`${number} ${name} ${platform}${type}`);
|
|
60
|
+
console.log(` ${id}`);
|
|
61
|
+
console.log();
|
|
62
|
+
});
|
|
63
|
+
console.log(chalk.gray("═".repeat(60)));
|
|
64
|
+
console.log(chalk.gray("To run on a specific device:"));
|
|
65
|
+
console.log(chalk.white(" optikit run --device <device-id>"));
|
|
66
|
+
console.log(chalk.gray("\nOr use interactive selection:"));
|
|
67
|
+
console.log(chalk.white(" optikit run-select"));
|
|
68
|
+
console.log(chalk.gray("═".repeat(60) + "\n"));
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (error instanceof Error) {
|
|
72
|
+
LoggerHelpers.error(`Error listing devices: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
LoggerHelpers.error(`Error listing devices: ${error}`);
|
|
76
|
+
}
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Runs the Flutter app on a connected device
|
|
82
|
+
*/
|
|
83
|
+
async function runApp(config) {
|
|
84
|
+
// Pre-flight validation
|
|
85
|
+
if (!validateFlutterProject()) {
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
if (!(await validateFlutterSdk(!config.useFvm))) {
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const flutterCommand = config.useFvm ? "fvm flutter" : "flutter";
|
|
93
|
+
// Build the run command
|
|
94
|
+
let command = `${flutterCommand} run`;
|
|
95
|
+
// Add device flag if specified
|
|
96
|
+
if (config.device) {
|
|
97
|
+
command += ` --device-id ${config.device}`;
|
|
98
|
+
LoggerHelpers.info(`Running on device: ${config.device}`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
LoggerHelpers.info("Running on default device...");
|
|
102
|
+
}
|
|
103
|
+
// Add release flag if specified
|
|
104
|
+
if (config.release) {
|
|
105
|
+
command += " --release";
|
|
106
|
+
LoggerHelpers.info("Running in release mode");
|
|
107
|
+
}
|
|
108
|
+
// Add flavor flag if specified
|
|
109
|
+
if (config.flavor) {
|
|
110
|
+
command += ` --flavor ${config.flavor}`;
|
|
111
|
+
LoggerHelpers.info(`Running with flavor: ${config.flavor}`);
|
|
112
|
+
}
|
|
113
|
+
console.log(chalk.cyan("\nStarting Flutter app..."));
|
|
114
|
+
console.log(chalk.gray(`Command: ${command}\n`));
|
|
115
|
+
await execCommand(command);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error instanceof Error) {
|
|
119
|
+
LoggerHelpers.error(`Error running app: ${error.message}`);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
LoggerHelpers.error(`Error running app: ${error}`);
|
|
123
|
+
}
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Interactive device selection and run
|
|
129
|
+
*/
|
|
130
|
+
async function runAppInteractive(config) {
|
|
131
|
+
// Pre-flight validation
|
|
132
|
+
if (!validateFlutterProject()) {
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
if (!(await validateFlutterSdk(!config.useFvm))) {
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
LoggerHelpers.info("Fetching connected devices...\n");
|
|
140
|
+
const devices = await getDevicesList(config.useFvm);
|
|
141
|
+
if (devices.length === 0) {
|
|
142
|
+
LoggerHelpers.error("No devices found. Please connect a device or start an emulator.");
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
// Show devices
|
|
146
|
+
console.log(chalk.bold("\n📱 Connected Devices:\n"));
|
|
147
|
+
devices.forEach((device, index) => {
|
|
148
|
+
const number = chalk.cyan.bold(`[${index + 1}]`);
|
|
149
|
+
const name = chalk.white.bold(device.name);
|
|
150
|
+
const platform = chalk.gray(`(${device.platform})`);
|
|
151
|
+
const type = device.isEmulator ? chalk.yellow(" [Emulator]") : chalk.green(" [Physical]");
|
|
152
|
+
console.log(`${number} ${name} ${platform}${type}`);
|
|
153
|
+
});
|
|
154
|
+
console.log(chalk.gray("\n" + "═".repeat(60)));
|
|
155
|
+
console.log(chalk.cyan("Enter device number to run on:"));
|
|
156
|
+
console.log(chalk.gray("═".repeat(60) + "\n"));
|
|
157
|
+
// Use readline for user input
|
|
158
|
+
const readline = require('readline');
|
|
159
|
+
const rl = readline.createInterface({
|
|
160
|
+
input: process.stdin,
|
|
161
|
+
output: process.stdout
|
|
162
|
+
});
|
|
163
|
+
rl.question(chalk.yellow("Device number: "), async (answer) => {
|
|
164
|
+
rl.close();
|
|
165
|
+
const deviceIndex = parseInt(answer) - 1;
|
|
166
|
+
if (isNaN(deviceIndex) || deviceIndex < 0 || deviceIndex >= devices.length) {
|
|
167
|
+
LoggerHelpers.error(`Invalid device number. Please choose between 1 and ${devices.length}`);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
const selectedDevice = devices[deviceIndex];
|
|
171
|
+
console.log(chalk.green(`\n✓ Selected: ${selectedDevice.name}\n`));
|
|
172
|
+
// Run on selected device
|
|
173
|
+
await runApp({
|
|
174
|
+
...config,
|
|
175
|
+
device: selectedDevice.id
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
if (error instanceof Error) {
|
|
181
|
+
LoggerHelpers.error(`Error: ${error.message}`);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
LoggerHelpers.error(`Error: ${error}`);
|
|
185
|
+
}
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { createDirectories, writeFile, getClassName, } from "../../utils/helpers/file.js";
|
|
4
|
+
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
5
|
+
export { generateModule };
|
|
6
|
+
function generateModule(moduleName) {
|
|
7
|
+
try {
|
|
8
|
+
// Validate module name
|
|
9
|
+
if (!moduleName || moduleName.trim().length === 0) {
|
|
10
|
+
LoggerHelpers.error("Module name cannot be empty.");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
// Validate module name format (only lowercase letters, numbers, and underscores)
|
|
14
|
+
const validNamePattern = /^[a-z0-9_]+$/;
|
|
15
|
+
if (!validNamePattern.test(moduleName)) {
|
|
16
|
+
LoggerHelpers.error("Module name must contain only lowercase letters, numbers, and underscores.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const modulePath = path.join("lib", "module", moduleName);
|
|
20
|
+
const directories = ["bloc", "event", "state", "screen", "import", "factory"];
|
|
21
|
+
// Check if module already exists
|
|
22
|
+
if (fs.existsSync(modulePath)) {
|
|
23
|
+
LoggerHelpers.warning(`Module ${moduleName} already exists at ${modulePath}`);
|
|
24
|
+
LoggerHelpers.info("Files will be overwritten...");
|
|
25
|
+
}
|
|
26
|
+
createDirectories(modulePath, directories);
|
|
27
|
+
LoggerHelpers.info(`Creating module structure for ${moduleName}...`);
|
|
28
|
+
generateBloc(moduleName, path.join(modulePath, "bloc"));
|
|
29
|
+
generateEvent(moduleName, path.join(modulePath, "event"));
|
|
30
|
+
generateState(moduleName, path.join(modulePath, "state"));
|
|
31
|
+
generateScreen(moduleName, path.join(modulePath, "screen"));
|
|
32
|
+
generateImport(moduleName, path.join(modulePath, "import"));
|
|
33
|
+
generateStateFactory(moduleName, path.join(modulePath, "factory"));
|
|
34
|
+
LoggerHelpers.success(`Module ${moduleName} created with full structure.`);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof Error) {
|
|
38
|
+
LoggerHelpers.error(`Error generating module: ${error.message}`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
LoggerHelpers.error(`Error generating module: ${error}`);
|
|
42
|
+
}
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function generateBloc(moduleName, blocPath) {
|
|
47
|
+
const blocFilePath = path.join(blocPath, `${moduleName}_bloc.dart`);
|
|
48
|
+
const className = getClassName(moduleName, "bloc");
|
|
49
|
+
const template = `part of '../import/${moduleName}_import.dart';
|
|
50
|
+
|
|
51
|
+
class ${className}Bloc extends BaseBloc {
|
|
52
|
+
${className}Bloc() : super(
|
|
53
|
+
${className}Factory(),
|
|
54
|
+
initialState: ${className}InitialState(),
|
|
55
|
+
) {}
|
|
56
|
+
|
|
57
|
+
@override
|
|
58
|
+
void onDispose() {}
|
|
59
|
+
}
|
|
60
|
+
`;
|
|
61
|
+
writeFile(blocFilePath, template);
|
|
62
|
+
LoggerHelpers.success(`Bloc file ${moduleName}_bloc.dart created in ${blocPath}`);
|
|
63
|
+
}
|
|
64
|
+
function generateEvent(moduleName, eventPath) {
|
|
65
|
+
const eventFilePath = path.join(eventPath, `${moduleName}_event.dart`);
|
|
66
|
+
const className = getClassName(moduleName, "event");
|
|
67
|
+
const template = `part of '../import/${moduleName}_import.dart';
|
|
68
|
+
|
|
69
|
+
class ${className}InitialEvent extends BaseEvent {}
|
|
70
|
+
`;
|
|
71
|
+
writeFile(eventFilePath, template);
|
|
72
|
+
LoggerHelpers.success(`Event file ${moduleName}_event.dart created in ${eventPath}`);
|
|
73
|
+
}
|
|
74
|
+
function generateState(moduleName, statePath) {
|
|
75
|
+
const stateFilePath = path.join(statePath, `${moduleName}_state.dart`);
|
|
76
|
+
const className = getClassName(moduleName, "state");
|
|
77
|
+
const template = `part of '../import/${moduleName}_import.dart';
|
|
78
|
+
|
|
79
|
+
class ${className}InitialState extends RenderDataState {
|
|
80
|
+
${className}InitialState() : super(null);
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
writeFile(stateFilePath, template);
|
|
84
|
+
LoggerHelpers.success(`State file ${moduleName}_state.dart created in ${statePath}`);
|
|
85
|
+
}
|
|
86
|
+
function generateScreen(moduleName, screenPath) {
|
|
87
|
+
const screenFilePath = path.join(screenPath, `${moduleName}_screen.dart`);
|
|
88
|
+
const className = getClassName(moduleName, "screen");
|
|
89
|
+
const template = `part of '../import/${moduleName}_import.dart';
|
|
90
|
+
|
|
91
|
+
class ${className}Screen extends StatefulWidget {
|
|
92
|
+
final ${className}Bloc bloc;
|
|
93
|
+
const ${className}Screen({super.key, required this.bloc});
|
|
94
|
+
|
|
95
|
+
@override
|
|
96
|
+
_${className}ScreenState createState() => _${className}ScreenState(bloc);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
class _${className}ScreenState extends BaseScreen<${className}Bloc, ${className}Screen, dynamic> {
|
|
100
|
+
_${className}ScreenState(super.bloc);
|
|
101
|
+
|
|
102
|
+
@override
|
|
103
|
+
Widget buildWidget(BuildContext context, RenderDataState state) {
|
|
104
|
+
return Container();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@override
|
|
108
|
+
void listenToState(BuildContext context, BaseState state) {}
|
|
109
|
+
}
|
|
110
|
+
`;
|
|
111
|
+
writeFile(screenFilePath, template);
|
|
112
|
+
LoggerHelpers.success(`Screen file ${moduleName}_screen.dart created in ${screenPath}`);
|
|
113
|
+
}
|
|
114
|
+
function generateImport(moduleName, importPath) {
|
|
115
|
+
const importFilePath = path.join(importPath, `${moduleName}_import.dart`);
|
|
116
|
+
const className = getClassName(moduleName, "import");
|
|
117
|
+
const template = `import 'package:flutter/material.dart';
|
|
118
|
+
import 'package:opticore/opticore.dart';
|
|
119
|
+
|
|
120
|
+
part '../bloc/${moduleName}_bloc.dart';
|
|
121
|
+
part '../event/${moduleName}_event.dart';
|
|
122
|
+
part '../screen/${moduleName}_screen.dart';
|
|
123
|
+
part '../state/${moduleName}_state.dart';
|
|
124
|
+
part '../factory/${moduleName}_factory.dart';
|
|
125
|
+
`;
|
|
126
|
+
writeFile(importFilePath, template);
|
|
127
|
+
LoggerHelpers.success(`Import file ${moduleName}_import.dart created in ${importPath}`);
|
|
128
|
+
}
|
|
129
|
+
function generateStateFactory(moduleName, factoryPath) {
|
|
130
|
+
const factoryFilePath = path.join(factoryPath, `${moduleName}_factory.dart`);
|
|
131
|
+
const className = getClassName(moduleName, "state_factory");
|
|
132
|
+
const template = `part of '../import/${moduleName}_import.dart';
|
|
133
|
+
|
|
134
|
+
class ${className}Factory extends BaseFactory {
|
|
135
|
+
@override
|
|
136
|
+
BaseState getState<M>(M data) {
|
|
137
|
+
return DefaultState();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
writeFile(factoryFilePath, template);
|
|
142
|
+
LoggerHelpers.success(`State Factory file ${moduleName}_factory.dart created in ${factoryPath}`);
|
|
143
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
2
|
+
import { execCommand } from "../../utils/services/exec.js";
|
|
3
|
+
import { platform } from "os";
|
|
4
|
+
import { validateFlutterProject, validateIosProject, validateAndroidProject } from "../../utils/validators/validation.js";
|
|
5
|
+
export { openIos, openAndroid };
|
|
6
|
+
async function openIos() {
|
|
7
|
+
LoggerHelpers.info("Opening the iOS project in Xcode...");
|
|
8
|
+
// Pre-flight validation
|
|
9
|
+
if (!validateFlutterProject()) {
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
if (!validateIosProject()) {
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const command = "open ios/Runner.xcworkspace";
|
|
16
|
+
try {
|
|
17
|
+
await execCommand(command);
|
|
18
|
+
LoggerHelpers.success("Xcode opened successfully.");
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
LoggerHelpers.error(`Error while opening Xcode: ${error.message}`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
LoggerHelpers.error(`Error while opening Xcode: ${error}`);
|
|
26
|
+
}
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function openAndroid() {
|
|
31
|
+
LoggerHelpers.info("Opening the Android project in Android Studio...");
|
|
32
|
+
// Pre-flight validation
|
|
33
|
+
if (!validateFlutterProject()) {
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (!validateAndroidProject()) {
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const osPlatform = platform();
|
|
40
|
+
let command;
|
|
41
|
+
if (osPlatform === "win32") {
|
|
42
|
+
command = "start android";
|
|
43
|
+
}
|
|
44
|
+
else if (osPlatform === "darwin") {
|
|
45
|
+
command = "open -a 'Android Studio' android";
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
command = "xdg-open android";
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await execCommand(command);
|
|
52
|
+
LoggerHelpers.success("Android Studio opened successfully.");
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error instanceof Error) {
|
|
56
|
+
LoggerHelpers.error(`Error while opening Android Studio: ${error.message}`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
LoggerHelpers.error(`Error while opening Android Studio: ${error}`);
|
|
60
|
+
}
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
4
|
+
export { createVscodeSettings, };
|
|
5
|
+
/**
|
|
6
|
+
* Creates a .vscode directory (if it doesn't exist) and writes a settings.json file
|
|
7
|
+
* with recommended Flutter configuration. The Flutter SDK path is set to ".fvm/flutter_sdk".
|
|
8
|
+
*/
|
|
9
|
+
async function createVscodeSettings() {
|
|
10
|
+
try {
|
|
11
|
+
const vscodeDir = path.join(process.cwd(), ".vscode");
|
|
12
|
+
const settingsPath = path.join(vscodeDir, "settings.json");
|
|
13
|
+
// Create the .vscode folder using Node.js fs (cross-platform)
|
|
14
|
+
if (!fs.existsSync(vscodeDir)) {
|
|
15
|
+
fs.mkdirSync(vscodeDir, { recursive: true });
|
|
16
|
+
LoggerHelpers.success("Created .vscode directory.");
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
LoggerHelpers.info(".vscode directory already exists.");
|
|
20
|
+
}
|
|
21
|
+
// Define the settings object
|
|
22
|
+
const settings = {
|
|
23
|
+
"dart.flutterSdkPath": ".fvm/flutter_sdk",
|
|
24
|
+
"editor.formatOnSave": true,
|
|
25
|
+
"dart.previewFlutterUiGuides": true,
|
|
26
|
+
"files.exclude": {
|
|
27
|
+
"**/.git": true,
|
|
28
|
+
"**/.DS_Store": true,
|
|
29
|
+
"**/node_modules": true,
|
|
30
|
+
"**/build": true
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
// Write settings.json using Node.js fs
|
|
34
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf8");
|
|
35
|
+
LoggerHelpers.success("Created .vscode/settings.json with Flutter configuration.");
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error instanceof Error) {
|
|
39
|
+
LoggerHelpers.error(`Error while creating VSCode settings: ${error.message}`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
LoggerHelpers.error(`Error while creating VSCode settings: ${error}`);
|
|
43
|
+
}
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
}
|