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

new cli #79

Merged
merged 10 commits into from
Nov 13, 2024
6 changes: 5 additions & 1 deletion frontend/packages/cli/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ dist-ssr
*.sw?

# typed-css-modules
*.css.d.ts
*.css.d.ts


dist-cli
public/schema.json
61 changes: 61 additions & 0 deletions frontend/packages/cli/README.md
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice README! 😄

Original file line number Diff line number Diff line change
@@ -1 +1,62 @@
# @liam/cli

Command-line tool designed to generate a web application that displays ER diagrams.

```bash
$ liam erd build --input {your .sql}
# Outputs the web application to the ./public and ./dist directories

$ liam erd preview
# Launches the web application for preview
```

## Building and Installing the Standalone CLI for Development

To build the CLI for development purposes, run:

```bash
pnpm run build:cli
# The executable will be output to dist-cli/bin/cli.js.
```

After building, you can invoke it locally with:

```bash
node ./dist-cli/bin/cli.js erd build --input ./fixtures/input.sql
```

To make it globally accessible as `liam`, use:

```bash
pnpm link --global
```

## Explanation of npm Scripts for Development

### Commands

1. **Build**
```bash
pnpm run build
```
- Internally, `./fixtures/input.sql` is passed as the `build --input` argument.
- Runs Vite's build process.

2. **Dev**
```bash
pnpm run dev
```
- Internally, `./fixtures/input.sql` is passed as the `dev --input` argument.
- Starts the Vite development server.

3. **Preview**
```bash
pnpm run preview
```
- Previews the production build using Vite's built-in preview functionality.

## File Structure

- **bin/cli.ts**: The main CLI script.
- **fixtures/input.sql**: A sample `.sql` file for testing purposes.
- **src/**: The web application that displays ER diagrams.
107 changes: 107 additions & 0 deletions frontend/packages/cli/bin/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { Command } from 'commander'
import { build, createServer, preview } from 'vite'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const root = path.resolve(__dirname, '../..')
const publicDir = path.join(process.cwd(), 'public')
const outDir = path.join(process.cwd(), 'dist')

function runPreprocess(inputPath: string | null) {
if (inputPath && !fs.existsSync(inputPath)) {
throw new Error('Invalid input path. Please provide a valid .sql file.')
}
FunamaYukina marked this conversation as resolved.
Show resolved Hide resolved

const sqlContent = inputPath ? fs.readFileSync(inputPath, 'utf8') : '{}'
const filePath = path.join(publicDir, 'schema.json')

if (!fs.existsSync(publicDir)) {
fs.mkdirSync(publicDir, { recursive: true })
}

try {
const jsonContent = JSON.stringify({ sql: sqlContent }, null, 2)
fs.writeFileSync(filePath, jsonContent, 'utf8')
return filePath
} catch (error) {
console.error(
`Error during preprocessing: ${error instanceof Error ? error.message : 'Unknown error'}`,
)
return null
}
}

const program = new Command()

program.name('liam').description('CLI tool for Liam').version('0.0.0')

const erdCommand = new Command('erd').description('ERD commands')

program.addCommand(erdCommand)

erdCommand
.command('build')
.description('Run Vite build')
.option('--input <path>', 'Path to the .sql file')
.action(async (options) => {
try {
const inputPath = options.input
runPreprocess(inputPath)
await build({
publicDir,
root,
build: {
outDir,
emptyOutDir: false,
},
})
} catch (error) {
console.error('Build failed:', error)
process.exit(1)
}
})

erdCommand
.command('dev')
.description('Run Vite dev server')
.option('--input <path>', 'Path to the .sql file')
.action(async (options) => {
try {
const inputPath = options.input
runPreprocess(inputPath)
const server = await createServer({ publicDir, root })
const address = server.httpServer?.address()
const port = typeof address === 'object' && address ? address.port : 5173
console.info(`Dev server is running at http://localhost:${port}`)
await server.listen()
} catch (error) {
console.error('Failed to start dev server:', error)
process.exit(1)
}
})

erdCommand
.command('preview')
.description('Preview the production build')
.action(async () => {
try {
const previewServer = await preview({
publicDir,
root,
build: {
outDir,
emptyOutDir: false,
},
})
const address = previewServer.httpServer?.address()
const port = typeof address === 'object' && address ? address.port : 4173
console.info(`Preview server is running at http://localhost:${port}`)
} catch (error) {
console.error('Failed to start preview server:', error)
process.exit(1)
}
})
program.parse(process.argv)
5 changes: 5 additions & 0 deletions frontend/packages/cli/fixtures/input.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATE TABLE products (
brand VARCHAR(255),
model VARCHAR(255),
year INT
);
18 changes: 12 additions & 6 deletions frontend/packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
"private": true,
"version": "0.0.0",
"type": "module",
"bin": {
"liam": "./dist-cli/bin/cli.js"
},
"scripts": {
"dev": "conc -c auto pnpm:dev:*",
"dev": "pnpm run build:cli && node ./dist-cli/bin/cli.js erd dev --input ./fixtures/input.sql",
"build": "pnpm run build:cli && node ./dist-cli/bin/cli.js erd build --input ./fixtures/input.sql",
"preview": "pnpm run build:cli && node ./dist-cli/bin/cli.js erd preview",
"build:cli": "tsc -p tsconfig.node.json",
"dev:app": "vite",
"dev:css": "tcm src --watch",
"gen": "conc -c auto pnpm:gen:*",
"gen:css": "tcm src",
"build": "tsc -b && vite build",
"preview": "vite preview",
"lint": "conc -c auto pnpm:lint:*",
"lint:biome": "biome check .",
"lint:tsc": "tsc --noEmit",
Expand All @@ -19,17 +23,19 @@
},
"dependencies": {
"@liam/erd-core": "workspace:*",
"commander": "^12.1.0",
"destyle.css": "^4.0.1",
"react": "^18",
"react-dom": "^18"
"react-dom": "^18",
"vite": "^5.4.10"
},
"devDependencies": {
"@biomejs/biome": "1.9.3",
"@types/node": "^22.9.0",
"@types/react": "^18",
"@types/react-dom": "^18",
"@vitejs/plugin-react": "^4.3.3",
"typed-css-modules": "^0.9.1",
"typescript": "^5",
"vite": "^5.4.10"
"typescript": "^5"
}
}
Empty file.
32 changes: 31 additions & 1 deletion frontend/packages/cli/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
import { ERDRenderer } from '@liam/erd-core'
import { useEffect, useState } from 'react'

function App() {
return <ERDRenderer />
const [fileContent, setFileContent] = useState<string | null>(null)

useEffect(() => {
async function loadSchemaContent() {
const response = await fetch('/schema.json')
const data = (await response.json()) || 'No file content available'
setFileContent(JSON.stringify(data, null, 2))
}

loadSchemaContent()
}, [])

return (
<>
<ERDRenderer />

{/* TODO: Remove this */}
{/* Display the file content in a pre tag for demo purposes */}
<pre
style={{
backgroundColor: '#f5f5f5',
padding: '10px',
borderRadius: '4px',
whiteSpace: 'pre-wrap',
}}
>
{fileContent || 'Loading...'}
</pre>
</>
)
}

export default App
2 changes: 2 additions & 0 deletions frontend/packages/cli/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"incremental": true,
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
Expand All @@ -13,6 +14,7 @@
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"outDir": "dist",
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
Expand Down
7 changes: 4 additions & 3 deletions frontend/packages/cli/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"incremental": true,
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"noEmit": false,
"strict": true,
"outDir": "dist-cli",
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
"include": ["vite.config.ts", "bin"]
}
Loading