45
loading...
This website collects cookies to deliver better user experience
# dependencias
$ yarn add ink ink-select-input ink-spinner ink-text-input react yaml fs-extra @babel/runtime
# dependencias de desarrollo
$ yarn add @babel/cli @babel/core @babel/node @babel/preset-env @babel/preset-react @babel/plugin-transform-runtime babel-loader nodemon --dev
{
"scripts": {
"build": "babel src -d dist",
"dev": "nodemon --no-stdin --exec babel-node src/index.js",
"start": "node ./dist/index.js"
}
}
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-transform-runtime"]
}
version: 1.0
templates:
- name: angular project
path: /angular
- name: react project
path: /react
- name: vue project
path: /vue
templates.generator
├── angular
├── react
└── vue
currentDirectory
: para ubicarnos en el directorio actual.templateDirectory
: Directorio donde se tendrá las plantillas.templateName
: Nombre del archivo de configuración.STEPS
: Pasos que se irán mostrando en el CLI.
//src/constants.js
export const currentDirectory = process.cwd();
export const templateDirectory = "templates.generator"
export const templateName = `${templateDirectory}.yaml`
export const STEPS = {
"NAME" : 1,
"SELECT" : 2,
"LOADING" : 3,
"END" : 4
}
//src/utils.js
import { currentDirectory, templateDirectory, templateName } from "./constants";
import fs from "fs";
import Yaml from "yaml";
import path from "path";
import fsExtra from "fs-extra"
export async function getTemplateGenerator() {
const file = fs.readFileSync(
path.join(currentDirectory, templateName),
"utf8"
);
const parseFile = Yaml.parse(file);
return formatPathsInTemplate(parseFile);
}
export function formatPathsInTemplate(json) {
const generator = { ...json };
generator.templates = generator.templates.map((template) => {
return {
...template,
path: path.join(currentDirectory,templateDirectory, template.path),
};
});
return generator.templates;
}
export function copyTemplateToCurrentDirectory({from,to}) {
return fsExtra.copy(from,path.join(currentDirectory,to))
}
//src/index.js
import React from "react";
import { render, Box, Text } from "ink";
const App = () => {
return(
<Box>
<Text>Hello world</Text>
</Box>
)
}
render(<App/>)
yarn dev
verémos en consola lo siguiente:$ Hello world
//src/core/state.js
import { STEPS } from "../constants";
export const state = {
step : STEPS.NAME,
templates: [],
directory: '.'
}
//src/core/reducer.js
export const ACTIONS = {
SET_TEMPLATES: "SET_TEMPLATES",
SET_STEP: "SET_STEP",
SET_NAME_DIRECTORY: "SET_NAME_DIRECTORY",
};
export function reducer(state, action) {
switch (action.type) {
case ACTIONS.SET_TEMPLATES:
return {
...state,
templates: action.payload,
};
case ACTIONS.SET_STEP:
return {
...state,
step: action.payload,
};
case ACTIONS.SET_NAME_DIRECTORY:
return {
...state,
directory: action.payload
}
default:
return state;
}
}
//src/useGenerator.js
import { useReducer } from "react";
import { STEPS } from "./constants";
import { ACTIONS, reducer } from "./core/reducer";
import { state as initialState } from "./core/state";
import { copyTemplateToCurrentDirectory } from "./utils";
export default function useGenerator() {
const [state, dispatch] = useReducer(reducer, initialState);
const setDirectory = (payload) => {
dispatch({
type: ACTIONS.SET_NAME_DIRECTORY,
payload,
});
};
const setStep = (payload) => {
dispatch({
type: ACTIONS.SET_STEP,
payload,
});
};
const setTemplates = (payload) => {
dispatch({
type: ACTIONS.SET_TEMPLATES,
payload,
});
};
const onSelectTemplate = async ({value}) => {
try {
setStep(STEPS.LOADING);
await copyTemplateToCurrentDirectory({
from: value,
to: state.directory,
});
setStep(STEPS.END);
process.exit();
} catch (error) {
console.log(error.message);
}
}
const onCompleteTypingDirectory = () => {
setStep(STEPS.SELECT);
}
return {
onSelectTemplate,
onCompleteTypingDirectory,
state,
setTemplates,
setDirectory,
setStep,
dispatch
};
}
//src/index.js
import React, { useEffect, useMemo } from "react";
import { render, Box, Text } from "ink";
import Select from "ink-select-input";
import Loading from "ink-spinner";
import { getTemplateGenerator } from "./utils";
import { STEPS } from "./constants";
import Input from "ink-text-input";
import useGenerator from "./useGenerator";
//...
const App = () => {
const {
state,
setTemplates,
setDirectory,
onCompleteTypingDirectory,
onSelectTemplate,
} = useGenerator();
const templateItems = useMemo(
() =>
state.templates.map((template) => {
return {
label: template.name,
value: template.path,
};
}),
[state.templates]
);
useEffect(() => {
getTemplateGenerator().then(setTemplates);
}, []);
return(
<Box>
<Text>hello</Text>
</Box>
)
}
const App = () => {
/// ...
return (
<Box>
{state.step === STEPS.NAME && (
<Box>
<Text color="cyanBright">Name directory:</Text>
<Input
value={state.directory}
onChange={setDirectory}
onSubmit={onCompleteTypingDirectory}
/>
</Box>
)}
{state.step === STEPS.SELECT && (
<Box flexDirection="column">
<Box marginTop={1}>
<Text color="cyanBright">Select a template</Text>
</Box>
<Select items={templateItems} onSelect={onSelectTemplate} />
</Box>
)}
{state.step === STEPS.LOADING && (
<Box>
<Text color="yellowBright">
<Loading type="dots" />
<Loading type="dots" />
<Loading type="dots" />
</Text>
<Text color="yellow">Creando proyecto...</Text>
</Box>
)}
{state.step === STEPS.END && (
<Box paddingY={2}>
<Text color="rgb(50,220,230)">
====================== ✨ Proyecto creado!!! ✨ ======================
</Text>
</Box>
)}
</Box>
);
};
render(<App />);
yarn build
y después yarn start
para poder ver el funcionamiento. Y listo, lo logramos!! 😄🎉🎉.