Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/experimetal transpile with swc #18

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,21 @@
},
"dependencies": {
"@expressots/boost-ts": "1.1.1",
"@swc/cli": "0.1.62",
"@swc/core": "1.3.80",
"@swc/register": "0.1.10",
"chalk-animation": "2.0.3",
"cli-progress": "3.11.2",
"concurrently": "8.2.1",
"degit": "2.8.4",
"glob": "10.2.6",
"inquirer": "8.0.0",
"mustache": "4.2.0",
"nodemon": "3.0.1",
"rimraf": "5.0.1",
"ts-node": "10.9.1",
"ts-node-dev": "2.0.0",
"tsconfig-paths": "4.2.0",
"yargs": "17.6.2"
},
"devDependencies": {
Expand All @@ -67,6 +75,7 @@
"@types/inquirer": "^9.0.3",
"@types/mustache": "^4.2.2",
"@types/node": "^18.11.19",
"@types/nodemon": "^1.19.2",
"@types/yargs": "^17.0.22",
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.53.0",
Expand All @@ -77,8 +86,6 @@
"husky": "^8.0.3",
"prettier": "^2.8.4",
"release-it": "^16.1.5",
"rimraf": "^4.1.2",
"ts-node-dev": "^2.0.0",
"typescript": "^4.9.5",
"vite": "^4.4.9",
"vitest": "^0.34.4"
Expand Down
7 changes: 7 additions & 0 deletions src/@types/command-args.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface CommandDevArgs {
experimental: boolean;
}

export interface CommandBuildArgs {
experimental: boolean;
}
2 changes: 2 additions & 0 deletions src/@types/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./config";
export * from "./template";
export * from "./command-args";
10 changes: 10 additions & 0 deletions src/@types/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum TemplateEnum {
OPINIONATED = "opinionated",
NON_OPINIONATED = "non-opinionated"
}

export interface Template {
name: TemplateEnum;
description: string;
path: string;
}
13 changes: 13 additions & 0 deletions src/build/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CommandModule } from "yargs";
import { projectForm } from "./form";
import { CommandDevArgs } from "../@types";

const buildProject = (): CommandModule<Record<string, never>, CommandDevArgs> => {
return {
command: "build",
describe: "Build project",
handler: projectForm,
};
};

export { buildProject };
45 changes: 45 additions & 0 deletions src/build/form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import path from "node:path";
import { existsSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { CommandBuildArgs } from "../@types";
import { printError } from "../utils/cli-ui";
import { getPlatformCommand } from "../utils/get-platform-command-bin";

const PATH = `${process.env.PATH}${path.delimiter}${path.resolve(__dirname, "../../node_modules/.bin")}`;
const env = { ...process.env, PATH };

const projectForm = async ({ experimental }: CommandBuildArgs): Promise<void> => {
console.time("Build succeed");

spawnSync("rimraf", ["dist"], { env, stdio: "inherit" });

if (experimental) {
if (!existsSync(".swcrc")) {
printError("Experimental features needs .swcrc file", ".swcrc");
process.exit(1);
}

const { result } = require("concurrently")([
{ name: "types", command: "tsc --noEmit" },
{ name: "lint", command: "eslint src/**/*.ts" },
{ name: "build", command: "swc src -d dist" },
], { raw: true });

result
.then(() => {
console.timeEnd("Build succeed");
})
.catch(() => {
printError("Build failed", "expressots build");
process.exit(1);
});

return;
}

spawnSync(getPlatformCommand("tsc"), ["-p", "tsconfig.build.json"], { env, stdio: "inherit" });
console.timeEnd("Build succeed");
};

export { projectForm };
1 change: 1 addition & 0 deletions src/build/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./cli";
8 changes: 8 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { hideBin } from "yargs/helpers";
import { generateProject } from "./generate";
import { infoProject } from "./info";
import { createProject } from "./new";
import { devProject } from "./dev";
import { buildProject } from "./build";

export const CLI_VERSION = "1.3.4";

Expand All @@ -15,13 +17,19 @@ yargs(hideBin(process.argv))
.command(createProject())
.command(generateProject())
.command(infoProject())
.command(devProject())
.command(buildProject())
.example("$0 new expressots-demo", "Create interactively")
.example("$0 new expressots-demo -d ./", "Create interactively with path")
.example("$0 new expressots-demo -p yarn -t opinionated", "Create silently")
.example(
"$0 new expressots-demo -p yarn -t opinionated -d ./",
"Create silently with path",
)
.example(
"$0 new expressots-demo -p yarn -t opinionated --experimental",
"Create using experimental, not battle-tested, features of ExpressoTS",
)
.example("$0 generate service user-create", "Scaffold a service")
.example("$0 info", "Show CLI details")
.demandCommand(1, "You need at least one command before moving on")
Expand Down
13 changes: 13 additions & 0 deletions src/dev/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CommandModule } from "yargs";
import { projectForm } from "./form";
import { CommandDevArgs } from "../@types";

