- Notifications
You must be signed in to change notification settings - Fork18
A JavaScript beautifier that can both infer coding style and transform code to reflect that style. You can also set style preferences explicitly in a variety of ways.
License
jednano/codepainter
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Code Painter is a JavaScript beautifier that can transform JavaScript filesinto the formatting style of your choice. Style settings can be supplied viapredefined styles, a custom JSON file, command line settings,EditorConfigsettings or it can even be inferred from one or more sample files. For example,you could provide a code snippet from the same project with which the new codeis intended to integrate.
It uses the excellentEsprima parser byAriya Hidayat and hiscontributors — thanks!
The name is inspired by Word's Format Painter, which does a similar job forrich text.
Code Painter requiresNode.js version 0.10.6 or above.
$ npm install codepainter
To access the command globally, do a global install:
$ npm install -g codepainter
*nix users might also have to add the following to their .bashrc file:
PATH=$PATH:/usr/local/share/npm/bin
You can see the usage in the CLI directly by typingcodepaint
orcodepaint --help
.
$ codepaint --help Code Painter beautifies JavaScript. Usage: codepaint [options] <command> Commands: infer [options] <globs>... Infer formatting style from file(s) xform [options] <globs>... Transform file(s) to specified style Options: -h, --help output help information -V, --version output version information$ codepaint infer --help Infer formatting style from file(s) Usage: infer [options] <globs>... Options: -h, --help output help information -d, --details give a detailed report with trend scores --ini use ini file format Examples: $ codepaint infer "**/*.js" $ codepaint infer "**/*view.js" "**/*model.js" $ codepaint infer -d "**/*.js" $ codepaint infer --ini "**/*.js"$ codepaint xform --help Transform file(s) to specified formatting style Usage: xform [options] <globs>... Options: -h, --help output help information -i, --infer <glob> code sample(s) to infer -p, --predef <name> cascade predefined style (e.g., idiomatic) -j, --json <path> cascade JSON style over predef style -s, --style <key>=<value> cascade explicit style over JSON -e, --editor-config cascade EditorConfig style over all others Examples: $ codepaint xform "**/*.js" $ codepaint xform "**/*view.js" "**/*model.js" $ codepaint xform %s "**/*.js" -i sample.js $ codepaint xform %s "**/*.js" -p idiomatic $ codepaint xform %s "**/*.js" -j custom.json $ codepaint xform %s "**/*.js" -s quote_type=null $ codepaint xform %s "**/*.js" -s indent_style=space -s indent_size=4 $ codepaint xform %s "**/*.js" -e
varcodepaint=require('codepainter');
Library usage is intended to be every bit the same as CLI usage, so you canexpect the same options and arguments that the CLI requires.
Example usage:
codepaint.infer('**/**.js',{details:true},function(inferredStyle){console.log(inferredStyle);});
Example usage:
codepaint.xform('input.js',{indent_size:4},function(err,xformed,skipped,errored){if(err){throwerr;}console.log('transformed:',xformed);console.log('skipped:',skipped);console.log('errored:',errored);});
The following example infers formatting style fromsample.js
and uses thatinferred style to transform all .js files under the current directory.
codepaint.infer('sample.js',function(inferredStyle){codepainter.xform('**/**.js',{style:inferredStyle});});
'sample.js' could also be an array or any readable stream.transform
is analias for thexform
method. You can use either one.
Great, so that's all nice and simple, but maybe you want to do something withthe output. We start by creating an instance of the Transformer class.
varTransformer=require('codepainter').Transformer;vartransformer=newTransformer();
Now, we can listen to any of the following events:
Every time one style cascades over another.
transformer.on('cascade',cascade);functioncascade(styleBefore,styleToMerge,styleType){// code here}
Every time a file is transformed.
transformer.on('transform',function(transformed,path){// code here}
transformer.on('error',function(err,inputPath){// code here}
When all transformations have taken place.
transformer.on('end',function(err,transformed,skipped,errored){// code here}
Of course, none of these events will fire if you don't perform the transform:
transformer.transform(globs, options);
$ codepaint infer "**/*.js"
Infers formatting style from all .js files under the current directory into asingle JSON object, which you can pipe out to another file if you want. It canthen be used in a transformation (below).
If you want to create an.editorconfig
file, use the--ini
flag:
$ codepaint infer --ini "**/*.js" > .editorconfig
Moving on to thexform
sub-command:
$ codepaint xform "**/*.js"
This doesn't transform any files, but it does show you how many files would beaffected by the glob you've provided. Globs absolutelymust be in quotes oryou will experience unexpected behavior!
$ codepaint xform -i infer.js "**/*.js"
Transforms all .js files under the current directory with the formatting styleinferred from infer.js
$ codepaint xform -p idiomatic "**/*.js"
Transforms all .js files under the current directory with a Code Painterpre-defined style. In this case, Idiomatic. The only other pre-defined stylesavailable at this time are mediawiki and hautelook.
$ codepaint xform -j custom.json "**/*.js"
Transforms all .js files under the current directory with a custom style inJSON format.
$ codepaint xform -s indent_style=space -s indent_size=4 "**/*.js"
Transforms all .js files under the current directory with 2 settings:indent_style=space
andindent_size=4
. You can specify as many settings asyou want and you can set values tonull
to disable them.
$ codepaint xform -e "**/*.js"
Transforms all .js files under the current directory with the EditorConfigsettings defined for each individual file.
Refer toEditorConfig Core Installation for installation instructions andEditorConfig for more information, including how to define and use.editorconfig
files.
$ codepaint xform -i infer.js -p idiomatic -j custom.json-s end_of_line=null -e "**/*.js"
As you can see, you can use as many options as you want. Code Painter willcascade your styles and report how the cascade has been performed, like so:
Inferred style: + indent_style = tab + insert_final_newline = true + quote_type = auto + space_after_anonymous_functions = false + space_after_control_statements = false + spaces_around_operators = false + trim_trailing_whitespace = false + spaces_in_brackets = false hautelook style: * indent_style = space + indent_size = 4 * trim_trailing_whitespace = true + end_of_line = lf = insert_final_newline = true = quote_type = auto * spaces_around_operators = true = space_after_control_statements = true = space_after_anonymous_functions = false * spaces_in_brackets = false Supplied JSON file: * space_after_control_statements = true = indent_style = space * indent_size = 3 Inline styles: x end_of_line = null Editor Config: + applied on a file-by-file basis ........................... REPORT: 27 files transformed
Tells CodePainter to skip the file (no formatting). This property reallyonly makes sense if you are using the--editor-config
CLI option. Thisallows you to, for example, skip a vendor scripts directory.
indent_style,indent_size,end_of_line,trim_trailing_whitespace andinsert_final_newline.
Refer toEditorConfig's documentation for more information.
Specifies what kind of quoting you would like to use for string literals:
console.log("Hello world!");// becomes console.log('Hello world!');
Adds proper escaping when necessary, obviously.
console.log('Foo "Bar" Baz');// becomes console.log("Foo \"Bar\" Baz");
Theauto setting infers the quoting with a precedence towardsinglemode.
console.log("Foo \"Bar\" Baz");// becomes console.log('Foo "Bar" Baz');console.log('Foo \'Bar\' Baz');// becomes console.log("Foo 'Bar' Baz");
Specifies whether or not there should be a space between if/for/while andthe following open paren:
If true:
if(x===4){}// becomes if (x === 4) {}
If false:
while(foo()){}// becomes while(foo()) {}
Specifies whether or not there should be a space between thefunction
keyword and the following parens in anonymous functions:
function(x){}// becomes function (x) {}
Specifies whether or not there should be spaces around operators such as+,=,+=,>=,!==
.
x=4;// becomes x=4;a>=b;// becomes a >= b;a>>2;// becomes a >> 2;
Unary operators!,~,+,-
are an exception to the rule; thus, no spacesare added. Also, any non-conditional:
operators do not receive a space(i.e., the switch...case operator and property identifiers):
switch(someVar){case'foo' :// becomes case 'foo':varx={foo :'bar'};// becomes {foo: 'bar'}break;}
Hybrid mode is mostly like thetrue setting, except it behaves asfalse on operators*,/,%
:
varx=4*2+1/7;// becomes var x = 4*2 + 1/7;
Specifies whether or not there should be spaces inside brackets, whichincludes(),[],{}
. Empty pairs of brackets will always be shortened.
If true:
if(x===4){}// becomes if ( x === 4 ) {}
If false:
if(x===4){}// becomes if (x === 4)
Thehybrid setting mostly reflects Idiomatic style. Refer toIdiomatic Style Manifesto.
On a unix command-line, you can transform a file from the stdin stream:
$ codepaint xform -s indent_size=2 < input.js
The stdout stream works a bit differently. Since Code Painter can transformmultiple files via glob syntax, it wouldn't make sense to output thetransformations of all those files to a single stream. Instead, only if youare using stdin as input and no-o, --output
option is provided will CodePainter send the transformation to the stdout stream:
$ codepaint xform -s indent_size=2 < input.js > output.js
Piping is supported as well:
$ codepaint xform -s indent_size=2 < input.js | othercommand`
Because Code Painter supports stdin and stdout streams, as explained above,Git "clean" and "smudge" filters can be used as well.
CAUTION: My personal experience has shown inconsistent results, so use withcaution! Also, please contact me if you figure out how to do this without anyhiccups.
First, change your.gitattributes
file to use your new filter. We'll call it"codepaint".
*.js filter=codepaint
Then, tell Git what the "codepaint" filter does. First, we will convert codeto tabs upon checkout with the "smudge" filter:
$ git config filter.codepaint.smudge "codepaint xform -s indent_style=tab"
Then, upon staging of files with the Git "clean" filter, the style is restoredto spaces and cleaned to reflect any other style preferences you may have set:
$ git config filter.codepaint.clean "codepaint xform -p style.json"
This allows you to work in the indentation of your preference without steppingon anyone's toes and checking in inconsistent indentation. Or maybe you haveyour own preference for spaces around operators? Smudge it to your preferenceand clean it to your company's formatting style.
WARNING: Git "clean" and "smudge" filters are bypassed with GitHub forWindows.
Refer toGit's documentation for more information on Git "smudge" and"clean" filters.
It is highly recommended that you use the EditorConfig approach to paintingyour code. To do so, do the following:
Place an.editorconfig
file at your project root. Refer to thisproject's.editorconfig file for a point of reference as to how thismight look. You can also scatter.editorconfig
files elsewherethroughout your project to prevent Code Painter from doing anytransformations (e.g., your vendor scripts folders). In this case, the.editorconfig
file would simply read:codepaint = false
.
Specify Code Painter in your devDependencies section of your package.json:
{"devDependencies": {"codepainter":"~0.3.15" }}
Define acodepaint
script in the scripts section of your package.json:
{"scripts": {"codepaint":"node node_modules/codepainter/bin/codepaint xform -e **/**.js" }}
If you have Code Painter installed globally, the command is as simple as:
{"scripts": {"codepaint":"codepaint xform -e **/**.js" }}
But Code Painter wouldn't install globally by default, so the firstapproach is the recommended one. Then, you can run Code Painter on yourentire project, consistently, with the following command:
$ npm run-script codepaint
Youcould runcodepaint
manually every time you want to do it, but youmight find this next.bashrc
shortcut more useful. The idea is to runthisgc
alias to a newly-definedcodepaint_git_commit
function. This,you do instead of runninggit commit
. The caveat is that you need tostage your changes withgit add
before doing so. This is because thecommand runscodepaint
only on staged.js
files. Aside from thiscaveat, you can commit things mostly the same as you were used to before.Now,gc
can paint your code before a commit and bail-out of the commitif there are issues with the process (e.g., JavaScript parse errors). Theidea of formatting code before a commit is definitely controversial, butif you choose to do so anyway, here's the neat trick to put in your.bashrc
file:
# Example usage: gc "initial commit"alias gc=codepaint_git_commitcodepaint_git_commit() {# 1. Gets a list of .js files in git staging and sends the list to CodePainter.# 2. CodePainter with the -e flag applies rules defined in your EditorConfig file(s).# 3. After CodePainter is done, your args are passed to the `git commit` command. jsfiles=$(git diff --name-only --cached| egrep'\.js$')if [$jsfiles ];then ./node_modules/codepainter/bin/codepaint xform -e$jsfilesfi git commit -m"$@"}
You could also compare Code Painter's output with the original file on a Gitpre-commit hook and reject the commit if the files don't match. Let's be realthough. This would happen almostevery time you commit and it would be aroyal pain in your workflow.
There are so many ways you could use Code Painter. How do you prefer to useCode Painter? Feel free to contact me, Jed, with tips or suggestions. Seepackage.json for contact information).
Code Painter can be used to enforce a formatting style in a number of creativeways. To failTravis CI if code does not comply with your organization'sstyle guide, the process would work something like this:
- Run Code Painter on the code base.
- Fail Travis if any file changes are detected. This encourages developersto run Code Painter before pushing code.
Running Code Painter with Travis is as simple as adding the command to thebefore_script
section of your.travis.yml
file:
before_script: -node node_modules/codepainter/bin/codepaint xform -e "**/**.js"
Notice I didn't use the commandnpm run-script codepaint
. This is becausethere were issues with the double-quoted glob being processed. If you find away around this, please let me know.
Next, you need to create a node script that exits the node process with anon-zero code if any changes are detected. This, we do withgit diff
:
varclc=require('cli-color');varspawn=require('child_process').spawn;vargit=spawn('git',['diff','--name-only']);git.stdout.setEncoding('utf8');git.stdout.on('data',exitWithErrorIfFilesHaveChanged);functionexitWithErrorIfFilesHaveChanged(data){console.log();console.log(clc.red('Error: The following files do not conform to the CompanyX style guide:'));console.log(data);process.exit(1);}
Finally, you can add this script to your.travis.yml
file in thescript
section:
script: -node gitdiff.js
Violä! Travis should now fail if code does not comply with your organization'sstyle guide.
Released under the MIT license.
About
A JavaScript beautifier that can both infer coding style and transform code to reflect that style. You can also set style preferences explicitly in a variety of ways.
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Languages
- JavaScript100.0%