Bladeren bron

chore(cta): add linting and formatting, closes #1520 (#1596)

Lucas Fernandes Nogueira 4 jaren geleden
bovenliggende
commit
07f5cd21be

+ 25 - 3
.github/workflows/js-lint.yml

@@ -9,6 +9,8 @@ on:
     paths:
       - '.github/workflows/js-lint.yml'
       - 'tooling/cli.js/**'
+      - 'tooling/api/**'
+      - 'tooling/create-tauri-app/**'
 
 jobs:
   eslint-check:
@@ -18,12 +20,32 @@ jobs:
       - uses: actions/setup-node@v1
         with:
           node-version: '12'
-      - name: install deps via yarn
+      - name: install cli.js deps via yarn
         working-directory: ./tooling/cli.js/
         run: yarn
-      - name: run eslint
+      - name: run cli.js lint
         working-directory: ./tooling/cli.js/
         run: yarn lint
-      - name: run prettier
+      - name: run cli.js format
         working-directory: ./tooling/cli.js/
         run: yarn format:check
+
+      - name: install api deps via yarn
+        working-directory: ./tooling/api/
+        run: yarn
+      - name: run api lint
+        working-directory: ./tooling/api/
+        run: yarn lint
+      - name: run api format
+        working-directory: ./tooling/api/
+        run: yarn format:check
+
+      - name: install create-tauri-app deps via yarn
+        working-directory: ./tooling/create-tauri-app/
+        run: yarn
+      - name: run create-tauri-app lint
+        working-directory: ./tooling/create-tauri-app/
+        run: yarn lint
+      - name: run create-tauri-app format
+        working-directory: ./tooling/create-tauri-app/
+        run: yarn format:check

+ 5 - 0
.husky/pre-commit

@@ -9,6 +9,11 @@
 cd tooling/api
 yarn format
 yarn lint-fix
+
 cd ../cli.js
 yarn format
 yarn lint-fix
+
+cd ../create-tauri-app
+yarn format
+yarn lint-fix

+ 55 - 0
tooling/create-tauri-app/.eslintrc.js

@@ -0,0 +1,55 @@
+module.exports = {
+  root: true,
+
+  env: {
+    node: true,
+    jest: true
+  },
+
+  parser: '@typescript-eslint/parser',
+
+  extends: [
+    'standard-with-typescript',
+    'plugin:@typescript-eslint/recommended-requiring-type-checking',
+    'plugin:lodash-template/recommended',
+    // TODO: make this work with typescript
+    // 'plugin:node/recommended'
+    'prettier'
+  ],
+
+  plugins: ['@typescript-eslint', 'node', 'security'],
+
+  parserOptions: {
+    tsconfigRootDir: __dirname,
+    project: './tsconfig.json'
+  },
+
+  globals: {
+    __statics: true,
+    process: true
+  },
+
+  // add your custom rules here
+  rules: {
+    // allow console.log during development only
+    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+    // allow debugger during development only
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+    'no-process-exit': 'off',
+    'security/detect-non-literal-fs-filename': 'warn',
+    'security/detect-unsafe-regex': 'error',
+    'security/detect-buffer-noassert': 'error',
+    'security/detect-child-process': 'warn',
+    'security/detect-disable-mustache-escape': 'error',
+    'security/detect-eval-with-expression': 'error',
+    'security/detect-no-csrf-before-method-override': 'error',
+    'security/detect-non-literal-regexp': 'error',
+    'security/detect-non-literal-require': 'warn',
+    'security/detect-object-injection': 'warn',
+    'security/detect-possible-timing-attacks': 'error',
+    'security/detect-pseudoRandomBytes': 'error',
+    'space-before-function-paren': 'off',
+    '@typescript-eslint/default-param-last': 'off',
+    '@typescript-eslint/strict-boolean-expressions': 0
+  }
+}

+ 5 - 0
tooling/create-tauri-app/.prettierrc.js

@@ -0,0 +1,5 @@
+module.exports = {
+  singleQuote: true,
+  semi: false,
+  trailingComma: 'none'
+}

+ 93 - 93
tooling/create-tauri-app/bin/create-tauri-app.js

