chore: first commit
This commit is contained in:
@@ -1,105 +1,125 @@
|
||||
import { mkdir, rename, rm } from "node:fs/promises"
|
||||
/**
|
||||
* FSD Component Generator - Flat Structure
|
||||
*
|
||||
* Creates components with flat structure:
|
||||
* ComponentName/
|
||||
* ├── index.ts
|
||||
* ├── ComponentName.tsx
|
||||
* ├── ComponentName.module.scss
|
||||
* └── ComponentName.d.ts
|
||||
*
|
||||
* Usage: bun gc <layer> <ComponentName>
|
||||
* Example: bun gc entity ProjectCard
|
||||
*/
|
||||
|
||||
import { mkdir, writeFile } from "node:fs/promises"
|
||||
|
||||
const segments = "ui,model,api"
|
||||
const args = Bun.argv.slice(2)
|
||||
|
||||
function printUsageAndExit(): never {
|
||||
console.error(
|
||||
"Ошибка: Необходимо указать <название слоя> и <название компонента>",
|
||||
)
|
||||
console.log("Пример: bun gc features MyButton")
|
||||
console.error("Error: Please provide <layer> and <ComponentName>")
|
||||
console.log("Usage: bun gc <layer> <ComponentName>")
|
||||
console.log("Layers: shared, entity, feature, widget, page")
|
||||
console.log("Example: bun gc entity ProjectCard")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function runShell(command: string): void {
|
||||
console.log(`Выполняется: ${command}`)
|
||||
function getComponentPath(layer: string, component: string): string {
|
||||
const base = "./src/"
|
||||
|
||||
const result = Bun.spawnSync({
|
||||
cmd: ["sh", "-lc", command],
|
||||
stdin: "inherit",
|
||||
stdout: "inherit",
|
||||
stderr: "inherit",
|
||||
})
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
const suffix = result.signalCode ? ` (signal ${result.signalCode})` : ""
|
||||
throw new Error(`Команда завершилась с кодом ${result.exitCode}${suffix}`)
|
||||
switch (layer) {
|
||||
case "shared":
|
||||
return `${base}shared/ui/${component}`
|
||||
case "app":
|
||||
return `${base}app/${component}`
|
||||
case "entity":
|
||||
case "entities":
|
||||
return `${base}entities/${component}`
|
||||
case "feature":
|
||||
case "features":
|
||||
return `${base}features/${component}`
|
||||
case "widget":
|
||||
case "widgets":
|
||||
return `${base}widgets/${component}`
|
||||
case "page":
|
||||
case "pages":
|
||||
return `${base}pages/${component}`
|
||||
default:
|
||||
return `${base}${layer}s/${component}`
|
||||
}
|
||||
}
|
||||
|
||||
function generateIndexTemplate(component: string): string {
|
||||
return `export * from "./${component}"
|
||||
`
|
||||
}
|
||||
|
||||
function generateComponentTemplate(component: string): string {
|
||||
return `import type { I${component}Props } from "./${component}.d"
|
||||
import type { JSX } from "react"
|
||||
|
||||
import { FunctionComponent } from "react"
|
||||
|
||||
import styles from "./${component}.module.scss"
|
||||
|
||||
export const ${component}: FunctionComponent<I${component}Props> = (): JSX.Element => {
|
||||
return (
|
||||
<div className={styles.root} data-testid="${component}">
|
||||
${component}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
function generateTypesTemplate(component: string): string {
|
||||
return `export interface I${component}Props {
|
||||
className?: string
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
function generateStylesTemplate(): string {
|
||||
return `.root {
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
printUsageAndExit()
|
||||
}
|
||||
|
||||
const layer = args[0]
|
||||
const component = args[1]
|
||||
const otherArgs = args.slice(2).join(" ")
|
||||
const componentPath = getComponentPath(layer, component)
|
||||
|
||||
let componentPath = "./src/"
|
||||
console.log(`Creating ${component} in ${componentPath}...`)
|
||||
|
||||
if (layer === "shared") {
|
||||
componentPath += `${layer}/ui/${component}`
|
||||
} else if (layer === "app") {
|
||||
componentPath += `${layer}/${component}`
|
||||
} else if (layer === "entity" || layer === "entities") {
|
||||
componentPath += `entities/${component}`
|
||||
} else {
|
||||
componentPath += `${layer}s/${component}`
|
||||
}
|
||||
|
||||
const fsdCommand = `fsd ${layer} ${component} ${otherArgs} --segments ${segments} -r src`
|
||||
|
||||
if (layer !== "shared") {
|
||||
try {
|
||||
runShell(fsdCommand)
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await mkdir(componentPath, { recursive: true })
|
||||
console.log("Пропущен fsd для shared: создаем компонент вручную")
|
||||
}
|
||||
|
||||
console.log(`Удаление индекс файла: ${componentPath}/index.ts`)
|
||||
await Promise.all([
|
||||
writeFile(`${componentPath}/index.ts`, generateIndexTemplate(component)),
|
||||
writeFile(
|
||||
`${componentPath}/${component}.tsx`,
|
||||
generateComponentTemplate(component),
|
||||
),
|
||||
writeFile(
|
||||
`${componentPath}/${component}.d.ts`,
|
||||
generateTypesTemplate(component),
|
||||
),
|
||||
writeFile(
|
||||
`${componentPath}/${component}.module.scss`,
|
||||
generateStylesTemplate(),
|
||||
),
|
||||
])
|
||||
|
||||
try {
|
||||
await rm(`${componentPath}/index.ts`, { force: true })
|
||||
console.log(`✅ Created ${component}:`)
|
||||
console.log(` ${componentPath}/index.ts`)
|
||||
console.log(` ${componentPath}/${component}.tsx`)
|
||||
console.log(` ${componentPath}/${component}.d.ts`)
|
||||
console.log(` ${componentPath}/${component}.module.scss`)
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const createTsx = `bunx generate-react-cli component ${component} --flat --path ${componentPath}`
|
||||
|
||||
try {
|
||||
runShell(createTsx)
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log("Перемещение файлов...")
|
||||
|
||||
const oldPath = `${componentPath}/${component}`
|
||||
const newPath = `${componentPath}`
|
||||
|
||||
try {
|
||||
await mkdir(`${newPath}/ui`, { recursive: true })
|
||||
await mkdir(`${newPath}/model`, { recursive: true })
|
||||
|
||||
await rename(`${oldPath}.tsx`, `${newPath}/ui/${component}.tsx`)
|
||||
console.log("TSX файл перемещен")
|
||||
|
||||
await rename(
|
||||
`${oldPath}.module.scss`,
|
||||
`${newPath}/ui/${component}.module.scss`,
|
||||
)
|
||||
console.log("SCSS файл перемещен")
|
||||
|
||||
await rename(`${oldPath}.d.ts`, `${newPath}/model/${component}.d.ts`)
|
||||
console.log("D.TS файл перемещен")
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
console.error(`Error: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import { mkdir, rename, rm } from "node:fs/promises"
|
||||
|
||||
const segments = "ui,model,api"
|
||||
const args = Bun.argv.slice(2)
|
||||
|
||||
function printUsageAndExit(): never {
|
||||
console.error(
|
||||
"Ошибка: Необходимо указать <название слоя> и <название компонента>",
|
||||
)
|
||||
console.log("Пример: bun gc features MyButton")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function runShell(command: string): void {
|
||||
console.log(`Выполняется: ${command}`)
|
||||
|
||||
const result = Bun.spawnSync({
|
||||
cmd: ["sh", "-lc", command],
|
||||
stdin: "inherit",
|
||||
stdout: "inherit",
|
||||
stderr: "inherit",
|
||||
})
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
const suffix = result.signalCode ? ` (signal ${result.signalCode})` : ""
|
||||
throw new Error(`Команда завершилась с кодом ${result.exitCode}${suffix}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
printUsageAndExit()
|
||||
}
|
||||
|
||||
const layer = args[0]
|
||||
const component = args[1]
|
||||
const otherArgs = args.slice(2).join(" ")
|
||||
|
||||
let componentPath = "./src/"
|
||||
|
||||
if (layer === "shared") {
|
||||
componentPath += `${layer}/ui/${component}`
|
||||
} else if (layer === "app") {
|
||||
componentPath += `${layer}/${component}`
|
||||
} else if (layer === "entity" || layer === "entities") {
|
||||
componentPath += `entities/${component}`
|
||||
} else {
|
||||
componentPath += `${layer}s/${component}`
|
||||
}
|
||||
|
||||
const fsdCommand = `fsd ${layer} ${component} ${otherArgs} --segments ${segments} -r src`
|
||||
|
||||
if (layer !== "shared") {
|
||||
try {
|
||||
runShell(fsdCommand)
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
} else {
|
||||
await mkdir(componentPath, { recursive: true })
|
||||
console.log("Пропущен fsd для shared: создаем компонент вручную")
|
||||
}
|
||||
|
||||
console.log(`Удаление индекс файла: ${componentPath}/index.ts`)
|
||||
|
||||
try {
|
||||
await rm(`${componentPath}/index.ts`, { force: true })
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const createTsx = `bunx generate-react-cli component ${component} --flat --path ${componentPath}`
|
||||
|
||||
try {
|
||||
runShell(createTsx)
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log("Перемещение файлов...")
|
||||
|
||||
const oldPath = `${componentPath}/${component}`
|
||||
const newPath = `${componentPath}`
|
||||
|
||||
try {
|
||||
await mkdir(`${newPath}/ui`, { recursive: true })
|
||||
await mkdir(`${newPath}/model`, { recursive: true })
|
||||
|
||||
await rename(`${oldPath}.tsx`, `${newPath}/ui/${component}.tsx`)
|
||||
console.log("TSX файл перемещен")
|
||||
|
||||
await rename(
|
||||
`${oldPath}.module.scss`,
|
||||
`${newPath}/ui/${component}.module.scss`,
|
||||
)
|
||||
console.log("SCSS файл перемещен")
|
||||
|
||||
await rename(`${oldPath}.d.ts`, `${newPath}/model/${component}.d.ts`)
|
||||
console.log("D.TS файл перемещен")
|
||||
} catch (error) {
|
||||
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
Reference in New Issue
Block a user