wlmaker 1.2.13 → 1.3.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/cli.mjs +438 -64
- package/package.json +3 -2
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { createRequire } from "module";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
-
import
|
|
6
|
+
import chalk9 from "chalk";
|
|
7
7
|
|
|
8
8
|
// src/core/create-bloc.ts
|
|
9
9
|
import * as fs3 from "fs";
|
|
@@ -956,11 +956,11 @@ async function createUseCase(name, tierInput, options) {
|
|
|
956
956
|
}
|
|
957
957
|
|
|
958
958
|
// src/interactive.ts
|
|
959
|
-
import * as
|
|
959
|
+
import * as fs13 from "fs";
|
|
960
960
|
import * as os from "os";
|
|
961
|
-
import * as
|
|
961
|
+
import * as path12 from "path";
|
|
962
962
|
import * as clack from "@clack/prompts";
|
|
963
|
-
import
|
|
963
|
+
import chalk8 from "chalk";
|
|
964
964
|
|
|
965
965
|
// src/core/create-endpoint.ts
|
|
966
966
|
import * as fs9 from "fs";
|
|
@@ -1049,8 +1049,8 @@ ${paramsClass}
|
|
|
1049
1049
|
}
|
|
1050
1050
|
`;
|
|
1051
1051
|
}
|
|
1052
|
-
function retrofitMethod(methodName,
|
|
1053
|
-
const httpAnnotation = `@${httpMethod.toUpperCase()}('${
|
|
1052
|
+
function retrofitMethod(methodName, path13, httpMethod, params, returnType) {
|
|
1053
|
+
const httpAnnotation = `@${httpMethod.toUpperCase()}('${path13}')`;
|
|
1054
1054
|
const paramList = params.map((p) => {
|
|
1055
1055
|
if (p.isPath) return `@Path('${p.name}') ${p.type} ${p.name}`;
|
|
1056
1056
|
if (p.isBody) return `@Body() ${p.type} ${p.name}`;
|
|
@@ -1464,6 +1464,289 @@ function injectModuleRegistration(filePath, className, registrationCode, dedupKe
|
|
|
1464
1464
|
fs9.writeFileSync(filePath, newContent);
|
|
1465
1465
|
}
|
|
1466
1466
|
|
|
1467
|
+
// src/core/docs-serve.ts
|
|
1468
|
+
import { spawn as spawn2 } from "child_process";
|
|
1469
|
+
import * as fs10 from "fs";
|
|
1470
|
+
import * as path9 from "path";
|
|
1471
|
+
import chalk5 from "chalk";
|
|
1472
|
+
function detectBookDir(startDir) {
|
|
1473
|
+
const root = findMonorepoRoot(startDir) ?? startDir;
|
|
1474
|
+
const bookDir = path9.join(root, "book");
|
|
1475
|
+
if (fs10.existsSync(bookDir) && (fs10.existsSync(path9.join(bookDir, "docusaurus.config.js")) || fs10.existsSync(path9.join(bookDir, "docusaurus.config.ts")) || fs10.existsSync(path9.join(bookDir, "docusaurus.config.mjs")))) {
|
|
1476
|
+
return bookDir;
|
|
1477
|
+
}
|
|
1478
|
+
return void 0;
|
|
1479
|
+
}
|
|
1480
|
+
function serveBook(bookDir) {
|
|
1481
|
+
return new Promise((resolve4, reject) => {
|
|
1482
|
+
const nodeModules = path9.join(bookDir, "node_modules");
|
|
1483
|
+
if (!fs10.existsSync(nodeModules)) {
|
|
1484
|
+
console.log(chalk5.cyan("Installing book dependencies..."));
|
|
1485
|
+
const install = spawn2("npm", ["install"], {
|
|
1486
|
+
cwd: bookDir,
|
|
1487
|
+
stdio: "inherit"
|
|
1488
|
+
});
|
|
1489
|
+
install.on("close", (code) => {
|
|
1490
|
+
if (code !== 0) {
|
|
1491
|
+
reject(new Error(`npm install failed with code ${code}`));
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
startDevServer(bookDir, resolve4);
|
|
1495
|
+
});
|
|
1496
|
+
install.on("error", (err) => {
|
|
1497
|
+
reject(err);
|
|
1498
|
+
});
|
|
1499
|
+
} else {
|
|
1500
|
+
startDevServer(bookDir, resolve4);
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
function startDevServer(bookDir, done) {
|
|
1505
|
+
const child = spawn2("npm", ["run", "start"], {
|
|
1506
|
+
cwd: bookDir,
|
|
1507
|
+
stdio: "inherit"
|
|
1508
|
+
});
|
|
1509
|
+
child.on("close", () => {
|
|
1510
|
+
done();
|
|
1511
|
+
});
|
|
1512
|
+
child.on("error", () => {
|
|
1513
|
+
done();
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
// src/core/docs-commands.ts
|
|
1518
|
+
import * as fs11 from "fs";
|
|
1519
|
+
import * as path10 from "path";
|
|
1520
|
+
import chalk6 from "chalk";
|
|
1521
|
+
import YAML2 from "yaml";
|
|
1522
|
+
function parseMakefile(filePath) {
|
|
1523
|
+
if (!fs11.existsSync(filePath)) return [];
|
|
1524
|
+
const content = fs11.readFileSync(filePath, "utf8");
|
|
1525
|
+
const lines = content.split("\n");
|
|
1526
|
+
const commands = [];
|
|
1527
|
+
const source = path10.basename(filePath);
|
|
1528
|
+
let pendingComments = [];
|
|
1529
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1530
|
+
const line = lines[i];
|
|
1531
|
+
if (line.startsWith("#")) {
|
|
1532
|
+
const commentText = line.replace(/^#+\s?/, "").trim();
|
|
1533
|
+
if (commentText) pendingComments.push(commentText);
|
|
1534
|
+
continue;
|
|
1535
|
+
}
|
|
1536
|
+
const targetMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\s*:/);
|
|
1537
|
+
if (targetMatch) {
|
|
1538
|
+
const name = targetMatch[1];
|
|
1539
|
+
if (name.startsWith(".") || name === "Makefile") {
|
|
1540
|
+
pendingComments = [];
|
|
1541
|
+
continue;
|
|
1542
|
+
}
|
|
1543
|
+
commands.push({
|
|
1544
|
+
name,
|
|
1545
|
+
description: pendingComments.join(" ").trim() || "",
|
|
1546
|
+
source: "Makefile",
|
|
1547
|
+
file: source
|
|
1548
|
+
});
|
|
1549
|
+
pendingComments = [];
|
|
1550
|
+
} else if (line.trim() !== "") {
|
|
1551
|
+
pendingComments = [];
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
return commands;
|
|
1555
|
+
}
|
|
1556
|
+
function parseMelosScripts(filePath) {
|
|
1557
|
+
if (!fs11.existsSync(filePath)) return [];
|
|
1558
|
+
const content = fs11.readFileSync(filePath, "utf8");
|
|
1559
|
+
const parsed = YAML2.parse(content);
|
|
1560
|
+
const scripts = parsed?.scripts;
|
|
1561
|
+
if (!scripts || typeof scripts !== "object") return [];
|
|
1562
|
+
const commands = [];
|
|
1563
|
+
const source = path10.basename(filePath);
|
|
1564
|
+
for (const [name, value] of Object.entries(scripts)) {
|
|
1565
|
+
let description = "";
|
|
1566
|
+
let command = "";
|
|
1567
|
+
if (typeof value === "string") {
|
|
1568
|
+
command = value;
|
|
1569
|
+
} else if (typeof value === "object" && value !== null) {
|
|
1570
|
+
description = value.description ?? "";
|
|
1571
|
+
command = value.run ?? value.exec ?? "";
|
|
1572
|
+
}
|
|
1573
|
+
commands.push({
|
|
1574
|
+
name,
|
|
1575
|
+
description: description || command,
|
|
1576
|
+
source: "melos",
|
|
1577
|
+
file: source
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
return commands;
|
|
1581
|
+
}
|
|
1582
|
+
function discoverCommands(startDir) {
|
|
1583
|
+
const root = findMonorepoRoot(startDir) ?? startDir;
|
|
1584
|
+
const commands = [];
|
|
1585
|
+
const rootMakefile = path10.join(root, "Makefile");
|
|
1586
|
+
commands.push(...parseMakefile(rootMakefile));
|
|
1587
|
+
const melosFile = path10.join(root, "melos.yaml");
|
|
1588
|
+
commands.push(...parseMelosScripts(melosFile));
|
|
1589
|
+
const bookMakefile = path10.join(root, "book", "Makefile");
|
|
1590
|
+
commands.push(...parseMakefile(bookMakefile));
|
|
1591
|
+
return commands;
|
|
1592
|
+
}
|
|
1593
|
+
function displayCommands(commands) {
|
|
1594
|
+
if (commands.length === 0) {
|
|
1595
|
+
console.log(chalk6.yellow("No commands found."));
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1599
|
+
for (const cmd of commands) {
|
|
1600
|
+
const key = `${cmd.source} (${cmd.file})`;
|
|
1601
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
1602
|
+
groups.get(key).push(cmd);
|
|
1603
|
+
}
|
|
1604
|
+
for (const [group, entries] of groups) {
|
|
1605
|
+
console.log(chalk6.bold(chalk6.cyan(`
|
|
1606
|
+
${group}`)));
|
|
1607
|
+
console.log(chalk6.cyan("\u2500".repeat(group.length)));
|
|
1608
|
+
const maxNameLen = Math.max(...entries.map((e) => e.name.length));
|
|
1609
|
+
for (const entry of entries) {
|
|
1610
|
+
const name = chalk6.white(entry.name.padEnd(maxNameLen + 2));
|
|
1611
|
+
const desc = entry.description ? chalk6.gray(entry.description) : chalk6.dim("(no description)");
|
|
1612
|
+
console.log(` ${name} ${desc}`);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
console.log();
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// src/core/docs-architecture.ts
|
|
1619
|
+
import * as fs12 from "fs";
|
|
1620
|
+
import * as path11 from "path";
|
|
1621
|
+
import chalk7 from "chalk";
|
|
1622
|
+
import YAML3 from "yaml";
|
|
1623
|
+
var KEY_DEPS = [
|
|
1624
|
+
"freezed",
|
|
1625
|
+
"freezed_annotation",
|
|
1626
|
+
"flutter_bloc",
|
|
1627
|
+
"bloc",
|
|
1628
|
+
"retrofit",
|
|
1629
|
+
"retrofit_generator",
|
|
1630
|
+
"json_serializable",
|
|
1631
|
+
"injectable",
|
|
1632
|
+
"get_it",
|
|
1633
|
+
"go_router",
|
|
1634
|
+
"widgetbook"
|
|
1635
|
+
];
|
|
1636
|
+
function discoverArchitecture(startDir) {
|
|
1637
|
+
const root = findMonorepoRoot(startDir);
|
|
1638
|
+
if (!root) return null;
|
|
1639
|
+
const melosPath = path11.join(root, "melos.yaml");
|
|
1640
|
+
if (!fs12.existsSync(melosPath)) return null;
|
|
1641
|
+
const melosContent = fs12.readFileSync(melosPath, "utf8");
|
|
1642
|
+
const melos = YAML3.parse(melosContent);
|
|
1643
|
+
const projectName = melos?.name ?? path11.basename(root);
|
|
1644
|
+
const apps = [];
|
|
1645
|
+
const appsDir = path11.join(root, "apps");
|
|
1646
|
+
if (fs12.existsSync(appsDir)) {
|
|
1647
|
+
for (const entry of fs12.readdirSync(appsDir, { withFileTypes: true })) {
|
|
1648
|
+
if (!entry.isDirectory()) continue;
|
|
1649
|
+
const candidate = path11.join(appsDir, entry.name);
|
|
1650
|
+
if (fs12.existsSync(path11.join(candidate, "pubspec.yaml"))) {
|
|
1651
|
+
apps.push({ name: entry.name, dir: candidate });
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
const packages = [];
|
|
1656
|
+
const packageBases = ["packages", "packages/features"];
|
|
1657
|
+
for (const base of packageBases) {
|
|
1658
|
+
const baseDir = path11.join(root, base);
|
|
1659
|
+
if (!fs12.existsSync(baseDir)) continue;
|
|
1660
|
+
for (const entry of fs12.readdirSync(baseDir, { withFileTypes: true })) {
|
|
1661
|
+
if (!entry.isDirectory()) continue;
|
|
1662
|
+
const candidate = path11.join(baseDir, entry.name);
|
|
1663
|
+
const pubspecPath = path11.join(candidate, "pubspec.yaml");
|
|
1664
|
+
if (!fs12.existsSync(pubspecPath)) continue;
|
|
1665
|
+
const content = fs12.readFileSync(pubspecPath, "utf8");
|
|
1666
|
+
const pubspec = YAML3.parse(content);
|
|
1667
|
+
const deps = {
|
|
1668
|
+
...pubspec?.dependencies,
|
|
1669
|
+
...pubspec?.dev_dependencies
|
|
1670
|
+
};
|
|
1671
|
+
const keyDeps = KEY_DEPS.filter((d) => d in deps);
|
|
1672
|
+
packages.push({
|
|
1673
|
+
name: pubspec?.name ?? entry.name,
|
|
1674
|
+
dir: candidate,
|
|
1675
|
+
keyDeps
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
let hasDesignSystem = false;
|
|
1680
|
+
let designSystemTiers = [];
|
|
1681
|
+
const ds = detectDesignSystem(root);
|
|
1682
|
+
if (ds) {
|
|
1683
|
+
hasDesignSystem = true;
|
|
1684
|
+
designSystemTiers = ds.availableTiers;
|
|
1685
|
+
}
|
|
1686
|
+
return {
|
|
1687
|
+
root,
|
|
1688
|
+
projectName,
|
|
1689
|
+
apps,
|
|
1690
|
+
packages,
|
|
1691
|
+
hasDesignSystem,
|
|
1692
|
+
designSystemTiers
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
function displayArchitecture(info) {
|
|
1696
|
+
const T = "\u251C\u2500\u2500 ";
|
|
1697
|
+
const L = "\u2514\u2500\u2500 ";
|
|
1698
|
+
const I = "\u2502 ";
|
|
1699
|
+
const S = " ";
|
|
1700
|
+
console.log(chalk7.bold(chalk7.cyan(info.projectName)) + chalk7.gray(` (${info.root})`));
|
|
1701
|
+
console.log(`${I}`);
|
|
1702
|
+
if (info.apps.length > 0) {
|
|
1703
|
+
console.log(chalk7.white(`${T}apps/`));
|
|
1704
|
+
for (let i = 0; i < info.apps.length; i++) {
|
|
1705
|
+
const app = info.apps[i];
|
|
1706
|
+
const prefix = i === info.apps.length - 1 ? `${I}${S}${L}` : `${I}${S}${T}`;
|
|
1707
|
+
console.log(`${prefix}${chalk7.green(app.name)}`);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
if (info.packages.length > 0) {
|
|
1711
|
+
const rootPkgs = info.packages.filter(
|
|
1712
|
+
(p) => !p.dir.includes(`${path11.sep}features${path11.sep}`)
|
|
1713
|
+
);
|
|
1714
|
+
const featurePkgs = info.packages.filter(
|
|
1715
|
+
(p) => p.dir.includes(`${path11.sep}features${path11.sep}`)
|
|
1716
|
+
);
|
|
1717
|
+
console.log(chalk7.white(`${T}packages/`));
|
|
1718
|
+
for (let i = 0; i < rootPkgs.length; i++) {
|
|
1719
|
+
const pkg2 = rootPkgs[i];
|
|
1720
|
+
const isLast = i === rootPkgs.length - 1 && featurePkgs.length === 0;
|
|
1721
|
+
const prefix = isLast ? `${I}${S}${L}` : `${I}${S}${T}`;
|
|
1722
|
+
const deps = pkg2.keyDeps.length > 0 ? chalk7.dim(` [${pkg2.keyDeps.join(", ")}]`) : "";
|
|
1723
|
+
console.log(`${prefix}${chalk7.yellow(pkg2.name)}${deps}`);
|
|
1724
|
+
}
|
|
1725
|
+
if (featurePkgs.length > 0) {
|
|
1726
|
+
console.log(`${I}${S}${T}features/`);
|
|
1727
|
+
for (let i = 0; i < featurePkgs.length; i++) {
|
|
1728
|
+
const pkg2 = featurePkgs[i];
|
|
1729
|
+
const isLast = i === featurePkgs.length - 1;
|
|
1730
|
+
const prefix = isLast ? `${I}${S}${S}${L}` : `${I}${S}${S}${T}`;
|
|
1731
|
+
const deps = pkg2.keyDeps.length > 0 ? chalk7.dim(` [${pkg2.keyDeps.join(", ")}]`) : "";
|
|
1732
|
+
console.log(`${prefix}${chalk7.yellow(pkg2.name)}${deps}`);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
if (info.hasDesignSystem) {
|
|
1737
|
+
const tiers = info.designSystemTiers.length > 0 ? chalk7.dim(` (${info.designSystemTiers.join(", ")})`) : "";
|
|
1738
|
+
console.log(`${T}${chalk7.magenta("design_system")}${tiers}`);
|
|
1739
|
+
}
|
|
1740
|
+
const bookDir = path11.join(info.root, "book");
|
|
1741
|
+
if (fs12.existsSync(bookDir)) {
|
|
1742
|
+
console.log(`${T}${chalk7.blue("book/")}` + chalk7.dim(" (Docusaurus)"));
|
|
1743
|
+
}
|
|
1744
|
+
if (fs12.existsSync(path11.join(info.root, "melos.yaml"))) {
|
|
1745
|
+
console.log(`${L}${chalk7.gray("melos.yaml")}`);
|
|
1746
|
+
}
|
|
1747
|
+
console.log();
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1467
1750
|
// src/interactive.ts
|
|
1468
1751
|
var SNAKE_CASE_REGEX4 = /^[a-z][a-z0-9_]*$/;
|
|
1469
1752
|
async function resolveProject() {
|
|
@@ -1471,7 +1754,7 @@ async function resolveProject() {
|
|
|
1471
1754
|
s.start("Analyzing current directory...");
|
|
1472
1755
|
const cwdProject = analyzeProject(process.cwd());
|
|
1473
1756
|
if (cwdProject && (cwdProject.hasFreezed || cwdProject.hasBloc)) {
|
|
1474
|
-
s.stop(`Found ${
|
|
1757
|
+
s.stop(`Found ${chalk8.green(cwdProject.projectName)}`);
|
|
1475
1758
|
return cwdProject;
|
|
1476
1759
|
}
|
|
1477
1760
|
s.message("Looking for Melos monorepo...");
|
|
@@ -1484,8 +1767,8 @@ async function resolveProject() {
|
|
|
1484
1767
|
}
|
|
1485
1768
|
}
|
|
1486
1769
|
s.message("Scanning for Flutter projects...");
|
|
1487
|
-
const homeDev =
|
|
1488
|
-
if (
|
|
1770
|
+
const homeDev = path12.join(os.homedir(), "Development");
|
|
1771
|
+
if (fs13.existsSync(homeDev)) {
|
|
1489
1772
|
const projects = discoverProjects(homeDev, 2);
|
|
1490
1773
|
if (projects.length > 0) {
|
|
1491
1774
|
s.stop(`Found ${projects.length} Flutter project(s)`);
|
|
@@ -1493,12 +1776,12 @@ async function resolveProject() {
|
|
|
1493
1776
|
}
|
|
1494
1777
|
}
|
|
1495
1778
|
s.stop("No Flutter projects found");
|
|
1496
|
-
clack.outro(
|
|
1779
|
+
clack.outro(chalk8.red("Could not find any Flutter project with freezed or flutter_bloc."));
|
|
1497
1780
|
return null;
|
|
1498
1781
|
}
|
|
1499
1782
|
async function selectPackage(projects) {
|
|
1500
1783
|
if (projects.length === 1) {
|
|
1501
|
-
clack.log.info(`Using ${
|
|
1784
|
+
clack.log.info(`Using ${chalk8.green(projects[0].projectName)}`);
|
|
1502
1785
|
return projects[0];
|
|
1503
1786
|
}
|
|
1504
1787
|
const selected = await clack.select({
|
|
@@ -1506,7 +1789,7 @@ async function selectPackage(projects) {
|
|
|
1506
1789
|
options: projects.map((p) => ({
|
|
1507
1790
|
value: p,
|
|
1508
1791
|
label: p.projectName,
|
|
1509
|
-
hint:
|
|
1792
|
+
hint: path12.relative(os.homedir(), p.projectRoot)
|
|
1510
1793
|
}))
|
|
1511
1794
|
});
|
|
1512
1795
|
if (clack.isCancel(selected)) {
|
|
@@ -1554,13 +1837,13 @@ async function blocFlow(project) {
|
|
|
1554
1837
|
clack.cancel("Cancelled");
|
|
1555
1838
|
return;
|
|
1556
1839
|
}
|
|
1557
|
-
targetDir =
|
|
1840
|
+
targetDir = path12.resolve(customPath);
|
|
1558
1841
|
} else {
|
|
1559
|
-
targetDir =
|
|
1842
|
+
targetDir = path12.join(project.projectRoot, "lib", "features", feature);
|
|
1560
1843
|
}
|
|
1561
|
-
} else if (
|
|
1562
|
-
targetDir =
|
|
1563
|
-
clack.log.info(`Target: ${
|
|
1844
|
+
} else if (fs13.existsSync(path12.join(project.projectRoot, "lib", "bloc"))) {
|
|
1845
|
+
targetDir = path12.join(project.projectRoot, "lib", "bloc");
|
|
1846
|
+
clack.log.info(`Target: ${chalk8.cyan("lib/bloc/")}`);
|
|
1564
1847
|
} else {
|
|
1565
1848
|
clack.note(
|
|
1566
1849
|
"No lib/features/ directory found. Provide a target path manually.",
|
|
@@ -1577,7 +1860,7 @@ async function blocFlow(project) {
|
|
|
1577
1860
|
clack.cancel("Cancelled");
|
|
1578
1861
|
return;
|
|
1579
1862
|
}
|
|
1580
|
-
targetDir =
|
|
1863
|
+
targetDir = path12.resolve(customPath);
|
|
1581
1864
|
}
|
|
1582
1865
|
const defaultRun = project.hasBuildRunner;
|
|
1583
1866
|
const runBuildRunner2 = await clack.confirm({
|
|
@@ -1596,10 +1879,10 @@ async function blocFlow(project) {
|
|
|
1596
1879
|
buildRunner: runBuildRunner2
|
|
1597
1880
|
});
|
|
1598
1881
|
genSpinner.stop("BLoC generated");
|
|
1599
|
-
clack.outro(
|
|
1882
|
+
clack.outro(chalk8.green("Done!"));
|
|
1600
1883
|
} catch (error) {
|
|
1601
1884
|
genSpinner.stop("Failed");
|
|
1602
|
-
clack.outro(
|
|
1885
|
+
clack.outro(chalk8.red(`Error: ${error}`));
|
|
1603
1886
|
}
|
|
1604
1887
|
}
|
|
1605
1888
|
async function widgetFlow() {
|
|
@@ -1607,14 +1890,14 @@ async function widgetFlow() {
|
|
|
1607
1890
|
const ds = detectDesignSystem(projectRoot);
|
|
1608
1891
|
if (!ds) {
|
|
1609
1892
|
clack.outro(
|
|
1610
|
-
|
|
1893
|
+
chalk8.red(
|
|
1611
1894
|
"No design system detected. Run this command from a project with wl_design_system/ directory."
|
|
1612
1895
|
)
|
|
1613
1896
|
);
|
|
1614
1897
|
return;
|
|
1615
1898
|
}
|
|
1616
1899
|
clack.log.info(
|
|
1617
|
-
`Design system: ${
|
|
1900
|
+
`Design system: ${chalk8.cyan(path12.relative(projectRoot, ds.componentsDir))}`
|
|
1618
1901
|
);
|
|
1619
1902
|
const name = await clack.text({
|
|
1620
1903
|
message: "Widget name (snake_case, without wl_ prefix)",
|
|
@@ -1679,17 +1962,17 @@ async function widgetFlow() {
|
|
|
1679
1962
|
genSpinner.stop(`Use-case skipped: ${e}`);
|
|
1680
1963
|
}
|
|
1681
1964
|
}
|
|
1682
|
-
clack.outro(
|
|
1965
|
+
clack.outro(chalk8.green("Done!"));
|
|
1683
1966
|
} catch (error) {
|
|
1684
1967
|
genSpinner.stop("Failed");
|
|
1685
|
-
clack.outro(
|
|
1968
|
+
clack.outro(chalk8.red(`Error: ${error}`));
|
|
1686
1969
|
}
|
|
1687
1970
|
}
|
|
1688
1971
|
async function useCaseFlow() {
|
|
1689
1972
|
const ds = detectDesignSystem(process.cwd());
|
|
1690
1973
|
if (!ds) {
|
|
1691
1974
|
clack.outro(
|
|
1692
|
-
|
|
1975
|
+
chalk8.red(
|
|
1693
1976
|
"No design system detected. Ensure wl_design_system/ directory exists."
|
|
1694
1977
|
)
|
|
1695
1978
|
);
|
|
@@ -1697,7 +1980,7 @@ async function useCaseFlow() {
|
|
|
1697
1980
|
}
|
|
1698
1981
|
if (!ds.widgetbookDir) {
|
|
1699
1982
|
clack.outro(
|
|
1700
|
-
|
|
1983
|
+
chalk8.red(
|
|
1701
1984
|
"No widgetbook package detected. Ensure apps/widgetbook/ exists."
|
|
1702
1985
|
)
|
|
1703
1986
|
);
|
|
@@ -1746,18 +2029,18 @@ async function useCaseFlow() {
|
|
|
1746
2029
|
buildRunner: runBuildRunner2
|
|
1747
2030
|
});
|
|
1748
2031
|
genSpinner.stop("Use-case generated");
|
|
1749
|
-
clack.outro(
|
|
2032
|
+
clack.outro(chalk8.green("Done!"));
|
|
1750
2033
|
} catch (error) {
|
|
1751
2034
|
genSpinner.stop("Failed");
|
|
1752
|
-
clack.outro(
|
|
2035
|
+
clack.outro(chalk8.red(`Error: ${error}`));
|
|
1753
2036
|
}
|
|
1754
2037
|
}
|
|
1755
2038
|
function findBffFiles(dir) {
|
|
1756
2039
|
const results = [];
|
|
1757
|
-
if (!
|
|
1758
|
-
const entries =
|
|
2040
|
+
if (!fs13.existsSync(dir)) return results;
|
|
2041
|
+
const entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
1759
2042
|
for (const entry of entries) {
|
|
1760
|
-
const fullPath =
|
|
2043
|
+
const fullPath = path12.join(dir, entry.name);
|
|
1761
2044
|
if (entry.isDirectory()) {
|
|
1762
2045
|
results.push(...findBffFiles(fullPath));
|
|
1763
2046
|
} else if (entry.isFile() && entry.name.endsWith(".dart") && !entry.name.includes(".g.")) {
|
|
@@ -1769,8 +2052,8 @@ function findBffFiles(dir) {
|
|
|
1769
2052
|
function inferBffFile(bffFiles, endpointPath) {
|
|
1770
2053
|
const firstSegment = endpointPath.replace(/^\//, "").split("/")[0].toLowerCase();
|
|
1771
2054
|
if (!firstSegment) return null;
|
|
1772
|
-
const withDomains = bffFiles.filter((f) => /^bff_.+_api\.dart$/.test(
|
|
1773
|
-
const base =
|
|
2055
|
+
const withDomains = bffFiles.filter((f) => /^bff_.+_api\.dart$/.test(path12.basename(f))).map((f) => {
|
|
2056
|
+
const base = path12.basename(f, ".dart");
|
|
1774
2057
|
const domain = base.replace(/^bff_/, "").replace(/_api$/, "");
|
|
1775
2058
|
return { file: f, domain };
|
|
1776
2059
|
});
|
|
@@ -1797,19 +2080,19 @@ async function resolveEndpointProject() {
|
|
|
1797
2080
|
s.message(`Monorepo found at ${monorepoRoot}`);
|
|
1798
2081
|
const packageBases = ["packages", "packages/features"];
|
|
1799
2082
|
for (const base of packageBases) {
|
|
1800
|
-
const baseDir =
|
|
1801
|
-
if (!
|
|
1802
|
-
const entries =
|
|
2083
|
+
const baseDir = path12.join(monorepoRoot, base);
|
|
2084
|
+
if (!fs13.existsSync(baseDir)) continue;
|
|
2085
|
+
const entries = fs13.readdirSync(baseDir, { withFileTypes: true });
|
|
1803
2086
|
for (const entry of entries) {
|
|
1804
2087
|
if (!entry.isDirectory()) continue;
|
|
1805
|
-
const candidate =
|
|
1806
|
-
if (!
|
|
1807
|
-
const bffPath =
|
|
1808
|
-
s.message(`Checking ${candidate} \u2192 bff exists: ${
|
|
1809
|
-
if (
|
|
2088
|
+
const candidate = path12.join(baseDir, entry.name);
|
|
2089
|
+
if (!fs13.existsSync(path12.join(candidate, "pubspec.yaml"))) continue;
|
|
2090
|
+
const bffPath = path12.join(candidate, "lib", "data", "api", "bff");
|
|
2091
|
+
s.message(`Checking ${candidate} \u2192 bff exists: ${fs13.existsSync(bffPath)}`);
|
|
2092
|
+
if (fs13.existsSync(bffPath)) {
|
|
1810
2093
|
const project2 = analyzeProject(candidate);
|
|
1811
2094
|
if (project2) {
|
|
1812
|
-
s.stop(`Using ${
|
|
2095
|
+
s.stop(`Using ${chalk8.green(project2.projectName)}`);
|
|
1813
2096
|
return project2;
|
|
1814
2097
|
}
|
|
1815
2098
|
}
|
|
@@ -1819,8 +2102,8 @@ async function resolveEndpointProject() {
|
|
|
1819
2102
|
s.message("No monorepo root found");
|
|
1820
2103
|
}
|
|
1821
2104
|
const cwdProject = analyzeProject(process.cwd());
|
|
1822
|
-
if (cwdProject &&
|
|
1823
|
-
s.stop(`Using ${
|
|
2105
|
+
if (cwdProject && fs13.existsSync(path12.join(cwdProject.projectRoot, "lib", "data", "api", "bff"))) {
|
|
2106
|
+
s.stop(`Using ${chalk8.green(cwdProject.projectName)}`);
|
|
1824
2107
|
return cwdProject;
|
|
1825
2108
|
}
|
|
1826
2109
|
s.stop("No BFF package found");
|
|
@@ -1829,33 +2112,33 @@ async function resolveEndpointProject() {
|
|
|
1829
2112
|
placeholder: "e.g. /path/to/my-package or ./packages/core",
|
|
1830
2113
|
validate: (v) => {
|
|
1831
2114
|
if (!v.trim()) return "Path is required";
|
|
1832
|
-
const resolved2 =
|
|
1833
|
-
if (!
|
|
1834
|
-
if (!
|
|
1835
|
-
if (!
|
|
2115
|
+
const resolved2 = path12.resolve(v.trim());
|
|
2116
|
+
if (!fs13.existsSync(resolved2)) return "Path does not exist";
|
|
2117
|
+
if (!fs13.existsSync(path12.join(resolved2, "pubspec.yaml"))) return "No pubspec.yaml found at this path";
|
|
2118
|
+
if (!fs13.existsSync(path12.join(resolved2, "lib", "data", "api", "bff"))) return "No lib/data/api/bff/ found at this path";
|
|
1836
2119
|
}
|
|
1837
2120
|
});
|
|
1838
2121
|
if (clack.isCancel(manualPath)) {
|
|
1839
2122
|
clack.cancel("Cancelled");
|
|
1840
2123
|
return null;
|
|
1841
2124
|
}
|
|
1842
|
-
const resolved =
|
|
2125
|
+
const resolved = path12.resolve(manualPath);
|
|
1843
2126
|
const project = analyzeProject(resolved);
|
|
1844
2127
|
if (!project) {
|
|
1845
|
-
clack.outro(
|
|
2128
|
+
clack.outro(chalk8.red(`Could not analyze project at ${resolved}`));
|
|
1846
2129
|
return null;
|
|
1847
2130
|
}
|
|
1848
|
-
clack.log.info(`Using ${
|
|
2131
|
+
clack.log.info(`Using ${chalk8.green(project.projectName)}`);
|
|
1849
2132
|
return project;
|
|
1850
2133
|
}
|
|
1851
2134
|
async function endpointFlow() {
|
|
1852
2135
|
const project = await resolveEndpointProject();
|
|
1853
2136
|
if (!project) return;
|
|
1854
|
-
const lib =
|
|
1855
|
-
const bffDir =
|
|
2137
|
+
const lib = path12.join(project.projectRoot, "lib");
|
|
2138
|
+
const bffDir = path12.join(lib, "data", "api", "bff");
|
|
1856
2139
|
const bffFiles = findBffFiles(bffDir);
|
|
1857
2140
|
if (bffFiles.length === 0) {
|
|
1858
|
-
clack.outro(
|
|
2141
|
+
clack.outro(chalk8.red("No BFF API files found. Ensure lib/data/api/bff/ exists with .dart files."));
|
|
1859
2142
|
return;
|
|
1860
2143
|
}
|
|
1861
2144
|
const httpMethod = await clack.select({
|
|
@@ -1885,13 +2168,13 @@ async function endpointFlow() {
|
|
|
1885
2168
|
}
|
|
1886
2169
|
let bffApiFile = inferBffFile(bffFiles, endpointPath);
|
|
1887
2170
|
if (bffApiFile) {
|
|
1888
|
-
clack.log.info(`Auto-detected BFF file: ${
|
|
2171
|
+
clack.log.info(`Auto-detected BFF file: ${chalk8.cyan(path12.basename(bffApiFile))}`);
|
|
1889
2172
|
} else {
|
|
1890
2173
|
const selected = await clack.select({
|
|
1891
2174
|
message: "Could not auto-detect BFF file. Select one:",
|
|
1892
2175
|
options: bffFiles.map((f) => ({
|
|
1893
2176
|
value: f,
|
|
1894
|
-
label:
|
|
2177
|
+
label: path12.relative(bffDir, f)
|
|
1895
2178
|
}))
|
|
1896
2179
|
});
|
|
1897
2180
|
if (clack.isCancel(selected)) {
|
|
@@ -1955,14 +2238,66 @@ async function endpointFlow() {
|
|
|
1955
2238
|
diLazySingleton
|
|
1956
2239
|
});
|
|
1957
2240
|
genSpinner.stop("Endpoint generated");
|
|
1958
|
-
clack.outro(
|
|
2241
|
+
clack.outro(chalk8.green("Done!"));
|
|
1959
2242
|
} catch (error) {
|
|
1960
2243
|
genSpinner.stop("Failed");
|
|
1961
|
-
clack.outro(
|
|
2244
|
+
clack.outro(chalk8.red(`Error: ${error}`));
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
async function docsInteractiveMode() {
|
|
2248
|
+
clack.intro(chalk8.bgCyan(chalk8.black(" wlmaker docs ")));
|
|
2249
|
+
const action = await clack.select({
|
|
2250
|
+
message: "What do you want to do?",
|
|
2251
|
+
options: [
|
|
2252
|
+
{ value: "serve", label: "Serve", hint: "Start Docusaurus dev server" },
|
|
2253
|
+
{ value: "commands", label: "Commands", hint: "Show Makefile & melos commands" },
|
|
2254
|
+
{ value: "architecture", label: "Architecture", hint: "Display monorepo tree" }
|
|
2255
|
+
]
|
|
2256
|
+
});
|
|
2257
|
+
if (clack.isCancel(action)) {
|
|
2258
|
+
clack.cancel("Cancelled");
|
|
2259
|
+
return;
|
|
2260
|
+
}
|
|
2261
|
+
switch (action) {
|
|
2262
|
+
case "serve": {
|
|
2263
|
+
const bookDir = detectBookDir(process.cwd());
|
|
2264
|
+
if (!bookDir) {
|
|
2265
|
+
clack.outro(
|
|
2266
|
+
chalk8.red("No Docusaurus book/ directory found. Run from a monorepo root.")
|
|
2267
|
+
);
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
clack.log.info(`Serving docs from ${chalk8.cyan(bookDir)}`);
|
|
2271
|
+
await serveBook(bookDir);
|
|
2272
|
+
break;
|
|
2273
|
+
}
|
|
2274
|
+
case "commands": {
|
|
2275
|
+
const commands = discoverCommands(process.cwd());
|
|
2276
|
+
if (commands.length === 0) {
|
|
2277
|
+
clack.outro(chalk8.yellow("No commands found. Run from a monorepo root."));
|
|
2278
|
+
return;
|
|
2279
|
+
}
|
|
2280
|
+
clack.log.info(`Found ${chalk8.green(commands.length.toString())} command(s)`);
|
|
2281
|
+
displayCommands(commands);
|
|
2282
|
+
clack.outro(chalk8.green("Done!"));
|
|
2283
|
+
break;
|
|
2284
|
+
}
|
|
2285
|
+
case "architecture": {
|
|
2286
|
+
const info = discoverArchitecture(process.cwd());
|
|
2287
|
+
if (!info) {
|
|
2288
|
+
clack.outro(
|
|
2289
|
+
chalk8.yellow("No monorepo detected. Run from within a Melos monorepo.")
|
|
2290
|
+
);
|
|
2291
|
+
return;
|
|
2292
|
+
}
|
|
2293
|
+
displayArchitecture(info);
|
|
2294
|
+
clack.outro(chalk8.green("Done!"));
|
|
2295
|
+
break;
|
|
2296
|
+
}
|
|
1962
2297
|
}
|
|
1963
2298
|
}
|
|
1964
2299
|
async function interactiveMode() {
|
|
1965
|
-
clack.intro(
|
|
2300
|
+
clack.intro(chalk8.bgCyan(chalk8.black(" wlmaker ")));
|
|
1966
2301
|
const createType = await clack.select({
|
|
1967
2302
|
message: "What do you want to create?",
|
|
1968
2303
|
options: [
|
|
@@ -1977,6 +2312,11 @@ async function interactiveMode() {
|
|
|
1977
2312
|
value: "endpoint",
|
|
1978
2313
|
label: "Endpoint",
|
|
1979
2314
|
hint: "BFF Clean Architecture stack"
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
value: "docs",
|
|
2318
|
+
label: "Docs",
|
|
2319
|
+
hint: "Project documentation tools"
|
|
1980
2320
|
}
|
|
1981
2321
|
]
|
|
1982
2322
|
});
|
|
@@ -2001,6 +2341,9 @@ async function interactiveMode() {
|
|
|
2001
2341
|
case "endpoint":
|
|
2002
2342
|
await endpointFlow();
|
|
2003
2343
|
break;
|
|
2344
|
+
case "docs":
|
|
2345
|
+
await docsInteractiveMode();
|
|
2346
|
+
break;
|
|
2004
2347
|
}
|
|
2005
2348
|
}
|
|
2006
2349
|
|
|
@@ -2020,7 +2363,7 @@ program.command("bloc").description("Create a new BLoC with Freezed sealed class
|
|
|
2020
2363
|
try {
|
|
2021
2364
|
await createBloc(name, options);
|
|
2022
2365
|
} catch (error) {
|
|
2023
|
-
console.error(
|
|
2366
|
+
console.error(chalk9.red(`Error: ${error}`));
|
|
2024
2367
|
process.exit(1);
|
|
2025
2368
|
}
|
|
2026
2369
|
}
|
|
@@ -2037,12 +2380,12 @@ program.command("widget").description("Create a new widget in the design system"
|
|
|
2037
2380
|
projectRoot: options.dir,
|
|
2038
2381
|
buildRunner: false
|
|
2039
2382
|
});
|
|
2040
|
-
console.log(
|
|
2383
|
+
console.log(chalk9.green("Widgetbook use-case created"));
|
|
2041
2384
|
} catch {
|
|
2042
|
-
console.log(
|
|
2385
|
+
console.log(chalk9.yellow("Use-case skipped (may already exist)"));
|
|
2043
2386
|
}
|
|
2044
2387
|
} catch (error) {
|
|
2045
|
-
console.error(
|
|
2388
|
+
console.error(chalk9.red(`Error: ${error}`));
|
|
2046
2389
|
process.exit(1);
|
|
2047
2390
|
}
|
|
2048
2391
|
}
|
|
@@ -2055,7 +2398,7 @@ program.command("usecase").description("Create a Widgetbook use-case for an exis
|
|
|
2055
2398
|
buildRunner: options.buildRunner
|
|
2056
2399
|
});
|
|
2057
2400
|
} catch (error) {
|
|
2058
|
-
console.error(
|
|
2401
|
+
console.error(chalk9.red(`Error: ${error}`));
|
|
2059
2402
|
process.exit(1);
|
|
2060
2403
|
}
|
|
2061
2404
|
}
|
|
@@ -2065,6 +2408,37 @@ program.command("endpoint").description("Generate Clean Architecture stack for a
|
|
|
2065
2408
|
if (!project) return;
|
|
2066
2409
|
await endpointFlow(project);
|
|
2067
2410
|
});
|
|
2411
|
+
var docsCmd = program.command("docs").description("Project documentation tools");
|
|
2412
|
+
docsCmd.command("serve").description("Start Docusaurus dev server").option("-d, --dir <path>", "project root directory", process.cwd()).action(async (options) => {
|
|
2413
|
+
const bookDir = detectBookDir(options.dir);
|
|
2414
|
+
if (!bookDir) {
|
|
2415
|
+
console.error(chalk9.red("No Docusaurus book/ directory found. Run from a monorepo root."));
|
|
2416
|
+
process.exit(1);
|
|
2417
|
+
}
|
|
2418
|
+
console.log(chalk9.cyan(`Serving docs from ${bookDir}`));
|
|
2419
|
+
await serveBook(bookDir);
|
|
2420
|
+
});
|
|
2421
|
+
docsCmd.command("commands").description("Show Makefile & melos commands reference").option("-d, --dir <path>", "project root directory", process.cwd()).action(async (options) => {
|
|
2422
|
+
const commands = discoverCommands(options.dir);
|
|
2423
|
+
if (commands.length === 0) {
|
|
2424
|
+
console.log(chalk9.yellow("No commands found. Run from a monorepo root."));
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
console.log(chalk9.green(`Found ${commands.length} command(s)
|
|
2428
|
+
`));
|
|
2429
|
+
displayCommands(commands);
|
|
2430
|
+
});
|
|
2431
|
+
docsCmd.command("architecture").description("Display monorepo architecture tree").option("-d, --dir <path>", "project root directory", process.cwd()).action(async (options) => {
|
|
2432
|
+
const info = discoverArchitecture(options.dir);
|
|
2433
|
+
if (!info) {
|
|
2434
|
+
console.log(chalk9.yellow("No monorepo detected. Run from within a Melos monorepo."));
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
displayArchitecture(info);
|
|
2438
|
+
});
|
|
2439
|
+
docsCmd.action(async () => {
|
|
2440
|
+
await docsInteractiveMode();
|
|
2441
|
+
});
|
|
2068
2442
|
program.action(async () => {
|
|
2069
2443
|
await interactiveMode();
|
|
2070
2444
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wlmaker",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Create Flutter BLoCs with Freezed sealed classes from the terminal",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"flutter",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"bin": {
|
|
19
|
-
"wlmaker": "./dist/cli.mjs"
|
|
19
|
+
"wlmaker": "./dist/cli.mjs",
|
|
20
|
+
"wl": "./dist/cli.mjs"
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
23
|
"dist"
|