@@ -3,9 +3,9 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-const parseArgs = require("minimist");
-const inquirer = require("inquirer");
-const { resolve, join } = require("path");
+const parseArgs = require('minimist')
+const inquirer = require('inquirer')
+const { resolve, join } = require('path')
 const {
   recipeShortNames,
   recipeDescriptiveNames,
@@ -14,8 +14,8 @@ const {
   install,
   checkPackageManager,
   shell,
-  addTauriScript,
-} = require("../dist/");
+  addTauriScript
+} = require('../dist/')
 
 /**
  * @type {object}
@@ -35,41 +35,41 @@ const {
 const createTauriApp = async (cliArgs) => {
   const argv = parseArgs(cliArgs, {
     alias: {
-      h: "help",
-      v: "version",
-      f: "force",
-      l: "log",
-      m: "manager",
-      d: "directory",
-      b: "binary",
-      t: "tauri-path",
-      A: "app-name",
-      W: "window-title",
-      D: "dist-dir",
-      P: "dev-path",
-      r: "recipe",
+      h: 'help',
+      v: 'version',
+      f: 'force',
+      l: 'log',
+      m: 'manager',
+      d: 'directory',
+      b: 'binary',
+      t: 'tauri-path',
+      A: 'app-name',
+      W: 'window-title',
+      D: 'dist-dir',
+      P: 'dev-path',
+      r: 'recipe'
     },
-    boolean: ["h", "l", "ci"],
-  });
+    boolean: ['h', 'l', 'ci']
+  })
 
   if (argv.help) {
-    printUsage();
-    return 0;
+    printUsage()
+    return 0
   }
 
   if (argv.v) {
-    console.log(require("../package.json").version);
-    return false; // do this for node consumers and tests
+    console.log(require('../package.json').version)
+    return false // do this for node consumers and tests
   }
 
   if (argv.ci) {
-    return runInit(argv);
+    return runInit(argv)
   } else {
     return getOptionsInteractive(argv).then((responses) =>
       runInit(argv, responses)
-    );
+    )
   }
-};
+}
 
 function printUsage() {
   console.log(`
@@ -91,146 +91,146 @@ function printUsage() {
     --dist-dir, -D       Web assets location, relative to <project-dir>/src-tauri
     --dev-path, -P       Url of your dev server
     --recipe, -r         Add UI framework recipe. None by default.
-                         Supported recipes: [${recipeShortNames.join("|")}]
-    `);
+                         Supported recipes: [${recipeShortNames.join('|')}]
+    `)
 }
 
 const getOptionsInteractive = (argv) => {
-  let defaultAppName = argv.A || "tauri-app";
+  let defaultAppName = argv.A || 'tauri-app'
 
   return inquirer
     .prompt([
       {
-        type: "input",
-        name: "appName",
-        message: "What is your app name?",
+        type: 'input',
+        name: 'appName',
+        message: 'What is your app name?',
         default: defaultAppName,
-        when: !argv.A,
+        when: !argv.A
       },
       {
-        type: "input",
-        name: "tauri.window.title",
-        message: "What should the window title be?",
-        default: "Tauri App",
-        when: () => !argv.W,
+        type: 'input',
+        name: 'tauri.window.title',
+        message: 'What should the window title be?',
+        default: 'Tauri App',
+        when: () => !argv.W
       },
       {
-        type: "list",
-        name: "recipeName",
-        message: "Would you like to add a UI recipe?",
+        type: 'list',
+        name: 'recipeName',
+        message: 'Would you like to add a UI recipe?',
         choices: recipeDescriptiveNames,
-        default: "No recipe",
-        when: () => !argv.r,
-      },
+        default: 'No recipe',
+        when: () => !argv.r
+      }
     ])
     .catch((error) => {
       if (error.isTtyError) {
         // Prompt couldn't be rendered in the current environment
         console.log(
-          "It appears your terminal does not support interactive prompts. Using default values."
-        );
-        runInit();
+          'It appears your terminal does not support interactive prompts. Using default values.'
+        )
+        runInit()
       } else {
         // Something else went wrong
-        console.error("An unknown error occurred:", error);
+        console.error('An unknown error occurred:', error)
       }
-    });
-};
+    })
+}
 
 async function runInit(argv, config = {}) {
   const {
     appName,
     recipeName,
     tauri: {
-      window: { title },
-    },
-  } = config;
+      window: { title }
+    }
+  } = config
   // this little fun snippet pulled from vite determines the package manager the script was run from
-  const packageManager = /yarn/.test(process.env.npm_execpath) ? "yarn" : "npm";
+  const packageManager = /yarn/.test(process.env.npm_execpath) ? 'yarn' : 'npm'
 
-  let recipe;
+  let recipe
 
   if (recipeName !== undefined) {
-    recipe = recipeByDescriptiveName(recipeName);
+    recipe = recipeByDescriptiveName(recipeName)
   } else if (argv.r) {
-    recipe = recipeByShortName(argv.r);
+    recipe = recipeByShortName(argv.r)
   }
 
   let buildConfig = {
     distDir: argv.D,
-    devPath: argv.P,
-  };
+    devPath: argv.P
+  }
 
   if (recipe !== undefined) {
-    buildConfig = recipe.configUpdate({ buildConfig, packageManager });
+    buildConfig = recipe.configUpdate({ buildConfig, packageManager })
   }
 
-  const directory = argv.d || process.cwd();
+  const directory = argv.d || process.cwd()
   const cfg = {
     ...buildConfig,
     appName: appName || argv.A,
-    windowTitle: title || argv.w,
-  };
+    windowTitle: title || argv.w
+  }
 
   // note that our app directory is reliant on the appName and
   // generally there are issues if the path has spaces (see Windows)
   // future TODO prevent app names with spaces or escape here?
-  const appDirectory = join(directory, cfg.appName);
+  const appDirectory = join(directory, cfg.appName)
 
   // this throws an error if we can't run the package manager they requested
-  await checkPackageManager({ cwd: directory, packageManager });
+  await checkPackageManager({ cwd: directory, packageManager })
 
   if (recipe.preInit) {
-    console.log("===== running initial command(s) =====");
-    await recipe.preInit({ cwd: directory, cfg, packageManager });
+    console.log('===== running initial command(s) =====')
+    await recipe.preInit({ cwd: directory, cfg, packageManager })
   }
 
   const initArgs = [
-    ["--app-name", cfg.appName],
-    ["--window-title", cfg.windowTitle],
-    ["--dist-dir", cfg.distDir],
-    ["--dev-path", cfg.devPath],
+    ['--app-name', cfg.appName],
+    ['--window-title', cfg.windowTitle],
+    ['--dist-dir', cfg.distDir],
+    ['--dev-path', cfg.devPath]
   ].reduce((final, argSet) => {
     if (argSet[1]) {
-      return final.concat(argSet);
+      return final.concat(argSet)
     } else {
-      return final;
+      return final
     }
-  }, []);
+  }, [])
 
   // Vue CLI plugin automatically runs these
-  if (recipe.shortName !== "vuecli") {
-    console.log("===== installing any additional needed deps =====");
+  if (recipe.shortName !== 'vuecli') {
+    console.log('===== installing any additional needed deps =====')
     await install({
       appDir: appDirectory,
       dependencies: recipe.extraNpmDependencies,
-      devDependencies: ["@tauri-apps/cli", ...recipe.extraNpmDevDependencies],
-      packageManager,
-    });
+      devDependencies: ['@tauri-apps/cli', ...recipe.extraNpmDevDependencies],
+      packageManager
+    })
 
-    console.log("===== running tauri init =====");
-    addTauriScript(appDirectory);
+    console.log('===== running tauri init =====')
+    addTauriScript(appDirectory)
 
-    const binary = !argv.b ? packageManager : resolve(appDirectory, argv.b);
+    const binary = !argv.b ? packageManager : resolve(appDirectory, argv.b)
     const runTauriArgs =
-      packageManager === "npm" && !argv.b
-        ? ["run", "tauri", "--", "init"]
-        : ["tauri", "init"];
+      packageManager === 'npm' && !argv.b
+        ? ['run', 'tauri', '--', 'init']
+        : ['tauri', 'init']
     await shell(binary, [...runTauriArgs, ...initArgs], {
-      cwd: appDirectory,
-    });
+      cwd: appDirectory
+    })
   }
 
   if (recipe.postInit) {
-    console.log("===== running final command(s) =====");
+    console.log('===== running final command(s) =====')
     await recipe.postInit({
       cwd: appDirectory,
       cfg,
-      packageManager,
-    });
+      packageManager
+    })
   }
 }
 
 createTauriApp(process.argv.slice(2)).catch((err) => {
-  console.error(err);
-});
+  console.error(err)
+})

+ 22 - 7
tooling/create-tauri-app/package.json

@@ -24,7 +24,12 @@
   "scripts": {
     "create-tauri-app": "create-tauri-app",
     "build": "rollup --config",
-    "prepublishOnly": "yarn build"
+    "prepublishOnly": "yarn build",
+    "lint": "eslint --ext ts \"./src/**/*.ts\"",
+    "lint-fix": "eslint --fix --ext ts \"./src/**/*.ts\"",
+    "lint:lockfile": "lockfile-lint --path yarn.lock --type yarn --validate-https --allowed-hosts npm yarn",
+    "format": "prettier --write --end-of-line=auto \"./**/*.{js,jsx,ts,tsx,html,css,json}\" --ignore-path .gitignore",
+    "format:check": "prettier --check --end-of-line=auto \"./**/*.{js,jsx,ts,tsx,html,css,json}\" --ignore-path .gitignore"
   },
   "dependencies": {
     "execa": "^5.0.0",
@@ -33,15 +38,25 @@
     "scaffe": "1.0.0"
   },
   "devDependencies": {
-    "@rollup/plugin-commonjs": "^18.0.0",
-    "@rollup/plugin-node-resolve": "^11.2.1",
-    "@rollup/plugin-typescript": "^8.2.1",
+    "@rollup/plugin-commonjs": "18.0.0",
+    "@rollup/plugin-node-resolve": "11.2.1",
+    "@rollup/plugin-typescript": "8.2.1",
+    "@typescript-eslint/eslint-plugin": "4.22.0",
+    "@typescript-eslint/parser": "4.22.0",
     "@types/cross-spawn": "6.0.2",
     "@types/inquirer": "7.3.1",
     "@types/semver": "7.3.4",
-    "prettier": "^2.2.1",
-    "rollup": "^2.45.1",
-    "tslib": "^2.2.0",
+    "eslint": "7.24.0",
+    "eslint-config-prettier": "8.2.0",
+    "eslint-config-standard-with-typescript": "20.0.0",
+    "eslint-plugin-import": "2.22.1",
+    "eslint-plugin-lodash-template": "0.19.0",
+    "eslint-plugin-node": "11.1.0",
+    "eslint-plugin-promise": "5.1.0",
+    "eslint-plugin-security": "1.4.0",
+    "prettier": "2.2.1",
+    "rollup": "2.45.1",
+    "tslib": "2.2.0",
     "typescript": "4.2.4"
   }
 }

