Преглед изворни кода

feat(cli.rs): infer devPath/distDir/appName from package.json (#1930)

Lucas Fernandes Nogueira пре 4 година
родитељ
комит
21a971c3b7

+ 6 - 0
.changes/cli-init-infer-prompts.md

@@ -0,0 +1,6 @@
+---
+"cli.rs": patch
+---
+
+Infer `app name` and `window title` from `package.json > productName` or `package.json > name`.
+Infer `distDir` and `devPath` by reading the package.json and trying to determine the UI framework (Vue.js, Angular, React, Svelte and some UI frameworks).

+ 111 - 0
tooling/cli.rs/src/helpers/framework.rs

@@ -0,0 +1,111 @@
+// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use std::fmt;
+
+#[derive(Debug, Clone)]
+pub enum Framework {
+  Svelte,
+  Angular,
+  React,
+  Nextjs,
+
+  Gatsby,
+  Nuxt,
+  Quasar,
+  VueCli,
+  Vue,
+}
+
+impl Framework {
+  pub fn dev_path(&self) -> String {
+    match self {
+      Self::Svelte => "http://localhost:5000",
+      Self::Angular => "http://localhost:4200",
+      Self::React => "http://localhost:3000",
+      Self::Nextjs => "http://localhost:3000",
+      Self::Gatsby => "http://localhost:8000",
+      Self::Nuxt => "http://localhost:3000",
+      Self::Quasar => "http://localhost:8080",
+      Self::VueCli => "http://localhost:8080",
+      Self::Vue => "http://localhost:8080",
+    }
+    .into()
+  }
+
+  pub fn dist_dir(&self) -> String {
+    match self {
+      Self::Svelte => "../public",
+      Self::Angular => "../dist",
+      Self::React => "../build",
+      Self::Nextjs => "../out",
+      Self::Gatsby => "../public",
+      Self::Nuxt => "../dist",
+      Self::Quasar => "../dist/spa",
+      Self::VueCli => "../dist",
+      Self::Vue => "../dist",
+    }
+    .into()
+  }
+}
+
+impl fmt::Display for Framework {
+  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    match self {
+      Self::Svelte => write!(f, "Svelte"),
+      Self::Angular => write!(f, "Angular"),
+      Self::React => write!(f, "React"),
+      Self::Nextjs => write!(f, "React (Next.js)"),
+      Self::Gatsby => write!(f, "React (Gatsby)"),
+      Self::Nuxt => write!(f, "Vue.js (Nuxt)"),
+      Self::Quasar => write!(f, "Vue.js (Quasar)"),
+      Self::VueCli => write!(f, "Vue.js (Vue CLI)"),
+      Self::Vue => write!(f, "Vue.js"),
+    }
+  }
+}
+
+#[derive(Debug, Clone)]
+pub enum Bundler {
+  Webpack,
+  Rollup,
+}
+
+impl fmt::Display for Bundler {
+  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    match self {
+      Self::Webpack => write!(f, "Webpack"),
+      Self::Rollup => write!(f, "Rollup"),
+    }
+  }
+}
+
+pub fn infer_from_package_json(package_json: &str) -> (Option<Framework>, Option<Bundler>) {
+  let framework_map = [
+    ("svelte", Framework::Svelte, None),
+    ("@angular", Framework::Angular, Some(Bundler::Webpack)),
+    (r#""next""#, Framework::Nextjs, Some(Bundler::Webpack)),
+    ("gatsby", Framework::Gatsby, Some(Bundler::Webpack)),
+    ("react", Framework::React, None),
+    ("nuxt", Framework::Nuxt, Some(Bundler::Webpack)),
+    ("quasar", Framework::Quasar, Some(Bundler::Webpack)),
+    ("@vue/cli", Framework::VueCli, Some(Bundler::Webpack)),
+    ("vue", Framework::Vue, None),
+  ];
+  let bundler_map = [("webpack", Bundler::Webpack), ("rollup", Bundler::Rollup)];
+
+  let (framework, framework_bundler) = framework_map
+    .iter()
+    .find(|(keyword, _, _)| package_json.contains(keyword))
+    .map(|(_, framework, bundler)| (Some(framework.clone()), bundler.clone()))
+    .unwrap_or((None, None));
+
+  let bundler = bundler_map
+    .iter()
+    .find(|(keyword, _)| package_json.contains(keyword))
+    .map(|(_, bundler)| bundler.clone())
+    .or(framework_bundler);
+
+  (framework, bundler)
+}

+ 1 - 0
tooling/cli.rs/src/helpers/logger.rs

@@ -29,6 +29,7 @@ impl<'a> Logger<'a> {
     );
   }
 
