Skip to content

Commit

Permalink
feat: add optional automatic dico client install
Browse files Browse the repository at this point in the history
  • Loading branch information
lihbr committed Jun 16, 2021
1 parent 8978e82 commit 889853c
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 10 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"cac": "^6.7.3",
"chalk": "^4.1.1",
"consola": "^2.15.3",
"cross-spawn": "7.0.3",
"detect-indent": "^6.1.0",
"execa": "^5.1.1",
"exit": "^0.1.2",
Expand All @@ -56,6 +57,7 @@
"devDependencies": {
"@commitlint/cli": "12.1.4",
"@commitlint/config-conventional": "12.1.4",
"@types/cross-spawn": "6.0.2",
"@types/exit": "0.1.31",
"@types/inquirer": "7.3.1",
"@types/listr": "0.14.3",
Expand Down
11 changes: 7 additions & 4 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import latestVersion from "latest-version";
import semver from "semver";

import * as commands from "./commands";
import { NAME, PACKAGE, VERSION } from "./const";
import { CLIENT_PKG, CONFIG_FILE, NAME, PACKAGE, VERSION } from "./const";
import { logger, ucFirst } from "./lib";
import * as middlewares from "./middlewares";
import * as messages from "./messages";
import chalk from "chalk";

const cli = cac(NAME);

Expand All @@ -29,7 +30,7 @@ cli.command("whoami", "Display current user").action(async options => {

cli
.command("init", "Init a dico in your project")
.option("-f, --force", "Override existing `dico.config.json`")
.option("-f, --force", `Override existing ${chalk.cyan(CONFIG_FILE)}`)
.action(async options => {
await middlewares.signedInOnly();
await commands.init(cli, options);
Expand All @@ -44,7 +45,9 @@ cli
.command("push", "Push current dico to Dico.app")
.option(
"-b, --build",
"Also build current project dico (performs `dico build` before pushing)"
`Also build current project dico (performs ${chalk.cyan(
"dico build"
)} before pushing)`
)
.option("-f, --force", "Force push, even if not in sync (not recommended)")
.action(async options => {
Expand All @@ -55,7 +58,7 @@ cli
cli
.command(
"fetch [base]",
"Fetch current dico from Dico.app using `@dico/client`"
`Fetch current dico from Dico.app using ${chalk.cyan(CLIENT_PKG)}`
)
.action(async options => {
await commands.fetch(cli, options);
Expand Down
122 changes: 119 additions & 3 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@ import inquirer from "inquirer";
import { lineBreak, logger } from "../lib";
import * as client from "../core/client";
import * as dicojson from "../core/dicojson";
import * as pkgjson from "../core/pkgjson";
import { Dico, Role } from "../types";
import * as messages from "../messages";
import { DEFAULT_SOURCES_PATTERN, DEFAULT_TIMEOUT } from "../const";
import {
CLIENT_PKG,
CONFIG_FILE,
DEFAULT_SOURCES_PATTERN,
DEFAULT_TIMEOUT
} from "../const";
import exit from "exit";
import chalk from "chalk";

class InitError extends Error {}

Expand Down Expand Up @@ -75,7 +82,7 @@ const initConfig = {
await new Listr(
[
{
title: "Creating `dico.config.json`...",
title: `Creating ${chalk.cyan(CONFIG_FILE)}...`,
// @ts-expect-error listr types are broken
task: (ctx: { config: ConfigJSON }, task: ListrTaskWrapper) =>
new Observable(observer => {
Expand All @@ -97,7 +104,7 @@ const initConfig = {
observer.error(error);
}

task.title = "`dico.config.json` created";
task.title = `${chalk.cyan(CONFIG_FILE)} created`;
ctx.config = config;
observer.complete();
})
Expand All @@ -111,6 +118,90 @@ const initConfig = {
).run()
};

const askInstallClient = {
run: async () =>
await inquirer.prompt<{ yes: boolean }>([
{
type: "confirm",
name: "yes",
message: `Would you like us to install and configure ${chalk.cyan(
CLIENT_PKG
)} (our client library) for you?\n This will edit your ${chalk.cyan(
"package.json"
)} file and create the client for you`
}
])
};

const installClient = {
run: async (manifest: pkgjson.Manifest) =>
await new Listr(
[
{
title: `Installing ${chalk.cyan(CLIENT_PKG)} with ${chalk.cyan(
pkgjson.getPackageManager() === "npm" ? "npm" : "Yarn"
)}...`,
// @ts-expect-error listr types are broken
task: (_: pkgjson.Manifest, task: ListrTaskWrapper) =>
new Observable(observer => {
Promise.all([
pkgjson.installClient(),
new Promise(resolve => setTimeout(resolve, DEFAULT_TIMEOUT))
])
.then(([_, __]) => {
task.title = `${chalk.cyan(CLIENT_PKG)} installed`;
observer.complete();
})
.catch(error => {
observer.error(error);
});
})
},
{
title: `Updating ${chalk.cyan("package.json")} scripts...`,
// @ts-expect-error listr types are broken
task: (_: pkgjson.Manifest, task: ListrTaskWrapper) =>
new Observable(observer => {
Promise.all([
pkgjson.updateScripts(manifest),
new Promise(resolve => setTimeout(resolve, DEFAULT_TIMEOUT))
])
.then(([_, __]) => {
task.title = `${chalk.cyan("package.json")} scripts updated`;
observer.complete();
})
.catch(error => {
observer.error(error);
});
})
},
{
title: `Creating ${chalk.cyan(
`dico.${pkgjson.isTypeScript() ? "ts" : "js"}`
)}...`,
// @ts-expect-error listr types are broken
task: (_: pkgjson.Manifest, task: ListrTaskWrapper) =>
new Observable(observer => {
Promise.all([
pkgjson.createDicoFile(manifest),
new Promise(resolve => setTimeout(resolve, DEFAULT_TIMEOUT))
])
.then(([_, __]) => {
task.title = `${chalk.cyan(
`dico.${pkgjson.isTypeScript() ? "ts" : "js"}`
)} created`;
observer.complete();
})
.catch(error => {
observer.error(error);
});
})
}
],
{ renderer: UpdateRenderer }
).run(manifest)
};

export const init = async (
_: CAC,
options: { [key: string]: unknown }
Expand All @@ -128,6 +219,31 @@ export const init = async (
const { dicos } = await getDicos.run();
const { dico } = await pickDico.run(dicos);
await initConfig.run(dico);
lineBreak();

// Try setup project if possible
if (pkgjson.exists()) {
if (!pkgjson.isInstalled()) {
const manifest = pkgjson.detectFramework();
logger.info(messages.FrameworkDetected, manifest.name);
const { yes } = await askInstallClient.run();
if (yes) {
await installClient.run(manifest);
logger.success(messages.AutomaticClientInstallSuccess);
} else {
logger.success(messages.NoAutomaticClientInstall);
logger.info(messages.InstallClientManually);
}
} else {
logger.info(messages.ClientAlreadyInstalledSkip);
}
} else {
logger.info(messages.PkgJSONNotDetected);
logger.info(messages.InstallClientManually);
}

lineBreak();

logger.success(messages.CommandSuccessful, "init");
lineBreak();
};
5 changes: 4 additions & 1 deletion src/commands/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import exit from "exit";
import { DEFAULT_TIMEOUT, CONFIG_FILE } from "../const";
import { ConfigJSON } from "../types";
import { build } from "./build";
import chalk from "chalk";

class PushError extends Error {}

Expand Down Expand Up @@ -42,7 +43,9 @@ const pushDico = new Listr(
}
}

task.title = `Production dico is in sync with local \`${CONFIG_FILE}\``;
task.title = `Production dico is in sync with local ${chalk.cyan(
CONFIG_FILE
)}`;

observer.complete();
})
Expand Down
2 changes: 2 additions & 0 deletions src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ export const DEFAULT_SOURCES_PATTERN = [
];
export const SOURCES_EXTRACT_REGEX = /\$dico(\.[\w\d]+)+/gm;
export const DEFAULT_TIMEOUT = 1000;
export const CLIENT_PKG = "@dico/client";
export const CLIENT_FETCH = "dico-fetch";
49 changes: 49 additions & 0 deletions src/core/createDicoTemplates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export const VanillaEsm = `import { createDico } from "@dico/client";
// Dico data file is created next to your \`dico.config.json\` file
import data from "../dico.data.json";
export const { $dico, $dicoI18n } = createDico(data);
`;

export const VanillaEsmRoot = `import { createDico } from "@dico/client";
// Dico data file is created next to your \`dico.config.json\` file
import data from "../dico.data.json";
export const { $dico, $dicoI18n } = createDico(data);
`;

export const VanillaCjs = `const { createDico } = require("@dico/client");
// Dico data file is created next to your \`dico.config.json\` file
const data = require("./dico.data.json");
const { $dico, $dicoI18n } = createDico(data);
exports.$dico = $dico;
exports.$dicoI18n = $dicoI18n;
`;

export const VanillaCjsRoot = `const { createDico } = require("@dico/client");
// Dico data file is created next to your \`dico.config.json\` file
const data = require("./dico.data.json");
const { $dico, $dicoI18n } = createDico(data);
exports.$dico = $dico;
exports.$dicoI18n = $dicoI18n;
`;

export const Vite = `import { reactive } from "vue";
import { createDico } from "@dico/client";
// Dico data file is created next to your \`dico.config.json\` file
import data from "../dico.data.json";
export const { $dico, $dicoI18n } = createDico(data);
export const useDico = () => {
return {
$dico: $dico,
$dicoI18n: reactive($dicoI18n)
};
};
`;
Loading

0 comments on commit 889853c

Please sign in to comment.