+ 16 - 16
tooling/create-tauri-app/rollup.config.js

@@ -1,27 +1,27 @@
-import typescript from "@rollup/plugin-typescript";
-import commonjs from "@rollup/plugin-commonjs";
-import pkg from "./package.json";
+import typescript from '@rollup/plugin-typescript'
+import commonjs from '@rollup/plugin-commonjs'
+import pkg from './package.json'
 
 export default {
   treeshake: true,
   perf: true,
-  input: "src/index.ts",
+  input: 'src/index.ts',
   output: {
-    dir: "dist",
-    format: "cjs",
-    entryFileNames: "[name].js",
-    exports: "named",
+    dir: 'dist',
+    format: 'cjs',
+    entryFileNames: '[name].js',
+    exports: 'named'
   },
-  plugins: [typescript(), commonjs({ extensions: [".js"] })],
+  plugins: [typescript(), commonjs({ extensions: ['.js'] })],
   external: [
-    "fs",
-    "path",
+    'fs',
+    'path',
     ...Object.keys(pkg.dependencies || {}),
-    ...Object.keys(pkg.peerDependencies || {}),
+    ...Object.keys(pkg.peerDependencies || {})
   ],
   watch: {
     chokidar: true,
-    include: "src/**",
-    exclude: "node_modules/**",
-  },
-};
+    include: 'src/**',
+    exclude: 'node_modules/**'
+  }
+}

