create-awesome-node-app 0.4.26 → 0.4.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,6 +67,21 @@ create-awesome-node-app --template react-vite-boilerplate --addons jotai materia
67
67
 
68
68
  This example uses the `react-vite-boilerplate` template and applies the `jotai`, `material-ui`, and `github-setup` extensions.
69
69
 
70
+ ### Listing Templates and Addons
71
+
72
+ You can list all available templates and addons using the following flags:
73
+
74
+ ```sh
75
+ # List all available templates
76
+ create-awesome-node-app --list-templates
77
+
78
+ # List all available addons
79
+ create-awesome-node-app --list-addons
80
+
81
+ # List addons compatible with a specific template
82
+ create-awesome-node-app --template react-vite-boilerplate --list-addons
83
+ ```
84
+
70
85
  ## 🔗 Full List of Templates and Extensions
71
86
 
72
87
  You can find the full list of available templates and extensions in the [cna-templates repository](https://github.com/Create-Node-App/cna-templates).
package/dist/index.cjs CHANGED
@@ -1342,14 +1342,14 @@ var require_templates = __commonJS({
1342
1342
  }
1343
1343
  return results;
1344
1344
  }
1345
- function buildStyle(chalk2, styles) {
1345
+ function buildStyle(chalk3, styles) {
1346
1346
  const enabled = {};
1347
1347
  for (const layer of styles) {
1348
1348
  for (const style of layer.styles) {
1349
1349
  enabled[style[0]] = layer.inverse ? null : style.slice(1);
1350
1350
  }
1351
1351
  }
1352
- let current = chalk2;
1352
+ let current = chalk3;
1353
1353
  for (const [styleName, styles2] of Object.entries(enabled)) {
1354
1354
  if (!Array.isArray(styles2)) {
1355
1355
  continue;
@@ -1361,7 +1361,7 @@ var require_templates = __commonJS({
1361
1361
  }
1362
1362
  return current;
1363
1363
  }
1364
- module2.exports = (chalk2, temporary) => {
1364
+ module2.exports = (chalk3, temporary) => {
1365
1365
  const styles = [];
1366
1366
  const chunks = [];
1367
1367
  let chunk = [];
@@ -1371,13 +1371,13 @@ var require_templates = __commonJS({
1371
1371
  } else if (style) {
1372
1372
  const string = chunk.join("");
1373
1373
  chunk = [];
1374
- chunks.push(styles.length === 0 ? string : buildStyle(chalk2, styles)(string));
1374
+ chunks.push(styles.length === 0 ? string : buildStyle(chalk3, styles)(string));
1375
1375
  styles.push({ inverse, styles: parseStyle(style) });
1376
1376
  } else if (close) {
1377
1377
  if (styles.length === 0) {
1378
1378
  throw new Error("Found extraneous } in Chalk template literal");
1379
1379
  }
1380
- chunks.push(buildStyle(chalk2, styles)(chunk.join("")));
1380
+ chunks.push(buildStyle(chalk3, styles)(chunk.join("")));
1381
1381
  chunk = [];
1382
1382
  styles.pop();
1383
1383
  } else {
@@ -1425,16 +1425,16 @@ var require_source = __commonJS({
1425
1425
  }
1426
1426
  };
1427
1427
  var chalkFactory = (options) => {
1428
- const chalk3 = {};
1429
- applyOptions(chalk3, options);
1430
- chalk3.template = (...arguments_) => chalkTag(chalk3.template, ...arguments_);
1431
- Object.setPrototypeOf(chalk3, Chalk.prototype);
1432
- Object.setPrototypeOf(chalk3.template, chalk3);
1433
- chalk3.template.constructor = () => {
1428
+ const chalk4 = {};
1429
+ applyOptions(chalk4, options);
1430
+ chalk4.template = (...arguments_) => chalkTag(chalk4.template, ...arguments_);
1431
+ Object.setPrototypeOf(chalk4, Chalk.prototype);
1432
+ Object.setPrototypeOf(chalk4.template, chalk4);
1433
+ chalk4.template.constructor = () => {
1434
1434
  throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
1435
1435
  };
1436
- chalk3.template.Instance = ChalkClass;
1437
- return chalk3.template;
1436
+ chalk4.template.Instance = ChalkClass;
1437
+ return chalk4.template;
1438
1438
  };
1439
1439
  function Chalk(options) {
1440
1440
  return chalkFactory(options);
@@ -1545,7 +1545,7 @@ var require_source = __commonJS({
1545
1545
  return openAll + string + closeAll;
1546
1546
  };
1547
1547
  var template;
1548
- var chalkTag = (chalk3, ...strings) => {
1548
+ var chalkTag = (chalk4, ...strings) => {
1549
1549
  const [firstString] = strings;
1550
1550
  if (!isArray(firstString) || !isArray(firstString.raw)) {
1551
1551
  return strings.join(" ");
@@ -1561,20 +1561,20 @@ var require_source = __commonJS({
1561
1561
  if (template === void 0) {
1562
1562
  template = require_templates();
1563
1563
  }
1564
- return template(chalk3, parts.join(""));
1564
+ return template(chalk4, parts.join(""));
1565
1565
  };
1566
1566
  Object.defineProperties(Chalk.prototype, styles);
1567
- var chalk2 = Chalk();
1568
- chalk2.supportsColor = stdoutColor;
1569
- chalk2.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
1570
- chalk2.stderr.supportsColor = stderrColor;
1571
- module2.exports = chalk2;
1567
+ var chalk3 = Chalk();
1568
+ chalk3.supportsColor = stdoutColor;
1569
+ chalk3.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
1570
+ chalk3.stderr.supportsColor = stderrColor;
1571
+ module2.exports = chalk3;
1572
1572
  }
1573
1573
  });
1574
1574
 
1575
1575
  // src/index.ts
1576
1576
  var import_commander = require("commander");
1577
- var import_chalk = __toESM(require_source(), 1);
1577
+ var import_chalk2 = __toESM(require_source(), 1);
1578
1578
  var import_semver = __toESM(require("semver"), 1);
1579
1579
  var import_core = require("@create-node-app/core");
1580
1580
 
@@ -1612,12 +1612,24 @@ var getTemplateCategories = async (cliArgs) => {
1612
1612
  return [cliArgs.category];
1613
1613
  }
1614
1614
  const templateData = await getTemplateData();
1615
+ if (templateData.categories && templateData.categories.length > 0) {
1616
+ return templateData.categories.map((category) => category.slug);
1617
+ }
1615
1618
  const categories = /* @__PURE__ */ new Set();
1616
1619
  templateData.templates.forEach((template) => {
1617
1620
  categories.add(template.category);
1618
1621
  });
1619
1622
  return Array.from(categories);
1620
1623
  };
1624
+ var getCategoryData = async (categorySlug) => {
1625
+ const templateData = await getTemplateData();
1626
+ if (templateData.categories && templateData.categories.length > 0) {
1627
+ return templateData.categories.find(
1628
+ (category) => category.slug === categorySlug
1629
+ );
1630
+ }
1631
+ return void 0;
1632
+ };
1621
1633
  var getTemplatesForCategory = async (category, cliArgs) => {
1622
1634
  const selectedCategory = (cliArgs == null ? void 0 : cliArgs.category) || category;
1623
1635
  if (!selectedCategory) {
@@ -1661,63 +1673,83 @@ var isValidUrl = (url) => {
1661
1673
  return false;
1662
1674
  }
1663
1675
  };
1664
- var getCnaOptions = async (options) => {
1676
+ var processNonInteractiveOptions = async (options) => {
1665
1677
  const categories = await getTemplateCategories();
1666
- if (import_ci_info.isCI || !options.interactive) {
1667
- let matchedTemplate;
1668
- if (options.template && !isValidUrl(options.template)) {
1669
- const allTemplates = (await Promise.all(
1670
- categories.map((category) => getTemplatesForCategory(category))
1671
- )).flat();
1672
- matchedTemplate = allTemplates.find(
1673
- (template) => template.slug === options.template
1678
+ let matchedTemplate;
1679
+ const templatesOrExtensions = [];
1680
+ if (options.template && !isValidUrl(options.template)) {
1681
+ const allTemplates = (await Promise.all(
1682
+ categories.map((category) => getTemplatesForCategory(category))
1683
+ )).flat();
1684
+ matchedTemplate = allTemplates.find(
1685
+ (template) => template.slug === options.template
1686
+ );
1687
+ if (matchedTemplate) {
1688
+ templatesOrExtensions.push({ url: matchedTemplate.url });
1689
+ if (matchedTemplate.customOptions) {
1690
+ matchedTemplate.customOptions.forEach((customOption) => {
1691
+ if (customOption.name && customOption.initial !== void 0) {
1692
+ options[customOption.name] = customOption.initial;
1693
+ }
1694
+ });
1695
+ }
1696
+ } else {
1697
+ throw new Error(
1698
+ `Invalid template slug: '${options.template}'. Please provide a valid template slug.`
1674
1699
  );
1675
- if (matchedTemplate) {
1676
- options.template = matchedTemplate.url;
1677
- if (matchedTemplate.customOptions) {
1678
- matchedTemplate.customOptions.forEach((customOption) => {
1679
- if (customOption.name && customOption.initial !== void 0) {
1680
- options[customOption.name] = customOption.initial;
1681
- }
1682
- });
1700
+ }
1701
+ } else if (options.template) {
1702
+ templatesOrExtensions.push({ url: options.template });
1703
+ }
1704
+ if (options.addons && Array.isArray(options.addons)) {
1705
+ const extensionsGroupedByCategory = await getExtensionsGroupedByCategory([
1706
+ (matchedTemplate == null ? void 0 : matchedTemplate.type) || "custom",
1707
+ "all"
1708
+ ]);
1709
+ const extensions = options.addons.map((addon) => {
1710
+ if (!isValidUrl(addon)) {
1711
+ for (const extensions2 of Object.values(extensionsGroupedByCategory)) {
1712
+ const matchedExtension = extensions2.find(
1713
+ (extension) => extension.slug === addon
1714
+ );
1715
+ if (matchedExtension) {
1716
+ return matchedExtension.url;
1717
+ }
1683
1718
  }
1684
- } else {
1685
1719
  throw new Error(
1686
- `Invalid template slug: '${options.template}'. Please provide a valid template slug.`
1720
+ `Invalid extension slug: '${addon}'. Please provide a valid extension slug.`
1687
1721
  );
1688
1722
  }
1689
- }
1690
- if (options.addons && Array.isArray(options.addons)) {
1691
- const extensionsGroupedByCategory2 = await getExtensionsGroupedByCategory([
1692
- (matchedTemplate == null ? void 0 : matchedTemplate.type) || "custom",
1693
- "all"
1694
- ]);
1695
- options.addons = options.addons.map((addon) => {
1696
- if (!isValidUrl(addon)) {
1697
- for (const extensions of Object.values(extensionsGroupedByCategory2)) {
1698
- const matchedExtension = extensions.find(
1699
- (extension) => extension.slug === addon
1700
- );
1701
- if (matchedExtension) {
1702
- return matchedExtension.url;
1703
- }
1704
- }
1705
- throw new Error(
1706
- `Invalid extension slug: '${addon}'. Please provide a valid extension slug.`
1707
- );
1708
- }
1709
- return addon;
1710
- });
1711
- }
1712
- if (options.verbose) {
1713
- console.log(JSON.stringify(options, null, 2));
1714
- }
1715
- return options;
1723
+ return addon;
1724
+ }).map((addon) => ({ url: addon }));
1725
+ templatesOrExtensions.push(...extensions);
1716
1726
  }
1727
+ if (options.extend && Array.isArray(options.extend)) {
1728
+ const additionalExtensions = options.extend.filter(Boolean).map((extension) => ({ url: extension }));
1729
+ templatesOrExtensions.push(...additionalExtensions);
1730
+ }
1731
+ options.templatesOrExtensions = templatesOrExtensions;
1732
+ if (options.verbose) {
1733
+ console.log(JSON.stringify(options, null, 2));
1734
+ }
1735
+ return options;
1736
+ };
1737
+ var processInteractiveOptions = async (options) => {
1738
+ const categories = await getTemplateCategories();
1739
+ const categoryDataPromises = categories.map(async (categorySlug) => {
1740
+ const categoryData = await getCategoryData(categorySlug);
1741
+ return {
1742
+ slug: categorySlug,
1743
+ name: (categoryData == null ? void 0 : categoryData.name) || categorySlug,
1744
+ description: (categoryData == null ? void 0 : categoryData.description) || ""
1745
+ };
1746
+ });
1747
+ const categoryDataList = await Promise.all(categoryDataPromises);
1717
1748
  const categoriesOptions = [
1718
- ...categories.map((category) => ({
1719
- title: category,
1720
- value: category
1749
+ ...categoryDataList.map((category) => ({
1750
+ title: category.name,
1751
+ value: category.slug,
1752
+ description: category.description
1721
1753
  })),
1722
1754
  {
1723
1755
  title: "None of the above",
@@ -1811,13 +1843,16 @@ var getCnaOptions = async (options) => {
1811
1843
  (existingTemplate == null ? void 0 : existingTemplate.type) || "custom",
1812
1844
  "all"
1813
1845
  ]);
1814
- for (const [category, extensions] of Object.entries(
1846
+ for (const [categorySlug, extensions] of Object.entries(
1815
1847
  extensionsGroupedByCategory
1816
1848
  )) {
1849
+ const categoryData = await getCategoryData(categorySlug);
1850
+ const categoryName = (categoryData == null ? void 0 : categoryData.name) || categorySlug;
1851
+ const categoryDescription = (categoryData == null ? void 0 : categoryData.description) || "";
1817
1852
  const { selected } = await (0, import_prompts.default)({
1818
1853
  type: "multiselect",
1819
1854
  name: "selected",
1820
- message: `Select extensions for ${category}`,
1855
+ message: `Select extensions for ${categoryName}${categoryDescription ? `: ${categoryDescription}` : ""}`,
1821
1856
  choices: extensions.map((extension) => {
1822
1857
  var _a;
1823
1858
  return {
@@ -1868,11 +1903,19 @@ var getCnaOptions = async (options) => {
1868
1903
  }
1869
1904
  return nextOptions;
1870
1905
  };
1906
+ var getCnaOptions = async (options) => {
1907
+ const shouldUseInteractiveMode = !import_ci_info.isCI && options.interactive;
1908
+ if (shouldUseInteractiveMode) {
1909
+ return processInteractiveOptions(options);
1910
+ } else {
1911
+ return processNonInteractiveOptions(options);
1912
+ }
1913
+ };
1871
1914
 
1872
1915
  // package.json
1873
1916
  var package_default = {
1874
1917
  name: "create-awesome-node-app",
1875
- version: "0.4.26",
1918
+ version: "0.4.27",
1876
1919
  type: "module",
1877
1920
  description: "Command line tool to create Node apps with a lot of different templates and extensions.",
1878
1921
  license: "MIT",
@@ -1937,11 +1980,87 @@ var package_default = {
1937
1980
  }
1938
1981
  };
1939
1982
 
1983
+ // src/list.ts
1984
+ var import_chalk = __toESM(require_source(), 1);
1985
+ var listTemplates = async () => {
1986
+ const categories = await getTemplateCategories();
1987
+ console.log(import_chalk.default.bold.blue("\nAvailable Templates:"));
1988
+ for (const categorySlug of categories) {
1989
+ const categoryData = await getCategoryData(categorySlug);
1990
+ const templates = await getTemplatesForCategory(categorySlug);
1991
+ const categoryName = (categoryData == null ? void 0 : categoryData.name) || categorySlug;
1992
+ console.log(import_chalk.default.bold.green(`
1993
+ ${categoryName}:`));
1994
+ if (categoryData == null ? void 0 : categoryData.description) {
1995
+ console.log(` ${categoryData.description}`);
1996
+ }
1997
+ templates.forEach((template) => {
1998
+ console.log(
1999
+ ` ${import_chalk.default.yellow(template.name)} (${import_chalk.default.cyan(template.slug)})`
2000
+ );
2001
+ console.log(` ${template.description}`);
2002
+ if (template.labels && template.labels.length > 0) {
2003
+ console.log(` Keywords: ${template.labels.join(", ")}`);
2004
+ }
2005
+ });
2006
+ }
2007
+ };
2008
+ var listAddons = async ({
2009
+ templateSlug,
2010
+ templateType
2011
+ }) => {
2012
+ if (templateSlug && !templateType) {
2013
+ templateType = await getTemplateTypeFromSlug(templateSlug);
2014
+ }
2015
+ const types = templateType ? [templateType, "all"] : ["all"];
2016
+ const extensionsGroupedByCategory = await getExtensionsGroupedByCategory(
2017
+ types
2018
+ );
2019
+ console.log(import_chalk.default.bold.blue("\nAvailable Addons:"));
2020
+ if (templateSlug) {
2021
+ console.log(
2022
+ import_chalk.default.bold.green(`
2023
+ Compatible with template: ${templateSlug}`)
2024
+ );
2025
+ }
2026
+ for (const [categorySlug, extensions] of Object.entries(
2027
+ extensionsGroupedByCategory
2028
+ )) {
2029
+ const categoryData = await getCategoryData(categorySlug);
2030
+ const categoryName = (categoryData == null ? void 0 : categoryData.name) || categorySlug;
2031
+ console.log(import_chalk.default.bold.green(`
2032
+ ${categoryName}:`));
2033
+ if (categoryData == null ? void 0 : categoryData.description) {
2034
+ console.log(` ${categoryData.description}`);
2035
+ }
2036
+ extensions.forEach((extension) => {
2037
+ console.log(
2038
+ ` ${import_chalk.default.yellow(extension.name)} (${import_chalk.default.cyan(extension.slug)})`
2039
+ );
2040
+ console.log(` ${extension.description}`);
2041
+ if (extension.labels && extension.labels.length > 0) {
2042
+ console.log(` Keywords: ${extension.labels.join(", ")}`);
2043
+ }
2044
+ });
2045
+ }
2046
+ };
2047
+ var getTemplateTypeFromSlug = async (templateSlug) => {
2048
+ const categories = await getTemplateCategories();
2049
+ for (const category of categories) {
2050
+ const templates = await getTemplatesForCategory(category);
2051
+ const template = templates.find((t) => t.slug === templateSlug);
2052
+ if (template) {
2053
+ return template.type;
2054
+ }
2055
+ }
2056
+ return void 0;
2057
+ };
2058
+
1940
2059
  // src/index.ts
1941
2060
  var program = new import_commander.Command();
1942
2061
  var main = async () => {
1943
2062
  let projectName = "my-project";
1944
- program.version(package_default.version).arguments("[project-directory]").usage(`${import_chalk.default.green("[project-directory]")} [options]`).option("-v, --verbose", "print additional logs").option("-i, --info", "print environment debug info").option(
2063
+ program.version(package_default.version).arguments("[project-directory]").usage(`${import_chalk2.default.green("[project-directory]")} [options]`).option("-v, --verbose", "print additional logs").option("-i, --info", "print environment debug info").option(
1945
2064
  "--no-install",
1946
2065
  "Generate package.json without installing dependencies"
1947
2066
  ).option(
@@ -1950,7 +2069,7 @@ var main = async () => {
1950
2069
  ).option(
1951
2070
  "--addons [extensions...]",
1952
2071
  "specify extensions to apply for the boilerplate generation"
1953
- ).option("--use-yarn", "use yarn instead of npm or pnpm").option("--use-pnpm", "use pnpm instead of yarn or npm").option("--interactive", "run in interactive mode to select options", false).action((providedProjectName) => {
2072
+ ).option("--use-yarn", "use yarn instead of npm or pnpm").option("--use-pnpm", "use pnpm instead of yarn or npm").option("--interactive", "run in interactive mode to select options", false).option("--list-templates", "list all available templates").option("--list-addons", "list all available addons").action((providedProjectName) => {
1954
2073
  projectName = providedProjectName || projectName;
1955
2074
  });
1956
2075
  program.parse(process.argv);
@@ -1960,7 +2079,7 @@ var main = async () => {
1960
2079
  if (latest && import_semver.default.lt(package_default.version, latest)) {
1961
2080
  console.log();
1962
2081
  console.error(
1963
- import_chalk.default.yellow(
2082
+ import_chalk2.default.yellow(
1964
2083
  `You are running \`create-awesome-node-app\` ${package_default.version}, which is behind the latest release (${latest}).
1965
2084
 
1966
2085
  We recommend always using the latest version of create-awesome-node-app if possible.`
@@ -1968,10 +2087,19 @@ We recommend always using the latest version of create-awesome-node-app if possi
1968
2087
  );
1969
2088
  return;
1970
2089
  }
1971
- const options = await getCnaOptions({ ...opts, projectName });
1972
- const { useYarn, usePnpm, ...restOptions } = options;
2090
+ if (opts.listTemplates) {
2091
+ await listTemplates();
2092
+ return;
2093
+ }
2094
+ if (opts.listAddons) {
2095
+ await listAddons({
2096
+ templateSlug: opts.template
2097
+ });
2098
+ return;
2099
+ }
2100
+ const { useYarn, usePnpm, ...restOpts } = opts;
1973
2101
  const packageManager = useYarn ? "yarn" : usePnpm ? "pnpm" : "npm";
1974
- const templatesOrExtensions = [restOptions.template].concat(Array.isArray(restOptions.addons) ? restOptions.addons : []).concat(Array.isArray(restOptions.extend) ? restOptions.extend : []).reduce((acc, templateOrExtension) => {
2102
+ const templatesOrExtensions = [restOpts.template].concat(Array.isArray(restOpts.extend) ? restOpts.extend : []).reduce((acc, templateOrExtension) => {
1975
2103
  if (!templateOrExtension) {
1976
2104
  return acc;
1977
2105
  }
@@ -1981,7 +2109,7 @@ We recommend always using the latest version of create-awesome-node-app if possi
1981
2109
  }, []);
1982
2110
  return (0, import_core.createNodeApp)(
1983
2111
  projectName,
1984
- { ...restOptions, packageManager, templatesOrExtensions, projectName },
2112
+ { ...restOpts, packageManager, templatesOrExtensions, projectName },
1985
2113
  getCnaOptions
1986
2114
  );
1987
2115
  };
package/dist/index.js CHANGED
@@ -1348,14 +1348,14 @@ var require_templates = __commonJS({
1348
1348
  }
1349
1349
  return results;
1350
1350
  }
1351
- function buildStyle(chalk2, styles) {
1351
+ function buildStyle(chalk3, styles) {
1352
1352
  const enabled = {};
1353
1353
  for (const layer of styles) {
1354
1354
  for (const style of layer.styles) {
1355
1355
  enabled[style[0]] = layer.inverse ? null : style.slice(1);
1356
1356
  }
1357
1357
  }
1358
- let current = chalk2;
1358
+ let current = chalk3;
1359
1359
  for (const [styleName, styles2] of Object.entries(enabled)) {
1360
1360
  if (!Array.isArray(styles2)) {
1361
1361
  continue;
@@ -1367,7 +1367,7 @@ var require_templates = __commonJS({
1367
1367
  }
1368
1368
  return current;
1369
1369
  }
1370
- module.exports = (chalk2, temporary) => {
1370
+ module.exports = (chalk3, temporary) => {
1371
1371
  const styles = [];
1372
1372
  const chunks = [];
1373
1373
  let chunk = [];
@@ -1377,13 +1377,13 @@ var require_templates = __commonJS({
1377
1377
  } else if (style) {
1378
1378
  const string = chunk.join("");
1379
1379
  chunk = [];
1380
- chunks.push(styles.length === 0 ? string : buildStyle(chalk2, styles)(string));
1380
+ chunks.push(styles.length === 0 ? string : buildStyle(chalk3, styles)(string));
1381
1381
  styles.push({ inverse, styles: parseStyle(style) });
1382
1382
  } else if (close) {
1383
1383
  if (styles.length === 0) {
1384
1384
  throw new Error("Found extraneous } in Chalk template literal");
1385
1385
  }
1386
- chunks.push(buildStyle(chalk2, styles)(chunk.join("")));
1386
+ chunks.push(buildStyle(chalk3, styles)(chunk.join("")));
1387
1387
  chunk = [];
1388
1388
  styles.pop();
1389
1389
  } else {
@@ -1431,16 +1431,16 @@ var require_source = __commonJS({
1431
1431
  }
1432
1432
  };
1433
1433
  var chalkFactory = (options) => {
1434
- const chalk3 = {};
1435
- applyOptions(chalk3, options);
1436
- chalk3.template = (...arguments_) => chalkTag(chalk3.template, ...arguments_);
1437
- Object.setPrototypeOf(chalk3, Chalk.prototype);
1438
- Object.setPrototypeOf(chalk3.template, chalk3);
1439
- chalk3.template.constructor = () => {
1434
+ const chalk4 = {};
1435
+ applyOptions(chalk4, options);
1436
+ chalk4.template = (...arguments_) => chalkTag(chalk4.template, ...arguments_);
1437
+ Object.setPrototypeOf(chalk4, Chalk.prototype);
1438
+ Object.setPrototypeOf(chalk4.template, chalk4);
1439
+ chalk4.template.constructor = () => {
1440
1440
  throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
1441
1441
  };
1442
- chalk3.template.Instance = ChalkClass;
1443
- return chalk3.template;
1442
+ chalk4.template.Instance = ChalkClass;
1443
+ return chalk4.template;
1444
1444
  };
1445
1445
  function Chalk(options) {
1446
1446
  return chalkFactory(options);
@@ -1551,7 +1551,7 @@ var require_source = __commonJS({
1551
1551
  return openAll + string + closeAll;
1552
1552
  };
1553
1553
  var template;
1554
- var chalkTag = (chalk3, ...strings) => {
1554
+ var chalkTag = (chalk4, ...strings) => {
1555
1555
  const [firstString] = strings;
1556
1556
  if (!isArray(firstString) || !isArray(firstString.raw)) {
1557
1557
  return strings.join(" ");
@@ -1567,19 +1567,19 @@ var require_source = __commonJS({
1567
1567
  if (template === void 0) {
1568
1568
  template = require_templates();
1569
1569
  }
1570
- return template(chalk3, parts.join(""));
1570
+ return template(chalk4, parts.join(""));
1571
1571
  };
1572
1572
  Object.defineProperties(Chalk.prototype, styles);
1573
- var chalk2 = Chalk();
1574
- chalk2.supportsColor = stdoutColor;
1575
- chalk2.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
1576
- chalk2.stderr.supportsColor = stderrColor;
1577
- module.exports = chalk2;
1573
+ var chalk3 = Chalk();
1574
+ chalk3.supportsColor = stdoutColor;
1575
+ chalk3.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
1576
+ chalk3.stderr.supportsColor = stderrColor;
1577
+ module.exports = chalk3;
1578
1578
  }
1579
1579
  });
1580
1580
 
1581
1581
  // src/index.ts
1582
- var import_chalk = __toESM(require_source(), 1);
1582
+ var import_chalk2 = __toESM(require_source(), 1);
1583
1583
  import { Command } from "commander";
1584
1584
  import semver from "semver";
1585
1585
  import {
@@ -1622,12 +1622,24 @@ var getTemplateCategories = async (cliArgs) => {
1622
1622
  return [cliArgs.category];
1623
1623
  }
1624
1624
  const templateData = await getTemplateData();
1625
+ if (templateData.categories && templateData.categories.length > 0) {
1626
+ return templateData.categories.map((category) => category.slug);
1627
+ }
1625
1628
  const categories = /* @__PURE__ */ new Set();
1626
1629
  templateData.templates.forEach((template) => {
1627
1630
  categories.add(template.category);
1628
1631
  });
1629
1632
  return Array.from(categories);
1630
1633
  };
1634
+ var getCategoryData = async (categorySlug) => {
1635
+ const templateData = await getTemplateData();
1636
+ if (templateData.categories && templateData.categories.length > 0) {
1637
+ return templateData.categories.find(
1638
+ (category) => category.slug === categorySlug
1639
+ );
1640
+ }
1641
+ return void 0;
1642
+ };
1631
1643
  var getTemplatesForCategory = async (category, cliArgs) => {
1632
1644
  const selectedCategory = (cliArgs == null ? void 0 : cliArgs.category) || category;
1633
1645
  if (!selectedCategory) {
@@ -1671,63 +1683,83 @@ var isValidUrl = (url) => {
1671
1683
  return false;
1672
1684
  }
1673
1685
  };
1674
- var getCnaOptions = async (options) => {
1686
+ var processNonInteractiveOptions = async (options) => {
1675
1687
  const categories = await getTemplateCategories();
1676
- if (isCI || !options.interactive) {
1677
- let matchedTemplate;
1678
- if (options.template && !isValidUrl(options.template)) {
1679
- const allTemplates = (await Promise.all(
1680
- categories.map((category) => getTemplatesForCategory(category))
1681
- )).flat();
1682
- matchedTemplate = allTemplates.find(
1683
- (template) => template.slug === options.template
1688
+ let matchedTemplate;
1689
+ const templatesOrExtensions = [];
1690
+ if (options.template && !isValidUrl(options.template)) {
1691
+ const allTemplates = (await Promise.all(
1692
+ categories.map((category) => getTemplatesForCategory(category))
1693
+ )).flat();
1694
+ matchedTemplate = allTemplates.find(
1695
+ (template) => template.slug === options.template
1696
+ );
1697
+ if (matchedTemplate) {
1698
+ templatesOrExtensions.push({ url: matchedTemplate.url });
1699
+ if (matchedTemplate.customOptions) {
1700
+ matchedTemplate.customOptions.forEach((customOption) => {
1701
+ if (customOption.name && customOption.initial !== void 0) {
1702
+ options[customOption.name] = customOption.initial;
1703
+ }
1704
+ });
1705
+ }
1706
+ } else {
1707
+ throw new Error(
1708
+ `Invalid template slug: '${options.template}'. Please provide a valid template slug.`
1684
1709
  );
1685
- if (matchedTemplate) {
1686
- options.template = matchedTemplate.url;
1687
- if (matchedTemplate.customOptions) {
1688
- matchedTemplate.customOptions.forEach((customOption) => {
1689
- if (customOption.name && customOption.initial !== void 0) {
1690
- options[customOption.name] = customOption.initial;
1691
- }
1692
- });
1710
+ }
1711
+ } else if (options.template) {
1712
+ templatesOrExtensions.push({ url: options.template });
1713
+ }
1714
+ if (options.addons && Array.isArray(options.addons)) {
1715
+ const extensionsGroupedByCategory = await getExtensionsGroupedByCategory([
1716
+ (matchedTemplate == null ? void 0 : matchedTemplate.type) || "custom",
1717
+ "all"
1718
+ ]);
1719
+ const extensions = options.addons.map((addon) => {
1720
+ if (!isValidUrl(addon)) {
1721
+ for (const extensions2 of Object.values(extensionsGroupedByCategory)) {
1722
+ const matchedExtension = extensions2.find(
1723
+ (extension) => extension.slug === addon
1724
+ );
1725
+ if (matchedExtension) {
1726
+ return matchedExtension.url;
1727
+ }
1693
1728
  }
1694
- } else {
1695
1729
  throw new Error(
1696
- `Invalid template slug: '${options.template}'. Please provide a valid template slug.`
1730
+ `Invalid extension slug: '${addon}'. Please provide a valid extension slug.`
1697
1731
  );
1698
1732
  }
1699
- }
1700
- if (options.addons && Array.isArray(options.addons)) {
1701
- const extensionsGroupedByCategory2 = await getExtensionsGroupedByCategory([
1702
- (matchedTemplate == null ? void 0 : matchedTemplate.type) || "custom",
1703
- "all"
1704
- ]);
1705
- options.addons = options.addons.map((addon) => {
1706
- if (!isValidUrl(addon)) {
1707
- for (const extensions of Object.values(extensionsGroupedByCategory2)) {
1708
- const matchedExtension = extensions.find(
1709
- (extension) => extension.slug === addon
1710
- );
1711
- if (matchedExtension) {
1712
- return matchedExtension.url;
1713
- }
1714
- }
1715
- throw new Error(
1716
- `Invalid extension slug: '${addon}'. Please provide a valid extension slug.`
1717
- );
1718
- }
1719
- return addon;
1720
- });
1721
- }
1722
- if (options.verbose) {
1723
- console.log(JSON.stringify(options, null, 2));
1724
- }
1725
- return options;
1733
+ return addon;
1734
+ }).map((addon) => ({ url: addon }));
1735
+ templatesOrExtensions.push(...extensions);
1726
1736
  }
1737
+ if (options.extend && Array.isArray(options.extend)) {
1738
+ const additionalExtensions = options.extend.filter(Boolean).map((extension) => ({ url: extension }));
1739
+ templatesOrExtensions.push(...additionalExtensions);
1740
+ }
1741
+ options.templatesOrExtensions = templatesOrExtensions;
1742
+ if (options.verbose) {
1743
+ console.log(JSON.stringify(options, null, 2));
1744
+ }
1745
+ return options;
1746
+ };
1747
+ var processInteractiveOptions = async (options) => {
1748
+ const categories = await getTemplateCategories();
1749
+ const categoryDataPromises = categories.map(async (categorySlug) => {
1750
+ const categoryData = await getCategoryData(categorySlug);
1751
+ return {
1752
+ slug: categorySlug,
1753
+ name: (categoryData == null ? void 0 : categoryData.name) || categorySlug,
1754
+ description: (categoryData == null ? void 0 : categoryData.description) || ""
1755
+ };
1756
+ });
1757
+ const categoryDataList = await Promise.all(categoryDataPromises);
1727
1758
  const categoriesOptions = [
1728
- ...categories.map((category) => ({
1729
- title: category,
1730
- value: category
1759
+ ...categoryDataList.map((category) => ({
1760
+ title: category.name,
1761
+ value: category.slug,
1762
+ description: category.description
1731
1763
  })),
1732
1764
  {
1733
1765
  title: "None of the above",
@@ -1821,13 +1853,16 @@ var getCnaOptions = async (options) => {
1821
1853
  (existingTemplate == null ? void 0 : existingTemplate.type) || "custom",
1822
1854
  "all"
1823
1855
  ]);
1824
- for (const [category, extensions] of Object.entries(
1856
+ for (const [categorySlug, extensions] of Object.entries(
1825
1857
  extensionsGroupedByCategory
1826
1858
  )) {
1859
+ const categoryData = await getCategoryData(categorySlug);
1860
+ const categoryName = (categoryData == null ? void 0 : categoryData.name) || categorySlug;
1861
+ const categoryDescription = (categoryData == null ? void 0 : categoryData.description) || "";
1827
1862
  const { selected } = await prompts({
1828
1863
  type: "multiselect",
1829
1864
  name: "selected",
1830
- message: `Select extensions for ${category}`,
1865
+ message: `Select extensions for ${categoryName}${categoryDescription ? `: ${categoryDescription}` : ""}`,
1831
1866
  choices: extensions.map((extension) => {
1832
1867
  var _a;
1833
1868
  return {
@@ -1878,11 +1913,19 @@ var getCnaOptions = async (options) => {
1878
1913
  }
1879
1914
  return nextOptions;
1880
1915
  };
1916
+ var getCnaOptions = async (options) => {
1917
+ const shouldUseInteractiveMode = !isCI && options.interactive;
1918
+ if (shouldUseInteractiveMode) {
1919
+ return processInteractiveOptions(options);
1920
+ } else {
1921
+ return processNonInteractiveOptions(options);
1922
+ }
1923
+ };
1881
1924
 
1882
1925
  // package.json
1883
1926
  var package_default = {
1884
1927
  name: "create-awesome-node-app",
1885
- version: "0.4.26",
1928
+ version: "0.4.27",
1886
1929
  type: "module",
1887
1930
  description: "Command line tool to create Node apps with a lot of different templates and extensions.",
1888
1931
  license: "MIT",
@@ -1947,11 +1990,87 @@ var package_default = {
1947
1990
  }
1948
1991
  };
1949
1992
 
1993
+ // src/list.ts
1994
+ var import_chalk = __toESM(require_source(), 1);
1995
+ var listTemplates = async () => {
1996
+ const categories = await getTemplateCategories();
1997
+ console.log(import_chalk.default.bold.blue("\nAvailable Templates:"));
1998
+ for (const categorySlug of categories) {
1999
+ const categoryData = await getCategoryData(categorySlug);
2000
+ const templates = await getTemplatesForCategory(categorySlug);
2001
+ const categoryName = (categoryData == null ? void 0 : categoryData.name) || categorySlug;
2002
+ console.log(import_chalk.default.bold.green(`
2003
+ ${categoryName}:`));
2004
+ if (categoryData == null ? void 0 : categoryData.description) {
2005
+ console.log(` ${categoryData.description}`);
2006
+ }
2007
+ templates.forEach((template) => {
2008
+ console.log(
2009
+ ` ${import_chalk.default.yellow(template.name)} (${import_chalk.default.cyan(template.slug)})`
2010
+ );
2011
+ console.log(` ${template.description}`);
2012
+ if (template.labels && template.labels.length > 0) {
2013
+ console.log(` Keywords: ${template.labels.join(", ")}`);
2014
+ }
2015
+ });
2016
+ }
2017
+ };
2018
+ var listAddons = async ({
2019
+ templateSlug,
2020
+ templateType
2021
+ }) => {
2022
+ if (templateSlug && !templateType) {
2023
+ templateType = await getTemplateTypeFromSlug(templateSlug);
2024
+ }
2025
+ const types = templateType ? [templateType, "all"] : ["all"];
2026
+ const extensionsGroupedByCategory = await getExtensionsGroupedByCategory(
2027
+ types
2028
+ );
2029
+ console.log(import_chalk.default.bold.blue("\nAvailable Addons:"));
2030
+ if (templateSlug) {
2031
+ console.log(
2032
+ import_chalk.default.bold.green(`
2033
+ Compatible with template: ${templateSlug}`)
2034
+ );
2035
+ }
2036
+ for (const [categorySlug, extensions] of Object.entries(
2037
+ extensionsGroupedByCategory
2038
+ )) {
2039
+ const categoryData = await getCategoryData(categorySlug);
2040
+ const categoryName = (categoryData == null ? void 0 : categoryData.name) || categorySlug;
2041
+ console.log(import_chalk.default.bold.green(`
2042
+ ${categoryName}:`));
2043
+ if (categoryData == null ? void 0 : categoryData.description) {
2044
+ console.log(` ${categoryData.description}`);
2045
+ }
2046
+ extensions.forEach((extension) => {
2047
+ console.log(
2048
+ ` ${import_chalk.default.yellow(extension.name)} (${import_chalk.default.cyan(extension.slug)})`
2049
+ );
2050
+ console.log(` ${extension.description}`);
2051
+ if (extension.labels && extension.labels.length > 0) {
2052
+ console.log(` Keywords: ${extension.labels.join(", ")}`);
2053
+ }
2054
+ });
2055
+ }
2056
+ };
2057
+ var getTemplateTypeFromSlug = async (templateSlug) => {
2058
+ const categories = await getTemplateCategories();
2059
+ for (const category of categories) {
2060
+ const templates = await getTemplatesForCategory(category);
2061
+ const template = templates.find((t) => t.slug === templateSlug);
2062
+ if (template) {
2063
+ return template.type;
2064
+ }
2065
+ }
2066
+ return void 0;
2067
+ };
2068
+
1950
2069
  // src/index.ts
1951
2070
  var program = new Command();
1952
2071
  var main = async () => {
1953
2072
  let projectName = "my-project";
1954
- program.version(package_default.version).arguments("[project-directory]").usage(`${import_chalk.default.green("[project-directory]")} [options]`).option("-v, --verbose", "print additional logs").option("-i, --info", "print environment debug info").option(
2073
+ program.version(package_default.version).arguments("[project-directory]").usage(`${import_chalk2.default.green("[project-directory]")} [options]`).option("-v, --verbose", "print additional logs").option("-i, --info", "print environment debug info").option(
1955
2074
  "--no-install",
1956
2075
  "Generate package.json without installing dependencies"
1957
2076
  ).option(
@@ -1960,7 +2079,7 @@ var main = async () => {
1960
2079
  ).option(
1961
2080
  "--addons [extensions...]",
1962
2081
  "specify extensions to apply for the boilerplate generation"
1963
- ).option("--use-yarn", "use yarn instead of npm or pnpm").option("--use-pnpm", "use pnpm instead of yarn or npm").option("--interactive", "run in interactive mode to select options", false).action((providedProjectName) => {
2082
+ ).option("--use-yarn", "use yarn instead of npm or pnpm").option("--use-pnpm", "use pnpm instead of yarn or npm").option("--interactive", "run in interactive mode to select options", false).option("--list-templates", "list all available templates").option("--list-addons", "list all available addons").action((providedProjectName) => {
1964
2083
  projectName = providedProjectName || projectName;
1965
2084
  });
1966
2085
  program.parse(process.argv);
@@ -1970,7 +2089,7 @@ var main = async () => {
1970
2089
  if (latest && semver.lt(package_default.version, latest)) {
1971
2090
  console.log();
1972
2091
  console.error(
1973
- import_chalk.default.yellow(
2092
+ import_chalk2.default.yellow(
1974
2093
  `You are running \`create-awesome-node-app\` ${package_default.version}, which is behind the latest release (${latest}).
1975
2094
 
1976
2095
  We recommend always using the latest version of create-awesome-node-app if possible.`
@@ -1978,10 +2097,19 @@ We recommend always using the latest version of create-awesome-node-app if possi
1978
2097
  );
1979
2098
  return;
1980
2099
  }
1981
- const options = await getCnaOptions({ ...opts, projectName });
1982
- const { useYarn, usePnpm, ...restOptions } = options;
2100
+ if (opts.listTemplates) {
2101
+ await listTemplates();
2102
+ return;
2103
+ }
2104
+ if (opts.listAddons) {
2105
+ await listAddons({
2106
+ templateSlug: opts.template
2107
+ });
2108
+ return;
2109
+ }
2110
+ const { useYarn, usePnpm, ...restOpts } = opts;
1983
2111
  const packageManager = useYarn ? "yarn" : usePnpm ? "pnpm" : "npm";
1984
- const templatesOrExtensions = [restOptions.template].concat(Array.isArray(restOptions.addons) ? restOptions.addons : []).concat(Array.isArray(restOptions.extend) ? restOptions.extend : []).reduce((acc, templateOrExtension) => {
2112
+ const templatesOrExtensions = [restOpts.template].concat(Array.isArray(restOpts.extend) ? restOpts.extend : []).reduce((acc, templateOrExtension) => {
1985
2113
  if (!templateOrExtension) {
1986
2114
  return acc;
1987
2115
  }
@@ -1991,7 +2119,7 @@ We recommend always using the latest version of create-awesome-node-app if possi
1991
2119
  }, []);
1992
2120
  return createNodeApp(
1993
2121
  projectName,
1994
- { ...restOptions, packageManager, templatesOrExtensions, projectName },
2122
+ { ...restOpts, packageManager, templatesOrExtensions, projectName },
1995
2123
  getCnaOptions
1996
2124
  );
1997
2125
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-awesome-node-app",
3
- "version": "0.4.26",
3
+ "version": "0.4.27",
4
4
  "type": "module",
5
5
  "description": "Command line tool to create Node apps with a lot of different templates and extensions.",
6
6
  "license": "MIT",