wlmaker 1.6.0 → 1.8.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.
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/generators/collaborative/collaborative-templates.ts
4
+ import { camelCase, pascalCase } from "change-case";
5
+ var WORKSPACE_PACKAGES = /* @__PURE__ */ new Set(["app_base", "core", "design_system", "localization"]);
6
+ var COLLABORATIVE_DEPS = [
7
+ "app_base",
8
+ "dio",
9
+ "equatable",
10
+ "flutter_bloc",
11
+ "freezed_annotation",
12
+ "get_it",
13
+ "go_router",
14
+ "injectable",
15
+ "json_annotation"
16
+ ];
17
+ var COLLABORATIVE_DEV_DEPS = [
18
+ "build_runner",
19
+ "freezed",
20
+ "injectable_generator",
21
+ "json_serializable",
22
+ "very_good_analysis"
23
+ ];
24
+ var COLLABORATIVE_OVERRIDE_EXCLUDE = /* @__PURE__ */ new Set([
25
+ "analyzer",
26
+ "dart_style",
27
+ "build_runner",
28
+ "source_gen"
29
+ ]);
30
+ function collaborativePubspec(featureName, description, versions, pubWorkspace = false) {
31
+ if (pubWorkspace) {
32
+ const depLines2 = [
33
+ " flutter:",
34
+ " sdk: flutter"
35
+ ];
36
+ for (const dep of COLLABORATIVE_DEPS) {
37
+ depLines2.push(
38
+ WORKSPACE_PACKAGES.has(dep) ? ` ${dep}:` : ` ${dep}: any`
39
+ );
40
+ }
41
+ const devDepLines2 = [
42
+ " flutter_test:",
43
+ " sdk: flutter"
44
+ ];
45
+ for (const dep of COLLABORATIVE_DEV_DEPS) {
46
+ devDepLines2.push(` ${dep}: any`);
47
+ }
48
+ return `name: ${featureName}
49
+ description: "${description}"
50
+ version: 0.0.1
51
+ publish_to: none
52
+
53
+ environment:
54
+ sdk: ^3.8.1
55
+ flutter: ">=1.17.0"
56
+
57
+ resolution: workspace
58
+
59
+ dependencies:
60
+ ${depLines2.join("\n")}
61
+
62
+ dev_dependencies:
63
+ ${devDepLines2.join("\n")}
64
+
65
+ flutter:
66
+ uses-material-design: true
67
+ `;
68
+ }
69
+ const depLines = [" app_base:"];
70
+ for (const dep of COLLABORATIVE_DEPS) {
71
+ if (dep === "app_base") continue;
72
+ const version = versions.dependencies[dep] ?? versions.devDependencies[dep];
73
+ if (version) {
74
+ depLines.push(` ${dep}: ${version}`);
75
+ }
76
+ }
77
+ const devDepLines = [
78
+ " flutter_test:",
79
+ " sdk: flutter"
80
+ ];
81
+ for (const dep of COLLABORATIVE_DEV_DEPS) {
82
+ const version = versions.devDependencies[dep] ?? versions.dependencies[dep];
83
+ if (version) {
84
+ devDepLines.push(` ${dep}: ${version}`);
85
+ }
86
+ }
87
+ const overrideLines = [];
88
+ for (const [name, version] of Object.entries(versions.dependencyOverrides)) {
89
+ if (!COLLABORATIVE_OVERRIDE_EXCLUDE.has(name)) {
90
+ overrideLines.push(` ${name}: ${version}`);
91
+ }
92
+ }
93
+ const overridesSection = overrideLines.length > 0 ? `
94
+ dependency_overrides:
95
+ ${overrideLines.join("\n")}
96
+ ` : "";
97
+ return `name: ${featureName}
98
+ description: "${description}"
99
+ version: 0.0.1
100
+ publish_to: none
101
+
102
+ environment:
103
+ sdk: ^3.8.1
104
+ flutter: ">=1.17.0"
105
+
106
+ dependencies:
107
+ flutter:
108
+ sdk: flutter
109
+ ${depLines.join("\n")}
110
+
111
+ dev_dependencies:
112
+ ${devDepLines.join("\n")}
113
+ ${overridesSection}
114
+ flutter:
115
+ uses-material-design: true
116
+ `;
117
+ }
118
+ function featureDiTemplate(featureName) {
119
+ const pascal = pascalCase(featureName);
120
+ return `import 'package:injectable/injectable.dart';
121
+
122
+ @InjectableInit.microPackage()
123
+ void init${pascal}Package() {}
124
+ `;
125
+ }
126
+ function blocsModuleTemplate(featureName) {
127
+ return `import 'package:injectable/injectable.dart';
128
+
129
+ @module
130
+ abstract class BlocsModule {}
131
+ `;
132
+ }
133
+ function datasourcesModuleTemplate(featureName) {
134
+ return `import 'package:injectable/injectable.dart';
135
+
136
+ @module
137
+ abstract class DatasourcesModule {}
138
+ `;
139
+ }
140
+ function repositoriesModuleTemplate(featureName) {
141
+ return `import 'package:injectable/injectable.dart';
142
+
143
+ @module
144
+ abstract class RepositoriesModule {}
145
+ `;
146
+ }
147
+ function usecasesModuleTemplate(featureName) {
148
+ return `import 'package:injectable/injectable.dart';
149
+
150
+ @module
151
+ abstract class UseCasesModule {}
152
+ `;
153
+ }
154
+ function collaborativeBlocTemplate(featureName, pascal) {
155
+ return `import 'package:flutter_bloc/flutter_bloc.dart';
156
+ import 'package:freezed_annotation/freezed_annotation.dart';
157
+
158
+ part '${featureName}_bloc.freezed.dart';
159
+ part '${featureName}_event.dart';
160
+ part '${featureName}_state.dart';
161
+
162
+ class ${pascal}Bloc extends Bloc<${pascal}Event, ${pascal}State> {
163
+ ${pascal}Bloc() : super(const ${pascal}State.initial()) {
164
+ on<_Started>(_onStarted);
165
+ }
166
+
167
+ Future<void> _onStarted(
168
+ _Started event,
169
+ Emitter<${pascal}State> emit,
170
+ ) async {
171
+ emit(const ${pascal}State.loading());
172
+ }
173
+ }
174
+ `;
175
+ }
176
+ function collaborativeBlocEventTemplate(featureName, pascal) {
177
+ return `part of '${featureName}_bloc.dart';
178
+
179
+ @freezed
180
+ sealed class ${pascal}Event with _$${pascal}Event {
181
+ const factory ${pascal}Event.started() = _Started;
182
+ }
183
+ `;
184
+ }
185
+ function collaborativeBlocStateTemplate(featureName, pascal) {
186
+ return `part of '${featureName}_bloc.dart';
187
+
188
+ @freezed
189
+ sealed class ${pascal}State with _$${pascal}State {
190
+ const factory ${pascal}State.initial() = _Initial;
191
+ const factory ${pascal}State.loading() = _Loading;
192
+ const factory ${pascal}State.error(String message) = _Error;
193
+ }
194
+ `;
195
+ }
196
+ function collaborativePageTemplate(featureName, pascal) {
197
+ const routePath = "/" + featureName.replace(/^feature_/, "");
198
+ return `import 'package:flutter/material.dart';
199
+ import 'package:go_router/go_router.dart';
200
+ import 'package:${featureName}/presentation/pages/views/views.dart';
201
+
202
+ class ${pascal}Page extends GoRoute {
203
+ ${pascal}Page({super.name, super.routes})
204
+ : super(
205
+ path: fullPath,
206
+ pageBuilder: (context, state) =>
207
+ const MaterialPage(child: ${pascal}View()),
208
+ );
209
+
210
+ static const fullPath = '${routePath}';
211
+
212
+ static void open(BuildContext context) => context.go(fullPath);
213
+ }
214
+ `;
215
+ }
216
+ function collaborativeViewTemplate(pascal) {
217
+ return `import 'package:flutter/material.dart';
218
+
219
+ class ${pascal}View extends StatelessWidget {
220
+ const ${pascal}View({super.key});
221
+
222
+ @override
223
+ Widget build(BuildContext context) {
224
+ return Scaffold(
225
+ appBar: AppBar(title: const Text('${pascal}')),
226
+ body: const Center(child: Text('${pascal}')),
227
+ );
228
+ }
229
+ }
230
+ `;
231
+ }
232
+ function emptyBarrelTemplate() {
233
+ return "";
234
+ }
235
+ function mainBarrelTemplate(featureName) {
236
+ return `export 'data/api/bff/bff.dart';
237
+ export 'data/datasources/datasources.dart';
238
+ export 'data/models/models.dart';
239
+ export 'data/repositories/repositories.dart';
240
+ export 'domain/entities/entities.dart';
241
+ export 'domain/repositories/repositories.dart';
242
+ export 'domain/usecases/usecases.dart';
243
+ export 'presentation/bloc/bloc.dart';
244
+ export 'presentation/pages/pages.dart';
245
+ export 'presentation/pages/views/views.dart';
246
+ export 'di/${featureName}_di.dart';
247
+ `;
248
+ }
249
+ function collaborativeGitignore() {
250
+ return `# Miscellaneous
251
+ *.class
252
+ *.log
253
+ *.pyc
254
+ *.swp
255
+ .DS_Store
256
+ .atom/
257
+ .buildlog/
258
+ .history
259
+ .svn/
260
+ migrate_working_dir/
261
+
262
+ # IntelliJ related
263
+ *.iml
264
+ *.ipr
265
+ *.iws
266
+ .idea/
267
+
268
+ # Flutter/Dart/Pub related
269
+ /pubspec.lock
270
+ **/doc/api/
271
+ .dart_tool/
272
+ .flutter-plugins
273
+ .flutter-plugins-dependencies
274
+ build/
275
+
276
+ coverage/
277
+ `;
278
+ }
279
+ function blocRegistrationSnippet(featureName, pascal) {
280
+ const blocClass = `${pascal}Bloc`;
281
+ const blocVar = camelCase(blocClass);
282
+ return ` @injectable
283
+ ${blocClass} ${blocVar}() => ${blocClass}();`;
284
+ }
285
+
286
+ export {
287
+ collaborativePubspec,
288
+ featureDiTemplate,
289
+ blocsModuleTemplate,
290
+ datasourcesModuleTemplate,
291
+ repositoriesModuleTemplate,
292
+ usecasesModuleTemplate,
293
+ collaborativeBlocTemplate,
294
+ collaborativeBlocEventTemplate,
295
+ collaborativeBlocStateTemplate,
296
+ collaborativePageTemplate,
297
+ collaborativeViewTemplate,
298
+ emptyBarrelTemplate,
299
+ mainBarrelTemplate,
300
+ collaborativeGitignore,
301
+ blocRegistrationSnippet
302
+ };
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ injectExport
4
+ } from "./chunk-7KUDXB2F.mjs";
5
+ import {
6
+ collaborativePageTemplate,
7
+ collaborativeViewTemplate
8
+ } from "./chunk-ELYQ3PL5.mjs";
9
+
10
+ // src/generators/collaborative/page/generator.ts
11
+ import * as fs from "fs";
12
+ import * as path from "path";
13
+ import chalk from "chalk";
14
+ import { pascalCase } from "change-case";
15
+ var SNAKE_CASE_REGEX = /^[a-z][a-z0-9_]*$/;
16
+ async function createCollaborativePage(options) {
17
+ const { featurePath, pageName } = options;
18
+ const pascal = pascalCase(pageName);
19
+ if (!SNAKE_CASE_REGEX.test(pageName)) {
20
+ throw new Error(
21
+ "Page name must be snake_case (lowercase letters, digits, underscores)."
22
+ );
23
+ }
24
+ const lib = path.join(featurePath, "lib");
25
+ const pagesDir = path.join(lib, "presentation", "pages");
26
+ const viewsDir = path.join(pagesDir, "views");
27
+ if (!fs.existsSync(pagesDir)) {
28
+ throw new Error(
29
+ `Not a collaborative feature structure. Missing: ${pagesDir}`
30
+ );
31
+ }
32
+ fs.mkdirSync(viewsDir, { recursive: true });
33
+ const pageFile = path.join(pagesDir, `${pageName}_page.dart`);
34
+ const viewFile = path.join(viewsDir, `${pageName}_view.dart`);
35
+ if (fs.existsSync(pageFile)) {
36
+ throw new Error(`Page "${pageName}" already exists at ${pageFile}`);
37
+ }
38
+ const featureName = extractFeatureName(featurePath);
39
+ fs.writeFileSync(
40
+ pageFile,
41
+ collaborativePageTemplate(pageName, pascal)
42
+ );
43
+ console.log(chalk.green(` Page created: ${pageFile}`));
44
+ fs.writeFileSync(viewFile, collaborativeViewTemplate(pascal));
45
+ console.log(chalk.green(` View created: ${viewFile}`));
46
+ if (featureName) {
47
+ const viewsBarrel = path.join(viewsDir, "views.dart");
48
+ injectExport(viewsBarrel, `export '${pageName}_view.dart';`);
49
+ const pagesBarrel = path.join(pagesDir, "pages.dart");
50
+ injectExport(pagesBarrel, `export '${pageName}_page.dart';`);
51
+ injectExport(pagesBarrel, `export 'views/views.dart';`);
52
+ const mainBarrel = path.join(lib, `${featureName}.dart`);
53
+ if (fs.existsSync(mainBarrel)) {
54
+ const content = fs.readFileSync(mainBarrel, "utf8");
55
+ if (!content.includes(`export 'presentation/pages/${pageName}_page.dart';`)) {
56
+ injectExport(
57
+ mainBarrel,
58
+ `export 'presentation/pages/${pageName}_page.dart';`
59
+ );
60
+ }
61
+ if (!content.includes(`export 'presentation/pages/views/${pageName}_view.dart';`)) {
62
+ injectExport(
63
+ mainBarrel,
64
+ `export 'presentation/pages/views/${pageName}_view.dart';`
65
+ );
66
+ }
67
+ }
68
+ }
69
+ }
70
+ function extractFeatureName(featurePath) {
71
+ const normalized = featurePath.replace(/\\/g, "/");
72
+ const match = normalized.match(/\/([^/]+)\/lib\/?$/);
73
+ if (match) return match[1];
74
+ return path.basename(featurePath);
75
+ }
76
+
77
+ export {
78
+ createCollaborativePage
79
+ };
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/analyzer/project.ts
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ import YAML from "yaml";
7
+ function analyzeProject(startDir) {
8
+ const projectRoot = findPubspecDir(startDir);
9
+ if (!projectRoot) return null;
10
+ const pubspecPath = path.join(projectRoot, "pubspec.yaml");
11
+ const content = fs.readFileSync(pubspecPath, "utf8");
12
+ const pubspec = YAML.parse(content);
13
+ const deps = {
14
+ ...pubspec?.dependencies,
15
+ ...pubspec?.dev_dependencies
16
+ };
17
+ const features = discoverFeatures(projectRoot);
18
+ return {
19
+ projectRoot,
20
+ projectName: pubspec?.name ?? path.basename(projectRoot),
21
+ hasFreezed: "freezed" in deps || "freezed_annotation" in deps,
22
+ hasBloc: "flutter_bloc" in deps || "bloc" in deps,
23
+ hasBuildRunner: "build_runner" in deps,
24
+ features
25
+ };
26
+ }
27
+ function findPubspecDir(startDir) {
28
+ let dir = startDir;
29
+ while (dir !== path.dirname(dir)) {
30
+ if (fs.existsSync(path.join(dir, "pubspec.yaml"))) {
31
+ return dir;
32
+ }
33
+ dir = path.dirname(dir);
34
+ }
35
+ return void 0;
36
+ }
37
+ function discoverFeatures(projectRoot) {
38
+ const featuresDir = path.join(projectRoot, "lib", "features");
39
+ if (!fs.existsSync(featuresDir)) return [];
40
+ return fs.readdirSync(featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
41
+ }
42
+ function isMonorepoRoot(dir) {
43
+ if (fs.existsSync(path.join(dir, "melos.yaml"))) {
44
+ return true;
45
+ }
46
+ const pubspecPath = path.join(dir, "pubspec.yaml");
47
+ if (!fs.existsSync(pubspecPath)) return false;
48
+ try {
49
+ const pubspec = YAML.parse(fs.readFileSync(pubspecPath, "utf8"));
50
+ return Boolean(pubspec?.workspace) || Boolean(pubspec?.melos);
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+ function findMonorepoRoot(startDir) {
56
+ let dir = startDir;
57
+ while (dir !== path.dirname(dir)) {
58
+ if (isMonorepoRoot(dir)) {
59
+ return dir;
60
+ }
61
+ dir = path.dirname(dir);
62
+ }
63
+ return void 0;
64
+ }
65
+ function discoverPackages(monorepoRoot) {
66
+ const packageDirs = ["packages", "packages/features"];
67
+ const projects = [];
68
+ for (const base of packageDirs) {
69
+ const baseDir = path.join(monorepoRoot, base);
70
+ if (!fs.existsSync(baseDir)) continue;
71
+ const entries = fs.readdirSync(baseDir, { withFileTypes: true });
72
+ for (const entry of entries) {
73
+ if (!entry.isDirectory()) continue;
74
+ const candidate = path.join(baseDir, entry.name);
75
+ if (!fs.existsSync(path.join(candidate, "pubspec.yaml"))) continue;
76
+ const project = analyzeProject(candidate);
77
+ if (project && (project.hasFreezed || project.hasBloc)) {
78
+ projects.push(project);
79
+ }
80
+ }
81
+ }
82
+ return projects.sort((a, b) => a.projectName.localeCompare(b.projectName));
83
+ }
84
+ function discoverCollaborativeFeatures(monorepoRoot) {
85
+ const collabDir = path.join(monorepoRoot, "packages", "collaborative");
86
+ if (!fs.existsSync(collabDir)) return [];
87
+ const projects = [];
88
+ const entries = fs.readdirSync(collabDir, { withFileTypes: true });
89
+ for (const entry of entries) {
90
+ if (!entry.isDirectory()) continue;
91
+ const candidate = path.join(collabDir, entry.name);
92
+ if (!fs.existsSync(path.join(candidate, "pubspec.yaml"))) continue;
93
+ const project = analyzeProject(candidate);
94
+ if (project) {
95
+ projects.push(project);
96
+ }
97
+ }
98
+ return projects.sort((a, b) => a.projectName.localeCompare(b.projectName));
99
+ }
100
+ var REFERENCE_PACKAGES = ["packages/core", "packages/app_base", "packages/design_system"];
101
+ function resolveWorkspaceVersions(monorepoRoot) {
102
+ const merged = {
103
+ dependencies: {},
104
+ devDependencies: {},
105
+ dependencyOverrides: {}
106
+ };
107
+ for (const relPath of REFERENCE_PACKAGES) {
108
+ const pubspecPath = path.join(monorepoRoot, relPath, "pubspec.yaml");
109
+ if (!fs.existsSync(pubspecPath)) continue;
110
+ const content = fs.readFileSync(pubspecPath, "utf8");
111
+ const pubspec = YAML.parse(content);
112
+ if (pubspec?.dependencies) {
113
+ for (const [name, version] of Object.entries(pubspec.dependencies)) {
114
+ if (typeof version === "string") {
115
+ merged.dependencies[name] = version;
116
+ }
117
+ }
118
+ }
119
+ if (pubspec?.dev_dependencies) {
120
+ for (const [name, version] of Object.entries(pubspec.dev_dependencies)) {
121
+ if (typeof version === "string") {
122
+ merged.devDependencies[name] = version;
123
+ }
124
+ }
125
+ }
126
+ if (pubspec?.dependency_overrides) {
127
+ for (const [name, version] of Object.entries(pubspec.dependency_overrides)) {
128
+ if (typeof version === "string") {
129
+ merged.dependencyOverrides[name] = version;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ return merged;
135
+ }
136
+ var IGNORED_DIRS = /* @__PURE__ */ new Set([
137
+ "node_modules",
138
+ ".dart_tool",
139
+ "build",
140
+ ".git",
141
+ ".idea",
142
+ ".fvm",
143
+ "coverage"
144
+ ]);
145
+ function discoverProjects(searchDir, maxDepth = 2) {
146
+ const projects = [];
147
+ function walk(dir, depth) {
148
+ if (depth > maxDepth) return;
149
+ const project = analyzeProject(dir);
150
+ if (project && (project.hasFreezed || project.hasBloc)) {
151
+ projects.push(project);
152
+ return;
153
+ }
154
+ if (!fs.existsSync(dir)) return;
155
+ let entries;
156
+ try {
157
+ entries = fs.readdirSync(dir, { withFileTypes: true });
158
+ } catch {
159
+ return;
160
+ }
161
+ for (const entry of entries) {
162
+ if (!entry.isDirectory() || IGNORED_DIRS.has(entry.name)) continue;
163
+ walk(path.join(dir, entry.name), depth + 1);
164
+ }
165
+ }
166
+ walk(searchDir, 0);
167
+ return projects.sort((a, b) => a.projectName.localeCompare(b.projectName));
168
+ }
169
+
170
+ export {
171
+ analyzeProject,
172
+ isMonorepoRoot,
173
+ findMonorepoRoot,
174
+ discoverPackages,
175
+ discoverCollaborativeFeatures,
176
+ resolveWorkspaceVersions,
177
+ discoverProjects
178
+ };