+ 40 - 40
tooling/create-tauri-app/src/dependency-manager.ts

@@ -2,46 +2,46 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import { ManagementType, Result } from "./types/deps";
-import { shell } from "./shell";
+import { ManagementType, Result } from './types/deps'
+import { shell } from './shell'
 
-export type PackageManager = "npm" | "yarn";
+export type PackageManager = 'npm' | 'yarn'
 
 export async function install({
   appDir,
   dependencies,
   devDependencies,
-  packageManager,
+  packageManager
 }: {
-  appDir: string;
-  dependencies: string[];
-  devDependencies: string[];
-  packageManager: PackageManager;
+  appDir: string
+  dependencies: string[]
+  devDependencies: string[]
+  packageManager: PackageManager
 }): Promise<Result> {
-  const result: Result = new Map<ManagementType, string[]>();
-  await installNpmDevPackage(devDependencies, packageManager, appDir);
-  result.set(ManagementType.Install, devDependencies);
+  const result: Result = new Map<ManagementType, string[]>()
+  await installNpmDevPackage(devDependencies, packageManager, appDir)
+  result.set(ManagementType.Install, devDependencies)
 
-  await installNpmPackage(dependencies, packageManager, appDir);
-  result.set(ManagementType.Install, dependencies);
+  await installNpmPackage(dependencies, packageManager, appDir)
+  result.set(ManagementType.Install, dependencies)
 
-  return result;
+  return result
 }
 
 export async function checkPackageManager({
   cwd,
-  packageManager,
+  packageManager
 }: {
-  cwd: string;
-  packageManager: PackageManager;
+  cwd: string
+  packageManager: PackageManager
 }): Promise<boolean> {
   try {
-    await shell(packageManager, ["--version"], { stdio: "pipe", cwd });
-    return true;
+    await shell(packageManager, ['--version'], { stdio: 'pipe', cwd })
+    return true
   } catch (error) {
     throw new Error(
       `Must have ${packageManager} installed to manage dependencies. Is either in your PATH? We tried running in ${cwd}`
-    );
+    )
   }
 }
 
@@ -50,16 +50,16 @@ async function installNpmPackage(
   packageManager: PackageManager,
   appDir: string
 ): Promise<void> {
-  if (packageNames.length === 0) return;
-  console.log(`Installing ${packageNames.join(", ")}...`);
-  if (packageManager === "yarn") {
-    await shell("yarn", ["add", packageNames.join(" ")], {
-      cwd: appDir,
-    });
+  if (packageNames.length === 0) return
+  console.log(`Installing ${packageNames.join(', ')}...`)
+  if (packageManager === 'yarn') {
+    await shell('yarn', ['add', packageNames.join(' ')], {
+      cwd: appDir
+    })
   } else {
-    await shell("npm", ["install", packageNames.join(" ")], {
-      cwd: appDir,
-    });
+    await shell('npm', ['install', packageNames.join(' ')], {
+      cwd: appDir
+    })
   }
 }
 
@@ -68,23 +68,23 @@ async function installNpmDevPackage(
   packageManager: PackageManager,
   appDir: string
 ): Promise<void> {
-  if (packageNames.length === 0) return;
-  console.log(`Installing ${packageNames.join(", ")}...`);
-  if (packageManager === "yarn") {
+  if (packageNames.length === 0) return
+  console.log(`Installing ${packageNames.join(', ')}...`)
+  if (packageManager === 'yarn') {
     await shell(
-      "yarn",
-      ["add", "--dev", "--ignore-scripts", packageNames.join(" ")],
+      'yarn',
+      ['add', '--dev', '--ignore-scripts', packageNames.join(' ')],
       {
-        cwd: appDir,
+        cwd: appDir
       }
-    );
+    )
   } else {
     await shell(
-      "npm",
-      ["install", "--save-dev", "--ignore-scripts", packageNames.join(" ")],
+      'npm',
+      ['install', '--save-dev', '--ignore-scripts', packageNames.join(' ')],
       {
-        cwd: appDir,
+        cwd: appDir
       }
-    );
+    )
   }
 }

+ 12 - 12
tooling/create-tauri-app/src/helpers/add-tauri-script.ts

@@ -2,25 +2,25 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import { readFileSync, writeFileSync } from "fs";
-import { join } from "path";
+import { readFileSync, writeFileSync } from 'fs'
+import { join } from 'path'
 
-export async function addTauriScript(appDirectory: string) {
-  const pkgPath = join(appDirectory, "package.json");
-  const pkgString = readFileSync(pkgPath, "utf8");
+export function addTauriScript(appDirectory: string): void {
+  const pkgPath = join(appDirectory, 'package.json')
+  const pkgString = readFileSync(pkgPath, 'utf8')
   const pkg = JSON.parse(pkgString) as {
     scripts: {
-      tauri: string;
-    };
-  };
+      tauri: string
+    }
+  }
 
   const outputPkg = {
     ...pkg,
     scripts: {
       ...pkg.scripts,
-      tauri: "tauri",
-    },
-  };
+      tauri: 'tauri'
+    }
+  }
 
