A simple and customizable scaffolding tool for all languages and frameworks
Battlecry is a cross-platform tool for automating repetitive software development tasks.
Designed to boost developers' performance, Battlecry provides an interface for creating simple and customizable commands that can perform any type of action. Since most of the time developers need to create
, copy
, move
, edit
or delete
text files, Battlecry already comes with file helpers that make templating a breeze.
Note: Battlecry got renamed from Samba to avoid confusions with the Samba Linux software
- ✅ Perfect for creating new modules, components and even new projects
- ✅ Easy to share with your team through your favorite version control system
- ✅ Use it with all languages and frameworks
- ✅ Plug'n play customizable generators
- ✅ Simple & Powerful API
- ✅ Next generation naming with casex
Why not just use Yeoman?
Yeoman is a great tool for creating new projects, but when it comes to updating ongoing projects, I think there's a lot of room for improvement. If you want to use a framework with a strict set of libraries and requirements you can probably find a Yeoman generator that suits you, but you won't be able to customize these generators with ease.
In my experience, the farther you go on a project, the more you'll need to shape your generators to fit it. Each project has it's own requirements and it's only fair that it get it's own generators. With Battlecry you can create your own or download generators to give you a nice quickstart, and when you need to customize them, it's very easy to do so and you can share the changes with your whole team.
Each example can be downloaded with cry download generator examples/example_name_here
.
- args: Working with arguments
- options: Working with options
- multiple-templates: Working with multiple template files
- aliases: Creating your own method aliases
- helpers: Using helpers to share methods across generators
- call-other-generators: Using one generator to call multiple generators in a clean fashion
- exec: Executing a command line
- load: Loading generators from a folder other than
battlecry/
Advanced examples
- [WIP] - advanced-crud: Make magical CRUDs
- NodeJS installed
🎩 If your project does not use NodeJS don't worry! Battlecry's API is very simple and you'll only need NodeJS installed to run the commands, no need to change your project setup.
npm install -g battlecry
Battlecry has a very simple structure.
cry <method> <generator> arguments --options
Battlecry can be used through both battlecry
and it's short verion cry
.
With BattleCry installed, go to your project folder and run:
cry g init
This will perform four actions:
- Create a
battlecry
folder on the root of your project - Add a
battlecry/battlecry-setup.js
that you can use to add special configurations - Create a generator called
component
- Play the just created
component
with the argtest-abc
You should now be able to see a file called it-worked/components/test-abc.txt
. This file was created using the generator at battlecry/generators/component.generator.js
folder.
Note: BattleCry uses ES6 with lots of polyfill, so most things should ✨ just work ✨ on your generator class.
If you need to check how your methods are registered, you can do so with:
cry --help
This project uses casex, an open source library designed to be an All in one function for transforming word casings
. You may see many functions that can optionally receive name?: string
. This means that all occurrences of the __name__
pattern will be substituted using casex
if the name
parameter is provided.
Here are a few examples of how it works, considering you're using the name John Doe
:
__name__
: johndoe__naMe__
: johnDoe__NaMe__
: JohnDoe__na-me__
: john-doe__na me__
: john doe
BattleCry provides pluralization and singularization out of the box with pluralize.
To use this feature, instead of __name__
, use _name_
, with one underscore. Here are a few examples of how it works:
- Regulars:
user
_name_
: user_name_s
: users
- Irregulars:
person
_name_
: person_name_s
: people
- Composed names:
user name
_na me_
: user name_na me_s
: user names
- Names in the plural:
users
_na me_
: user_na me_s
: users
cry g generator your_generator_name_here
This command will create a battlecry/generators/your_generator_name_here
Each generator must have a config
variable defining all BattleCry methods.
config = {
options?: {
[name: string]: {
description: string,
arg?: 'required' | 'optional', // An option may receive an argument
alias?: string // Defaults to the first letter of the option name
}
},
args?: string, // name ...surnames?
description?: string
}
files(pattern: string, name?: ?string, globOptions?: Object): File[]
: Get files that matchpattern
file(pattern: string, name?: ?string, globOptions?: Object): File
: Get first file that matchespattern
delete(path: string, name?: string): void
: Delete a file or directory
templates(pattern?: string, globOptions?: Object): File[]
: Get files inside the generator'stemplates/
subdirectorytemplate(pattern?: string, globOptions?: Object): File
: Get first file that matches the pattern
As you may have noticed, most of these methods return one or an array of File(s). For more details about the File
class API, please check the [File API](#File API) section below.
Note: BattleCry performs all IO operations synchronously
By default BattleCry lists all files except for .DS_Store
(created on OSX).
If you need to provide custom globOptions
, please refer to the list of options is available on the node-glob (this is the library used to do globbing on BattleCry) repository: https://github.com/isaacs/node-glob#options
There may be cases when you may want to call multiple generators from one generators. BattleCry provides nice helpers for you to accomplish that in you Generator
class.
generator(name: string): Generator
: Get a new generator instance by namesetArgs(args: Object): this
: Setup generator arguments to be consumed whenplay
is calledsetOptions(options: Object): this
: Setup generator options to be consumed whenplay
is calledplay(methodName: string)
: Play a generator method
In some cases you may wanna call command lines directly.
exec(command: string): string | Buffer
: Execute command line
Both text files and binaries (such as images) are supported out of the box.
In most cases you'll use the file helpers on the generator. But if you need to create it manually:
constructor(path: string, name?: string)
get binary(): boolean
: Check if it's a binary or text fileget exists(): boolean
: Check if the file existsget filename(): string
: Get file nameget dirname(): string
: Get file directory pathget extension(): string
: Get file extension
save(): void
: Save file changes on it's current pathsaveAs(path: string, name?: string): File
: Save file on a different pathdelete(): void
: Delete file
Tip: When using saveAs
, you can end the path with /
and BattleCry will add the current filename.
Lot's of text
helpers receive search: number | string
. This means that if a number is provided it assumes it as being a line number, otherwise it wil search for a line with the given string or throw an error.
get text(): string
: Get content as textset text(text: string): void
: Set content as string (Eg.file.text = 'abc'
)
get lines(): string[]
: Return file text split by lineset lines(lines: string[]): void
: Set file text from an array of lines (Eg.file.lines = ['a', 'b', 'c']
)
replaceText(search: string | RegExp, replace: string, name?: string): this
: Replace one text ocurrencereplaceAllText(search: string, replace: string, name?: string): this
: Replace all text occurrencesreplaceNames(name: string): this
: Replace casex namings
search(search: string | number, name?: string): number
: Get line number of the first line includingsearch
last(search: string | number, name?: string): number
: Likesearch
, but starting from the last line
before(search: string | number, text: string | string[], name?: string): this
: Add text before given linebeforeLast(search: string | number, text: string | string[], name?: string): this
: Likebefore
, but usinglast
after(search: number | string, text: string | string[], name?: string): this
: Add text after given lineafterLast(search: number | string, text: string | string[], name?: string): this
: Likeafter
, but usinglast
prepend(text: string | string[], name?: string): this
: Add text at the beginning of the fileappend(text: string | string[], name?: string): this
: Add text at the end of the file
replace(search: string | number, text: string | string[], name?: string): this
: Replace line with a given textreplaceLast(search: string | number, text: string | string[], name?: string): this
: Likereplace
, but usinglast
remove(search: string | number, name?: string): this
: Remove line (search
method is called to resolve line number)removeLast(search: string | number, name?: string): this
: Likeremove
, but usinglast
Note: If you attempt to use any text helper in a binary file (such as an image), BattleCry will throw an error.
It's not uncommon to have multiple generators share similar helpers. To facilitate you doing that, you can include files from your BattleCry directory directly, without navigating with ..
.
If you have a testHelper.js
file under BattleCry/helpers/testHelper.js
for instance, you could include it as:
import testHelper from 'helpers/testHelper';
You may not have to write all your generators yourself. BattleCry comes with a handy tool for downloading generators from GitHub.
cry download generator owner/path
If you want to a service provider other then GitHub, please check the download-git-repo examples
BattleCry looks for a battlecry/
folder in the repository root. If none is found it defaults to the repository root. You may also set a custom directory to start BattleCry's search with --dir
.
cry download generator owner/path --dir test-battlecry
export default function setup(battlecry) {
battlecry.load('node_modules/battlecry-generatores-from-node-modules');
}
By default BattleCry comes with two aliases: g: generate
and d: destroy
. You can both override these aliases and/or create new ones.
export default function setup(battlecry) {
battlecry.aliases.s = 'strike';
// You can now use `cry s component` and it will be translated to `cry strike component`
}
BattleCry values convention over configuration, so it comes with the following optinos by default: { dot: true, ignore: ['**/.DS_Store'] }
. This means that files starting with .
, such as .babelrc
will be included on your list (if it matches the pattern provided).
export default function setup(battlecry) {
battlecry.globOptions({ dot: false, nocase: false });
}
For a complete list of options available, please refer to https://github.com/isaacs/node-glob#options.
Sometimes you may need to apply casex namings separetely. This usually happens when you want to apply casex naming to two different values in the same line or piece of text.
import { namedCasex } from 'battlecry';
namedCasex(text: string, name?: string);
Battlecry exports a few internal methods and libraries that it uses.
You can import them in case you need to so something that can't be covered by file or generator helpers.
-
Battlecry classes
-
namedCasex
internal methods: