jcberquist / commandbox-cfformat Goto Github PK
View Code? Open in Web Editor NEWA CommandBox module for formatting CFML component files.
License: MIT License
A CommandBox module for formatting CFML component files.
License: MIT License
Input:
if (isTrue(url.debug ?: false)) {
setting showdebugoutput="true";
};
Output:
if (isTrue(url.debug ?: false)) {
setting showdebugoutput="true";
}
;
Expected:
if (isTrue(url.debug ?: false)) {
setting showdebugoutput="true";
};
In a CI environment, we'd like to fail the build if there are any formatting changes CFFormat would make. We do not want to overwrite the formatting in CI because this would likely create git conflicts.
I see the message looking something like the following:
The following files do not match the cfformat rules:
/app/models/Foo.cfc
/app/handlers/Main.cfc
Please format the files using the `—overwrite` flag.
This line of code throws an error that 1 doesn't exist on tag-based code where a comment is inside of another comment.
https://github.com/jcberquist/commandbox-cfformat/blob/master/models/cftags/TagComments.cfc#L20
like so
<!--- test
<!--- moar comments
--->
--->
The array on the line above expects to find only nested arrays, but instead, nested structs are present which cannot be indexed as t[1]
.
Our house coding style stipulates alignment of multiline arguments or struct items on the separator. For example:
doSomething(
arg1 = ""
, argument2 = ""
, aThirdArgument = ""
);
should be formatted as:
doSomething(
arg1 = ""
, argument2 = ""
, aThirdArgument = ""
);
We also align argument declarations like so:
function doSomething(
required string id
, required numeric numberValue
, string optionalValue
) {
// do something...
}
Would it be possible to implement this in CFFormat? We also try to align multiple variable declarations in the same way, but I understand that might be beyond the scope of an automatic procedure...
Hi @jcberquist just wanted to report some weird alignment issues. Please see attached screenshot. The correct alignments look really bad for properties where we use line breaks to align.
Here is our .cfformat.json
{
"array.empty_padding": false,
"array.padding": true,
"array.multiline.min_length": 40,
"array.multiline.element_count": 4,
"array.multiline.leading_comma.padding": true,
"array.multiline.leading_comma": false,
"alignment.consecutive.assignments": true,
"alignment.consecutive.properties": true,
"alignment.consecutive.params": true,
"brackets.padding": true,
"comment.asterisks": "align",
"binary_operators.padding": true,
"for_loop_semicolons.padding": true,
"function_call.empty_padding": false,
"function_call.padding": true,
"function_call.multiline.leading_comma.padding": true,
"function_call.casing.builtin": "cfdocs",
"function_call.casing.userdefined": "",
"function_call.multiline.element_count": 4,
"function_call.multiline.leading_comma": false,
"function_call.multiline.min_length": 40,
"function_declaration.padding": true,
"function_declaration.empty_padding": false,
"function_declaration.multiline.leading_comma": false,
"function_declaration.multiline.leading_comma.padding": true,
"function_declaration.multiline.element_count": 4,
"function_declaration.multiline.min_length": 40,
"function_declaration.group_to_block_spacing": "compact",
"function_anonymous.empty_padding": false,
"function_anonymous.group_to_block_spacing": "compact",
"function_anonymous.multiline.element_count": 4,
"function_anonymous.multiline.leading_comma": false,
"function_anonymous.multiline.leading_comma.padding": true,
"function_anonymous.multiline.min_length": 40,
"function_anonymous.padding": true,
"indent_size": 4,
"keywords.block_to_keyword_spacing": "spaced",
"keywords.group_to_block_spacing": "spaced",
"keywords.padding_inside_group": true,
"keywords.spacing_to_block": "spaced",
"keywords.spacing_to_group": true,
"keywords.empty_group_spacing": false,
"max_columns": 120,
"parentheses.padding": true,
"strings.quote": "double",
"strings.attributes.quote": "double",
"struct.separator": " : ",
"struct.padding": true,
"struct.empty_padding": false,
"struct.multiline.leading_comma": false,
"struct.multiline.leading_comma.padding": true,
"struct.multiline.element_count": 4,
"struct.multiline.min_length": 40,
"tab_indent": true
}
Sorry that I've got all of these weird edge cases!
The following example crashes the parser with this error:
key [1] doesn't exist
/modules/commandbox-cfformat/models/cfscript/Keywords.cfc: line 188
186: } else if (['do', 'try', 'catch'].find(keyword)) {
187: var nextToken = cftokens.peek(true);
188: if (!isNull(nextToken) && ['while', 'catch', 'finally'].find(nextToken[1])) {
189: formatted = formatted.rtrim();
190: if (settings['keywords.block_to_keyword_spacing'] == 'spaced') {
called from /modules/commandbox-cfformat/models/cfscript/Keywords.cfc: line 200
called from /modules/commandbox-cfformat/models/cfscript/Keywords.cfc: line 55
called from /modules/commandbox-cfformat/models/CFScript.cfc: line 98
Bad code:
component {
public void function foo () {
try {
loadData();
} catch (any e) {
}
/* <cfset bar = 'baz'> */
}
}
Good code 1:
component {
public void function foo () {
try {
loadData();
} catch (any e) {
}
}
}
Good code 2:
component {
public void function foo () {
/* <cfset bar = 'baz'> */
}
}
component {
function run() {
param arguments.ownerKey = related.getKey();
}
}
{
"alignment.consecutive.assignments":false,
"alignment.consecutive.params":false,
"alignment.consecutive.properties":false,
"array.empty_padding":false,
"array.multiline.element_count":4,
"array.multiline.leading_comma":false,
"array.multiline.leading_comma.padding":true,
"array.multiline.min_length":40,
"array.padding":true,
"binary_operators.padding":true,
"brackets.padding":true,
"comment.asterisks":"align",
"for_loop_semicolons.padding":true,
"function_anonymous.empty_padding":false,
"function_anonymous.group_to_block_spacing":"spaced",
"function_anonymous.multiline.element_count":4,
"function_anonymous.multiline.leading_comma":false,
"function_anonymous.multiline.leading_comma.padding":true,
"function_anonymous.multiline.min_length":40,
"function_anonymous.padding":true,
"function_call.casing.builtin":"cfdocs",
"function_call.casing.userdefined":"camel",
"function_call.empty_padding":false,
"function_call.multiline.element_count":4,
"function_call.multiline.leading_comma":false,
"function_call.multiline.leading_comma.padding":true,
"function_call.multiline.min_length":40,
"function_call.padding":true,
"function_declaration.empty_padding":false,
"function_declaration.group_to_block_spacing":"spaced",
"function_declaration.multiline.element_count":4,
"function_declaration.multiline.leading_comma":false,
"function_declaration.multiline.leading_comma.padding":true,
"function_declaration.multiline.min_length":40,
"function_declaration.padding":true,
"indent_size":4,
"keywords.block_to_keyword_spacing":"spaced",
"keywords.empty_group_spacing":false,
"keywords.group_to_block_spacing":"spaced",
"keywords.padding_inside_group":true,
"keywords.spacing_to_block":"spaced",
"keywords.spacing_to_group":true,
"max_columns":120,
"method_call.chain.multiline":3,
"newline":"os",
"parentheses.padding":true,
"strings.attributes.quote":"double",
"strings.quote":"double",
"struct.empty_padding":false,
"struct.multiline.element_count":4,
"struct.multiline.leading_comma":false,
"struct.multiline.leading_comma.padding":true,
"struct.multiline.min_length":40,
"struct.padding":true,
"struct.separator":": ",
"tab_indent":false
}
Here the param formatting breaks on a dot (.
) but doesn't indent on the next line.
component {
function run() {
param arguments.ownerKey = related
.getKey();
}
}
Affected v0.12.* and v0.13.0
<cfelse>
tag is incorrectly indented and also uses spaces even when "tab_indent": true
Input:
<cfcomponent>
<cffunction name="init">
<cfif 1>
<cfset foo()>
<cfelse>
<cfset bar()>
</cfif>
</cffunction>
</cfcomponent>
Expected (unmodified):
<cfcomponent>
<cffunction name="init">
<cfif 1>
<cfset foo()>
<cfelse>
<cfset bar()>
</cfif>
</cffunction>
</cfcomponent>
Actual:
<cfcomponent>
<cffunction name="init">
<cfif 1>
<cfset foo()>
<cfelse>
<cfset bar()>
</cfif>
</cffunction>
</cfcomponent>
The watch
command would watch all .cfc
files for changes and format each added or changed file.
The biggest question here would be if you nested the original command (like cfformat run
) to allow for cfformat watch
or if you used a different command name (like cfformat-watch
).
(Again, happy to implement this.)
I'm running CommandBox 4.7 on Ubuntu 19.04. I get the same output on an older Ubuntu machine which is also running CommandBox 4.7 from the apt repository.
I created a CFC component for testing purposes:
component {}
When running cfformat test.cfc
, I get the following output:
CommandBox> cfformat Application.cfc
ERROR (4.7.0+00026) Error invoking external process
/home/mark/.CommandBox/cfml/modules/commandbox-cfformat/bin/v0.7.0/cftokens_osx: 1: /home/mark/.CommandBox/cfml/modules/commandbox-cfformat/bin/v0.7.0/cftokens_osx: Syntax error: ")" unexpected
/home/mark/.CommandBox/cfml/modules/commandbox-cfformat/models/CFFormat.cfc: line 185
183: function tokenizeFile(fullFilePath) {
184: var tokens = '';
185: cfexecute(name=executable arguments="""#fullFilePath#""" variable="tokens" timeout=10);
186: if (!isJSON(tokens)) {
187: throw(tokens);
called from /home/mark/.CommandBox/cfml/modules/commandbox-cfformat/models/CFFormat.cfc: line 76
called from /home/mark/.CommandBox/cfml/modules/commandbox-cfformat/commands/cfformat.cfc: line 284
called from /home/mark/.CommandBox/cfml/modules/commandbox-cfformat/commands/cfformat.cfc: line 128
called from /home/mark/.CommandBox/cfml/system/services/CommandService.cfc: line 342
called from /home/mark/.CommandBox/cfml/system/services/CommandService.cfc: line 138
called from /home/mark/.CommandBox/cfml/system/Shell.cfc: line 758
called from /home/mark/.CommandBox/cfml/system/Shell.cfc: line 578
called from /home/mark/.CommandBox/cfml/system/Bootstrap.cfm: line 145
lucee.runtime.exp.ApplicationException: Error invoking external process
at lucee.runtime.tag.Execute.doEndTag(Execute.java:258)
at modules.commandbox_cfformat495.models.cfformat_cfc$cf.udfCall2(/commandbox/modules/commandbox-cfformat/models/CFFormat.cfc:185)
at modules.commandbox_cfformat495.models.cfformat_cfc$cf.udfCall(/commandbox/modules/commandbox-cfformat/models/CFFormat.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.call(UDFImpl.java:226)
at lucee.runtime.type.scope.UndefinedImpl.call(UndefinedImpl.java:803)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:756)
at lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1718)
at modules.commandbox_cfformat495.models.cfformat_cfc$cf.udfCall1(/commandbox/modules/commandbox-cfformat/models/CFFormat.cfc:76)
at modules.commandbox_cfformat495.models.cfformat_cfc$cf.udfCall(/commandbox/modules/commandbox-cfformat/models/CFFormat.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.call(UDFImpl.java:226)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:693)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:573)
at lucee.runtime.ComponentImpl.call(ComponentImpl.java:1997)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:756)
at lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1718)
at modules.commandbox_cfformat495.commands.cfformat_cfc$cf.udfCall2(/commandbox/modules/commandbox-cfformat/commands/cfformat.cfc:284)
at modules.commandbox_cfformat495.commands.cfformat_cfc$cf.udfCall(/commandbox/modules/commandbox-cfformat/commands/cfformat.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.call(UDFImpl.java:226)
at lucee.runtime.type.scope.UndefinedImpl.call(UndefinedImpl.java:803)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:756)
at lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1718)
at modules.commandbox_cfformat495.commands.cfformat_cfc$cf.udfCall1(/commandbox/modules/commandbox-cfformat/commands/cfformat.cfc:128)
at modules.commandbox_cfformat495.commands.cfformat_cfc$cf.udfCall(/commandbox/modules/commandbox-cfformat/commands/cfformat.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:212)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:695)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:573)
at lucee.runtime.ComponentImpl.callWithNamedValues(ComponentImpl.java:2014)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:833)
at lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1737)
at system.services.commandservice_cfc$cf.udfCall1(/commandbox/system/services/CommandService.cfc:342)
at system.services.commandservice_cfc$cf.udfCall(/commandbox/system/services/CommandService.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:212)
at lucee.runtime.type.scope.UndefinedImpl.callWithNamedValues(UndefinedImpl.java:812)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:833)
at lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1737)
at system.services.commandservice_cfc$cf.udfCall1(/commandbox/system/services/CommandService.cfc:138)
at system.services.commandservice_cfc$cf.udfCall(/commandbox/system/services/CommandService.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.call(UDFImpl.java:226)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:693)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:573)
at lucee.runtime.ComponentImpl.call(ComponentImpl.java:1997)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:756)
at lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1718)
at system.shell_cfc$cf.udfCall4(/commandbox/system/Shell.cfc:758)
at system.shell_cfc$cf.udfCall(/commandbox/system/Shell.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:212)
at lucee.runtime.type.scope.UndefinedImpl.callWithNamedValues(UndefinedImpl.java:812)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:833)
at lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1737)
at system.shell_cfc$cf.udfCall3(/commandbox/system/Shell.cfc:578)
at system.shell_cfc$cf.udfCall(/commandbox/system/Shell.cfc)
at lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:107)
at lucee.runtime.type.UDFImpl._call(UDFImpl.java:357)
at lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:212)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:695)
at lucee.runtime.ComponentImpl._call(ComponentImpl.java:573)
at lucee.runtime.ComponentImpl.callWithNamedValues(ComponentImpl.java:2014)
at lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:833)
at lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1737)
at mark._commandbox46.cfml.system.bootstrap_cfm$cf.call(/__commandbox_root/mark/.CommandBox/cfml/system/Bootstrap.cfm:145)
at lucee.runtime.PageContextImpl._doInclude(PageContextImpl.java:933)
at lucee.runtime.PageContextImpl._doInclude(PageContextImpl.java:823)
at lucee.runtime.PageContextImpl.doInclude(PageContextImpl.java:805)
at g6u3r6cj3p08.call(Unknown Source)
at lucee.runtime.compiler.Renderer.tag(Renderer.java:113)
at lucee.runtime.compiler.Renderer.script(Renderer.java:101)
at lucee.runtime.jsr223.ScriptEngineImpl.eval(ScriptEngineImpl.java:64)
at lucee.runtime.jsr223.ScriptEngineImpl.eval(ScriptEngineImpl.java:199)
at cliloader.LoaderCLIMain.execute(LoaderCLIMain.java:285)
at cliloader.LoaderCLIMain.execute(LoaderCLIMain.java:152)
at cliloader.LoaderCLIMain.main(LoaderCLIMain.java:509)
This is edge case.
When watching a folder and using touch SomeComponent.cfc
, the error below is generated.
ERROR (4.7.0+00026)
Array index [1] out of range, array size is [0]
/modules/commandbox-cfformat/models/CFFormat.cfc: line 167
165: var bom = '';
166: if (
167: isArray(tokens.elements[1]) &&
168: arrayLen(tokens.elements[1][2]) &&
169: tokens.elements[1][2][1] == 'bom'
called from /modules/commandbox-cfformat/models/CFFormat.cfc: line 75
called from /modules/commandbox-cfformat/commands/cfformat.cfc: line 303
called from /modules/commandbox-cfformat/commands/cfformat.cfc: line 170
called from /system/util/Watcher.cfc: line 110
With the following settings file:
{
"strings.quote": "double"
}
Running the following file:
component extends='coldbox.system.testing.BaseTestCase' appMapping='/' {
function run() {
describe( "about Suite", function() {
beforeEach( function( currentSpec ) {
setup();
} );
it( "index", function() {
var event = execute( event = "about.index", renderResults = true );
// expectations go here.
expect( false ).toBeTrue();
} );
} );
}
}
The quotes in the component metadata (extends
, appMapping
) are not converted.
This is kind of an absurd request, since you've already built a Sublime Text plugin for formatting CFML, but I was wondering if there are any plans to make this new engine available as an editor plugin.
I'm interested in this because we're working on setting up command-line code formatting, but we also really like the "just format the selected code" capability of your ST plugin. We'd rather not use both formatters, because even with the same author, it seems like the output isn't always going to be exactly the same. We'd also prefer to have a single configuration for both the CLI and editor-based formatter.
Let me know your thoughts. Thanks so much for building all of these great tools!
The formatter currently strips all leading and trailing white space and then indents.
/**
* Description
*
* @param Some parameter info
*/
is now
/**
* Description
*
* @param Some parameter info
*/
Unfortunately, this breaks my doc-block extension since it is expecting an extra space after the indent.
Small thing, but I like to have space between a bang (!
) and the code it is negating.
component {
function run() {
if ( ! true ) {
writeDump( "Hi!" );
}
}
}
Currently this squashes into if ( !true ) {
.
Additionally, if I use a double bang (!!
) I would keep the bangs together: if ( !! true ) {
.
Input:
loop from=1 to=#params.quantity# index="local.i" {
}
Expected:
loop from=1 to=#params.quantity# index="local.i" {
}
Actual:
loop from=1 to=# params {
}
Admittedly, the input syntax is pretty smelly.. but a fair chunk of code was eaten.
It would be nice if this module would automatic pass a .cfformat.json
file (or similar name) if it was present as the settingsPath
.
(I'd be happy to implement this as a PR if you like it.)
Allow this
{
foo: 'bar'
}
to be this
{
foo : 'bar'
}
Please see attached image. I am also attaching my rules below. But the formatting is not affecting
the inner closures.
{
"array.empty_padding" : false,
"array.padding" : true,
"array.multiline.min_length" : 40,
"array.multiline.element_count" : 4,
"array.multiline.leading_comma.padding" : true,
"array.multiline.leading_comma" : false,
"assignments.consecutive.alignment" : true,
"brackets.padding" : true,
"comment.asterisks" : "align",
"binary_operators.padding" : true,
"for_loop_semicolons.padding" : true,
"function_call.empty_padding" : false,
"function_call.padding" : true,
"function_call.multiline.leading_comma.padding" : true,
"function_call.casing.builtin" : "cfdocs",
"function_call.casing.userdefined" : "",
"function_call.multiline.element_count" : 4,
"function_call.multiline.leading_comma" : false,
"function_call.multiline.min_length" : 40,
"function_declaration.padding" : true,
"function_declaration.empty_padding" : false,
"function_declaration.multiline.leading_comma" : false,
"function_declaration.multiline.leading_comma.padding" : true,
"function_declaration.multiline.element_count" : 4,
"function_declaration.multiline.min_length" : 40,
"function_declaration.group_to_block_spacing" : "compact",
"function_anonymous.empty_padding" : false,
"function_anonymous.group_to_block_spacing" : "compact",
"function_anonymous.multiline.element_count" : 4,
"function_anonymous.multiline.leading_comma" : false,
"function_anonymous.multiline.leading_comma.padding" : true,
"function_anonymous.multiline.min_length" : 40,
"function_anonymous.padding" : false,
"indent_size" : 4,
"keywords.block_to_keyword_spacing" : "spaced",
"keywords.group_to_block_spacing" : "spaced",
"keywords.padding_inside_group" : true,
"keywords.spacing_to_block" : "spaced",
"keywords.spacing_to_group" : true,
"keywords.empty_group_spacing" : false,
"max_columns" : 120,
"parentheses.padding" : true,
"strings.quote" : "double",
"strings.attributes.quote" : "double",
"struct.separator" : " : ",
"struct.padding" : true,
"struct.empty_padding" : false,
"struct.multiline.leading_comma" : false,
"struct.multiline.leading_comma.padding" : true,
"struct.multiline.element_count" : 4,
"struct.multiline.min_length" : 40,
"tab_indent" : true
}
Improve settings command (or add another command) that outputs a snippet of code to the console demonstrating the current configured settings.
cfformat ./ --watch
Gives me this error on save:
```Error invoking external process
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 123, kind: Other, message: "The filename, directory name, or volume label syntax is incorrect." }', src\libcore\result.rs:999:5note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
D:\.Command Box\cfml\modules\commandbox-cfformat\models\CFFormat.cfc: line 140
138: function tokenizeFile(fullFilePath) {
139: var tokens = '';
140: cfexecute(name=executable arguments="""#fullFilePath#""" variable="tokens" timeout=10);
141: if (!isJSON(tokens)) {
142: throw(tokens);```
Looks like we're double appending the base path on this line:
var allFiles = files.added.append(files.changed, true).map((p) => fullPath & p);
Removing the map made it work for me.
It's unusual, but sometimes we use inline comments to explain what's going on in a complex conditional. Running cfformat
on this code breaks the syntax, making the file unparseable.
Input:
component {
if (
status == 0 // explanation
|| (
[1, 2, 3].contains(status) // explanation
&& someOtherCondition // explanation
)
) {
Echo('foo');
}
}
Actual Output:
component {
if (
status == 0 // explanation
|| ([1, 2, 3].contains(status) // explanation && someOtherCondition // explanation)
) {
Echo('foo');
}
}
Expected Output:
component {
if (
status == 0 // explanation
|| ([1, 2, 3].contains(status) // explanation
&& someOtherCondition // explanation
)
) {
Echo('foo');
}
}
It looks like the safe navigation operator (?.
) is being interpreted as a ternary operator. This causes some code breakage.
Config: default
Source:
component {
function functionCallWithSafeNavigationOperator() {
return getFoo()?.getBar();
}
function structWithSafeNavigationOperator() {
return variables?.foo?.bar;
}
}
Current Output:
component {
function functionCallWithSafeNavigationOperator() {
return getFoo() ? .getBar();
}
function structWithSafeNavigationOperator() {
return variables ? .foo ? .bar;
}
}
It would be useful to have a settings that removed the space that is added after the comma moved by the .leading_comma
settings. Maybe a setting like .leading_comma.padding
For example:
From this...
this.constraints = {
'Title': { required: true, size: '1..255' },
'Forename': { size: '0..255' },
'Surname': { required: true, size: '1..255' }
}
...to this ("struct.multiline.leading_comma":true
)...
this.constraints = {
'Title': { required: true, size: '1..255' }
, 'Forename': { size: '0..255' }
, 'Surname': { required: true, size: '1..255' }
}
...finally to this ("struct.multiline.leading_comma.padding":false
)...
this.constraints = {
'Title': { required: true, size: '1..255' }
,'Forename': { size: '0..255' }
,'Surname': { required: true, size: '1..255' }
}
Here's a fun one: a non-terminated string in a file causes cfformat to delete code.
Source:
component extends="coldbox.system.testing.BaseTestCase" appMapping="/" {
function run() {
describe( 'about Suite", function() {
it( "index", function() {
var event = execute( event = "about.index", renderResults = true );
expect( false ).toBeTrue();
} );
} );
}
}
Output:
about Suite", function() {
it( "index", function() {
var event = execute( event = "about.index", renderResults = true );
expect( false ).toBeTrue();
} );
} );
}
}
I'm not sure how, but deleting code on a typo isn't exactly helpful. 😅
I am currently creating scripts that specify all the globs I want to format in my box.json
package scripts. This can get rather long and repetitive....
{
"scripts":{
"format":"cfformat run handlers/**/*.cfc,models/**/*.cfc,modules_app/**/*.cfc,tests/resources/**/*.cfc,tests/specs/**/*.cfc --overwrite",
"format:check":"cfformat check handlers/**/*.cfc,models/**/*.cfc,modules_app/**/*.cfc,tests/resources/**/*.cfc,tests/specs/**/*.cfc"
}
}
It could be a nice feature to check for some kind of ignore file so I could add files that should never get formatted. I assume this would follow the .gitignore
syntax. (I believe CommandBox has some built in functions to help with this.) The command could look for a .cfformatignore
file by default while allowing an alternate file name to be passed in. Additionally, perhaps a global .cfformatignore
could be specified as a module setting. Then I won't ever accidently format all of ColdBox again. 😅
I don't know how easy this one is or if it falls in the purview of CFFormat since it's actually adding code, not just whitespace. One of my big pet peeves is this:
if( condition )
randomOrphan.codeThatCanGetSeperated();
I'd love to see an option to change it to this:
if( condition ) {
niceCodeSecurley.insideIfBody();
}
I think something is off with the min_length
determination.
component {
public any function update( struct attributes = {}, boolean ignoreNonExistentAttributes = false, sssssssssss = "s" ) {
writeDump( var = "Hello!" );
}
}
This component does not split the arguments on to new lines no matter what I choose for any of min_length
settings. However, add one more character to the argument list up there and it will split.
This may be an edge case and tricky to solve, but changing leading to trailing commas with a commented line of code results in a syntax exception. Note missing comma after local.from
,
input:
send(
to = local.to
,from = local.from
// ,user=local.user
// ,thing=local.thing
,body = local.body
);
result:
send(
to = local.to,
from = local.from
// ,user=local.user, // ,thing=local.thing
body = local.body
);
expected:
send(
to = local.to,
from = local.from,
// ,user=local.user, // ,thing=local.thing
body = local.body
);
It would be great to be able to add additional file extensions to run through the same formatting that .cfc gets now.
The following code causes cfformat to return invalid syntax:
Input:
include "foo.cfm";
Returns:
include"foo.cfm";
Workaround:
include template="foo.cfm";
Right now there's no way to tell what some settings do outside of experimentation.
It would be handy to be able to:
cfformat /models controllers/ config/ --watch
Thanks again for this great package!
Add a command for use with commandbox-githooks that will do the following: https://prettier.io/docs/en/precommit.html#option-5-bash-script
This code block is formatted by CFFormat
component {
function doSomething() {
if( condition ) {
} var i = 0; i++; i--;
}
}
it did not add line breaks after the trailing }
nor the individual statements.
It would be awesome to have chained methods be indented on a new line. ex.
bookService
.getVersions( bookDirectory )
.each( ( v ) => print.line( v ) );
as opposed to
bookService.getVersions( bookDirectory ).each( (v) => print.line( v ) );
or maybe have a max length
I currently have a component declration like so:
component
extends="coldbox.system.testing.BaseModelTest"
model="cbvalidation.models.validators.MethodValidator"
{
I would have expected for the formmater to respect the breaks. However, it does this:
component extends="coldbox.system.testing.BaseModelTest" model="cbvalidation.models.validators.MethodValidator" {
Here are my rules
{
"array.empty_padding": false,
"array.padding": true,
"array.multiline.min_length": 40,
"array.multiline.element_count": 4,
"array.multiline.leading_comma.padding": true,
"array.multiline.leading_comma": false,
"alignment.consecutive.assignments": true,
"alignment.consecutive.properties": true,
"alignment.consecutive.params": true,
"brackets.padding": true,
"comment.asterisks": "align",
"binary_operators.padding": true,
"for_loop_semicolons.padding": true,
"function_call.empty_padding": false,
"function_call.padding": true,
"function_call.multiline.leading_comma.padding": true,
"function_call.casing.builtin": "cfdocs",
"function_call.casing.userdefined": "camel",
"function_call.multiline.element_count": 4,
"function_call.multiline.leading_comma": false,
"function_call.multiline.min_length": 40,
"function_declaration.padding": true,
"function_declaration.empty_padding": false,
"function_declaration.multiline.leading_comma": false,
"function_declaration.multiline.leading_comma.padding": true,
"function_declaration.multiline.element_count": 4,
"function_declaration.multiline.min_length": 40,
"function_declaration.group_to_block_spacing": "compact",
"function_anonymous.empty_padding": false,
"function_anonymous.group_to_block_spacing": "compact",
"function_anonymous.multiline.element_count": 4,
"function_anonymous.multiline.leading_comma": false,
"function_anonymous.multiline.leading_comma.padding": true,
"function_anonymous.multiline.min_length": 40,
"function_anonymous.padding": true,
"indent_size": 4,
"keywords.block_to_keyword_spacing": "spaced",
"keywords.group_to_block_spacing": "spaced",
"keywords.padding_inside_group": true,
"keywords.spacing_to_block": "spaced",
"keywords.spacing_to_group": true,
"keywords.empty_group_spacing": false,
"max_columns": 120,
"parentheses.padding": true,
"strings.quote": "double",
"strings.attributes.quote": "double",
"struct.separator": " : ",
"struct.padding": true,
"struct.empty_padding": false,
"struct.multiline.leading_comma": false,
"struct.multiline.leading_comma.padding": true,
"struct.multiline.element_count": 4,
"struct.multiline.min_length": 40,
"tab_indent": true
}
cfformat dir/$$foo.cfc
Returns "dir/22004foo.cfc is not a valid file or directory."
I'm working on a Application that has the following code in it
<cfif len(event.getValue('filter_service','')) eq 0
AND len(event.getValue('filter_client','')) eq 0
AND len(event.getValue('filter_filenumber','')) eq 0
AND len(event.getValue('filter_selfrom','')) eq 0
AND len(event.getValue('filter_selto','')) eq 0
AND len(event.getValue('filter_period','')) eq 0
AND len(event.getValue('filter_status','')) eq 0
AND len(event.getValue('q','')) eq 0
and not isDefined("rc.medicalReportsNeedApproval")>
When I run cfformat
on it, with the default settings, it removes the space between AND
and len(event.getValue....
<cfif len(event.getValue('filter_service', '')) eq 0
ANDlen(event.getValue('filter_client', '')) eq 0
ANDlen(event.getValue('filter_filenumber', '')) eq 0
ANDlen(event.getValue('filter_selfrom', '')) eq 0
ANDlen(event.getValue('filter_selto', '')) eq 0
ANDlen(event.getValue('filter_period', '')) eq 0
ANDlen(event.getValue('filter_status', '')) eq 0
ANDlen(event.getValue('q', '')) eq 0
andnot isDefined('rc.medicalReportsNeedApproval')>
when I first refactor it to cfscript, and then run cfformat, this issue does NOT occur
These are my settings:
{
"brackets.padding": true,
"strings.quote": "double",
"strings.attributes.quote": "double",
"function_call.empty_padding": false,
"function_call.padding": true,
"function_declaration.padding": true,
"function_call.multiline.leading_comma.padding": true,
"function_declaration.multiline.leading_comma.padding" : true,
"function_declaration.empty_padding": false,
"function_declaration.group_to_block_spacing": "compact",
"struct.padding": true,
"struct.empty_padding": false,
"struct.multiline.leading_comma.padding" : true,
"array.empty_padding":false,
"array.padding":true,
"array.multiline.leading_comma.padding":true,
"binary_operators.padding":true,
"for_loop_semicolons.padding":true,
"indent_size":4,
"parentheses.padding":true,
"struct.separator":" : ",
"tab_indent":true,
"keywords.block_to_keyword_spacing" : "spaced",
"keywords.group_to_block_spacing" : "spaced",
"keywords.padding_inside_group" : true,
"keywords.spacing_to_block" : "compact",
"keywords.spacing_to_group" : true
}
This is current code
/**
* Set form params
* @name The name of the key in the form params
* @value The value
*/
OrtusPDF function setFormParam( required string name, required string value ){
variables.formparams[ arguments.name ] = arguments.value;
return this;
}
This is the formated code:
/**
* Set form params
* @name The name of the key in the form params
* @value The value
*/
OrtusPDF
function setFormParam( required string name, required string value ){
variables.formparams[ arguments.name ] = arguments.value;
return this;
}
As you can see it puts the return type of functions in a new line
https://www.forgebox.io/view/commandbox-cfformat
the reference link points to https://www.forgebox.io/reference.md
I have this line of code in my app - it's essentially stripping out query parameters which don't have an explicit value set.
params = params.filter( ( key, param ) => param.value <> "<NOTSET>" );
CFFormat changed this to: (Notice the double spaces between <
and >
.
params = params.filter( ( key, param ) => param.value < > "<NOTSET>" );
I'm not sure what language construct CFFormat thinks that is, but it's definitely converting valid CFML to invalid CFML.
Is there somehow I can help fix this?
It would be great to configure function case separately for native functions and user defined functions.
One code standard I have observed is that native cfml functions are PascalCase
and user defined functions are camelCase
.
Eg:
"function_call.native.case":"PascalCase" -- or "Upper / Lower"
"function_call.user_defined.case":"camelCase"
Input:
today = now();
earlier = OneDayAgo();
Output:
today = Now();
earlier = oneDayAgo();
Thanks again for a great extenstion!
This is just a random idea, but how about a command that presents the user with a little wizard to choose each setting with a code sample of each one. I'm imagining clearing the screen after each question and outputting two (or however many options there are) code samples demonstrating what the setting does, and then use the multi-select input for the user to toggle between the settings to choose what they want. Default each question to the default value. When the user is finished, we spit out a JSON file based on their responses and show them an example of their final choice.
Ability to point cfformat at an existing CFC that held the standards you liked and have it spit out a json file that matched for use on the rest of your app.
Input:
return $$badRequest();
Output:
return $$badRequest( );
Expected:
return $$badRequest();
Settings:
{
"array.empty_padding": false,
"array.multiline.element_count": 4,
"array.multiline.leading_comma": false,
"array.multiline.leading_comma.padding": true,
"array.multiline.min_length": 40,
"array.padding": false,
"binary_operators.padding": true,
"brackets.padding": false,
"for_loop_semicolons.padding": true,
"function_call.casing.builtin": "pascal",
"function_call.casing.userdefined": "camel",
"function_call.empty_padding": false,
"function_call.multiline.element_count": 4,
"function_call.multiline.leading_comma": false,
"function_call.multiline.leading_comma.padding": true,
"function_call.multiline.min_length": 40,
"function_call.padding": false,
"function_declaration.empty_padding": false,
"function_declaration.group_to_block_spacing": "spaced",
"function_declaration.multiline.element_count": 4,
"function_declaration.multiline.leading_comma": false,
"function_declaration.multiline.leading_comma.padding": true,
"function_declaration.multiline.min_length": 40,
"function_declaration.padding": false,
"indent_size": 2,
"keywords.block_to_keyword_spacing": "spaced",
"keywords.empty_group_spacing": false,
"keywords.group_to_block_spacing": "spaced",
"keywords.padding_inside_group": false,
"keywords.spacing_to_block": "spaced",
"keywords.spacing_to_group": true,
"max_columns": 120,
"parentheses.padding": false,
"strings.quote": "double",
"strings.attributes.quote": "double",
"struct.empty_padding": false,
"struct.multiline.element_count": 4,
"struct.multiline.leading_comma": false,
"struct.multiline.leading_comma.padding": true,
"struct.multiline.min_length": 40,
"struct.padding": false,
"struct.separator": " = ",
"tab_indent": true
}
This example has an extra comma before the comment:
component {
function doSomething() {
var options = {
datasource: 'xyz',
// other stuff
};
}
}
instead of throwing an error about an invalid syntax, CFFormat does this which comments out the end of the struct literal.
component {
function doSomething() {
var options = { datasource: 'xyz', // other stuff };
}
}
Input:
qry = querySim("
id , fk_id , create_date
1 | 3 | #Now()#
2 | 4 | -
");
Output:
qry = querySim(
"
id , fk_id , create_date
1 | 3 | #Now()#
2 | 4 | -
"
);
Expected:
qry = querySim("
id , fk_id , create_date
1 | 3 | #Now()#
2 | 4 | -
");
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.