-  writeFileSync(pkgPath, JSON.stringify(outputPkg, undefined, 2));
+  writeFileSync(pkgPath, JSON.stringify(outputPkg, undefined, 2))
 }

+ 36 - 36
tooling/create-tauri-app/src/index.ts

@@ -2,62 +2,62 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import { TauriBuildConfig } from "./types/config";
-import { reactjs, reactts } from "./recipes/react";
-import { vuecli } from "./recipes/vue-cli";
-import { vanillajs } from "./recipes/vanilla";
-import { vite } from "./recipes/vite";
+import { TauriBuildConfig } from './types/config'
+import { reactjs, reactts } from './recipes/react'
+import { vuecli } from './recipes/vue-cli'
+import { vanillajs } from './recipes/vanilla'
+import { vite } from './recipes/vite'
+import { PackageManager } from './dependency-manager'
 
-export { shell } from "./shell";
-export { install, checkPackageManager } from "./dependency-manager";
-export { addTauriScript } from "./helpers/add-tauri-script";
-import { PackageManager } from "./dependency-manager";
+export { shell } from './shell'
+export { install, checkPackageManager } from './dependency-manager'
+export { addTauriScript } from './helpers/add-tauri-script'
 
 export interface Recipe {
-  descriptiveName: string;
-  shortName: string;
+  descriptiveName: string
+  shortName: string
   configUpdate?: ({
     cfg,
-    packageManager,
+    packageManager
   }: {
-    cfg: TauriBuildConfig;
-    packageManager: PackageManager;
-  }) => TauriBuildConfig;
-  extraNpmDependencies: string[];
-  extraNpmDevDependencies: string[];
+    cfg: TauriBuildConfig
+    packageManager: PackageManager
+  }) => TauriBuildConfig
+  extraNpmDependencies: string[]
+  extraNpmDevDependencies: string[]
   preInit?: ({
     cwd,
     cfg,
-    packageManager,
+    packageManager
   }: {
-    cwd: string;
-    cfg: TauriBuildConfig;
-    packageManager: PackageManager;
-  }) => Promise<void>;
+    cwd: string
+    cfg: TauriBuildConfig
+    packageManager: PackageManager
+  }) => Promise<void>
   postInit?: ({
     cwd,
     cfg,
-    packageManager,
+    packageManager
   }: {
-    cwd: string;
-    cfg: TauriBuildConfig;
-    packageManager: PackageManager;
-  }) => Promise<void>;
+    cwd: string
+    cfg: TauriBuildConfig
+    packageManager: PackageManager
+  }) => Promise<void>
 }
 
-export const allRecipes: Recipe[] = [vanillajs, reactjs, reactts, vite, vuecli];
+export const allRecipes: Recipe[] = [vanillajs, reactjs, reactts, vite, vuecli]
 
 export const recipeNames: Array<[string, string]> = allRecipes.map((r) => [
   r.shortName,
-  r.descriptiveName,
-]);
+  r.descriptiveName
+])
 
-export const recipeByShortName = (name: string) =>
-  allRecipes.find((r) => r.shortName === name);
+export const recipeByShortName = (name: string): Recipe | undefined =>
+  allRecipes.find((r) => r.shortName === name)
 
-export const recipeByDescriptiveName = (name: string) =>
-  allRecipes.find((r) => r.descriptiveName === name);
+export const recipeByDescriptiveName = (name: string): Recipe | undefined =>
+  allRecipes.find((r) => r.descriptiveName === name)
 
-export const recipeShortNames = allRecipes.map((r) => r.shortName);
+export const recipeShortNames = allRecipes.map((r) => r.shortName)
 
-export const recipeDescriptiveNames = allRecipes.map((r) => r.descriptiveName);
+export const recipeDescriptiveNames = allRecipes.map((r) => r.descriptiveName)

+ 53 - 50
tooling/create-tauri-app/src/recipes/react.ts

@@ -2,104 +2,107 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import { Recipe } from "..";
-import { join } from "path";
-//@ts-ignore
-import scaffe from "scaffe";
-import { shell } from "../shell";
+import { Recipe } from '..'
+import { join } from 'path'
+// @ts-expect-error
+import scaffe from 'scaffe'
+import { shell } from '../shell'
 
 const afterCra = async (
   cwd: string,
   appName: string,
   typescript: boolean = false
-) => {
+): Promise<void> => {
   const templateDir = join(
     __dirname,
-    `../src/templates/react/${typescript ? "react-ts" : "react"}`
-  );
+    `../src/templates/react/${typescript ? 'react-ts' : 'react'}`
+  )
 
   try {
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
     await scaffe.generate(templateDir, join(cwd, appName), {
-      overwrite: true,
-    });
+      overwrite: true
+    })
   } catch (err) {
-    console.log(err);
+    console.log(err)
   }
