wlmaker 1.7.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.
- package/README.md +749 -1
- package/dist/chunk-4AOS33ZX.mjs +390 -0
- package/dist/{chunk-LHUDYCA5.mjs → chunk-554WKK3Z.mjs} +1 -1
- package/dist/chunk-6JXSEAVX.mjs +49 -0
- package/dist/{chunk-OTFDN3HG.mjs → chunk-ELYQ3PL5.mjs} +40 -1
- package/dist/{chunk-BVPCRMD4.mjs → chunk-P7W5YVTZ.mjs} +1 -1
- package/dist/{chunk-KBIXWYFD.mjs → chunk-V4S7DQDN.mjs} +15 -1
- package/dist/chunk-ZYOPXWRK.mjs +221 -0
- package/dist/cli.mjs +2520 -1478
- package/dist/compose-flow-JPC2CZ72.mjs +202 -0
- package/dist/{generator-PWZL3JNY.mjs → generator-CACGWIBO.mjs} +2 -2
- package/dist/{generator-PEYFNXBT.mjs → generator-NQ6GX2L6.mjs} +3 -3
- package/dist/{generator-DDKHXUAT.mjs → generator-OYLKPDQC.mjs} +2 -2
- package/dist/{project-RTR7EV3X.mjs → project-433ZRUBC.mjs} +3 -1
- package/dist/validate-regions-UIGBXPHU.mjs +49 -0
- package/package.json +4 -2
- package/dist/chunk-FXU2ADDY.mjs +0 -146
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
blocsModuleTemplate,
|
|
4
|
+
collaborativeGitignore,
|
|
5
|
+
collaborativePubspec,
|
|
6
|
+
datasourcesModuleTemplate,
|
|
7
|
+
emptyBarrelTemplate,
|
|
8
|
+
featureDiTemplate,
|
|
9
|
+
mainBarrelTemplate,
|
|
10
|
+
repositoriesModuleTemplate,
|
|
11
|
+
usecasesModuleTemplate
|
|
12
|
+
} from "./chunk-ELYQ3PL5.mjs";
|
|
13
|
+
import {
|
|
14
|
+
resolveWorkspaceVersions
|
|
15
|
+
} from "./chunk-V4S7DQDN.mjs";
|
|
16
|
+
|
|
17
|
+
// src/generators/collaborative/feature/generator.ts
|
|
18
|
+
import * as fs3 from "fs";
|
|
19
|
+
import * as path3 from "path";
|
|
20
|
+
import { execSync } from "child_process";
|
|
21
|
+
import chalk3 from "chalk";
|
|
22
|
+
import { pascalCase } from "change-case";
|
|
23
|
+
|
|
24
|
+
// src/shared/pub-workspace.ts
|
|
25
|
+
import * as fs from "fs";
|
|
26
|
+
import * as path from "path";
|
|
27
|
+
import YAML from "yaml";
|
|
28
|
+
import chalk from "chalk";
|
|
29
|
+
var WORKSPACE_MEMBER_RE = /^(\s*)-\s+(\S+)\s*$/;
|
|
30
|
+
function usesPubWorkspace(monorepoRoot) {
|
|
31
|
+
const pubspecPath = path.join(monorepoRoot, "pubspec.yaml");
|
|
32
|
+
if (!fs.existsSync(pubspecPath)) return false;
|
|
33
|
+
try {
|
|
34
|
+
const pubspec = YAML.parse(fs.readFileSync(pubspecPath, "utf8"));
|
|
35
|
+
return Array.isArray(pubspec?.workspace);
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function addWorkspaceMember(monorepoRoot, memberPath) {
|
|
41
|
+
const pubspecPath = path.join(monorepoRoot, "pubspec.yaml");
|
|
42
|
+
if (!fs.existsSync(pubspecPath)) {
|
|
43
|
+
console.log(chalk.yellow(" No root pubspec.yaml found, skipping workspace registration"));
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const content = fs.readFileSync(pubspecPath, "utf8");
|
|
47
|
+
const lines = content.split("\n");
|
|
48
|
+
const workspaceIdx = lines.findIndex((l) => /^workspace:\s*$/.test(l));
|
|
49
|
+
if (workspaceIdx === -1) {
|
|
50
|
+
console.log(
|
|
51
|
+
chalk.yellow(" No workspace: list in root pubspec.yaml (legacy Melos), skipping")
|
|
52
|
+
);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
let blockStart = workspaceIdx + 1;
|
|
56
|
+
let blockEnd = blockStart;
|
|
57
|
+
while (blockEnd < lines.length) {
|
|
58
|
+
const line = lines[blockEnd];
|
|
59
|
+
if (line.trim() === "") break;
|
|
60
|
+
if (!WORKSPACE_MEMBER_RE.test(line)) break;
|
|
61
|
+
blockEnd++;
|
|
62
|
+
}
|
|
63
|
+
for (let i = blockStart; i < blockEnd; i++) {
|
|
64
|
+
const match = lines[i].match(WORKSPACE_MEMBER_RE);
|
|
65
|
+
if (match?.[2] === memberPath) {
|
|
66
|
+
console.log(chalk.yellow(` Already in workspace: ${memberPath}`));
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
let insertAt = blockEnd;
|
|
71
|
+
for (let i = blockStart; i < blockEnd; i++) {
|
|
72
|
+
const match = lines[i].match(WORKSPACE_MEMBER_RE);
|
|
73
|
+
if (match && match[2].localeCompare(memberPath) > 0) {
|
|
74
|
+
insertAt = i;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
lines.splice(insertAt, 0, ` - ${memberPath}`);
|
|
79
|
+
fs.writeFileSync(pubspecPath, lines.join("\n"));
|
|
80
|
+
console.log(chalk.green(` Added ${memberPath} to root pubspec.yaml workspace`));
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
function removeMemberPubspecLock(memberDir) {
|
|
84
|
+
const lockPath = path.join(memberDir, "pubspec.lock");
|
|
85
|
+
if (fs.existsSync(lockPath)) {
|
|
86
|
+
fs.unlinkSync(lockPath);
|
|
87
|
+
console.log(chalk.green(" Removed member pubspec.lock (workspace uses root lock)"));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/shared/ide-workspace.ts
|
|
92
|
+
import * as fs2 from "fs";
|
|
93
|
+
import * as path2 from "path";
|
|
94
|
+
import chalk2 from "chalk";
|
|
95
|
+
function findWorkspaceFile(monorepoRoot) {
|
|
96
|
+
const files = fs2.readdirSync(monorepoRoot);
|
|
97
|
+
return files.find((f) => f.endsWith(".code-workspace")) ?? null;
|
|
98
|
+
}
|
|
99
|
+
function updateCodeWorkspaceFolder(monorepoRoot, folderPath, displayName) {
|
|
100
|
+
const wsFileName = findWorkspaceFile(monorepoRoot);
|
|
101
|
+
if (!wsFileName) {
|
|
102
|
+
console.log(chalk2.yellow(" No .code-workspace file found, skipping"));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const wsPath = path2.join(monorepoRoot, wsFileName);
|
|
106
|
+
const content = fs2.readFileSync(wsPath, "utf8");
|
|
107
|
+
if (content.includes(`"path": "${folderPath}"`)) {
|
|
108
|
+
console.log(chalk2.yellow(` Already in ${wsFileName}`));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const label = displayName ?? path2.basename(folderPath);
|
|
112
|
+
const folderName = `\u{1F4E6} ${label}`;
|
|
113
|
+
const newBlock = ` {
|
|
114
|
+
"name": "${folderName}",
|
|
115
|
+
"path": "${folderPath}"
|
|
116
|
+
},`;
|
|
117
|
+
const lines = content.split("\n");
|
|
118
|
+
const foldersLineIdx = lines.findIndex((l) => l.includes('"folders"'));
|
|
119
|
+
if (foldersLineIdx === -1) {
|
|
120
|
+
console.log(chalk2.yellow(' No "folders" key found in workspace, skipping'));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
let foldersOpenBracket = -1;
|
|
124
|
+
for (let j = foldersLineIdx; j < lines.length; j++) {
|
|
125
|
+
if (lines[j].includes("[")) {
|
|
126
|
+
foldersOpenBracket = j;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (foldersOpenBracket === -1) {
|
|
131
|
+
console.log(chalk2.yellow(" Could not find folders array, skipping"));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
let bracketCount = 0;
|
|
135
|
+
let foldersCloseBracket = -1;
|
|
136
|
+
for (let j = foldersOpenBracket; j < lines.length; j++) {
|
|
137
|
+
for (const ch of lines[j]) {
|
|
138
|
+
if (ch === "[") bracketCount++;
|
|
139
|
+
else if (ch === "]") {
|
|
140
|
+
bracketCount--;
|
|
141
|
+
if (bracketCount === 0) {
|
|
142
|
+
foldersCloseBracket = j;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (foldersCloseBracket !== -1) break;
|
|
148
|
+
}
|
|
149
|
+
if (foldersCloseBracket === -1) {
|
|
150
|
+
console.log(chalk2.yellow(" Could not find folders array end, skipping"));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
let widgetbookBlockStart = -1;
|
|
154
|
+
let idx = foldersOpenBracket + 1;
|
|
155
|
+
while (idx <= foldersCloseBracket) {
|
|
156
|
+
const trimmed = lines[idx].trim();
|
|
157
|
+
if (trimmed === "{" || trimmed.startsWith("{")) {
|
|
158
|
+
let braceCount = 0;
|
|
159
|
+
let blockEnd = -1;
|
|
160
|
+
for (let j = idx; j <= foldersCloseBracket; j++) {
|
|
161
|
+
for (const ch of lines[j]) {
|
|
162
|
+
if (ch === "{") braceCount++;
|
|
163
|
+
else if (ch === "}") {
|
|
164
|
+
braceCount--;
|
|
165
|
+
if (braceCount === 0) {
|
|
166
|
+
blockEnd = j;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (blockEnd !== -1) break;
|
|
172
|
+
}
|
|
173
|
+
if (blockEnd !== -1) {
|
|
174
|
+
const blockText = lines.slice(idx, blockEnd + 1).join("\n");
|
|
175
|
+
if (blockText.includes("widgetbook")) {
|
|
176
|
+
widgetbookBlockStart = idx;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
idx = blockEnd + 1;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
idx++;
|
|
184
|
+
}
|
|
185
|
+
if (widgetbookBlockStart === -1) {
|
|
186
|
+
console.log(chalk2.yellow(" No widgetbook entry found in workspace, skipping"));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
lines.splice(widgetbookBlockStart, 0, newBlock);
|
|
190
|
+
fs2.writeFileSync(wsPath, lines.join("\n"));
|
|
191
|
+
console.log(chalk2.green(` Updated ${wsFileName}`));
|
|
192
|
+
}
|
|
193
|
+
function updateHelixWorkspaceFolder(monorepoRoot, folderPath) {
|
|
194
|
+
const helixPath = path2.join(monorepoRoot, ".helix", "languages.toml");
|
|
195
|
+
if (!fs2.existsSync(helixPath)) {
|
|
196
|
+
console.log(chalk2.yellow(" No .helix/languages.toml found, skipping"));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const content = fs2.readFileSync(helixPath, "utf8");
|
|
200
|
+
const entry = `{ path = "${folderPath}" }`;
|
|
201
|
+
if (content.includes(entry)) {
|
|
202
|
+
console.log(chalk2.yellow(" Already in .helix/languages.toml"));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const workspaceLineRegex = /^\s*\{\s*path\s*=\s*"(?:apps|packages)\//;
|
|
206
|
+
const lines = content.split("\n");
|
|
207
|
+
let lastPackageLineIdx = -1;
|
|
208
|
+
for (let i = 0; i < lines.length; i++) {
|
|
209
|
+
if (workspaceLineRegex.test(lines[i])) {
|
|
210
|
+
lastPackageLineIdx = i;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const sortKey = folderPath.replace(/^(apps|packages)\//, "");
|
|
214
|
+
if (lastPackageLineIdx === -1) {
|
|
215
|
+
const closingBracketIdx = lines.findIndex((l) => l.trim() === "]");
|
|
216
|
+
if (closingBracketIdx === -1) {
|
|
217
|
+
console.log(chalk2.yellow(" Could not parse .helix/languages.toml"));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
lines.splice(closingBracketIdx, 0, ` { path = "${folderPath}" },`);
|
|
221
|
+
} else {
|
|
222
|
+
const allEntries = [];
|
|
223
|
+
for (let i = 0; i < lines.length; i++) {
|
|
224
|
+
const m = lines[i].match(/^\s*\{\s*path\s*=\s*"(?:apps|packages)\/([^"]+)"\s*\}/);
|
|
225
|
+
if (m) {
|
|
226
|
+
allEntries.push({ lineIdx: i, entry: m[1] });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
allEntries.push({ lineIdx: -1, entry: sortKey });
|
|
230
|
+
allEntries.sort((a, b) => a.entry.localeCompare(b.entry));
|
|
231
|
+
const insertIdx = allEntries.findIndex((e) => e.entry === sortKey);
|
|
232
|
+
let targetLine;
|
|
233
|
+
if (insertIdx === 0) {
|
|
234
|
+
const firstLine = lines.findIndex((l) => workspaceLineRegex.test(l));
|
|
235
|
+
targetLine = firstLine;
|
|
236
|
+
} else {
|
|
237
|
+
const prevEntry = allEntries[insertIdx - 1];
|
|
238
|
+
targetLine = prevEntry.lineIdx + 1;
|
|
239
|
+
}
|
|
240
|
+
lines.splice(targetLine, 0, ` { path = "${folderPath}" },`);
|
|
241
|
+
}
|
|
242
|
+
fs2.writeFileSync(helixPath, lines.join("\n"));
|
|
243
|
+
console.log(chalk2.green(" Updated .helix/languages.toml"));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// src/generators/collaborative/feature/generator.ts
|
|
247
|
+
var SNAKE_CASE_REGEX = /^[a-z][a-z0-9_]*$/;
|
|
248
|
+
async function createCollaborativeFeature(options) {
|
|
249
|
+
const { monorepoRoot, featureName } = options;
|
|
250
|
+
const pascal = pascalCase(featureName);
|
|
251
|
+
const description = options.description ?? `${pascal} collaborative feature`;
|
|
252
|
+
if (!SNAKE_CASE_REGEX.test(featureName)) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
"Feature name must be snake_case (lowercase letters, digits, underscores)."
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
const collaborativeDir = path3.join(monorepoRoot, "packages", "collaborative");
|
|
258
|
+
if (!fs3.existsSync(collaborativeDir)) {
|
|
259
|
+
fs3.mkdirSync(collaborativeDir, { recursive: true });
|
|
260
|
+
}
|
|
261
|
+
const pkgDir = path3.join(collaborativeDir, featureName);
|
|
262
|
+
if (fs3.existsSync(pkgDir)) {
|
|
263
|
+
throw new Error(`packages/collaborative/${featureName} already exists`);
|
|
264
|
+
}
|
|
265
|
+
console.log(
|
|
266
|
+
chalk3.bold(`
|
|
267
|
+
Creating collaborative feature: ${chalk3.cyan(featureName)}
|
|
268
|
+
`)
|
|
269
|
+
);
|
|
270
|
+
console.log(chalk3.cyan(" -> Running flutter create..."));
|
|
271
|
+
execSync(
|
|
272
|
+
`flutter create --template=package packages/collaborative/${featureName}`,
|
|
273
|
+
{ cwd: monorepoRoot, stdio: "pipe" }
|
|
274
|
+
);
|
|
275
|
+
const autoTestFile = path3.join(pkgDir, "test", `${featureName}_test.dart`);
|
|
276
|
+
if (fs3.existsSync(autoTestFile)) {
|
|
277
|
+
fs3.unlinkSync(autoTestFile);
|
|
278
|
+
}
|
|
279
|
+
removeMemberPubspecLock(pkgDir);
|
|
280
|
+
console.log(chalk3.cyan(" -> Generating feature structure..."));
|
|
281
|
+
const lib = path3.join(pkgDir, "lib");
|
|
282
|
+
const dirs = [
|
|
283
|
+
path3.join(lib, "data", "api", "bff"),
|
|
284
|
+
path3.join(lib, "data", "datasources"),
|
|
285
|
+
path3.join(lib, "data", "models"),
|
|
286
|
+
path3.join(lib, "data", "repositories"),
|
|
287
|
+
path3.join(lib, "domain", "entities"),
|
|
288
|
+
path3.join(lib, "domain", "repositories"),
|
|
289
|
+
path3.join(lib, "domain", "usecases"),
|
|
290
|
+
path3.join(lib, "presentation", "bloc"),
|
|
291
|
+
path3.join(lib, "presentation", "pages", "views"),
|
|
292
|
+
path3.join(lib, "di")
|
|
293
|
+
];
|
|
294
|
+
for (const dir of dirs) {
|
|
295
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
296
|
+
}
|
|
297
|
+
const pubWorkspace = usesPubWorkspace(monorepoRoot);
|
|
298
|
+
const workspaceVersions = resolveWorkspaceVersions(monorepoRoot);
|
|
299
|
+
fs3.writeFileSync(
|
|
300
|
+
path3.join(pkgDir, "pubspec.yaml"),
|
|
301
|
+
collaborativePubspec(featureName, description, workspaceVersions, pubWorkspace)
|
|
302
|
+
);
|
|
303
|
+
fs3.writeFileSync(
|
|
304
|
+
path3.join(pkgDir, ".gitignore"),
|
|
305
|
+
collaborativeGitignore()
|
|
306
|
+
);
|
|
307
|
+
const diDir = path3.join(lib, "di");
|
|
308
|
+
fs3.writeFileSync(
|
|
309
|
+
path3.join(diDir, `${featureName}_di.dart`),
|
|
310
|
+
featureDiTemplate(featureName)
|
|
311
|
+
);
|
|
312
|
+
fs3.writeFileSync(
|
|
313
|
+
path3.join(diDir, "blocs_module.dart"),
|
|
314
|
+
blocsModuleTemplate(featureName)
|
|
315
|
+
);
|
|
316
|
+
fs3.writeFileSync(
|
|
317
|
+
path3.join(diDir, "datasources_module.dart"),
|
|
318
|
+
datasourcesModuleTemplate(featureName)
|
|
319
|
+
);
|
|
320
|
+
fs3.writeFileSync(
|
|
321
|
+
path3.join(diDir, "repositories_module.dart"),
|
|
322
|
+
repositoriesModuleTemplate(featureName)
|
|
323
|
+
);
|
|
324
|
+
fs3.writeFileSync(
|
|
325
|
+
path3.join(diDir, "usecases_module.dart"),
|
|
326
|
+
usecasesModuleTemplate(featureName)
|
|
327
|
+
);
|
|
328
|
+
const barrelPaths = [
|
|
329
|
+
path3.join(lib, "data", "api", "bff", "bff.dart"),
|
|
330
|
+
path3.join(lib, "data", "datasources", "datasources.dart"),
|
|
331
|
+
path3.join(lib, "data", "models", "models.dart"),
|
|
332
|
+
path3.join(lib, "data", "repositories", "repositories.dart"),
|
|
333
|
+
path3.join(lib, "domain", "entities", "entities.dart"),
|
|
334
|
+
path3.join(lib, "domain", "repositories", "repositories.dart"),
|
|
335
|
+
path3.join(lib, "domain", "usecases", "usecases.dart"),
|
|
336
|
+
path3.join(lib, "presentation", "bloc", "bloc.dart"),
|
|
337
|
+
path3.join(lib, "presentation", "pages", "views", "views.dart"),
|
|
338
|
+
path3.join(lib, "presentation", "pages", "pages.dart")
|
|
339
|
+
];
|
|
340
|
+
for (const barrelPath of barrelPaths) {
|
|
341
|
+
fs3.writeFileSync(barrelPath, emptyBarrelTemplate());
|
|
342
|
+
}
|
|
343
|
+
fs3.writeFileSync(
|
|
344
|
+
path3.join(lib, `${featureName}.dart`),
|
|
345
|
+
mainBarrelTemplate(featureName)
|
|
346
|
+
);
|
|
347
|
+
console.log(chalk3.cyan(" -> Updating workspace configuration..."));
|
|
348
|
+
if (pubWorkspace) {
|
|
349
|
+
addWorkspaceMember(monorepoRoot, `packages/collaborative/${featureName}`);
|
|
350
|
+
}
|
|
351
|
+
updateCodeWorkspaceFolder(
|
|
352
|
+
monorepoRoot,
|
|
353
|
+
`packages/collaborative/${featureName}`,
|
|
354
|
+
`collaborative/${featureName}`
|
|
355
|
+
);
|
|
356
|
+
updateHelixWorkspaceFolder(
|
|
357
|
+
monorepoRoot,
|
|
358
|
+
`packages/collaborative/${featureName}`
|
|
359
|
+
);
|
|
360
|
+
if (options.runBootstrap !== false) {
|
|
361
|
+
console.log(chalk3.cyan(" -> Running melos bootstrap..."));
|
|
362
|
+
try {
|
|
363
|
+
execSync("melos bootstrap", { cwd: monorepoRoot, stdio: "pipe" });
|
|
364
|
+
console.log(chalk3.green(" melos bootstrap completed"));
|
|
365
|
+
} catch {
|
|
366
|
+
console.log(
|
|
367
|
+
chalk3.yellow(" melos bootstrap failed (you may need to run it manually)")
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
console.log(
|
|
372
|
+
chalk3.green(`
|
|
373
|
+
Feature "${featureName}" created successfully!`)
|
|
374
|
+
);
|
|
375
|
+
console.log(chalk3.gray(` ${pkgDir}`));
|
|
376
|
+
console.log(chalk3.gray(`
|
|
377
|
+
Next steps:`));
|
|
378
|
+
console.log(chalk3.gray(` wlmaker collaborative endpoint ...`));
|
|
379
|
+
console.log(chalk3.gray(` wlmaker collaborative bloc ...`));
|
|
380
|
+
console.log(chalk3.gray(` wlmaker collaborative page ...`));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export {
|
|
384
|
+
usesPubWorkspace,
|
|
385
|
+
addWorkspaceMember,
|
|
386
|
+
removeMemberPubspecLock,
|
|
387
|
+
updateCodeWorkspaceFolder,
|
|
388
|
+
updateHelixWorkspaceFolder,
|
|
389
|
+
createCollaborativeFeature
|
|
390
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/analyzer/region-parser.ts
|
|
4
|
+
function parseRegions(code) {
|
|
5
|
+
const regions = {};
|
|
6
|
+
const errors = [];
|
|
7
|
+
const openStack = [];
|
|
8
|
+
const lines = code.split("\n");
|
|
9
|
+
const regionStart = /\/\/\s*#?\s*region\s+(.+)/i;
|
|
10
|
+
const regionEnd = /\/\/\s*#?\s*endregion/i;
|
|
11
|
+
for (let i = 0; i < lines.length; i++) {
|
|
12
|
+
const line = lines[i];
|
|
13
|
+
const lineNum = i + 1;
|
|
14
|
+
const startMatch = line.match(regionStart);
|
|
15
|
+
if (startMatch) {
|
|
16
|
+
const name = startMatch[1].trim();
|
|
17
|
+
if (openStack.length > 0) {
|
|
18
|
+
errors.push(
|
|
19
|
+
`Line ${lineNum}: nested region "${name}" inside "${openStack[openStack.length - 1].name}" \u2014 regions cannot be nested`
|
|
20
|
+
);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
openStack.push({ name, startLine: lineNum });
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const endMatch = line.match(regionEnd);
|
|
27
|
+
if (endMatch) {
|
|
28
|
+
if (openStack.length === 0) {
|
|
29
|
+
errors.push(`Line ${lineNum}: //#endregion without matching //#region`);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const opened = openStack.pop();
|
|
33
|
+
regions[opened.name] = {
|
|
34
|
+
name: opened.name,
|
|
35
|
+
content: lines.slice(opened.startLine, i).join("\n").trim(),
|
|
36
|
+
startLine: opened.startLine,
|
|
37
|
+
endLine: lineNum
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const opened of openStack) {
|
|
42
|
+
errors.push(`Line ${opened.startLine}: unclosed region "${opened.name}" \u2014 missing //#endregion`);
|
|
43
|
+
}
|
|
44
|
+
return { regions, errors };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
parseRegions
|
|
49
|
+
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/generators/collaborative/collaborative-templates.ts
|
|
4
4
|
import { camelCase, pascalCase } from "change-case";
|
|
5
|
+
var WORKSPACE_PACKAGES = /* @__PURE__ */ new Set(["app_base", "core", "design_system", "localization"]);
|
|
5
6
|
var COLLABORATIVE_DEPS = [
|
|
6
7
|
"app_base",
|
|
7
8
|
"dio",
|
|
@@ -26,7 +27,45 @@ var COLLABORATIVE_OVERRIDE_EXCLUDE = /* @__PURE__ */ new Set([
|
|
|
26
27
|
"build_runner",
|
|
27
28
|
"source_gen"
|
|
28
29
|
]);
|
|
29
|
-
function collaborativePubspec(featureName, description, versions) {
|
|
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
|
+
}
|
|
30
69
|
const depLines = [" app_base:"];
|
|
31
70
|
for (const dep of COLLABORATIVE_DEPS) {
|
|
32
71
|
if (dep === "app_base") continue;
|
|
@@ -39,10 +39,23 @@ function discoverFeatures(projectRoot) {
|
|
|
39
39
|
if (!fs.existsSync(featuresDir)) return [];
|
|
40
40
|
return fs.readdirSync(featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
|
41
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
|
+
}
|
|
42
55
|
function findMonorepoRoot(startDir) {
|
|
43
56
|
let dir = startDir;
|
|
44
57
|
while (dir !== path.dirname(dir)) {
|
|
45
|
-
if (
|
|
58
|
+
if (isMonorepoRoot(dir)) {
|
|
46
59
|
return dir;
|
|
47
60
|
}
|
|
48
61
|
dir = path.dirname(dir);
|
|
@@ -156,6 +169,7 @@ function discoverProjects(searchDir, maxDepth = 2) {
|
|
|
156
169
|
|
|
157
170
|
export {
|
|
158
171
|
analyzeProject,
|
|
172
|
+
isMonorepoRoot,
|
|
159
173
|
findMonorepoRoot,
|
|
160
174
|
discoverPackages,
|
|
161
175
|
discoverCollaborativeFeatures,
|