+  #[allow(dead_code)]
   pub fn error(&self, message: impl AsRef<str>) {
     println!(
       "{} {}",

+ 1 - 0
tooling/cli.rs/src/helpers/mod.rs

@@ -4,6 +4,7 @@
 
 pub mod app_paths;
 pub mod config;
+pub mod framework;
 mod logger;
 pub mod manifest;
 pub mod updater_signature;

+ 8 - 29
tooling/cli.rs/src/info.rs

@@ -5,6 +5,7 @@
 use crate::helpers::{
   app_paths::{app_dir, tauri_dir},
   config::get as get_config,
+  framework::infer_from_package_json as infer_framework,
 };
 use serde::Deserialize;
 
@@ -552,38 +553,16 @@ impl Info {
           .display();
       }
       if let Ok(package_json) = read_to_string(app_dir.join("package.json")) {
-        let framework_map = [
-          ("svelte", "Svelte", None),
-          ("@angular", "Angular", Some("Webpack")),
-          (r#""next""#, "React (Next.js)", Some("Webpack")),
-          ("gatsby", "React (Gatsby)", Some("Webpack")),
-          ("react", "React", None),
-          ("nuxt", "Vue.js (Nuxt)", Some("Webpack")),
-          ("quasar", "Vue.js (Quasar)", Some("Webpack")),
-          ("@vue/cli", "Vue.js (Vue CLI)", Some("Webpack")),
-          ("vue", "Vue.js", None),
-        ];
-        let bundler_map = [("webpack", "Webpack"), ("rollup", "Rollup")];
-
-        let (framework, framework_bundler) = framework_map
-          .iter()
-          .find(|(keyword, _, _)| package_json.contains(keyword))
-          .map(|(_, framework, bundler)| {
-            (Some(framework.to_string()), bundler.map(|b| b.to_string()))
-          })
-          .unwrap_or((None, None));
-
-        let bundler = bundler_map
-          .iter()
-          .find(|(keyword, _)| package_json.contains(keyword))
-          .map(|(_, bundler)| bundler.to_string())
-          .or(framework_bundler);
-
+        let (framework, bundler) = infer_framework(&package_json);
         if let Some(framework) = framework {
-          InfoBlock::new("  framework").value(framework).display();
+          InfoBlock::new("  framework")
+            .value(framework.to_string())
+            .display();
         }
         if let Some(bundler) = bundler {
-          InfoBlock::new("  bundler").value(bundler).display();
+          InfoBlock::new("  bundler")
+            .value(bundler.to_string())
+            .display();
         }
       } else {
         println!("package.json not found");

+ 2 - 1
tooling/cli.rs/src/init.rs

@@ -4,6 +4,7 @@
 
 use std::{
   collections::BTreeMap,
+  env::current_dir,
   fs::{create_dir_all, remove_dir_all, File},
   io::Write,
   path::{Path, PathBuf},
@@ -38,7 +39,7 @@ impl Default for Init {
   fn default() -> Self {
     Self {
       force: false,
-      directory: std::env::current_dir().expect("failed to read cwd"),
+      directory: current_dir().expect("failed to read cwd"),
       tauri_path: None,
       app_name: None,
       window_title: None,

+ 50 - 11
tooling/cli.rs/src/main.rs

@@ -5,6 +5,7 @@
 pub use anyhow::Result;
 use clap::{crate_version, load_yaml, App, AppSettings, ArgMatches};
 use dialoguer::Input;
+use serde::Deserialize;
 
 mod build;
 mod dev;
@@ -20,17 +21,34 @@ mod console;
 #[allow(dead_code)]
 mod dialoguer;
 
-pub use helpers::Logger;
+use helpers::framework::{infer_from_package_json as infer_framework, Framework};
+
+use std::{env::current_dir, fs::read_to_string, path::PathBuf};
+
+#[derive(Deserialize)]
+struct PackageJson {
+  name: Option<String>,
+  product_name: Option<String>,
+}
+
+#[derive(Default)]
+struct InitDefaults {
+  app_name: Option<String>,
+  framework: Option<Framework>,
+}
 
 macro_rules! value_or_prompt {
-  ($init_runner: ident, $setter_fn: ident, $value: ident, $ci: ident, $prompt_message: expr) => {{
+  ($init_runner: ident, $setter_fn: ident, $value: ident, $ci: ident, $prompt_message: expr, $prompt_default: expr) => {{
     let mut init_runner = $init_runner;
     if let Some(value) = $value {
       init_runner = init_runner.$setter_fn(value);
     } else if !$ci {
-      let input = Input::<String>::new()
-        .with_prompt($prompt_message)
-        .interact_text()?;
+      let mut builder = Input::<String>::new();
+      builder.with_prompt($prompt_message);
+      if let Some(default) = $prompt_default {
+        builder.default(default);
+      }
+      let input = builder.interact_text()?;
       init_runner = init_runner.$setter_fn(input);
     }
     init_runner
@@ -51,39 +69,60 @@ fn init_command(matches: &ArgMatches) -> Result<()> {
   if force {
     init_runner = init_runner.force();
   }
-  if let Some(directory) = directory {
+  let base_directory = if let Some(directory) = directory {
     init_runner = init_runner.directory(directory);
-  }
+    PathBuf::from(directory)
+  } else {
+    current_dir().expect("failed to read cwd")
+  };
   if let Some(tauri_path) = tauri_path {
     init_runner = init_runner.tauri_path(tauri_path);
   }
+
+  let package_json_path = base_directory.join("package.json");
+  let init_defaults = if package_json_path.exists() {
+    let package_json_text = read_to_string(package_json_path)?;
+    let package_json: PackageJson = serde_json::from_str(&package_json_text)?;
+    let (framework, _) = infer_framework(&package_json_text);
+    InitDefaults {
+      app_name: package_json.product_name.or(package_json.name),
+      framework,
+    }
+  } else {
+    Default::default()
+  };
+
   init_runner = value_or_prompt!(
     init_runner,
     app_name,
     app_name,
     ci,
-    "What is your app name?"
+    "What is your app name?",
+    init_defaults.app_name.clone()
   );
   init_runner = value_or_prompt!(
     init_runner,
     window_title,
     window_title,
     ci,
-    "What should the window title be?"
+    "What should the window title be?",
+    init_defaults.app_name.clone()
   );
   init_runner = value_or_prompt!(
     init_runner,
     dist_dir,
     dist_dir,
     ci,
-    r#"Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri" folder that will be created?"#
+    r#"Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri" folder that will be created?"#,
+    init_defaults.framework.as_ref().map(|f| f.dist_dir())
   );
   init_runner = value_or_prompt!(
     init_runner,
     dev_path,
     dev_path,
     ci,
-    "What is the url of your dev server?"
+    "What is the url of your dev server?",
+    init_defaults.framework.map(|f| f.dev_path())
   );
 
   init_runner.run()