-};
+}
 
 const reactjs: Recipe = {
-  descriptiveName: "React.js",
-  shortName: "reactjs",
+  descriptiveName: 'React.js',
+  shortName: 'reactjs',
   configUpdate: ({ cfg, packageManager }) => ({
     ...cfg,
     distDir: `../build`,
-    devPath: "http://localhost:3000",
-    beforeDevCommand: `${packageManager === "yarn" ? "yarn" : "npm run"} start`,
+    devPath: 'http://localhost:3000',
+    beforeDevCommand: `${packageManager === 'yarn' ? 'yarn' : 'npm run'} start`,
     beforeBuildCommand: `${
-      packageManager === "yarn" ? "yarn" : "npm run"
-    } build`,
+      packageManager === 'yarn' ? 'yarn' : 'npm run'
+    } build`
   }),
   extraNpmDevDependencies: [],
   extraNpmDependencies: [],
   preInit: async ({ cwd, cfg, packageManager }) => {
     // CRA creates the folder for you
-    if (packageManager === "yarn") {
-      await shell("yarn", ["create", "react-app", `${cfg.appName}`], {
-        cwd,
-      });
+    if (packageManager === 'yarn') {
+      await shell('yarn', ['create', 'react-app', `${cfg.appName}`], {
+        cwd
+      })
     } else {
-      await shell("npx", ["create-react-app", `${cfg.appName}`, "--use-npm"], {
-        cwd,
-      });
+      await shell('npx', ['create-react-app', `${cfg.appName}`, '--use-npm'], {
+        cwd
+      })
     }
-    await afterCra(cwd, cfg.appName);
+    await afterCra(cwd, cfg.appName)
   },
   postInit: async ({ packageManager }) => {
     console.log(`
     Your installation completed.
-    To start, run ${packageManager === "yarn" ? "yarn" : "npm run"} tauri dev
-  `);
-  },
-};
+    To start, run ${packageManager === 'yarn' ? 'yarn' : 'npm run'} tauri dev
+  `)
+    return await Promise.resolve()
+  }
+}
 
 const reactts: Recipe = {
   ...reactjs,
-  descriptiveName: "React with Typescript",
-  shortName: "reactts",
+  descriptiveName: 'React with Typescript',
+  shortName: 'reactts',
   extraNpmDependencies: [],
   preInit: async ({ cwd, cfg, packageManager }) => {
     // CRA creates the folder for you
-    if (packageManager === "yarn") {
+    if (packageManager === 'yarn') {
       await shell(
-        "yarn",
-        ["create", "react-app", "--template", "typescript", `${cfg.appName}`],
+        'yarn',
+        ['create', 'react-app', '--template', 'typescript', `${cfg.appName}`],
         {
-          cwd,
+          cwd
         }
-      );
+      )
     } else {
       await shell(
-        "npx",
+        'npx',
         [
-          "create-react-app",
+          'create-react-app',
           `${cfg.appName}`,
-          "--use-npm",
-          "--template",
-          "typescript",
+          '--use-npm',
+          '--template',
+          'typescript'
         ],
         {
-          cwd,
+          cwd
         }
-      );
+      )
     }
-    await afterCra(cwd, cfg.appName, true);
+    await afterCra(cwd, cfg.appName, true)
   },
   postInit: async ({ packageManager }) => {
     console.log(`
     Your installation completed.
-    To start, run ${packageManager === "yarn" ? "yarn" : "npm run"} tauri dev
-  `);
-  },
-};
+    To start, run ${packageManager === 'yarn' ? 'yarn' : 'npm run'} tauri dev
+  `)
+    return await Promise.resolve()
+  }
+}
 
-export { reactjs, reactts };
+export { reactjs, reactts }

+ 25 - 23
tooling/create-tauri-app/src/recipes/vanilla.ts

@@ -2,49 +2,50 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import { Recipe } from "..";
-import { join } from "path";
-//@ts-ignore
-import scaffe from "scaffe";
+import { Recipe } from '..'
+import { join } from 'path'
+// @ts-expect-error
+import scaffe from 'scaffe'
 
 export const vanillajs: Recipe = {
-  descriptiveName: "Vanilla.js",
-  shortName: "vanillajs",
+  descriptiveName: 'Vanilla.js',
+  shortName: 'vanillajs',
   configUpdate: ({ cfg, packageManager }) => ({
     ...cfg,
     distDir: `../dist`,
     devPath: `../dist`,
-    beforeDevCommand: `${packageManager === "yarn" ? "yarn" : "npm run"} start`,
+    beforeDevCommand: `${packageManager === 'yarn' ? 'yarn' : 'npm run'} start`,
     beforeBuildCommand: `${
-      packageManager === "yarn" ? "yarn" : "npm run"
-    } build`,
+      packageManager === 'yarn' ? 'yarn' : 'npm run'
+    } build`
   }),
   extraNpmDevDependencies: [],
   extraNpmDependencies: [],
   preInit: async ({ cwd, cfg }) => {
-    const { appName } = cfg;
-    const templateDir = join(__dirname, "../src/templates/vanilla");
+    const { appName } = cfg
+    const templateDir = join(__dirname, '../src/templates/vanilla')
     const variables = {
-      name: appName,
-    };
+      name: appName
+    }
 
     try {
+      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
       await scaffe.generate(templateDir, join(cwd, appName), {
         overwrite: true,
-        variables,
-      });
+        variables
+      })
     } catch (err) {
-      console.log(err);
+      console.log(err)
     }
   },
   postInit: async ({ cfg, packageManager }) => {
     const setApp =
-      packageManager === "npm"
+      packageManager === 'npm'
         ? `
 set tauri script once
   $ npm set-script tauri tauri
     `
-        : "";
+        : ''
 
     console.log(`
 change directory:
@@ -54,9 +55,10 @@ install dependencies:
   $ ${packageManager} install
 
 run the app:
-  $ ${packageManager === "yarn" ? "yarn" : "npm run"} tauri ${
-      packageManager === "npm" ? "-- " : ""
+  $ ${packageManager === 'yarn' ? 'yarn' : 'npm run'} tauri ${
+      packageManager === 'npm' ? '-- ' : ''
     }dev
-            `);
-  },
-};
+            `)
+    return await Promise.resolve()
+  }
+}

+ 57 - 50
tooling/create-tauri-app/src/recipes/vite.ts

@@ -2,98 +2,105 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import { Recipe } from "..";
-import { join } from "path";
-import { readdirSync } from "fs";
-//@ts-ignore
-import scaffe from "scaffe";
-import { shell } from "../shell";
-import inquirer from "inquirer";
+import { Recipe } from '..'
+import { join } from 'path'
+import { readdirSync } from 'fs'
+// @ts-expect-error
+import scaffe from 'scaffe'
+import { shell } from '../shell'
+import inquirer from 'inquirer'
 
-const afterViteCA = async (cwd: string, appName: string, template: string) => {
-  const templateDir = join(__dirname, `../src/templates/vite/${template}`);
+const afterViteCA = async (
+  cwd: string,
+  appName: string,
+  template: string
+): Promise<void> => {
+  const templateDir = join(__dirname, `../src/templates/vite/${template}`)
 
   try {
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
     await scaffe.generate(templateDir, join(cwd, appName), {
-      overwrite: true,
-    });
+      overwrite: true
+    })
   } catch (err) {
-    console.log(err);
+    console.log(err)
   }
-};
+}
 
 const vite: Recipe = {
-  descriptiveName: "Vite backed recipe",
-  shortName: "vite",
+  descriptiveName: 'Vite backed recipe',
+  shortName: 'vite',
   configUpdate: ({ cfg, packageManager }) => ({
     ...cfg,
     distDir: `../dist`,
-    devPath: "http://localhost:3000",
-    beforeDevCommand: `${packageManager === "yarn" ? "yarn" : "npm run"} start`,
+    devPath: 'http://localhost:3000',
+    beforeDevCommand: `${packageManager === 'yarn' ? 'yarn' : 'npm run'} start`,
     beforeBuildCommand: `${
-      packageManager === "yarn" ? "yarn" : "npm run"
-    } build`,
+      packageManager === 'yarn' ? 'yarn' : 'npm run'
+    } build`
   }),
   extraNpmDevDependencies: [],
   extraNpmDependencies: [],
   preInit: async ({ cwd, cfg, packageManager }) => {
     try {
-      const { template } = await inquirer.prompt([
+      const { template } = (await inquirer.prompt([
         {
-          type: "list",
-          name: "template",
-          message: "Which vite template would you like to use?",
-          choices: readdirSync(join(__dirname, "../src/templates/vite")),
-          default: "vue",
-        },
-      ]);
+          type: 'list',
+          name: 'template',
+          message: 'Which vite template would you like to use?',
+          choices: readdirSync(join(__dirname, '../src/templates/vite')),
+          default: 'vue'
+        }
+      ])) as { template: string }
 
       // Vite creates the folder for you
-      if (packageManager === "yarn") {
+      if (packageManager === 'yarn') {
         await shell(
-          "yarn",
+          'yarn',
           [
-            "create",
-            "@vitejs/app",
+            'create',
+            '@vitejs/app',
             `${cfg.appName}`,
-            "--template",
-            `${template}`,
+            '--template',
+            `${template}`
           ],
           {
-            cwd,
+            cwd
           }
-        );
+        )
       } else {
         await shell(
-          "npx",
-          ["@vitejs/create-app", `${cfg.appName}`, "--template", `${template}`],
+          'npx',
+          ['@vitejs/create-app', `${cfg.appName}`, '--template', `${template}`],
           {
-            cwd,
+            cwd
           }
-        );
+        )
       }
 