const devProject = (): CommandModule<Record<string, never>, CommandDevArgs> => {
return {
command: "dev",
describe: "Run project in development mode",
handler: projectForm,
};
};

export { devProject };
38 changes: 38 additions & 0 deletions src/dev/form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import path from "node:path";
import { existsSync } from "node:fs";
import { spawn, spawnSync } from "node:child_process";
import nodemon from "nodemon";
import { CommandDevArgs } from "../@types";
import { printError } from "../utils/cli-ui";
import { getPlatformCommand } from "../utils/get-platform-command-bin";

const projectForm = async ({ experimental }: CommandDevArgs): Promise<void> => {
if (experimental) {
if (!existsSync(".swcrc")) {
printError("Experimental features needs .swcrc file", ".swcrc");
process.exit(1);
}

require('@swc/register');

function nodemonRestart() {
spawn(getPlatformCommand("eslint"), ["src/**/*.ts"], { stdio: "inherit" });
spawn(getPlatformCommand("tsc"), ["--noEmit"], { stdio: "inherit" });
}

nodemon({
ext: "ts",
exec: `node -r ${require.resolve("@swc/register")} src/main.ts`,
})
.on("start", nodemonRestart)
.on("restart", nodemonRestart);


return;
}

spawnSync(getPlatformCommand("ts-node-dev"), ["src/main.ts"], { stdio: "inherit" });
};

export { projectForm };
1 change: 1 addition & 0 deletions src/dev/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./cli";
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./types";
export * from "./generate";
export * from "./utils";
export * from "./new";
export * from "./dev";
20 changes: 8 additions & 12 deletions src/new/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const createProject = (): CommandModule<CommandModuleArgs, any> => {
}

return {
command: "new <project-name> [package-manager] [template] [directory]",
command: "new <project-name> [package-manager] [template] [directory] [experimental]",
describe: "Create a new project",
builder: (yargs: Argv): Argv => {
yargs
Expand All @@ -37,22 +37,18 @@ const createProject = (): CommandModule<CommandModuleArgs, any> => {
type: "string",
alias: "d",
})
.option("experimental", {
describe: "Use experimental, not battle-tested, features of ExpressoTS",
type: "boolean",
default: false,
})
.implies("package-manager", "template")
.implies("template", "package-manager");

return yargs;
},
handler: async ({
projectName,
packageManager,
template,
directory,
}) => {
return await projectForm(projectName, [
packageManager,
template,
directory,
]);
handler: async ({ projectName, packageManager, template, directory, experimental }) => {
return await projectForm(projectName, [packageManager, template, directory, experimental]);
},
};
};
Expand Down
60 changes: 36 additions & 24 deletions src/new/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import fs from "node:fs";
import path from "node:path";
import { centerText } from "../utils/center-text";
import { printError } from "../utils/cli-ui";
import { TemplateEnum } from "../@types";
import { getPlatformCommand } from "../utils/get-platform-command-bin";
import templateList from "../templates-list";

