Code Monkey home page Code Monkey logo

toscript's Introduction

toScript()

Build Status

Converts tag based CFML code into CFML Script.

Usage

Invoke the toScript(filePath="", options={}, fileContent="") function.

Options

The options struct currently only supports one option indentChars which defaults to a tab character. You could pass {indentChars=" "} if you wanted to indent with 4 spaces instead of a tabs.

To see an example of how it works look at the unit tests. It converts a Tag Based CFC Test Suite TagTemplate.cfc into a Script CFC test suite GeneratedScriptCode.cfc

Example

converter = new ToScript();
result = converter.toScript(filePath="someFile.cfc");
fileWrite("result.cfc", result.code);

Generated CFML Script

All of the generated script should run on ColdFusion 11+ or Lucee 4.5+

Much of it will also run on older versions of CFML, but it depends on which tags you use.

toscript's People

Contributors

ivan-mca avatar pfreitag avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

toscript's Issues

Function Hints

Currently the function hint attribute is moved to a comment above the function. Both Lucee and ACF prefer that it is in a function argument instead (Which show up in the meta data when you dump the function).

<cffunction name="test" hint="Hint">
    <cfreturn 1>
</cffunction>

Should become:

function test() hint="Hint" {
    return 1;
} 

CFHTTP "getAsBinary" cannot be boolean.

CFHTTP's getAsBinary option must be a textual yes, no or auto in order to be compatible with Adobe ColdFusion. (When converting tag-based CFML, the value is currently being converted to boolean true.)

Write exception report

Would be a nice feature of the CLI to write out a report file with all the errors encountered. They're in the output right now, but since there's so much other (yellow) text they can get lost, especially once the console is closed.

An exception report would let the user know what files to go back and finalize.

loops without index not working properly

<cfloop array="#myArray#" item="i">
    
</cfloop>

<cfloop collection="#myStruct#" item="key">
    
</cfloop>

returns

/* toScript ERROR: key [INDEX] doesn't exist

<cfloop array="#myArray#" item="i">
    
</cfloop>

*/

}

/* toScript ERROR: Unimplemented cfloop condition

<cfloop collection="#myStruct#" item="key">
    
</cfloop>

*/

}

also note the extra } being returned below the error.

cfdump not implemented

/* toScript ERROR: Unable to convert tag: cfdump to CFML Script

<cfdump var="#foo#" abort="true" />

*/

Fix nested cfoutput

Input (from the Adobe docs):

<!--- Upload video --->
<cfhttp url="#youTubeUploadURL#" result="result" method="POST" timeout="450" multipartType="related"> 
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#authdata.auth#"> 
<cfhttpparam type="header" name="X-GData-Client" value="#variables.clientkey#"> 
<cfhttpparam type="header" name="X-GData-Key" value="key=#variables.devkey#"> 
<cfhttpparam type="header" name="Slug" value="#videoFileName#"> 
<!---<CFHTTPPARAM type="HEADER" name="Connection" value="Keep-Alive"> --->
<!--- Send 2 files --->
<cfhttpparam type="file" name="API_XML_Request" file="#tmpfile#"
mimetype="application/atom+xml"> 
<cfhttpparam type="file" name="file" file="#videoName#" mimetype="video/*"> 
</cfhttp>

Output:

//  Upload video 
cfhttp( url=youTubeUploadURL, multipartType="related", timeout=450, result="result", method="POST" );
cfhttpparam( name="Authorization", type="header", value="#authdata.auth#"" );
cfhttpparam( name="X-GData-Client", type="header", value=variables.clientkey );
cfhttpparam( name="X-GData-Key", type="header", value="#variables.devkey#"" );
cfhttpparam( name="Slug", type="header", value=videoFileName );
// <CFHTTPPARAM type="HEADER" name="Connection" value="Keep-Alive"> 
//  Send 2 files 
cfhttpparam( file=tmpfile, name="API_XML_Request", type="file", mimetype="application/atom+xml" );
cfhttpparam( file=videoName, name="file", type="file", mimetype="video/*" );

Obvs. should use a block construct when there are nested tags here.

Double scroll bars

A double scrollbar appears with large docs (as soon as the doc is larger than the viewscreen). (seen in Chrome)

Quoted quotes breaks conversion

It seems that the single quote contained in double quotes is preventing the code afterward from being converted.

<cfset foo = get(where="mycolumn IN (#ListQualify(myList, "'")#)")>
<cfif true>
    <cfset bar = false>
</cfif>

converts to:

foo = get(where="mycolumn IN (#ListQualify(myList, "'")#)")>
<cfif true>
    <cfset bar = false>
</cfif;

Custom argument attributes not carried over

Code such as:

<cfargument name="controller" inject="coldbox">

Does not pass the inject argument over.

Could be converted as:

any controller inject='coldbox'

Note that the type may be required in this case.

Reduce font size

26px seems unusually large and viewing is a little awkward when converting those tag-a-licious components and functions. 12px or 14px would mirror most code editor defaults.

Great tool!

Unimplemented condition: cfloop on a list

This code couldn't be converted:

<cfloop list="#defaultSort#" index="orderByPart">
  <cfset orderByString = listAppend( orderByString, "mainEntity.#orderByPart#" ) />
</cfloop>

Probably because CF9 doesn't support for..in on lists I think.

Cfloop query= fails

<CFLOOP query="qReport”> becomes toScript ERROR: Unimplemented cfloop condition: query="qReport”

Cfscript.me - Created a "cfoutput()" on converted tag based code.

The following tag-based code:

<cfloop condition="#atribEnum.hasMore()#"> <cfset attribute = atribEnum.next()> <cfoutput>#attribute.toString()#</cfoutput><br /> </cfloop>

Created the following cfscript:

`while ( condition="#atribEnum.hasMore()#" ) {
attribute = atribEnum.next();
cfoutput( ) {

	writeOutput("#attribute.toString()#");
}

writeOutput("<br />");

}`

The cfoutput() {} is not required nor valid cfscript.

Apologies for the above cfscript. I could not get it to stay in the code tags. :(

cfquery is not handled properly

<cfquery name="local.test" result="local.qResult">
select * from myTable 
where x = <cfqueryparam cfsqltype="cf_sql_char" value="#arguments.x#">
order by y ASC
</cfquery>

becomes

cfquery( name="local.test", result="local.qResult" ) {

writeOutput("select * from myTable 
where x =");
cfqueryparam( cfsqltype="cf_sql_char", value=arguments.x );
writeOutput("order by y ASC");
}

<cfstoredproc> Throwing error

Input

`
< cffunction name="myQuery" returntype="query" >

	    <cfstoredproc procedure="Insert_Book" datasource="somedsn"> 

            <cfprocparam cfsqltype="cf_sql_varchar" value="sometitle"> 
         
        </cfstoredproc> 
	    
		<cfreturn Insert_Book>
	< /cffunction >

`

Output

`
public query function myQuery() {
/* toScript ERROR: Unable to convert tag: cfstoredproc to CFML Script

			<cfstoredproc procedure="Insert_Book" datasource="somedsn"> 

            <cfprocparam cfsqltype="cf_sql_varchar" value="sometitle"> 
         
        </cfstoredproc>

	*/

	return Insert_Book;
}

`

Flush CLI output while processing

Use .toConsole() to flush the output of the CLI command out to the console while processing is happening so it's not just a long pause and then all the output at once.

Ex:

print.greenLine("#checkMark()#  (Converted): " & normalizedPath).toConsole();

cfcase delimited case items incorrectly translated

tag based cf supports multiple delimiters,
script requires a separate case statement for each value

https://trycf.com/gist/7dbd3abca9e8cc10fd427e2ac13b1df3/lucee5?theme=monokai

<cfswitch` expression="3">
    <cfcase value="1,2,3">
        <cfoutput>it's a positive value</cfoutput>
    </cfcase>
    <cfcase value="0">
        <cfoutput>a zero</cfoutput>
    </cfcase>
    <cfdefaultcase>
        <cfoutput>don't know</cfoutput>
    </cfdefaultcase>
</cfswitch>
<hr>
<cfscript>
    switch (3) {
    	case  "1,2,3":
    		writeOutput("it's a positive value");
    		break;
    	case 0:
    	    writeOutput("it's 0");
    		break;
    	default:
    		writeOutput("don't know");
    		break;
    }
    writeOutput("<hr>");
    switch (3) {
// correct syntax
        case  "1":
    	case  "2":
    	case  "3":
    		writeOutput("it's a positive value");
    		break;
    	case 0:
    	    writeOutput("it's 0");
    		break;
    	default:
    		writeOutput("don't know");
    		break;
    }
</cfscript>

String literals being converted

The convertOperators function does not discriminate between what is code and what is not, which results in the issue demonstrated below.

<cfset variables.message = "This is not supposed to be converted">
converts to
variables.message = "This != supposed to be converted";

mixed case cfml tags confusion

<Cfif arguments.throw_exception>
    <cfreturn true>
<cfelse>
    <cfreturn false>
</cfif>

is returned as

if ( Cfif arguments.throw_exception ) {
    return true;
} else {
    return false;
}

cfinterface and messaging

Testing the CLI command on the ColdBox source code (which still has some tags floating around) I noticed that interfaces don't work.

! Error: system\ioc\scopes\IScope.cfc
  Unable to convert tag: cfinterface to CFML Script
+  (Converted): system\ioc\scopes\IScope.cfc

Also, the messaging is confusing since it says it was unable to convert, but then says the file was converted (it wasn't).

Don't ask for confirmation if a CFC is already script

Don't ask the user if they want to convert a CFC, only to tell them it's already script. Parse it first and then if it's script but them. I would still out the message that it's been looked at, but perhaps hide it behind a --verbose flag since the output might get a little cray cray on a large app.

CommandBox:cfscript> cfscriptme ./
cfscript.me v0.1.4 built by Foundeo Inc.

    ___                      _
   / __)                    | |
 _| |__ ___  _   _ ____   __| |_____  ___
(_   __) _ \| | | |  _ \ / _  | ___ |/ _ \
  | | | |_| | |_| | | | ( (_| | ____| |_| |
  |_|  \___/|____/|_| |_|\____|_____)\___/
                                         inc.

Can I overwrite Application.cfc? (yes/no): y
+  (Already CFML Script): Application.cfc
Can I overwrite config\Application.cfc? (yes/no): y
+  (Already CFML Script): config\Application.cfc
Can I overwrite config\CacheBox.cfc? (yes/no): y
+  (Converted): config\CacheBox.cfc
Can I overwrite config\Coldbox.cfc? (yes/no): y
+  (Already CFML Script): config\Coldbox.cfc
Can I overwrite config\WireBox.cfc? (yes/no): y
+  (Converted): config\WireBox.cfc
Can I overwrite handlers\Main.cfc? (yes/no): y
+  (Converted): handlers\Main.cfc
Can I overwrite tests\Application.cfc? (yes/no): y
+  (Converted): tests\Application.cfc
Can I overwrite tests\specs\integration\MainBDDTest.cfc? (yes/no): y
+  (Already CFML Script): tests\specs\integration\MainBDDTest.cfc
Can I overwrite tests\specs\integration\MainTest.cfc? (yes/no): y
+  (Converted): tests\specs\integration\MainTest.cfc

Done. Bugs / Suggestions: https://github.com/foundeo/toscript/issues

CFQuery not converting to new query()

Input

` < cfcomponent >
< cfset variables.n = 10 >
< cffunction name="init" >
< cfargument name="number" >
< cfset variables.n = arguments.number >
< cfreturn this >

	<cffunction name="myQuery" returntype="query">
	    <cfquery name="myQuery" datasource="myDataSource">
	        SELECT 
	            Column1,
	            Column2
            FROM [dbo].[myTable]
	    </cfquery>
		<cfreturn myQuery>
	</cffunction>

`

OUTPUT

`component {
variables.n = 10;

public function init(number) {
	variables.n = arguments.number;
	return this;
}

public query function myQuery() {
	cfquery( name="myQuery", datasource="myDataSource" ) { //Note: queryExecute() is the preferred syntax but this syntax is easier to convert generically

		writeOutput("SELECT 
	            Column1,
	            Column2
            FROM [dbo].[myTable]");
	}
	return myQuery;
}

}
`

Allow for file globbing in paths

So it would be super cool to allow for file globbing (especially for the CLI command) so I could say to convert folders like /models/**.cfc, **.cfc, or /handlers/oneSpecificPackage/*.cfc.

I've already got a library for this that I use in CommandBox that you can just pull in as a dependency.
https://www.forgebox.io/view/globber

It's a transient with a nice fluent DSL to get directory listings for you and even handle FP-style iterations over the results.

wirebox.getInstance( 'globber' )
    .setPattern( 'C:/myFolder/*.md' )
    .apply( function( path ) {
        fileDelete( path );
    } );

It's also worth noting that CommandBox 3.7 will have native support for globbing parameters in commands by just setting the parameter type, but it's still in beta.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.