-      await afterViteCA(cwd, cfg.appName, template);
+      await afterViteCA(cwd, cfg.appName, template)
     } catch (error) {
-      if (error.isTtyError) {
+      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+      if (error?.isTtyError) {
         // Prompt couldn't be rendered in the current environment
         console.log(
-          "It appears your terminal does not support interactive prompts. Using default values."
-        );
+          'It appears your terminal does not support interactive prompts. Using default values.'
+        )
       } else {
         // Something else went wrong
-        console.error("An unknown error occurred:", error);
+        console.error('An unknown error occurred:', error)
       }
     }
   },
   postInit: async ({ packageManager }) => {
     console.log(`
     Your installation completed.
-    To start, run ${packageManager === "yarn" ? "yarn" : "npm run"} tauri ${
-      packageManager === "npm" ? "--" : ""
+    To start, run ${packageManager === 'yarn' ? 'yarn' : 'npm run'} tauri ${
+      packageManager === 'npm' ? '--' : ''
     } dev
-  `);
-  },
-};
+  `)
+    return await Promise.resolve()
+  }
+}
 
-export { vite };
+export { vite }

+ 21 - 20
tooling/create-tauri-app/src/recipes/vue-cli.ts

@@ -2,43 +2,44 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import { Recipe } from "..";
-import { join } from "path";
-import { shell } from "../shell";
+import { Recipe } from '..'
+import { join } from 'path'
+import { shell } from '../shell'
 
 const completeLogMsg = `
   Your installation completed.
   To start, run yarn tauri:serve
