Skip to content

Commit

Permalink
feat(cli): ✨ add monorepo lib generator
Browse files Browse the repository at this point in the history
  • Loading branch information
recallwei committed Jun 29, 2024
1 parent 99467c3 commit 8602fe3
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 29 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"release:generate": "pnpm changeset",
"release:version": "pnpm changeset version",
"release:publish": "pnpm build:packages && pnpm changeset publish",
"bo:cspell": "pnpm bo cspell",
"cz": "git-cz",
"prepare": "husky"
},
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/assets/templates/monorepo-lib/README.md.hbs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# @{{ org }}/{{ name }}
# @{{ packageOrgName }}/{{ packageName }}

![npm](https://img.shields.io/npm/v/@{{ org }}/{{ name }}?logo=typescript&label={{ name}})
![npm](https://img.shields.io/npm/v/@{{ org }}/{{ packageName }}?logo=typescript&label={{ packageName }})

> {{ description }}
> {{ pacakgeDescription }}

## Installation

```bash
pnpm add @{{ org }}/{{ name }}
pnpm add @{{ org }}/{{ packageName }}
```

## License
Expand Down
10 changes: 5 additions & 5 deletions packages/cli/assets/templates/monorepo-lib/package.json.hbs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"name": "{{ name }}",
"name": "@{{ packageOrgName }}/{{ packageName }}",
"version": "0.0.0",
"description": "{{ description }}",
"description": "{{ packageDescription }}",
"author": "Bruce Song <recall4056@gmail.com> (https://github.com/recallwei/)",
"homepage": "https://github.com/{{ org }}/{{ repo }}#readme",
"bugs": "https://github.com/{{ org }}/{{ repo }}/issues",
"repository": {
"type": "git",
"url": "https://github.com/{{ org }}/infra.git",
"directory": "packages/{{ name }}"
"directory": "packages/{{ packageName }}"
},
"keywords": [
"{{ org }}",
"{{ name }}"
"{{ packageOrgName }}",
"{{ packageName }}"
],
"files": [
"dist"
Expand Down
35 changes: 31 additions & 4 deletions packages/cli/src/generators/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,29 @@ export const g = async () => {
},
{
type: (_, values) => (values.action === ActionChoice.MONOREPO_LIB ? 'text' : null),
name: 'name',
name: 'packageName',
message: 'Enter the lib name:',
initial: 'my-lib'
},
{
type: (_, values) => (values.action === ActionChoice.MONOREPO_LIB ? 'text' : null),
name: 'packageDescription',
message: 'Enter the lib description:',
initial: 'My lib description.'
},
{
type: (_, values) => (values.action === ActionChoice.MONOREPO_LIB ? 'text' : null),
name: 'packageOrgName',
message: 'Enter the npm org name:',
initial: gitRepoInfo.org,
hint: (_, values) => `Your lib name will be: @${values.packageOrgName}/${values.packageName}`
},
{
type: (_, values) => (values.action === ActionChoice.CONFIG ? 'text' : null),
name: 'repo',
message: 'Enter the GitHub repository name:',
initial: gitRepoInfo.repo
},
{
type: (_, values) => (values.action === ActionChoice.CONFIG ? 'text' : null),
name: 'org',
Expand All @@ -57,13 +76,21 @@ export const g = async () => {
}
])

const { action, name, org, repo } = response
const {
action,
packageName,
packageOrgName,
packageDescription,
org = gitRepoInfo.org,
repo = gitRepoInfo.repo
} = response

switch (action) {
case ActionChoice.MONOREPO_LIB:
generateMonorepoLib({
name,
description: '123',
packageName,
packageOrgName,
packageDescription,
repo,
org
})
Expand Down
107 changes: 92 additions & 15 deletions packages/cli/src/generators/monorepo-lib.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,111 @@
import { readdir, readFile, writeFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'
import { join, relative, resolve } from 'node:path'
import { cwd } from 'node:process'

import Handlebars from 'handlebars'

import { Logger } from '@/utils'

interface GenerateMonorepoLibOptions {
name: string
description: string
packageName: string
packageOrgName: string
packageDescription: string
org: string
repo: string
}

interface PathInfo {
type: 'dir' | 'file'
path: string
relativePath: string
level: number
}

enum PathType {
DIR = 'dir',
FILE = 'file'
}

export const generateMonorepoLib = async (options: GenerateMonorepoLibOptions) => {
const { name } = options
const { packageName } = options
const sourcePath = resolve(import.meta.dirname, '../assets/templates/monorepo-lib')
const targetPath = resolve(cwd(), 'bit-ocean.config.js', '../packages', name)
const targetPath = resolve(cwd(), 'bit-ocean.config.js', '../packages', packageName)

try {
const templatePaths = await readdir(sourcePath, {
recursive: true
})

const processTemplateFile = async (file: string) => {
const templateContent = await readFile(file, 'utf-8')
const renderedContent = Handlebars.compile(templateContent)(options)
await writeFile(resolve(targetPath, file), renderedContent)
const templatePaths = await getTemplatePaths(sourcePath)

const processTemplateFile = async (p: PathInfo) => {
const targetWritePath = resolve(targetPath, p.relativePath)
let byteCount: number = 0
if (p.type === PathType.DIR) {
await mkdir(targetWritePath)
} else {
const templateContent = await readFile(p.path, 'utf-8')
const renderedContent = Handlebars.compile(templateContent)(options)
await writeFile(targetWritePath, renderedContent)
byteCount = Buffer.byteLength(renderedContent, 'utf-8')
}
Logger.success(
`CREATED ${relative(cwd(), targetWritePath)}${byteCount ? ` (${byteCount} bytes)` : ''}`
)
}

// TODO: Check if the target path already exists, and if so, ask the user if they want to overwrite it
try {
await rm(targetPath, { recursive: true })
} catch {
//
}

await Promise.all(templatePaths.map(processTemplateFile))
await mkdir(targetPath)

while (templatePaths.length) {
// eslint-disable-next-line no-await-in-loop
await processTemplateFile(templatePaths.shift()!)
}
} catch (err) {
Logger.error(err as Error)
}
}

async function getTemplatePaths(rootPath: string) {
const results: PathInfo[] = []

async function traverseDirectory(currentPath: string, level = 0) {
try {
const entries = await readdir(currentPath, { withFileTypes: true })

const entryPromise = entries.map(async (entry) => {
const entryPath = join(currentPath, entry.name)
const relativePath = relative(
rootPath,
entryPath.endsWith('.hbs') ? entryPath.slice(0, -4) : entryPath
)

if (entry.isDirectory()) {
results.push({
type: PathType.DIR,
path: entryPath,
relativePath,
level
})
await traverseDirectory(entryPath, level + 1)
} else {
results.push({
type: PathType.FILE,
path: entryPath,
relativePath,
level
})
}
})

await Promise.all(entryPromise)
} catch (err) {
Logger.error(err as Error)
}
}

await traverseDirectory(rootPath)
return results.toSorted((a, b) => a.level - b.level)
}

0 comments on commit 8602fe3

Please sign in to comment.