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.
Files changed (2) hide show
  1. package/dist/cli.mjs +472 -64
  2. 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 chalk6 from "chalk";
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 fs10 from "fs";
959
+ import * as fs13 from "fs";
960
960
  import * as os from "os";
961
- import * as path9 from "path";
961
+ import * as path12 from "path";
962
+ import { execSync } from "child_process";
962
963
  import * as clack from "@clack/prompts";
963
- import chalk5 from "chalk";
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, path10, httpMethod, params, returnType) {
1053
- const httpAnnotation = `@${httpMethod.toUpperCase()}('${path10}')`;
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 ${chalk5.green(cwdProject.projectName)}`);
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 = path9.join(os.homedir(), "Development");
1488
- if (fs10.existsSync(homeDev)) {
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(chalk5.red("Could not find any Flutter project with freezed or flutter_bloc."));
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 ${chalk5.green(projects[0].projectName)}`);
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: path9.relative(os.homedir(), p.projectRoot)
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 = path9.resolve(customPath);
1841
+ targetDir = path12.resolve(customPath);
1558
1842
  } else {
1559
- targetDir = path9.join(project.projectRoot, "lib", "features", feature);
1843
+ targetDir = path12.join(project.projectRoot, "lib", "features", feature);
1560
1844
  }
1561
- } else if (fs10.existsSync(path9.join(project.projectRoot, "lib", "bloc"))) {
1562
- targetDir = path9.join(project.projectRoot, "lib", "bloc");
1563
- clack.log.info(`Target: ${chalk5.cyan("lib/bloc/")}`);
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 = path9.resolve(customPath);
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(chalk5.green("Done!"));
1883
+ clack.outro(chalk8.green("Done!"));
1600
1884
  } catch (error) {
1601
1885
  genSpinner.stop("Failed");
1602
- clack.outro(chalk5.red(`Error: ${error}`));
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
- chalk5.red(
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: ${chalk5.cyan(path9.relative(projectRoot, ds.componentsDir))}`
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(chalk5.green("Done!"));
1966
+ clack.outro(chalk8.green("Done!"));
1683
1967
  } catch (error) {
1684
1968
  genSpinner.stop("Failed");
1685
- clack.outro(chalk5.red(`Error: ${error}`));
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
- chalk5.red(
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
- chalk5.red(
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(chalk5.green("Done!"));
2033
+ clack.outro(chalk8.green("Done!"));
1750
2034
  } catch (error) {
1751
2035
  genSpinner.stop("Failed");
1752
- clack.outro(chalk5.red(`Error: ${error}`));
2036
+ clack.outro(chalk8.red(`Error: ${error}`));
1753
2037
  }
1754
2038
  }
1755
2039
  function findBffFiles(dir) {
1756
2040
  const results = [];
1757
- if (!fs10.existsSync(dir)) return results;
1758
- const entries = fs10.readdirSync(dir, { withFileTypes: true });
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 = path9.join(dir, entry.name);
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(path9.basename(f))).map((f) => {
1773
- const base = path9.basename(f, ".dart");
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 = path9.join(monorepoRoot, base);
1801
- if (!fs10.existsSync(baseDir)) continue;
1802
- const entries = fs10.readdirSync(baseDir, { withFileTypes: true });
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 = path9.join(baseDir, entry.name);
1806
- if (!fs10.existsSync(path9.join(candidate, "pubspec.yaml"))) continue;
1807
- const bffPath = path9.join(candidate, "lib", "data", "api", "bff");
1808
- s.message(`Checking ${candidate} \u2192 bff exists: ${fs10.existsSync(bffPath)}`);
1809
- if (fs10.existsSync(bffPath)) {
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 ${chalk5.green(project2.projectName)}`);
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 && fs10.existsSync(path9.join(cwdProject.projectRoot, "lib", "data", "api", "bff"))) {
1823
- s.stop(`Using ${chalk5.green(cwdProject.projectName)}`);
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 = path9.resolve(v.trim());
1833
- if (!fs10.existsSync(resolved2)) return "Path does not exist";
1834
- if (!fs10.existsSync(path9.join(resolved2, "pubspec.yaml"))) return "No pubspec.yaml found at this path";
1835
- if (!fs10.existsSync(path9.join(resolved2, "lib", "data", "api", "bff"))) return "No lib/data/api/bff/ found at this path";
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 = path9.resolve(manualPath);
2126
+ const resolved = path12.resolve(manualPath);
1843
2127
  const project = analyzeProject(resolved);
1844
2128
  if (!project) {
1845
- clack.outro(chalk5.red(`Could not analyze project at ${resolved}`));
2129
+ clack.outro(chalk8.red(`Could not analyze project at ${resolved}`));
1846
2130
  return null;
1847
2131
  }
1848
- clack.log.info(`Using ${chalk5.green(project.projectName)}`);
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 = path9.join(project.projectRoot, "lib");
1855
- const bffDir = path9.join(lib, "data", "api", "bff");
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(chalk5.red("No BFF API files found. Ensure lib/data/api/bff/ exists with .dart files."));
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: ${chalk5.cyan(path9.basename(bffApiFile))}`);
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: path9.relative(bffDir, f)
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(chalk5.green("Done!"));
2242
+ clack.outro(chalk8.green("Done!"));
1959
2243
  } catch (error) {
1960
2244
  genSpinner.stop("Failed");
1961
- clack.outro(chalk5.red(`Error: ${error}`));
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(chalk5.bgCyan(chalk5.black(" wlmaker ")));
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(chalk6.red(`Error: ${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(chalk6.green("Widgetbook use-case created"));
2417
+ console.log(chalk9.green("Widgetbook use-case created"));
2041
2418
  } catch {
2042
- console.log(chalk6.yellow("Use-case skipped (may already exist)"));
2419
+ console.log(chalk9.yellow("Use-case skipped (may already exist)"));
2043
2420
  }
2044
2421
  } catch (error) {
2045
- console.error(chalk6.red(`Error: ${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(chalk6.red(`Error: ${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.2.13",
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"