create-projx 1.4.1 → 1.4.2

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/index.js +56 -30
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -251,6 +251,35 @@ async function discoverComponentPaths(cwd, components) {
251
251
  }
252
252
  return paths;
253
253
  }
254
+ async function discoverComponentsFromMarkers(cwd) {
255
+ const components = [];
256
+ const paths = {};
257
+ const entries = await readdir(cwd, { withFileTypes: true });
258
+ for (const entry of entries) {
259
+ if (!entry.isDirectory()) continue;
260
+ if (EXCLUDE.has(entry.name)) continue;
261
+ if (entry.name.startsWith(".")) continue;
262
+ const full = join(cwd, entry.name);
263
+ const marker = join(full, COMPONENT_MARKER);
264
+ if (existsSync(marker)) {
265
+ try {
266
+ const data = JSON.parse(await readFile(marker, "utf-8"));
267
+ const markerComponents = data.components ?? (data.component ? [data.component] : []);
268
+ for (const mc of markerComponents) {
269
+ if (COMPONENTS.includes(mc) && !components.includes(mc)) {
270
+ components.push(mc);
271
+ paths[mc] = entry.name;
272
+ }
273
+ }
274
+ } catch {
275
+ }
276
+ }
277
+ }
278
+ for (const c of components) {
279
+ if (!paths[c]) paths[c] = c;
280
+ }
281
+ return { components, paths };
282
+ }
254
283
  function render(template, vars) {
255
284
  const components = vars.components;
256
285
  const projectName = vars.projectName;
@@ -925,17 +954,19 @@ async function update(cwd, localRepo) {
925
954
  const configPath = join5(cwd, ".projx");
926
955
  let config;
927
956
  if (existsSync4(configPath)) {
928
- config = JSON.parse(await readFile5(configPath, "utf-8"));
957
+ const raw = JSON.parse(await readFile5(configPath, "utf-8"));
958
+ const { components: discovered } = await discoverComponentsFromMarkers(cwd);
959
+ config = { ...raw, components: discovered.length > 0 ? discovered : raw.components };
929
960
  p3.log.info(`Found .projx (v${config.version}, components: ${config.components.join(", ")})`);
930
961
  } else {
931
962
  p3.log.warn("No .projx file found. Detecting components from directories.");
932
- const detected = COMPONENTS.filter((c) => existsSync4(join5(cwd, c)));
933
- if (detected.length === 0) {
963
+ const { components: discovered } = await discoverComponentsFromMarkers(cwd);
964
+ if (discovered.length === 0) {
934
965
  p3.log.error("No projx components found. Run 'projx init' first.");
935
966
  process.exit(1);
936
967
  }
937
- config = { version: "0.0.0", components: detected, createdAt: "unknown" };
938
- p3.log.info(`Detected: ${detected.join(", ")}`);
968
+ config = { version: "0.0.0", components: discovered, createdAt: "unknown" };
969
+ p3.log.info(`Detected: ${discovered.join(", ")}`);
939
970
  }
940
971
  const componentPaths = await discoverComponentPaths(cwd, config.components);
941
972
  for (const c of config.components) {
@@ -1493,7 +1524,7 @@ async function pin(cwd, patterns) {
1493
1524
  process.exit(1);
1494
1525
  }
1495
1526
  const config = JSON.parse(await readFile8(configPath, "utf-8"));
1496
- const componentPaths = await discoverComponentPaths(cwd, config.components);
1527
+ const componentPaths = (await discoverComponentsFromMarkers(cwd)).paths;
1497
1528
  const rootAdds = [];
1498
1529
  const componentAdds = {};
1499
1530
  for (const pattern of patterns) {
@@ -1550,7 +1581,7 @@ async function unpin(cwd, patterns) {
1550
1581
  process.exit(1);
1551
1582
  }
1552
1583
  const config = JSON.parse(await readFile8(configPath, "utf-8"));
1553
- const componentPaths = await discoverComponentPaths(cwd, config.components);
1584
+ const componentPaths = (await discoverComponentsFromMarkers(cwd)).paths;
1554
1585
  const rootRemoves = [];
1555
1586
  const componentRemoves = {};
1556
1587
  for (const pattern of patterns) {
@@ -1611,7 +1642,7 @@ async function listPins(cwd) {
1611
1642
  process.exit(1);
1612
1643
  }
1613
1644
  const config = JSON.parse(await readFile8(configPath, "utf-8"));
1614
- const componentPaths = await discoverComponentPaths(cwd, config.components);
1645
+ const { components: discovered, paths: componentPaths } = await discoverComponentsFromMarkers(cwd);
1615
1646
  let hasAny = false;
1616
1647
  if (config.skip && config.skip.length > 0) {
1617
1648
  hasAny = true;
@@ -1620,7 +1651,7 @@ async function listPins(cwd) {
1620
1651
  p6.log.info(` ${s}`);
1621
1652
  }
1622
1653
  }
1623
- for (const component of config.components) {
1654
+ for (const component of discovered) {
1624
1655
  const dir = componentPaths[component];
1625
1656
  const marker = await readComponentMarker(join9(cwd, dir));
1626
1657
  if (marker?.skip && marker.skip.length > 0) {
@@ -1877,10 +1908,11 @@ async function doctor(cwd, fix = false) {
1877
1908
  printReport(allResults);
1878
1909
  process.exit(1);
1879
1910
  }
1880
- const componentPaths = await discoverComponentPaths(cwd, config.components);
1881
- allResults.push(...await checkComponents(cwd, config, componentPaths));
1911
+ const { components: discovered, paths: componentPaths } = await discoverComponentsFromMarkers(cwd);
1912
+ const resolvedConfig = { ...config, components: discovered.length > 0 ? discovered : config.components };
1913
+ allResults.push(...await checkComponents(cwd, resolvedConfig, componentPaths));
1882
1914
  allResults.push(...checkGit(cwd, fix));
1883
- allResults.push(...await checkSkipPatterns(cwd, config, componentPaths));
1915
+ allResults.push(...await checkSkipPatterns(cwd, resolvedConfig, componentPaths));
1884
1916
  printReport(allResults);
1885
1917
  const passed = allResults.filter((r) => r.status === "pass").length;
1886
1918
  const warns = allResults.filter((r) => r.status === "warn").length;
@@ -1935,8 +1967,9 @@ async function diff(cwd, localRepo) {
1935
1967
  p8.log.error("No .projx file found. Run 'npx create-projx init' first.");
1936
1968
  process.exit(1);
1937
1969
  }
1938
- const config = JSON.parse(await readFile10(configPath, "utf-8"));
1939
- const componentPaths = await discoverComponentPaths(cwd, config.components);
1970
+ const raw = JSON.parse(await readFile10(configPath, "utf-8"));
1971
+ const { components: discovered, paths: componentPaths } = await discoverComponentsFromMarkers(cwd);
1972
+ const config = { ...raw, components: discovered.length > 0 ? discovered : raw.components };
1940
1973
  const componentSkips = {};
1941
1974
  for (const component of config.components) {
1942
1975
  const dir = componentPaths[component];
@@ -2596,12 +2629,11 @@ async function gen(cwd, entityName, fieldsFlag) {
2596
2629
  p9.log.error("No .projx file found. Run 'npx create-projx init' first.");
2597
2630
  process.exit(1);
2598
2631
  }
2599
- const projxConfig = JSON.parse(await readFile11(configPath, "utf-8"));
2600
- const componentPaths = await discoverComponentPaths(cwd, projxConfig.components);
2601
- const hasFastapi = projxConfig.components.includes("fastapi");
2602
- const hasFastify = projxConfig.components.includes("fastify");
2603
- const hasFrontend = projxConfig.components.includes("frontend");
2604
- const hasMobile = projxConfig.components.includes("mobile");
2632
+ const { components: discovered, paths: componentPaths } = await discoverComponentsFromMarkers(cwd);
2633
+ const hasFastapi = discovered.includes("fastapi");
2634
+ const hasFastify = discovered.includes("fastify");
2635
+ const hasFrontend = discovered.includes("frontend");
2636
+ const hasMobile = discovered.includes("mobile");
2605
2637
  if (!hasFastapi && !hasFastify) {
2606
2638
  p9.log.error("No backend component found. Need fastapi or fastify.");
2607
2639
  process.exit(1);
@@ -2749,7 +2781,7 @@ async function gen(cwd, entityName, fieldsFlag) {
2749
2781
 
2750
2782
  // src/sync.ts
2751
2783
  import { existsSync as existsSync12, readFileSync as readFileSync2 } from "fs";
2752
- import { readFile as readFile12, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
2784
+ import { writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
2753
2785
  import { join as join13 } from "path";
2754
2786
  import * as p10 from "@clack/prompts";
2755
2787
  function toPascal2(s) {
@@ -2926,15 +2958,9 @@ async function sync(cwd, url) {
2926
2958
  p10.log.error("No .projx file found. Run 'npx create-projx init' first.");
2927
2959
  process.exit(1);
2928
2960
  }
2929
- const projxConfig = JSON.parse(
2930
- await readFile12(configPath, "utf-8")
2931
- );
2932
- const componentPaths = await discoverComponentPaths(
2933
- cwd,
2934
- projxConfig.components
2935
- );
2936
- const hasFrontend = projxConfig.components.includes("frontend");
2937
- const hasMobile = projxConfig.components.includes("mobile");
2961
+ const { components: discovered, paths: componentPaths } = await discoverComponentsFromMarkers(cwd);
2962
+ const hasFrontend = discovered.includes("frontend");
2963
+ const hasMobile = discovered.includes("mobile");
2938
2964
  if (!hasFrontend && !hasMobile) {
2939
2965
  p10.log.error("No frontend or mobile component found. Nothing to sync.");
2940
2966
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-projx",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Scaffold production-grade fullstack projects in seconds. FastAPI, Fastify, React, Flutter, Terraform — with auth, database, CI/CD, E2E tests, and Docker. One command, ready to deploy.",
5
5
  "type": "module",
6
6
  "bin": {