wlmaker 1.0.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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.mjs +155 -0
  3. package/package.json +38 -0
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # wlmaker-cli
package/dist/cli.mjs ADDED
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/core/create-bloc.ts
7
+ import * as fs3 from "fs";
8
+ import * as path3 from "path";
9
+ import chalk from "chalk";
10
+ import { pascalCase } from "change-case";
11
+
12
+ // src/core/templates.ts
13
+ function blocTemplate(name, pascal) {
14
+ return `import 'package:flutter_bloc/flutter_bloc.dart';
15
+ import 'package:freezed_annotation/freezed_annotation.dart';
16
+
17
+ part '${name}_bloc.freezed.dart';
18
+ part '${name}_event.dart';
19
+ part '${name}_state.dart';
20
+
21
+ class ${pascal}Bloc extends Bloc<${pascal}Event, ${pascal}State> {
22
+ ${pascal}Bloc() : super(${pascal}State.initial()) {
23
+ on<_Started>(_startedEvent);
24
+ }
25
+
26
+ void _startedEvent(_Started event, Emitter<${pascal}State> emit) {
27
+ // TODO: implement event
28
+ }
29
+ }
30
+ `;
31
+ }
32
+ function blocEventTemplate(name, pascal) {
33
+ return `part of '${name}_bloc.dart';
34
+
35
+ @freezed
36
+ sealed class ${pascal}Event with _$${pascal}Event {
37
+ const factory ${pascal}Event.started() = _Started;
38
+ }
39
+ `;
40
+ }
41
+ function blocStateTemplate(name, pascal) {
42
+ return `part of '${name}_bloc.dart';
43
+
44
+ @freezed
45
+ sealed class ${pascal}State with _$${pascal}State {
46
+ const factory ${pascal}State({
47
+ @Default(false) bool fakeVar,
48
+ }) = _${pascal}State;
49
+
50
+ const ${pascal}State._();
51
+
52
+ factory ${pascal}State.initial() => const ${pascal}State();
53
+ }
54
+ `;
55
+ }
56
+
57
+ // src/core/barrel.ts
58
+ import * as fs from "fs";
59
+ import * as path from "path";
60
+ function updateBarrelFile(parentDir, name) {
61
+ const barrelPath = path.join(parentDir, "bloc.dart");
62
+ const exportLine = `export '${name}/${name}_bloc.dart';`;
63
+ if (fs.existsSync(barrelPath)) {
64
+ const content = fs.readFileSync(barrelPath, "utf8");
65
+ if (content.includes(exportLine)) {
66
+ return;
67
+ }
68
+ fs.writeFileSync(barrelPath, content.trimEnd() + "\n" + exportLine + "\n");
69
+ } else {
70
+ fs.writeFileSync(barrelPath, exportLine + "\n");
71
+ }
72
+ }
73
+
74
+ // src/core/build-runner.ts
75
+ import { spawn } from "child_process";
76
+ import * as fs2 from "fs";
77
+ import * as path2 from "path";
78
+ function findPubspecDir(startDir) {
79
+ let dir = startDir;
80
+ while (dir !== path2.dirname(dir)) {
81
+ if (fs2.existsSync(path2.join(dir, "pubspec.yaml"))) {
82
+ return dir;
83
+ }
84
+ dir = path2.dirname(dir);
85
+ }
86
+ return void 0;
87
+ }
88
+ function hasBuildRunner(projectRoot) {
89
+ const pubspec = fs2.readFileSync(path2.join(projectRoot, "pubspec.yaml"), "utf8");
90
+ return /build_runner/.test(pubspec);
91
+ }
92
+ function runBuildRunner(projectRoot) {
93
+ return new Promise((resolve2) => {
94
+ const child = spawn(
95
+ "dart",
96
+ ["run", "build_runner", "build", "--delete-conflicting-outputs"],
97
+ { cwd: projectRoot, stdio: "inherit" }
98
+ );
99
+ child.on("close", (code) => {
100
+ resolve2();
101
+ });
102
+ child.on("error", () => {
103
+ resolve2();
104
+ });
105
+ });
106
+ }
107
+
108
+ // src/core/create-bloc.ts
109
+ var SNAKE_CASE_REGEX = /^[a-z][a-z0-9_]*$/;
110
+ async function createBloc(name, options) {
111
+ const targetDir = path3.resolve(options.dir);
112
+ if (!name || name.trim().length === 0) {
113
+ console.error(chalk.red("Error: Name cannot be empty."));
114
+ process.exit(1);
115
+ }
116
+ if (!SNAKE_CASE_REGEX.test(name)) {
117
+ console.error(chalk.red("Error: Name must be snake_case (lowercase letters, digits, underscores)."));
118
+ process.exit(1);
119
+ }
120
+ if (fs3.existsSync(path3.join(targetDir, name))) {
121
+ console.error(chalk.red(`Error: Directory "${name}" already exists.`));
122
+ process.exit(1);
123
+ }
124
+ const pascal = pascalCase(name);
125
+ const blocDir = path3.join(targetDir, name);
126
+ try {
127
+ fs3.mkdirSync(blocDir, { recursive: true });
128
+ fs3.writeFileSync(path3.join(blocDir, `${name}_bloc.dart`), blocTemplate(name, pascal));
129
+ fs3.writeFileSync(path3.join(blocDir, `${name}_event.dart`), blocEventTemplate(name, pascal));
130
+ fs3.writeFileSync(path3.join(blocDir, `${name}_state.dart`), blocStateTemplate(name, pascal));
131
+ updateBarrelFile(targetDir, name);
132
+ console.log(chalk.green(`\u2713 BLoC "${pascal}Bloc" created successfully.`));
133
+ if (options.buildRunner) {
134
+ const projectRoot = findPubspecDir(targetDir);
135
+ if (projectRoot && hasBuildRunner(projectRoot)) {
136
+ console.log(chalk.blue("Running build_runner..."));
137
+ await runBuildRunner(projectRoot);
138
+ console.log(chalk.green("\u2713 build_runner completed."));
139
+ } else {
140
+ console.log(chalk.yellow("Skipping build_runner (no pubspec.yaml or build_runner dependency found)."));
141
+ }
142
+ }
143
+ } catch (error) {
144
+ console.error(chalk.red(`Failed to create BLoC: ${error}`));
145
+ process.exit(1);
146
+ }
147
+ }
148
+
149
+ // src/cli.ts
150
+ var program = new Command();
151
+ program.name("wlmaker").description("Create Flutter BLoCs with Freezed sealed classes from the terminal").version("1.0.0");
152
+ program.command("bloc").description("Create a new BLoC with Freezed sealed classes").argument("<name>", "BLoC name in snake_case (e.g. user_login)").option("-d, --dir <path>", "target directory", process.cwd()).option("--no-build-runner", "skip build_runner execution").action(async (name, options) => {
153
+ await createBloc(name, options);
154
+ });
155
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "wlmaker",
3
+ "version": "1.0.0",
4
+ "description": "Create Flutter BLoCs with Freezed sealed classes from the terminal",
5
+ "keywords": [
6
+ "flutter",
7
+ "bloc",
8
+ "freezed",
9
+ "dart",
10
+ "code generation",
11
+ "cli"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/MatiasZL/wlmaker-cli"
16
+ },
17
+ "license": "MIT",
18
+ "bin": {
19
+ "wlmaker": "./dist/cli.mjs"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsup --watch"
27
+ },
28
+ "dependencies": {
29
+ "chalk": "^5.3.0",
30
+ "change-case": "^5.4.0",
31
+ "commander": "^12.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^22.0.0",
35
+ "tsup": "^8.0.0",
36
+ "typescript": "^5.4.0"
37
+ }
38
+ }