async function packageManagerInstall({
packageManager,
Expand All @@ -18,10 +21,7 @@ async function packageManagerInstall({
progressBar: SingleBar;
}) {
return new Promise((resolve, reject) => {
const isWindows: boolean = process.platform === "win32";
const command: string = isWindows
? `${packageManager}.cmd`
: packageManager;
const command = getPlatformCommand(packageManager);

const installProcess = spawn(command, ["install"], {
cwd: directory,
Expand Down Expand Up @@ -79,11 +79,6 @@ function changePackageName({
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
}

enum Template {
"non-opinionated" = "Non-Opinionated :: A simple ExpressoTS project.",
opinionated = "Opinionated :: A complete ExpressoTS project with an opinionated structure and features.",
}

const enum PackageManager {
npm = "npm",
yarn = "yarn",
Expand All @@ -95,10 +90,12 @@ const projectForm = async (projectName: string, args: any[]): Promise<void> => {
let answer: any;
const projName: string = projectName;
let packageManager: PackageManager | undefined;
let template: keyof typeof Template | undefined;
let template: TemplateEnum | undefined;
let directory: string | undefined;
let experimental: boolean;

// Resolving the argument order problem
// @todo: intent to remove for/in, see PR #17
for (const arg of args) {
if (args.length >= 3) {
if (
Expand All @@ -109,7 +106,9 @@ const projectForm = async (projectName: string, args: any[]): Promise<void> => {
) {
packageManager = arg as PackageManager;
} else if (arg === "non-opinionated" || arg === "opinionated") {
template = arg as keyof typeof Template;
template = arg as TemplateEnum;
} else if (arg === true) {
experimental = arg;
} else {
directory = arg;
}
Expand All @@ -120,7 +119,8 @@ const projectForm = async (projectName: string, args: any[]): Promise<void> => {
answer = {
name: projectName,
packageManager: packageManager,
template: Template[template],
template: template,
experimental: experimental,
confirm: true,
};
} else {
Expand All @@ -140,14 +140,25 @@ const projectForm = async (projectName: string, args: any[]): Promise<void> => {
message: "Package manager",
choices: ["npm", "yarn", "pnpm", "bun"],
},
{
type: "confirm",
name: "experimental",
message: "Use experimental, not battle-tested, features of ExpressoTS",
default: false,
},
{
type: "list",
name: "template",
message: "Select a template",
choices: [
"Non-Opinionated :: A simple ExpressoTS project.",
"Opinionated :: A complete ExpressoTS project with an opinionated structure and features.",
],
when: ({ experimental }) => !experimental,
choices: templateList.stable.map(({ description }) => description),
},
{
type: "list",
name: "template",
message: "Select a experimental template",
when: ({ experimental }) => experimental,
choices: templateList.experimental.map(({ description }) => description),
},
{
type: "confirm",
Expand All @@ -168,9 +179,9 @@ const projectForm = async (projectName: string, args: any[]): Promise<void> => {
}

// Hashmap of templates and their directories
const templates: Record<string, unknown> = {
"Non-Opinionated": "non_opinionated",
Opinionated: "opinionated",
const templates: Record<string, TemplateEnum> = {
"Non-Opinionated": TemplateEnum.NON_OPINIONATED,
Opinionated: TemplateEnum.OPINIONATED,
};

if (answer.confirm) {
Expand Down Expand Up @@ -202,11 +213,12 @@ const projectForm = async (projectName: string, args: any[]): Promise<void> => {

const [_, template] = answer.template.match(/(.*) ::/) as Array<string>;

try {
const emitter = degit(
`expressots/expressots/templates/${templates[template]}`,
);

try {
// @todo: new templates, see expressots/expressots PR #79
const stability = answer.experimental ? "experimental" : "stable";
const { path } = templateList[stability].find((item) => (item.name = templates[template]));
const emitter = degit(path);

await emitter.clone(answer.name);
} catch (err: any) {
printError(
Expand Down
Loading