From de3cb4272f77e6c4e48c0af51a1c4b78ba6b9815 Mon Sep 17 00:00:00 2001 From: jclausen Date: Mon, 3 Jun 2024 17:37:22 -0400 Subject: [PATCH] initial release of WDDX module --- .gitignore | 1 + .ortus-java-style.xml | 774 +++++++++--------- readme.md | 120 +-- .../boxlang/modules/wddx/components/WDDX.java | 98 ++- .../boxlang/modules/wddx/util/WDDXKeys.java | 36 + .../boxlang/modules/wddx/util/WDDXUtil.java | 60 ++ .../modules/wddx/components/WDDXTest.java | 88 +- 7 files changed, 656 insertions(+), 521 deletions(-) create mode 100644 src/main/java/ortus/boxlang/modules/wddx/util/WDDXKeys.java diff --git a/.gitignore b/.gitignore index 783301f..f1b015c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ build/** ### Mac OS ### .DS_Store +grapher ### BOXLANG ### /libs/ diff --git a/.ortus-java-style.xml b/.ortus-java-style.xml index a20d49b..1f339c6 100644 --- a/.ortus-java-style.xml +++ b/.ortus-java-style.xml @@ -1,393 +1,393 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.md b/readme.md index 4cb0913..f67d2be 100644 --- a/readme.md +++ b/readme.md @@ -1,126 +1,20 @@ # ⚡︎ BoxLang Module: WDDX Module -``` -|:------------------------------------------------------:| -| ⚡︎ B o x L a n g ⚡︎ -| Dynamic : Modular : Productive -|:------------------------------------------------------:| -``` +The WDDX module provides the bridge between the WDDX exchange format and BoxLang. It involves reading and parsing XML, converting data types, handling errors, and ensuring performance and compatibility. The module enables the integration of legacy systems with new applications. -
- Copyright Since 2023 by Ortus Solutions, Corp -
- www.boxlang.io | - www.ortussolutions.com -
+It provides the `wddx` component along with its actions of `bx2wddx`, `wddx2bx`, `bx2js` and `wddx2js`. Note that if the compatibility module is installed in the BoxLang runtime, the usage of `bx` in the action changes to `cfml`. -

 

+_*Important Note:* WDDX is, effectively, no longer supported for new development and its continued use as a data interchange format is is highly discouraged. This module should only be used to maintain compatibility for legacy code and developers should be encouraged to sunset its usage._ -This template can be used to create Ortus based BoxLang Modules. To use, just click the `Use this Template` button in the github repository: https://github.com/boxlang-modules/module-template and run the setup task from where you cloned it. -```bash -box task run taskFile=src/build/SetupTemplate -``` -The `SetupTemplate` task will ask you for your module name, id and description and configure the template for you! Enjoy! +## Contributed Functions -## Directory Structure +The compat module will contribute the following components globally: -Here is a brief overview of the directory structure: - -* `.github/workflows` - These are the github actions to test and build the module via CI -* `build` - This is a temporary non-sourced folder that contains the build assets for the module that gradle produces -* `gradle` - The gradle wrapper and configuration -* `src` - Where your module source code lives -* `.cfformat.json` - A CFFormat using the Ortus Standards -* `.editorconfig` - Smooth consistency between editors -* `.gitattributes` - Git attributes -* `.gitignore` - Basic ignores. Modify as needed. -* `.markdownlint.json` - A linting file for markdown docs -* `.ortus-java-style.xml` - Ortus Java Style for IntelliJ, VScode, Eclipse. -* `box.json` - The box.json for your module used to publish to ForgeBox -* `build.gradle` - The gradle build file for the module -* `changelog.md` - A nice changelog tracking file -* `CONTRIBUTING.md` - A contribution guideline -* `gradlew` - The gradle wrapper -* `gradlew.bat` - The gradle wrapper for windows -* `ModuleConfig.cfc` - Your module's configuration. Modify as needed. -* `readme.md` - Your module's readme. Modify as needed. -* `settings.gradle` - The gradle settings file - -Here is a brief overview of the source directory structure: - -* `build` - Build scripts and assets -* `main` - The main module source code - * `bx` - The BoxLang source code - * `ModuleConfig.bx` - The BoxLang module configuration - * `bifs` - BoxLang built-in functions - * `components` - BoxLang components - * `config` - BoxLang configuration, schedulers, etc. - * `interceptors` - BoxLang interceptors - * `libs` - Java libraries to use that are NOT managed by gradle - * `models` - BoxLang models - * `java` - Java source code - * `resources` - Resources for the module placed in final jar -* `test` - * `bx` - The BoxLang test code - * `java` - Java test code - * `resources` - Resources for testing - * `libs` - BoxLang binary goes here for now. - -## Project Properties - -The project name is defined in the `settings.gradle` file. You can change it there. -The project version, BoxLang Version and JDK version is defined in the `build.gradle` file. You can change it there. - -## Gradle Tasks - -Before you get started, you need to run the `downloadBoxLang` task in order to download the latest BoxLang binary until we publish to Maven. - -```bash -gradle downloadBoxLang -``` - -This will store the binary under `/src/test/resources/libs` for you to use in your tests and compiler. Here are some basic tasks - - -| Task | Description | -|---------------------|---------------------------------------------------------------------------------------------------------------------| -| `build` | The default lifecycle task that triggers the build process, including tasks like `clean`, `assemble`, and others. | -| `clean` | Deletes the `build` folders. It helps ensure a clean build by removing any previously generated artifacts. | -| `compileJava` | Compiles Java source code files located in the `src/main/java` directory | -| `compileTestJava` | Compiles Java test source code files located in the `src/test/java` directory | -| `dependencyUpdates` | Checks for updated versions of all dependencies | -| `downloadBoxLang` | Downloads the latest BoxLang binary for testing | -| `jar` | Packages your project's compiled classes and resources into a JAR file `build/libs` folder | -| `javadoc` | Generates the Javadocs for your project and places them in the `build/docs/javadoc` folder | -| `serviceLoader` | Generates the ServiceLoader file for your project | -| `spotlessApply` | Runs the Spotless plugin to format the code | -| `spotlessCheck` | Runs the Spotless plugin to check the formatting of the code | -| `tasks` | Show all the available tasks in the project | -| `test` | Executes the unit tests in your project and produces the reports in the `build/reports/tests` folder | - -## Tests - -Please use the `src/test` folder for your unit tests. You can either test using TestBox o JUnit if it's Java. - -## Github Actions Automation - -The github actions will clone, test, package, deploy your module to ForgeBox and the Ortus S3 accounts for API Docs and Artifacts. So please make sure the following environment variables are set in your repository. - -> Please note that most of them are already defined at the org level - -* `FORGEBOX_TOKEN` - The Ortus ForgeBox API Token -* `AWS_ACCESS_KEY` - The travis user S3 account -* `AWS_ACCESS_SECRET` - The travis secret S3 - -> Please contact the admins in the `#infrastructure` channel for these credentials if needed +* wddx ( e.g. `` and `` depending on the template type, and `wddx...;` in script ) ## Ortus Sponsors -BoxLang is a professional open-source project and it is completely funded by the [community](https://patreon.com/ortussolutions) and [Ortus Solutions, Corp](https://www.ortussolutions.com). Ortus Patreons get many benefits like a cfcasts account, a FORGEBOX Pro account and so much more. If you are interested in becoming a sponsor, please visit our patronage page: [https://patreon.com/ortussolutions](https://patreon.com/ortussolutions) - -### THE DAILY BREAD - - > "I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12 +BoxLang is a professional open-source project and it is completely funded by the [community](https://patreon.com/ortussolutions) and [Ortus Solutions, Corp](https://www.ortussolutions.com). Ortus Patreons get many benefits like a cfcasts account, a FORGEBOX Pro account and so much more. If you are interested in becoming a sponsor, please visits our patronage page: [https://patreon.com/ortussolutions](https://patreon.com/ortussolutions) \ No newline at end of file diff --git a/src/main/java/ortus/boxlang/modules/wddx/components/WDDX.java b/src/main/java/ortus/boxlang/modules/wddx/components/WDDX.java index cdbf25a..6b1ff36 100644 --- a/src/main/java/ortus/boxlang/modules/wddx/components/WDDX.java +++ b/src/main/java/ortus/boxlang/modules/wddx/components/WDDX.java @@ -19,10 +19,18 @@ import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ortus.boxlang.modules.wddx.util.WDDXKeys; +import ortus.boxlang.modules.wddx.util.WDDXUtil; +import ortus.boxlang.runtime.BoxRuntime; import ortus.boxlang.runtime.components.Attribute; import ortus.boxlang.runtime.components.BoxComponent; import ortus.boxlang.runtime.components.Component; import ortus.boxlang.runtime.context.IBoxContext; +import ortus.boxlang.runtime.dynamic.ExpressionInterpreter; +import ortus.boxlang.runtime.dynamic.casters.StringCaster; import ortus.boxlang.runtime.scopes.Key; import ortus.boxlang.runtime.types.IStruct; import ortus.boxlang.runtime.validation.Validator; @@ -30,41 +38,101 @@ @BoxComponent( allowsBody = false ) public class WDDX extends Component { - static Key locationKey = Key.of( "location" ); - static Key shoutKey = Key.of( "shout" ); + private static final Boolean isCompatMode = BoxRuntime.getInstance().getModuleService().getModuleNames().contains( Key.of( "compat" ) ); + private static final String languageTag = isCompatMode ? "cfml" : "bx"; + + public static final Key toWDDXKey = Key.of( languageTag + "2wddx" ); + public static final Key toCFMLKey = Key.of( "wddx2" + languageTag ); + public static final Key toJSKey = Key.of( languageTag + "2js" ); + public static final Key XtoJSKey = Key.of( "wddx2js" ); + + static Logger logger = LoggerFactory.getLogger( WDDX.class ); public WDDX() { super(); declaredAttributes = new Attribute[] { - new Attribute( Key._NAME, "string", Set.of( Validator.REQUIRED ) ), - new Attribute( locationKey, "string", "world", Set.of( Validator.REQUIRED, Validator.valueOneOf( "world", "universe" ) ) ), - new Attribute( shoutKey, "boolean", false, Set.of( Validator.REQUIRED ) ), + new Attribute( Key.action, "string", languageTag + "2wddx", + Set.of( Validator.REQUIRED, Validator.valueOneOf( languageTag + "2wddx", "wddx2" + languageTag, languageTag + "2js", "wddx2js" ) ) ), + new Attribute( Key.input, "any", Set.of( Validator.REQUIRED ) ), + new Attribute( Key.output, "string", Set.of( Validator.REQUIRED ) ), + new Attribute( WDDXKeys.toplevelvariable, "string" ), + new Attribute( WDDXKeys.usetimezoneinfo, "boolean", true ), + // TODO: we warn that these are not supported, for now. Deprecate in a future release + new Attribute( WDDXKeys.validate, "boolean", false ), + new Attribute( WDDXKeys.xmlconform, "boolean", true ), }; } /** - * An example component that says hello + * Serializes and de-serializes CFML data structures to the XML-based WDDX format. + * + * Generates JavaScript statements to instantiate JavaScript objects equivalent to the contents of a WDDX packet or some CFML data structures. + * + * This tag cannot have a body. + * + * Note: If the [compatibility module](https://forgebox.io/view/bx-compat) is installed, the use of `bx` in the action attribute changes to `cfml` instead ( e.g. `cfml2wddx` ) * * @param context The context in which the Component is being invoked * @param attributes The attributes to the Component * @param body The body of the Component * @param executionState The execution state of the Component * - * @attribute.name The name of the person greeting us. + * @attribute.input The input data to be converted * - * @attribute.location The location of the person. + * @attribute.output The variable to which the converted data will be assigned * - * @attribute.shout Whether the person is shouting or not. + * @attribute.action The action to be performed on the input data. One of: bx2wddx, wddx2bx, bx2js, wddx2js * + * @attribute.toplevelvariable The name of the top-level variable to be used in the generated JavaScript code + * + * @attribute.usetimezoneinfo Whether to use timezone information in the generated JavaScript code + * + * @attribute.validate Whether to validate the input XML + * + * @attribute.xmlconform Whether the WDDX input shoud conform to the WDDX DTD */ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBody body, IStruct executionState ) { - String name = attributes.getAsString( Key._NAME ); - String location = attributes.getAsString( locationKey ); - Boolean shout = attributes.getAsBoolean( shoutKey ); + Key actionKey = Key.of( attributes.get( Key.action ) ); + Object input = attributes.get( Key.input ); + String variable = attributes.getAsString( Key.output ); + String toplevelvariable = attributes.getAsString( WDDXKeys.toplevelvariable ); + if ( toplevelvariable == null ) { + toplevelvariable = actionKey + "_JS"; + } + + if ( attributes.getAsBoolean( WDDXKeys.validate ) ) { + logger.warn( "WDDX DTDs are no longer published nor available. Validation cannot not be performed" ); + } + + if ( !attributes.getAsBoolean( WDDXKeys.xmlconform ) ) { + logger.warn( "The WDDX component only allows valid XML. All input must be valid xml. The argument `xmlConform` will be ignored." ); + } - StringBuilder sb = new StringBuilder(); - String greeting = sb.append( "Hello, " ).append( location ).append( " - from " ).append( name ).append( "." ).toString(); - context.writeToBuffer( shout ? greeting.toUpperCase() : greeting ); + if ( actionKey.equals( toWDDXKey ) ) { + ExpressionInterpreter.setVariable( + context, + variable, + WDDXUtil.serialize( input ) + ); + } else if ( actionKey.equals( toCFMLKey ) ) { + ExpressionInterpreter.setVariable( + context, + variable, + WDDXUtil.parse( StringCaster.cast( input ) ) + ); + } else if ( actionKey.equals( toJSKey ) ) { + ExpressionInterpreter.setVariable( + context, + variable, + WDDXUtil.serializeToJavascript( input, toplevelvariable ) + ); + } else if ( actionKey.equals( XtoJSKey ) ) { + ExpressionInterpreter.setVariable( + context, + variable, + WDDXUtil.translateToJavascript( StringCaster.cast( input ), toplevelvariable ) + ); + } return DEFAULT_RETURN; } diff --git a/src/main/java/ortus/boxlang/modules/wddx/util/WDDXKeys.java b/src/main/java/ortus/boxlang/modules/wddx/util/WDDXKeys.java new file mode 100644 index 0000000..b31cd29 --- /dev/null +++ b/src/main/java/ortus/boxlang/modules/wddx/util/WDDXKeys.java @@ -0,0 +1,36 @@ +/** + * [BoxLang] + * + * Copyright [2023] [Ortus Solutions, Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ortus.boxlang.modules.wddx.util; + +import ortus.boxlang.runtime.scopes.Key; + +/** + * Represents a case-insenstive key, while retaining the original case too. + * Implements the Serializable interface in case duplication is requested within + * a native HashMap or ArrayList + */ +public class WDDXKeys { + + public static final Key _MODULE_NAME = Key.of( "wddx" ); + + public static final Key toplevelvariable = Key.of( "toplevelvariable" ); + public static final Key usetimezoneinfo = Key.of( "usetimezoneinfo" ); + public static final Key validate = Key.of( "validate" ); + public static final Key xmlconform = Key.of( "xmlconform" ); + +} \ No newline at end of file diff --git a/src/main/java/ortus/boxlang/modules/wddx/util/WDDXUtil.java b/src/main/java/ortus/boxlang/modules/wddx/util/WDDXUtil.java index eaf47a0..b45a9f8 100644 --- a/src/main/java/ortus/boxlang/modules/wddx/util/WDDXUtil.java +++ b/src/main/java/ortus/boxlang/modules/wddx/util/WDDXUtil.java @@ -18,6 +18,7 @@ package ortus.boxlang.modules.wddx.util; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import ortus.boxlang.runtime.BoxRuntime; @@ -25,8 +26,10 @@ import ortus.boxlang.runtime.dynamic.casters.ArrayCaster; import ortus.boxlang.runtime.dynamic.casters.DateTimeCaster; import ortus.boxlang.runtime.dynamic.casters.GenericCaster; +import ortus.boxlang.runtime.dynamic.casters.IntegerCaster; import ortus.boxlang.runtime.dynamic.casters.KeyCaster; import ortus.boxlang.runtime.dynamic.casters.QueryCaster; +import ortus.boxlang.runtime.dynamic.casters.StringCaster; import ortus.boxlang.runtime.scopes.Key; import ortus.boxlang.runtime.types.Array; import ortus.boxlang.runtime.types.DateTime; @@ -61,6 +64,27 @@ public static Object parse( String wddx ) { public static Object deserializeObject( XML obj ) { switch ( obj.getNode().getNodeName() ) { + case "recordset" : { + Array columnNames = obj.getXMLChildrenAsList().stream().map( child -> child.getXMLAttributes().get( Key._NAME ) ) + .collect( BLCollector.toArray() ); + Array columnTypes = obj.getXMLChildrenAsList().stream() + .map( child -> child.getXMLAttributes().get( Key.type ) != null ? child.getXMLAttributes().get( Key.type ) : "string" ) + .collect( BLCollector.toArray() ); + Query result = Query.fromArray( columnNames, columnTypes, null ); + Array rowData = new Array(); + Integer rowCount = IntegerCaster.cast( obj.getXMLAttributes().get( Key.of( "rowCount" ) ) ); + IntStream.range( 0, rowCount ).forEach( idx -> { + IStruct row = new Struct(); + obj.getXMLChildrenAsList().forEach( ( field ) -> { + String fieldName = StringCaster.cast( field.getXMLAttributes().get( Key._NAME ) ); + Object fieldValue = deserializeObject( field.getXMLChildrenAsList().get( idx ) ); + row.put( Key.of( fieldName ), fieldValue ); + } ); + rowData.add( row ); + } ); + result.addData( rowData ); + return result; + } case "struct" : { IStruct structResult = new Struct( IStruct.TYPES.LINKED_CASE_SENSITIVE ); obj.getXMLChildrenAsList().forEach( ( child ) -> { @@ -158,4 +182,40 @@ public static String serializeQuery( Query obj ) { return serialization; } + /** + * + * Serializes an object to a Javascript variable string + * + * @param obj + * @param variableName + * + * @return + */ + public static String serializeToJavascript( Object obj, String variableName ) { + Key serializeKey = Key.of( "JSONSerialize" ); + IStruct serializeArgs = Struct.of( + Key.var, obj, + Key.queryFormat, "row", + Key.useSecureJSONPrefix, false, + Key.useCustomSerializer, false + ); + + return variableName + " = " + + StringCaster.cast( runtime.getFunctionService().getGlobalFunction( serializeKey ).invoke( context, serializeArgs, false, serializeKey ) ) + ";"; + } + + /** + * + * Translates a WDDX packet to a Javascript variable string + * + * @param wddx + * @param variableName + * + * @return + */ + public static String translateToJavascript( String wddx, String variableName ) { + Object obj = parse( wddx ); + return serializeToJavascript( obj, variableName ); + } + } \ No newline at end of file diff --git a/src/test/java/ortus/boxlang/modules/wddx/components/WDDXTest.java b/src/test/java/ortus/boxlang/modules/wddx/components/WDDXTest.java index 346a506..19bd056 100644 --- a/src/test/java/ortus/boxlang/modules/wddx/components/WDDXTest.java +++ b/src/test/java/ortus/boxlang/modules/wddx/components/WDDXTest.java @@ -1,5 +1,6 @@ package ortus.boxlang.modules.wddx.components; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeAll; @@ -11,6 +12,7 @@ import ortus.boxlang.runtime.BoxRuntime; import ortus.boxlang.runtime.context.IBoxContext; import ortus.boxlang.runtime.context.ScriptingRequestBoxContext; +import ortus.boxlang.runtime.dynamic.casters.QueryCaster; import ortus.boxlang.runtime.scopes.IScope; import ortus.boxlang.runtime.scopes.Key; import ortus.boxlang.runtime.scopes.VariablesScope; @@ -33,14 +35,88 @@ public void setupEach() { variables = context.getScopeNearby( VariablesScope.name ); } - @DisplayName( "It can test the ExampleComponent" ) + @DisplayName( "It tests BX2WDDX in CF Template" ) @Test - public void testExampleComponent() { + public void testBX2WDDXCF() { instance.executeSource( """ - - - """, context, BoxSourceType.CFTEMPLATE ); - assertTrue( variables.getAsString( result ).contains( "Hello, world - from Ortus Solutions." ) ); + + + """, context, BoxSourceType.CFTEMPLATE ); + assertEquals( + variables.getAsString( result ), + "
12testname" + ); + } + + @DisplayName( "It tests BX2WDDX in BX Template" ) + @Test + public void testBX2WDDXBX() { + instance.executeSource( """ + + + """, context, BoxSourceType.BOXTEMPLATE ); + assertEquals( + variables.getAsString( result ), + "
12testname" + ); + } + + @DisplayName( "It tests BX2WDDX in BX Script" ) + @Test + public void testBX2WDDXBXS() { + instance.executeSource( """ + qry = queryNew("id,test","integer,varchar",[{id:1,test:"test"},{id:2,test:"name"}]); + wddx action="bx2wddx" input=qry output="result"; + """, context, BoxSourceType.BOXSCRIPT ); + assertEquals( + variables.getAsString( result ), + "
12testname" + ); + } + + @DisplayName( "It tests WDDX2BX in BX Script" ) + @Test + public void testWDDX2BX() { + variables.put( Key.of( "packet" ), + "
12testname" ); + instance.executeSource( """ + wddx action="wddx2bx" input=packet output="result"; + """, context, BoxSourceType.BOXSCRIPT ); + + assertTrue( variables.get( result ) instanceof ortus.boxlang.runtime.types.Query ); + assertEquals( 2, QueryCaster.cast( variables.get( result ) ).getData().size() ); + + } + + @DisplayName( "It tests WDDX2JS in BX Script" ) + @Test + public void testWDDX2JS() { + variables.put( Key.of( "packet" ), + "
12testname" ); + instance.executeSource( """ + wddx action="wddx2js" input=packet output="result" topLevelVariable="myData"; + """, context, BoxSourceType.BOXSCRIPT ); + + assertTrue( variables.get( result ) instanceof String ); + assertTrue( variables.getAsString( result ).contains( "myData" ) ); + assertTrue( variables.getAsString( result ).contains( "\"columns\"" ) ); + assertTrue( variables.getAsString( result ).contains( "\"data\"" ) ); + + } + + @DisplayName( "It tests CFML2JS in BX Script" ) + @Test + public void testCFMLToJS() { + instance.executeSource( """ + qry = queryNew("id,test","integer,varchar",[{id:1,test:"test"},{id:2,test:"name"}]); + wddx action="bx2js" input=qry output="result" topLevelVariable="myData"; + """, context, BoxSourceType.BOXSCRIPT ); + System.out.println( variables.getAsString( result ) ); + assertTrue( variables.get( result ) instanceof String ); + assertTrue( variables.getAsString( result ).contains( "myData" ) ); + assertTrue( variables.getAsString( result ).contains( "\"columns\"" ) ); + assertTrue( variables.getAsString( result ).contains( "\"data\"" ) ); + } }