-
-
Notifications
You must be signed in to change notification settings - Fork 162
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(cli): new cli #1245
Merged
Merged
feat(cli): new cli #1245
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
d2e25fc
feat(cli): rename from `executable` to `cli`
ryoppippi b16cf8e
feat(cli): create new bin endpoint
ryoppippi 7d1dec1
feat(cli): build as esm format
ryoppippi f5855e3
feat(cli): create parent command with `cleye`
ryoppippi 6e83d3d
feat(cli/utils): create logger
ryoppippi 9ac71b9
feat(cli/utils): create command executor
ryoppippi ed7cdc7
feat(cli/utils): create message fucnctions
ryoppippi aba8bf5
feat(cli): add patch command
ryoppippi f4bb030
feat(cli/utils): add confFiles
ryoppippi 391452c
feat(cli/utils): add fs.ts
ryoppippi 01486f7
feat(cli): add generate command
ryoppippi 080de24
feat(cli): add setup command
ryoppippi 0563d81
feat(package.json): add cli run commands
ryoppippi 135c054
feat(cli): delete old commands
ryoppippi 940c5cf
feat(cli): add setup command
ryoppippi d7580a4
chore(package.json): revert deleted private
ryoppippi 40f22e2
chore(package.json): update dependencies
ryoppippi 890e708
refactor(cli): use namespace exports for subcommand
ryoppippi 397ef22
refactor(cli): use namespace exports for utility
ryoppippi 2684e81
refactor(cli): re-export modules of `package-manager-detector` and im…
ryoppippi fe16cc6
Merge branch 'feature/cli' into feature/improve-cli2
samchon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
bin/ | ||
!/bin | ||
lib/ | ||
node_modules/ | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env node | ||
|
||
import { cli } from '../lib/cli/index.js' | ||
|
||
await cli() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { cli as cleye } from 'cleye' | ||
import * as Subcommand from './subcommands' | ||
import { wizard } from './utils/message'; | ||
|
||
export async function cli(){ | ||
wizard(); | ||
const argv = cleye({ | ||
name: "typia", | ||
version: "1.0.0", | ||
description: "CLI for Typia operations", | ||
|
||
commands: [ | ||
Subcommand.patch, | ||
Subcommand.generate, | ||
Subcommand.setup, | ||
], | ||
|
||
}) | ||
|
||
/* if no subcommand is provided, show help */ | ||
argv.showHelp(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { command } from 'cleye'; | ||
import { TypiaProgrammer } from "../../programmers/TypiaProgrammer"; | ||
|
||
import * as ConfFileUtils from "../utils/confFiles"; | ||
import * as Logger from "../utils/logger"; | ||
import * as MessageUtils from "../utils/message"; | ||
|
||
export const generate = command({ | ||
name: "generate", | ||
|
||
flags: { | ||
input: { | ||
type: String, | ||
description: "input directory", | ||
}, | ||
output: { | ||
type: String, | ||
description: "output directory", | ||
}, | ||
project: { | ||
type: String, | ||
description: "tsconfig.json file path (e.g. ./tsconfig.test.json)", | ||
}, | ||
}, | ||
|
||
help: { | ||
description: "Generate Typia files", | ||
} | ||
}, async (argv) => { | ||
let { input, output, project } = argv.flags; | ||
|
||
input ??= await Logger.logger.prompt("input directory", { type: "text" }); | ||
output ??= await Logger.logger.prompt("output directory", { type: "text" }); | ||
project ??= await ConfFileUtils.findTsConfig(); | ||
|
||
if (project == null) { | ||
MessageUtils.bail("tsconfig.json not found"); | ||
} | ||
|
||
await TypiaProgrammer.build({ input, output, project }); | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export { patch } from "./patch"; | ||
export { setup } from "./setup"; | ||
export { generate } from "./generate"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { command } from 'cleye'; | ||
import fs from "node:fs/promises"; | ||
|
||
import * as Logger from "../utils/logger"; | ||
|
||
const FROM_WITH_COMMENT = `var defaultJSDocParsingMode = 2 /* ParseForTypeErrors */`; | ||
const TO_WITH_COMMENT = `var defaultJSDocParsingMode = 0 /* ParseAll */`; | ||
const FROM_ONLY = `var defaultJSDocParsingMode = 2`; | ||
const TO_ONLY = `var defaultJSDocParsingMode = 0`; | ||
|
||
export const patch = command({ | ||
name: "patch", | ||
|
||
aliases: ["p"], | ||
|
||
help: { | ||
description: "Extra patching for TypeScript", | ||
} | ||
}, async () => { | ||
Logger.logger.info( | ||
[ | ||
`Since TypeScript v5.3 update, "tsc" no more parses JSDoc comments.`, | ||
``, | ||
`Therefore, "typia" revives the JSDoc parsing feature by patching "tsc".`, | ||
``, | ||
`This is a temporary feature of "typia", and it would be removed when "ts-patch" being updated.`, | ||
].join("\n"), | ||
); | ||
|
||
await executePatch(); | ||
Logger.logger.success("Patched TypeScript"); | ||
} | ||
); | ||
|
||
export async function executePatch(): Promise<void> { | ||
const location: string = require.resolve("typescript/lib/tsc.js"); | ||
const content: string = await fs.readFile(location, "utf8"); | ||
if (!content.includes(FROM_WITH_COMMENT)) { | ||
await fs.writeFile( | ||
location, | ||
content.replace(FROM_WITH_COMMENT, TO_WITH_COMMENT), | ||
"utf8", | ||
); | ||
} else if (!content.includes(FROM_ONLY)) { | ||
await fs.writeFile(location, content.replace(FROM_ONLY, TO_ONLY), "utf8"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import { command } from 'cleye'; | ||
import process from "node:process"; | ||
import { existsSync } from 'node:fs'; | ||
import { resolve } from 'node:path'; | ||
|
||
import * as PackageManager from '../utils/packageManager'; | ||
import * as CommandExecutor from "../utils/command"; | ||
import * as ConfFileUtils from "../utils/confFiles"; | ||
import * as FsUtils from "../utils/fs"; | ||
import * as Logger from "../utils/logger"; | ||
import * as MessageUtils from "../utils/message"; | ||
|
||
const TSPATCH_COMMAND = `ts-patch install`; | ||
const TYPIA_PATCH_COMMAND = `typia patch`; | ||
const TYPIA_TRANSFORM = `typia/lib/transform`; | ||
|
||
/** package.json type */ | ||
interface PackageJson { | ||
scripts?: Record<string, string>; | ||
} | ||
|
||
/** tsconfig.json type */ | ||
interface TSConfig { | ||
compilerOptions?: { | ||
strictNullChecks?: boolean; | ||
strict?: boolean; | ||
plugins?: { | ||
transform: string; | ||
}[]; | ||
}; | ||
} | ||
|
||
/** dependency type */ | ||
interface Dependency { | ||
dev: boolean; | ||
modulo: string; | ||
version: string; | ||
} | ||
|
||
export const setup = command({ | ||
name: "setup", | ||
|
||
flags: { | ||
project: { | ||
type: String, | ||
description: "tsconfig.json file path (e.g. ./tsconfig.test.json)", | ||
}, | ||
}, | ||
|
||
help: { | ||
description: "Setup Typia", | ||
} | ||
}, async (argv) => { | ||
const { flags } = argv; | ||
const cwd = process.cwd(); | ||
const manager = await PackageManager.detect({ cwd }); | ||
let agent = manager?.agent; | ||
|
||
if (agent == null) { | ||
const selected = await Logger.logger.prompt("Select a package manager", { | ||
initial: "npm", | ||
options: PackageManager.AGENTS, | ||
}) as PackageManager.Agent; | ||
agent = selected; | ||
} | ||
|
||
/* yarn@berry is not supported */ | ||
if (agent === "yarn@berry") { | ||
MessageUtils.bail("yarn@berry is not supported."); | ||
} | ||
|
||
/* install dependencies */ | ||
for (const dep of DEPENDENCIES) { | ||
const addArgs= [ | ||
`${dep.modulo}@${dep.version}`, | ||
dep.dev ? "-D" : "", | ||
(agent==='pnpm' || agent==='pnpm@6') && existsSync(resolve(cwd, 'pnpm-workspace.yaml')) ? '-w' : '' | ||
] | ||
const { command, args } = PackageManager.resolveCommand(agent, 'add', addArgs)!; | ||
CommandExecutor.run(`${command} ${args.join(" ")}`); | ||
} | ||
|
||
/* === prepare package.json === */ | ||
{ | ||
const path = await FsUtils.findUp("package.json", { cwd }); | ||
if (path == null) { | ||
MessageUtils.bail("package.json not found."); | ||
} | ||
const json = await FsUtils.readJsonFile<PackageJson>(path, cwd); | ||
|
||
let prepare = ( | ||
(json.data?.scripts?.prepare as string | undefined) ?? "" | ||
).trim(); | ||
|
||
const FULL_COMMAND = `${TSPATCH_COMMAND} && ${TYPIA_PATCH_COMMAND}`; | ||
|
||
/* if ony `ts-patch install` is found, add `typia patch` */ | ||
prepare.replace(TSPATCH_COMMAND, FULL_COMMAND); | ||
|
||
/* if prepare script is empty, set it to `typia patch` */ | ||
if (prepare === "") { | ||
prepare = FULL_COMMAND; | ||
} | ||
|
||
/* if prepare script does not contain `typia patch`, add it */ | ||
if (prepare !== FULL_COMMAND && !prepare.includes(FULL_COMMAND)) { | ||
prepare = `${FULL_COMMAND} && ${prepare}`; | ||
} | ||
|
||
/* update prepare script */ | ||
json.data.scripts = { ...(json.data.scripts ?? {}), prepare }; | ||
await FsUtils.writeJsonFile(json); | ||
} | ||
|
||
/* === prepare tsconfig.json === */ | ||
{ | ||
const tsConfigPath = flags.project ?? (await ConfFileUtils.findTsConfig({ cwd })); | ||
/* if tsconfig.json is not found, create it */ | ||
if (tsConfigPath == null) { | ||
const { command, args } = PackageManager.resolveCommand(agent, 'execute', ['tsc --init'])!; | ||
CommandExecutor.run(`${command} ${args.join(" ")}`); | ||
} | ||
|
||
const tsConfig = await FsUtils.readJsonFile<TSConfig>(tsConfigPath, cwd); | ||
|
||
if (tsConfig.data.compilerOptions == null) { | ||
tsConfig.data.compilerOptions = {}; | ||
} | ||
|
||
tsConfig.data.compilerOptions.strictNullChecks = true; | ||
tsConfig.data.compilerOptions.strict = true; | ||
|
||
tsConfig.data.compilerOptions.plugins = [ | ||
{ transform: TYPIA_TRANSFORM }, | ||
...(tsConfig.data.compilerOptions.plugins ?? []), | ||
]; | ||
await FsUtils.writeJsonFile(tsConfig); | ||
} | ||
|
||
/* === run prepare script === */ | ||
const { command, args } = PackageManager.resolveCommand(agent, 'run', ['prepare'])!; | ||
CommandExecutor.run(`${command} ${args.join(" ")}`); | ||
}, | ||
); | ||
|
||
/** dependencies to be installed */ | ||
const DEPENDENCIES = [ | ||
{ dev: true, modulo: "typescript", version: "5.5.2" }, | ||
{ dev: true, modulo: "ts-patch", version: "latest" }, | ||
] as const satisfies Dependency[]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import cp from "child_process"; | ||
|
||
export function run(str: string): void { | ||
console.log(`\n$ ${str}`); | ||
cp.execSync(str, { stdio: "inherit" }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import process from "node:process"; | ||
import { glob } from "tinyglobby"; | ||
|
||
import * as Logger from "../utils/logger"; | ||
import * as MessageUtils from "../utils/message"; | ||
|
||
export async function findTsConfig( | ||
{ cwd }: { cwd: string } = { cwd: process.cwd() }, | ||
): Promise<string> { | ||
const tsConfigs = await glob(["tsconfig.json", "tsconfig.*.json"], { cwd }); | ||
|
||
if (tsConfigs.length === 0) { | ||
MessageUtils.bail("tsconfig.json not found"); | ||
} | ||
|
||
if (tsConfigs.length === 1) { | ||
const tsconfig = tsConfigs.at(0); | ||
if (tsconfig != null) { | ||
return tsconfig; | ||
} | ||
} | ||
|
||
return await Logger.logger.prompt( | ||
"Multiple tsconfig.json files found. Please specify the one to use:", | ||
{ | ||
type: "select", | ||
options: tsConfigs, | ||
}, | ||
); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in CJS environment, generating declarations fails for the cleye library, so I split the build command