crafter
Crafter is configurable and powerful file scaffolder. It can scaffold pretty much any ASCII file.
Crafter is based on :
- NodeJS
- @zouloux/cli to ask questions
- @zouloux/files for file manipulations
- stach for templating
Install
npm i -D @zouloux/crafter
Usage
craft $CRAFTER_PATH $APP_PATH
craft ./crafters/reflex/reflex-crafter.js ./src/my-app/
In package scripts
{
"scripts" : {
"craft-reflex": "craft ./crafters/reflex/reflex-crafter.js ./src/front/",
"craft-route": "craft ./crafters/fastify/fastify-crafter.js ./src/back/"
}
}
Crafter file
A Crafter file is a JS file which create craft actions. Craft actions create a menu for the user. A craft action can ask user questions and scaffold files from those questions.
crafters/reflex-crafter.js
import { askInput } from "@zouloux/cli"
// createCraftAction( crafterID:string, menuEntry:string, async (crafterRoot?:string, appPath?:string, env?:TEnv) => { ... } )
createCraftAction('symbol', 'Symbol (icons / logos ...)', async (craft, crafterRoot, appPath, env) => {
// Ask user for category name
const category = await askInput(
// Uses nicePrint to style text, @see https://github.com/zouloux/cli/blob/main/src/Output.ts#L67
// {u} -> underline
// {/} -> remove previous styling
// {d} -> dim
`Symbol {u}c{/}ategory folder ? {d}(use plural) ex: icons, logos ...`,
{ shortcuts: ['category', 'cat', 'c'], notEmpty: true }
);
// Ask user for symbol name
const name = await askInput(
`Symbol {u}n{/}ame ? {d}(use CamelCase, with category as suffix) ex : HomeIcon, BrandLogo, ...`,
{ shortcuts: ['name', 'n'], notEmpty: true }
);
// Scaffold with those parameters
// craft <GVars extends object>( vars:GVars, steps:TStep<GVars>[] )
craft({
// Those will be avaible in source template
category: category.toLowerCase(),
name: lowerCaseFirst( name ),
Name: upperCaseFirst( name ),
}, [
vars => [
// Source is templated with vars given
// relative to $CRAFTER_PATH from cli
`1-symbols/Name.tsx.template`,
// And templated file is written here
// relative to $APP_PATH from cli
`1-symbols/${vars.category}/${vars.Name}.tsx`
],
// Can have other steps (other files templated)
vars => [
// ...
]
])
})
Step can also be a custom async function without auto-templating
createCraftAction('app', 'App', async (craft, crafterRoot, appPath, env) => {
// Ask user questions
// ...
craft({
name: lowerCaseFirst( name )
}, [
// A step can be custom if it does not return a tuple
// Custom step ( no auto-templating, do anything you want using cli and files )
async (vars) => {
// Check if app already exists
if ( await FileFinder.exists( appPath ) )
throw new Error(`Reflex crafter, app ${vars.name} already exists`)
// Clone app template with all directories
const appTemplate = new Directory( path.join(crafterPath, '_app') )
const children = await appTemplate.children('all', { dot: true })
for ( const child of children )
await child.copyTo( appPath )
// Remove all gitkeeps
const gitKeeps = await FileFinder.find('file', `src/**/.gitkeep`, { dot: true })
for ( const gitKeep of gitKeeps )
await gitKeep.delete()
}
])
})
Templates
Those files are templated with vars
thanks to stach.
Template delimiters are {{varName}}
crafter/1-symbols/Name.tsx.template
import { h, DefaultReflexProps } from "@zouloux/reflex";
interface Props extends DefaultReflexProps {
}
export function {{Name}} ( props:Props ) {
return <svg fill="currentColor" viewBox="0 0 40 40"></svg>
}
Examples
See examples here :
To test example :
git clone https://github.com/zouloux/crafter
cd examples/simple
npm i
npm run craft
Legacy module loading
In case you have this error
(node:56647) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
Add "type": "module"
to your package.json
If this is not possible, use craft-legacy
instead of craft
in your package.json
scripts.