-`;
+`
 
 const vuecli: Recipe = {
-  descriptiveName: "Vue CLI",
-  shortName: "vuecli",
+  descriptiveName: 'Vue CLI',
+  shortName: 'vuecli',
   extraNpmDevDependencies: [],
   extraNpmDependencies: [],
   configUpdate: ({ cfg }) => cfg,
   preInit: async ({ cwd, cfg }) => {
     // Vue CLI creates the folder for you
-    await shell("npx", ["@vue/cli", "create", `${cfg.appName}`], { cwd });
+    await shell('npx', ['@vue/cli', 'create', `${cfg.appName}`], { cwd })
     await shell(
-      "npx",
+      'npx',
       [
-        "@vue/cli",
-        "add",
-        "tauri",
-        "--appName",
+        '@vue/cli',
+        'add',
+        'tauri',
+        '--appName',
         `${cfg.appName}`,
-        "--windowTitle",
-        `${cfg.windowTitle}`,
+        '--windowTitle',
+        `${cfg.windowTitle}`
       ],
       {
-        cwd: join(cwd, cfg.appName),
+        cwd: join(cwd, cfg.appName)
       }
-    );
+    )
   },
   postInit: async () => {
-    console.log(completeLogMsg);
-  },
-};
+    console.log(completeLogMsg)
+    return await Promise.resolve()
+  }
+}
 
-export { vuecli };
+export { vuecli }

+ 14 - 14
tooling/create-tauri-app/src/shell.ts

@@ -2,35 +2,35 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-import execa from "execa";
+import execa from 'execa'
 
 export const shell = async (
   command: string,
   args?: string[],
   options?: execa.Options,
   log: boolean = false
-) => {
+): Promise<execa.ExecaReturnValue> => {
   try {
     if (options && options.shell === true) {
-      const stringCommand = [command, ...(!args ? [] : args)].join(" ");
-      if (log) console.log(`[running]: ${stringCommand}`);
+      const stringCommand = [command, ...(!args ? [] : args)].join(' ')
+      if (log) console.log(`[running]: ${stringCommand}`)
       return await execa(stringCommand, {
-        stdio: "inherit",
+        stdio: 'inherit',
         cwd: process.cwd(),
         env: process.env,
-        ...options,
-      });
+        ...options
+      })
     } else {
-      if (log) console.log(`[running]: ${command}`);
+      if (log) console.log(`[running]: ${command}`)
       return await execa(command, args, {
-        stdio: "inherit",
+        stdio: 'inherit',
         cwd: process.cwd(),
         env: process.env,
-        ...options,
-      });
+        ...options
+      })
     }
   } catch (error) {
-    console.error("Error with command: %s", command);
-    throw new Error(error);
+    console.error('Error with command: %s', command)
+    throw new Error(error)
   }
-};
+}

+ 7 - 7
tooling/create-tauri-app/src/templates/react/react-ts/src/App.tsx

@@ -1,8 +1,8 @@
-import React from "react";
-import logo from "./logo.svg";
-import tauriCircles from "./tauri.svg";
-import tauriWord from "./wordmark.svg";
-import "./App.css";
+import React from 'react'
+import logo from './logo.svg'
+import tauriCircles from './tauri.svg'
+import tauriWord from './wordmark.svg'
+import './App.css'
 
 function App() {
   return (
@@ -34,7 +34,7 @@ function App() {
         </p>
       </header>
     </div>
-  );
+  )
 }
 
-export default App;
+export default App

+ 7 - 7
tooling/create-tauri-app/src/templates/react/react/src/App.js

@@ -1,8 +1,8 @@
-import React from "react";
-import logo from "./logo.svg";
-import tauriCircles from "./tauri.svg";
-import tauriWord from "./wordmark.svg";
-import "./App.css";
+import React from 'react'
+import logo from './logo.svg'
+import tauriCircles from './tauri.svg'
+import tauriWord from './wordmark.svg'
+import './App.css'
 
 function App() {
   return (
@@ -34,7 +34,7 @@ function App() {
         </p>
       </header>
     </div>
-  );
+  )
 }
 
-export default App;
+export default App

+ 7 - 7
tooling/create-tauri-app/src/types/config.ts

@@ -3,24 +3,24 @@
 // SPDX-License-Identifier: MIT
 
 export interface TauriBuildConfig {
-  appName: string;
-  windowTitle: string;
+  appName: string
+  windowTitle: string
   /**
    * the path to the app's dist dir
    * this path must contain your index.html file
    */
-  distDir: string;
+  distDir: string
   /**
    * the app's dev server URL, or the path to the directory containing an index.html to open
    */
-  devPath: string;
+  devPath: string
   /**
    * a shell command to run before `tauri dev` kicks in
    */
-  beforeDevCommand?: string;
+  beforeDevCommand?: string
   /**
    * a shell command to run before `tauri build` kicks in
    */
-  beforeBuildCommand?: string;
-  withGlobalTauri?: boolean;
+  beforeBuildCommand?: string
+  withGlobalTauri?: boolean
 }

+ 2 - 2
tooling/create-tauri-app/src/types/deps.ts

@@ -5,7 +5,7 @@
 export enum ManagementType {
   Install,
   InstallDev,
-  Update,
+  Update
 }
 
-export type Result = Map<ManagementType, string[]>;
+export type Result = Map<ManagementType, string[]>