Skip to content

Commit

Permalink
Merge pull request #249 from samchon/features/cli
Browse files Browse the repository at this point in the history
Complement #248 - recommend `ts-patch`
  • Loading branch information
samchon authored Feb 16, 2023
2 parents 45be5a1 + 9e1c478 commit 8f41010
Show file tree
Hide file tree
Showing 25 changed files with 899 additions and 393 deletions.
31 changes: 16 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,30 @@ Just run above command, then boilerplate project would be constructed.
npx nestia setup
```

When you want to use `nestia` in orindary project, just type above command.
Just type `npx nestia setup`, that's all.

All installation and configuration processes would be automatically done.

Also, you can specify package manager or target `tsconfig.json` file like below:
If you've installed [ttypescript](https://github.com/cevek/ttypescript) during setup, you should compile `@nestia/core` utilization code through `ttsc` command, instead of `tsc`.

```bash
npx nestia setup --manager npm
npx nestia setup --manager pnpm
npx nestia setup --manager yarn
# COMPILE THROUGH TTYPESCRIPT
npx ttsc

npx nestia setup --project tsconfig.json
npx nestia setup --project tsconfig.test.json
# RUN TS-NODE WITH TTYPESCRIPT
npx ts-node -C ttypescript src/index.ts
```

After the setup, you can compile `@nestia/core` utilization code by using `ttsc` ([`ttypescript`](https://github.com/cevek/ttypescript)) command. If you want to run your TypeScript file directly through `ts-node`, add `-C ttypescript` argument like below:
Otherwise, you've chosen [ts-patch](https://github.com/nonara/ts-patch), you can use original `tsc` command. However, [ts-patch](https://github.com/nonara/ts-patch) hacks `node_modules/typescript` source code. Also, whenever update `typescript` version, you've to run `npm run prepare` command repeatedly.

By the way, when using `@nest/cli`, you must just choose [ts-patch](https://github.com/nonara/ts-patch).

```bash
# COMPILE THROUGH TTYPESCRIPT
npx ttsc
# USE ORIGINAL TSC COMMAND
tsc
npx ts-node src/index.ts

# RUN TS-NODE WITH TTYPESCRIPT
npx ts-node -C ttypescript src/index.ts
# WHENVER UPDATE
npm install --save-dev typescript@latest
npm run prepare
```

### Manual Setup
Expand Down Expand Up @@ -89,7 +90,7 @@ export class BbsArticlesController {
* @param inupt Content to store
* @returns Newly archived article
*/
@TypedRoute.Post() // 10x faster and safer JSON.stringify()
@TypedRoute.Post() // 50x faster and safer JSON.stringify()
public async store(
@TypedBody() input: IBbsArticle.IStore // super-fast validator
): Promise<IBbsArticle>;
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nestia",
"version": "4.0.5",
"version": "4.0.6",
"description": "Nestia CLI",
"main": "bin/index.js",
"bin": {
Expand Down Expand Up @@ -31,7 +31,11 @@
"devDependencies": {
"@nestia/core": "^1.0.6",
"@nestia/sdk": "^1.0.1",
"@types/inquirer": "^9.0.3",
"@types/node": "^18.11.16",
"commander": "^10.0.0",
"comment-json": "^4.2.3",
"inquirer": "^8.2.5",
"rimraf": "^3.0.2",
"typescript": "^4.9.4"
},
Expand Down
24 changes: 15 additions & 9 deletions packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,30 @@ npx nestia setup
npx @nestia/core setup
```

When you run `npx nestia setup` command, all installation and configuration processes would be automatically done. If you want to setup `@nestia/core` only, run `npx @nestia/core setup` command instead.
Just type `npx nestia setup`, that's all.

After the setup has been fully completed, you can compile your backend server code by using `ttsc` command. If you want to run your TypeScript file directly through `ts-node`, add `-C ttypescript` argument like below:
If you've installed [ttypescript](https://github.com/cevek/ttypescript) during setup, you should compile `@nestia/core` utilization code through `ttsc` command, instead of `tsc`.

```bash
# COMPILE THROUGH TTYPESCRIPT
npx ttsc

# RUN TS-NODE WITH TTYPESCRIPT
npx ts-node -C ttypescript src/index.ts
```

Also, you can specify package manager or target `tsconfig.json` file like below:
Otherwise, you've chosen [ts-patch](https://github.com/nonara/ts-patch), you can use original `tsc` command. However, [ts-patch](https://github.com/nonara/ts-patch) hacks `node_modules/typescript` source code. Also, whenever update `typescript` version, you've to run `npm run prepare` command repeatedly.

