chore: init read-star monorepo

This commit is contained in:
2026-01-16 13:06:44 +08:00
commit 1e510efe8e
508 changed files with 44803 additions and 0 deletions

View File

@ -0,0 +1,11 @@
import type { ChangelogOption } from '@soybeanjs/changelog'
import { generateChangelog, generateTotalChangelog } from '@soybeanjs/changelog'
export async function genChangelog(options?: Partial<ChangelogOption>, total = false) {
if (total) {
await generateTotalChangelog(options)
}
else {
await generateChangelog(options)
}
}

View File

@ -0,0 +1,5 @@
import { rimraf } from 'rimraf'
export async function cleanup(paths: string[]) {
await rimraf(paths, { glob: true })
}

View File

@ -0,0 +1,85 @@
import type { Lang } from '../locales'
import { readFileSync } from 'node:fs'
import path from 'node:path'
import { prompt } from 'enquirer'
import { locales } from '../locales'
import { execCommand } from '../shared'
interface PromptObject {
types: string
scopes: string
description: string
}
/**
* Git commit with Conventional Commits standard
*
* @param lang
*/
export async function gitCommit(lang: Lang = 'en-us') {
const { gitCommitMessages, gitCommitTypes, gitCommitScopes } = locales[lang]
const typesChoices = gitCommitTypes.map(([value, msg]) => {
const nameWithSuffix = `${value}:`
const message = `${nameWithSuffix.padEnd(12)}${msg}`
return {
name: value,
message,
}
})
const scopesChoices = gitCommitScopes.map(([value, msg]) => ({
name: value,
message: `${value.padEnd(30)} (${msg})`,
}))
const result = await prompt<PromptObject>([
{
name: 'types',
type: 'select',
message: gitCommitMessages.types,
choices: typesChoices,
},
{
name: 'scopes',
type: 'select',
message: gitCommitMessages.scopes,
choices: scopesChoices,
},
{
name: 'description',
type: 'text',
message: gitCommitMessages.description,
},
])
const breaking = result.description.startsWith('!') ? '!' : ''
const description = result.description.replace(/^!/, '').trim()
const commitMsg = `${result.types}(${result.scopes})${breaking}: ${description}`
await execCommand('git', ['commit', '-m', commitMsg], { stdio: 'inherit' })
}
/** Git commit message verify */
export async function gitCommitVerify(lang: Lang = 'en-us', ignores: RegExp[] = []) {
const gitPath = await execCommand('git', ['rev-parse', '--show-toplevel'])
const gitMsgPath = path.join(gitPath, '.git', 'COMMIT_EDITMSG')
const commitMsg = readFileSync(gitMsgPath, 'utf8').trim()
if (ignores.some(regExp => regExp.test(commitMsg)))
return
const REG_EXP = /(?<type>[a-z]+)(?:\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i
if (!REG_EXP.test(commitMsg)) {
const errorMsg = locales[lang].gitCommitVerify
throw new Error(errorMsg)
}
}

View File

@ -0,0 +1,6 @@
export * from './changelog'
export * from './cleanup'
export * from './git-commit'
export * from './release'
export * from './router'
export * from './update-pkg'

View File

@ -0,0 +1,12 @@
import { versionBump } from 'bumpp'
export async function release(execute = 'pnpm sa changelog', push = true) {
await versionBump({
files: ['**/package.json', '!**/node_modules'],
execute,
all: true,
tag: true,
commit: 'chore(projects): release v%s',
push,
})
}

View File

@ -0,0 +1,91 @@
import { existsSync, mkdirSync } from 'node:fs'
import { writeFile } from 'node:fs/promises'
import path from 'node:path'
import process from 'node:process'
import { prompt } from 'enquirer'
import { green, red } from 'kolorist'
interface PromptObject {
routeName: string
addRouteParams: boolean
routeParams: string
}
/** generate route */
export async function generateRoute() {
const result = await prompt<PromptObject>([
{
name: 'routeName',
type: 'text',
message: 'please enter route name',
initial: 'demo-route_child',
},
{
name: 'addRouteParams',
type: 'confirm',
message: 'add route params?',
initial: false,
},
])
if (result.addRouteParams) {
const answers = await prompt<PromptObject>({
name: 'routeParams',
type: 'text',
message: 'please enter route params',
initial: 'id',
})
Object.assign(result, answers)
}
const PAGE_DIR_NAME_PATTERN = /^[\w-]+[0-9a-z]$/i
if (!PAGE_DIR_NAME_PATTERN.test(result.routeName)) {
throw new Error(`${red('route name is invalid, it only allow letters, numbers, "-" or "_"')}.
For example:
(1) one level route: ${green('demo-route')}
(2) two level route: ${green('demo-route_child')}
(3) multi level route: ${green('demo-route_child_child')}
(4) group route: ${green('_ignore_demo-route')}'
`)
}
const PARAM_REG = /^\w+$/g
if (result.routeParams && !PARAM_REG.test(result.routeParams)) {
throw new Error(red('route params is invalid, it only allow letters, numbers or "_".'))
}
const cwd = process.cwd()
const [dir, ...rest] = result.routeName.split('_') as string[]
let routeDir = path.join(cwd, 'src', 'views', dir)
if (rest.length) {
routeDir = path.join(routeDir, rest.join('_'))
}
if (!existsSync(routeDir)) {
mkdirSync(routeDir, { recursive: true })
}
else {
throw new Error(red('route already exists'))
}
const fileName = result.routeParams ? `[${result.routeParams}].vue` : 'index.vue'
const vueTemplate = `<script setup lang="ts"></script>
<template>
<div>${result.routeName}</div>
</template>
<style scoped></style>
`
const filePath = path.join(routeDir, fileName)
await writeFile(filePath, vueTemplate)
}

View File

@ -0,0 +1,5 @@
import { execCommand } from '../shared'
export async function updatePkg(args: string[] = ['--deep', '-u']) {
execCommand('npx', ['npm-check-updates', ...args], { stdio: 'inherit' })
}