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