By the way, when using `@nest/cli`, you must just choose [ts-patch](https://github.com/nonara/ts-patch).

```bash
npx @nestia/core setup --manager npm
npx @nestia/core setup --manager pnpm
npx @nestia/core setup --manager yarn
# USE ORIGINAL TSC COMMAND
tsc
npx ts-node src/index.ts

npx @nestia/core setup --project tsconfig.json
npx @nestia/core setup --project tsconfig.test.json
# HOWEVER, WHENVER UPDATE
npm install --save-dev typescript@latest
npm run prepare
```

### Manual Setup
Expand All @@ -99,7 +105,7 @@ export class BbsArticlesController {
* @param inupt Content to store
* @returns Newly archived article
*/
@TypedRoute.Put(":id") // 10x faster and safer JSON.stringify()
@TypedRoute.Put(":id") // 50x faster and safer JSON.stringify()
public async store(
@TypedParam("section", "string") section: string,
@TypedParam("id", "uuid") id: string,
Expand Down
10 changes: 7 additions & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nestia/core",
"version": "1.0.10",
"version": "1.0.11",
"description": "Super-fast validation decorators of NestJS",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
Expand Down Expand Up @@ -39,16 +39,20 @@
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
"@types/express": "^4.17.15",
"@types/inquirer": "^9.0.3",
"@typescript-eslint/eslint-plugin": "^5.46.1",
"@typescript-eslint/parser": "^5.46.1",
"commander": "^10.0.0",
"comment-json": "^4.2.3",
"eslint-plugin-deprecation": "^1.3.3",
"git-last-commit": "^1.0.1",
"inquirer": "^8.2.5",
"rimraf": "^3.0.2",
"ts-node": "^10.9.1",
"tstl": "^2.5.13",
"ttypescript": "^1.5.15",
"typescript": "^4.9.5"
"typescript": "^4.9.5",
"typescript-transform-paths": "^3.4.6"
},
"dependencies": {
"@nestia/fetcher": "^1.0.0",
Expand All @@ -59,7 +63,7 @@
"raw-body": "*",
"reflect-metadata": "*",
"rxjs": "*",
"typia": "^3.4.22"
"typia": "^3.5.3"
},
"peerDependencies": {
"ttypescript": ">= 1.5.15",
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/decorators/EncryptedRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import { route_error } from "./internal/route_error";
*
* `EncryptedRoute` is a module containing router decorator functions which encrypts
* response body data through AES-128/256 encryption. Furthermore, they can boost
* up JSON string conversion speed about 10x times faster, even type safe through
* [typia](https://github.com/samchon/typia).
* up JSON string conversion speed about 50x times faster than `class-transformer`,
* even type safe through [typia](https://github.com/samchon/typia).
*
* For reference, router functions of `EncryptedRoute` can convert custom error classes
* to regular {@link nest.HttpException} class automatically, through
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/decorators/TypedRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ import { route_error } from "./internal/route_error";
* Type safe router decorator functions.
*
* `TypedRoute` is a module containing router decorator functions which can boost up
* JSON string conversion speed about 10x times faster. Furthermore, such JSON string
* conversion is even type safe through [typia](https://github.com/samchon/typia).
* JSON string conversion speed about 50x times faster than `class-transformer`.
* Furthermore, such JSON string conversion is even type safe through
* [typia](https://github.com/samchon/typia).
*
* For reference, router functions of `TypedRoute` can convert custom error classes to
* the regular {@link nest.HttpException} class automatically, through
Expand Down
57 changes: 39 additions & 18 deletions packages/core/src/executable/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env node
import { CommandParser } from "./internal/CommandParser";
import { CoreSetupWizard } from "./internal/CoreSetupWizard";
import { ArgumentParser } from "./internal/ArgumentParser";
import { CommandExecutor } from "./internal/CommandExecutor";
import { PackageManager } from "./internal/PackageManager";
import { PluginConfigurator } from "./internal/PluginConfigurator";

const USAGE = `Wrong command has been detected. Use like below:
Expand All @@ -20,22 +22,41 @@ function halt(desc: string): never {
}

async function setup(): Promise<void> {
const options: Record<string, string> = CommandParser.parse(
process.argv.slice(3),
);
const manager: string = options.manager ?? "npm";
const compiler: string = options.compiler ?? "ttypescript";
const project: string = options.project ?? "tsconfig.json";
console.log(options);

if (
(compiler !== "ttypescript" && compiler !== "ts-patch") ||
(manager !== "npm" && manager !== "pnpm" && manager !== "yarn")
)
halt(USAGE);
else if (compiler === "ttypescript")
await CoreSetupWizard.ttypescript({ manager, project });
else await CoreSetupWizard.tsPatch({ manager, project });
console.log("----------------------------------------");
console.log(" Nestia Setup Wizard");
console.log("----------------------------------------");

// LOAD PACKAGE.JSON INFO
const pack: PackageManager = await PackageManager.mount();

// TAKE ARGUMENTS
const args: ArgumentParser.IArguments = await ArgumentParser.parse(pack);

// INSTALL TYPESCRIPT
pack.install({ dev: true, modulo: "typescript" });
args.project ??= (() => {
CommandExecutor.run("npx tsc --init", false);
return (args.project = "tsconfig.json");
})();
pack.install({ dev: true, modulo: "ts-node" });

// INSTALL COMPILER
pack.install({ dev: true, modulo: args.compiler });
if (args.compiler === "ts-patch") {
await pack.save((data) => {
data.scripts ??= {};
if (typeof data.scripts.prepare === "string")
data.scripts.prepare =
"ts-patch install && " + data.scripts.prepare;
else data.scripts.prepare = "ts-patch install";
});
CommandExecutor.run("npm run prepare", false);
}

// INSTALL AND CONFIGURE TYPIA
pack.install({ dev: false, modulo: "typia" });
pack.install({ dev: false, modulo: "@nestia/core" });
await PluginConfigurator.configure(pack, args);
}

async function main(): Promise<void> {
Expand Down
144 changes: 144 additions & 0 deletions packages/core/src/executable/internal/ArgumentParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import type CommanderModule from "commander";
import fs from "fs";
import type * as InquirerModule from "inquirer";
import path from "path";

import { PackageManager } from "./PackageManager";

export namespace ArgumentParser {
export interface IArguments {
compiler: "ts-patch" | "ttypescript";
manager: "npm" | "pnpm" | "yarn";
project: string | null;
}

export async function parse(pack: PackageManager): Promise<IArguments> {
// INSTALL TEMPORARY PACKAGES
const newbie = {
commander: pack.install({
dev: true,
modulo: "commander",
version: "10.0.0",
silent: true,
}),
inquirer: pack.install({
dev: true,
modulo: "inquirer",
version: "8.2.5",
silent: true,
}),
};

// TAKE OPTIONS
const output: IArguments | Error = await (async () => {
try {
return await _Parse(pack);
} catch (error) {
return error as Error;
}
})();

// REMOVE TEMPORARY PACKAGES
if (newbie.commander) pack.erase({ modulo: "commander", silent: true });
if (newbie.inquirer) pack.erase({ modulo: "inquirer", silent: true });

// RETURNS
if (output instanceof Error) throw output;
return output;
}

async function _Parse(pack: PackageManager): Promise<IArguments> {
// PREPARE ASSETS
const { createPromptModule }: typeof InquirerModule = await import(
path.join(pack.directory, "node_modules", "inquirer")
);
const { program }: typeof CommanderModule = await import(
path.join(pack.directory, "node_modules", "commander")
);

program.option("--compiler [compiler]", "compiler type");
program.option("--manager [manager", "package manager");
program.option("--project [project]", "tsconfig.json file location");

// INTERNAL PROCEDURES
const questioned = { value: false };
const action = (
closure: (options: Partial<IArguments>) => Promise<IArguments>,
) => {
return new Promise<IArguments>((resolve, reject) => {
program.action(async (options) => {
try {
resolve(await closure(options));
} catch (exp) {
reject(exp);
}
});
program.parseAsync().catch(reject);
});
};
const select =
(name: string) =>
(message: string) =>
async <Choice extends string>(
choices: Choice[],
): Promise<Choice> => {
questioned.value = true;
return (
await createPromptModule()({
type: "list",
name: name,
message: message,
choices: choices,
})
)[name];
};
const configure = async () => {
const fileList: string[] = await (
await fs.promises.readdir(process.cwd())
).filter(
(str) =>
str.substring(0, 8) === "tsconfig" &&
str.substring(str.length - 5) === ".json",
);
if (fileList.length === 0) {
if (process.cwd() !== pack.directory)
throw new Error(`Unable to find "tsconfig.json" file.`);
return null;
} else if (fileList.length === 1) return fileList[0];
return select("tsconfig")("TS Config File")(fileList);
};

// DO CONSTRUCT
return action(async (options) => {
if (options.compiler === undefined) {
console.log(COMPILER_DESCRIPTION);
options.compiler = await select("compiler")(`Compiler`)(
pack.data.scripts?.build === "nest build"
? ["ts-patch" as const, "ttypescript" as const]
: ["ttypescript" as const, "ts-patch" as const],
);
}
options.manager ??= await select("manager")("Package Manager")([
"npm" as const,
"pnpm" as const,
"yarn" as const,
]);
pack.manager = options.manager;
options.project ??= await configure();

if (questioned.value) console.log("");
return options as IArguments;
});
}
}

const COMPILER_DESCRIPTION = [
`About compiler, if you adapt "ttypescript", you should use "ttsc" instead.`,
``,
`Otherwise, you choose "ts-patch", you can use the original "tsc" command.`,
`However, the "ts-patch" hacks "node_modules/typescript" source code.`,
`Also, whenever update "typescript", you've to run "npm run prepare" command.`,
``,
`By the way, when using "@nest/cli", you must just choose "ts-patch".`,
``,
].join("\n");
Loading

0 comments on commit 8f41010

Please sign in to comment.