From 27fca8cf6c43e42f7113e9e0619b03d79240d316 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:54:29 +0000 Subject: [PATCH 01/13] Bump com.diffplug.spotless from 7.0.1 to 7.0.2 Bumps com.diffplug.spotless from 7.0.1 to 7.0.2. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7c0cd79b2..7f66ea637 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { id "application" id 'antlr' // For source code formatting - id "com.diffplug.spotless" version "7.0.1" + id "com.diffplug.spotless" version "7.0.2" // For building shadow jars with jdk 17 ONLY //id 'com.github.johnrengelman.shadow' version '8.1.1' // For building shadow jars using JDK 21 +, they had to fork From dd897bceb94c6c10f911ef6a47fc0fd82b36e2c6 Mon Sep 17 00:00:00 2001 From: Jon Clausen Date: Mon, 20 Jan 2025 12:24:32 -0500 Subject: [PATCH 02/13] BL-958 Resolve - Fix duplicates being returned if top-level key is array --- .../runtime/types/util/StructUtil.java | 8 ++-- .../bifs/global/struct/StructFindKeyTest.java | 43 ++++++++++++++++--- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java index 79ec61000..eeac54fe7 100644 --- a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java +++ b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java @@ -464,11 +464,11 @@ public static Stream findKey( IStruct struct, String key ) { flatMap.entrySet() .stream() .filter( entry -> { - Array splitParts = Array.of( entry.getKey().getName().toLowerCase().split( "\\." ) ); + String[] splitParts = entry.getKey().getName().toLowerCase().split( "\\." ); String stringKey = entry.getKey().getName().toLowerCase(); - return splitParts.size() > 1 - ? splitParts.get( splitParts.size() - 1 ).equals( key.toLowerCase() ) || stringKey.equals( key.toLowerCase() ) - : stringKey.equals( key.toLowerCase() ); + return splitParts.length > 1 + ? splitParts[ splitParts.length - 1 ].equals( key.toLowerCase() ) || stringKey.equals( key.toLowerCase() ) + : results.stream().filter( result -> result.get( Key.value ).equals( entry.getValue() ) ).count() == 0 && stringKey.equals( key.toLowerCase() ); } ) .map( entry -> { Struct returnStruct = new Struct( Struct.TYPES.LINKED ); diff --git a/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java b/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java index 8b59a8f1f..a66e59812 100644 --- a/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java +++ b/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java @@ -239,9 +239,10 @@ public void testOwnerValues() { } }; result = StructFindKey( myStruct, "pig.total" ); - resultTop = StructFindKey( myStruct, "cat" ); - resultCat = resultTop.first(); - resultOwner = resultCat.owner; + resultTop = StructFindKey( myStruct, "bird", "all" ); + resultTopLength = resultTop.len(); + resultBird = resultTop.first(); + resultOwner = resultBird.owner; resultNested = structFindKey( myStruct, "size", "all" ); nestedOwner = resultNested.first().owner; resultParrotNames = structFindKey( myStruct, "bird.species.parrot.names", "all" ); @@ -253,8 +254,9 @@ public void testOwnerValues() { assertEquals( 1, variables.getAsArray( result ).size() ); assertEquals( 1, variables.getAsArray( Key.of( "resultTop" ) ).size() ); assertEquals( Struct.class, variables.get( Key.of( "resultOwner" ) ).getClass() ); - assertEquals( variables.getAsStruct( Key.of( "resultCat" ) ).getAsStruct( Key.of( "value" ) ), - variables.getAsStruct( Key.of( "resultOwner" ) ).getAsStruct( Key.of( "cat" ) ) ); + assertEquals( 1, variables.getAsInteger( Key.of( "resultTopLength" ) ) ); + assertEquals( variables.getAsStruct( Key.of( "resultBird" ) ).getAsStruct( Key.of( "value" ) ), + variables.getAsStruct( Key.of( "resultOwner" ) ).getAsStruct( Key.of( "bird" ) ) ); assertEquals( Array.class, variables.get( Key.of( "resultNested" ) ).getClass() ); assertEquals( 3, variables.getAsArray( Key.of( "resultNested" ) ).size() ); assertEquals( Struct.class, variables.get( Key.of( "nestedOwner" ) ).getClass() ); @@ -265,4 +267,35 @@ public void testOwnerValues() { assertEquals( Array.class, variables.getAsStruct( Key.of( "parrotResult" ) ).get( Key.value ).getClass() ); } + @DisplayName( "It tests top level struct find with arrays" ) + @Test + public void testTopLevelArrays() { + //@formatter:off + instance.executeSource( + """ + myStruct = { + animals: [ + { + type: "dog", + age: 12 + }, + { + type: "cat", + age: 3 + }, + { + type: "pig", + age: 5 + } + ] + }; + result = StructFindKey( myStruct, "animals", "all" ); + """, + context ); + //@formatter:on + assertTrue( variables.get( result ) instanceof Array ); + assertEquals( 1, variables.getAsArray( result ).size() ); + + } + } From 4558172e403d0e872465cd359d285dd2c3329675 Mon Sep 17 00:00:00 2001 From: jclausen <5255645+jclausen@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:26:30 +0000 Subject: [PATCH 03/13] Apply cfformat changes --- src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java index eeac54fe7..263e35b7f 100644 --- a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java +++ b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java @@ -468,7 +468,8 @@ public static Stream findKey( IStruct struct, String key ) { String stringKey = entry.getKey().getName().toLowerCase(); return splitParts.length > 1 ? splitParts[ splitParts.length - 1 ].equals( key.toLowerCase() ) || stringKey.equals( key.toLowerCase() ) - : results.stream().filter( result -> result.get( Key.value ).equals( entry.getValue() ) ).count() == 0 && stringKey.equals( key.toLowerCase() ); + : results.stream().filter( result -> result.get( Key.value ).equals( entry.getValue() ) ).count() == 0 + && stringKey.equals( key.toLowerCase() ); } ) .map( entry -> { Struct returnStruct = new Struct( Struct.TYPES.LINKED ); From 06cb84022baa756dd7ae3501ccc713d231c08402 Mon Sep 17 00:00:00 2001 From: Jon Clausen Date: Mon, 20 Jan 2025 12:49:32 -0500 Subject: [PATCH 04/13] add comment to force release --- src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java index 263e35b7f..1844a30b6 100644 --- a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java +++ b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java @@ -468,6 +468,7 @@ public static Stream findKey( IStruct struct, String key ) { String stringKey = entry.getKey().getName().toLowerCase(); return splitParts.length > 1 ? splitParts[ splitParts.length - 1 ].equals( key.toLowerCase() ) || stringKey.equals( key.toLowerCase() ) + // For single keys make sure we check that it wasn't added above : results.stream().filter( result -> result.get( Key.value ).equals( entry.getValue() ) ).count() == 0 && stringKey.equals( key.toLowerCase() ); } ) From 818fe20a9d2924b1435bd484a1b72be3dbfbb02a Mon Sep 17 00:00:00 2001 From: Jon Clausen Date: Mon, 20 Jan 2025 14:23:47 -0500 Subject: [PATCH 05/13] defensive coding updates --- .../boxlang/runtime/types/util/StructUtil.java | 14 +++++++++++++- .../bifs/global/struct/StructFindKeyTest.java | 10 +++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java index 1844a30b6..5a9401ea1 100644 --- a/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java +++ b/src/main/java/ortus/boxlang/runtime/types/util/StructUtil.java @@ -469,7 +469,19 @@ public static Stream findKey( IStruct struct, String key ) { return splitParts.length > 1 ? splitParts[ splitParts.length - 1 ].equals( key.toLowerCase() ) || stringKey.equals( key.toLowerCase() ) // For single keys make sure we check that it wasn't added above - : results.stream().filter( result -> result.get( Key.value ).equals( entry.getValue() ) ).count() == 0 + : results.stream() + .filter( + result -> { + Object resultObj = result.get( Key.value ); + Object entryObj = entry.getValue(); + if ( resultObj == null ) { + return entry.getValue() == null; + } else { + return entryObj != null ? resultObj.equals( entryObj ) : false; + } + } + ) + .count() == 0 && stringKey.equals( key.toLowerCase() ); } ) .map( entry -> { diff --git a/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java b/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java index a66e59812..c45402d6c 100644 --- a/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java +++ b/src/test/java/ortus/boxlang/runtime/bifs/global/struct/StructFindKeyTest.java @@ -274,18 +274,22 @@ public void testTopLevelArrays() { instance.executeSource( """ myStruct = { + fruits : nullValue(), animals: [ { type: "dog", - age: 12 + age: 12, + breed: "collie" }, { type: "cat", - age: 3 + age: 3, + breed: "siamese" }, { type: "pig", - age: 5 + age: 5, + breed: nullValue() } ] }; From 04168aaa62290b56056bdbd78fd9ea080f062557 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 20 Jan 2025 16:37:57 -0600 Subject: [PATCH 06/13] BL-959 --- .../ortus/boxlang/runtime/util/DumpUtil.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/java/ortus/boxlang/runtime/util/DumpUtil.java b/src/main/java/ortus/boxlang/runtime/util/DumpUtil.java index 239d46b4d..b9ab9b797 100644 --- a/src/main/java/ortus/boxlang/runtime/util/DumpUtil.java +++ b/src/main/java/ortus/boxlang/runtime/util/DumpUtil.java @@ -78,28 +78,28 @@ public class DumpUtil { /** * This is used to track objects that have been dumped to prevent infinite recursion. */ - private static final ThreadLocal> dumpedObjects = ThreadLocal.withInitial( HashSet::new ); + private static final ThreadLocal> dumpedObjects = ThreadLocal.withInitial( HashSet::new ); /** * This is used to cache the templates for dumping objects. */ - private static final ConcurrentMap dumpTemplateCache = new ConcurrentHashMap<>(); + private static final ConcurrentMap dumpTemplateCache = new ConcurrentHashMap<>(); /** * This is used to cache the templates for dumping objects. */ - private static final Logger logger = LoggerFactory.getLogger( DumpUtil.class ); + private static final Logger logger = LoggerFactory.getLogger( DumpUtil.class ); /** * This is the base path for the templates when using the HTML format. * This inside of the jar as a resource. {@see resources/dump/html} */ - private static final String TEMPLATES_BASE_PATH = "/dump/html/"; + private static final String TEMPLATES_BASE_PATH = "/dump/html/"; /** * This is the default template name to use when the target object does not have a template. */ - private static final String DEFAULT_DUMP_TEMPLATE = "Class.bxm"; + private static final String DEFAULT_DUMP_TEMPLATE = "Class.bxm"; /** * @@ -357,13 +357,18 @@ public static void dumpHTMLToBuffer( // Prep variables to use for dumping String posInCode = ""; - String dumpTemplate = null; + DumpTemplate dumpTemplate = null; StringBuffer buffer = null; String templateName = discoverTemplateName( target, context ); try { // Get and Compile the Dump template to execute. dumpTemplate = getDumpTemplate( context, templateName ); + } catch ( Throwable t ) { + throw new BoxRuntimeException( "Error loading dump template [" + templateName + "]", t ); + } + + try { // Just using this so I can have my own variables scope to use. IBoxContext dumpContext = new ContainerBoxContext( context ); // This is expensive, so only do it on the outer dump @@ -372,8 +377,8 @@ public static void dumpHTMLToBuffer( context.pushBuffer( buffer ); posInCode = ExceptionUtil.getCurrentPositionInCode(); // This assumes HTML output. Needs to be dynamic as XML or plain text output wouldn't have CSS - dumpContext.writeToBuffer( "", true ); - dumpContext.writeToBuffer( "", true ); + dumpContext.writeToBuffer( "", true ); + dumpContext.writeToBuffer( "", true ); } // Place the variables in the scope @@ -389,7 +394,9 @@ public static void dumpHTMLToBuffer( ) ); // Execute the dump template - context.getRuntime().executeSource( dumpTemplate, dumpContext, BoxSourceType.BOXTEMPLATE ); + context.getRuntime().executeSource( dumpTemplate.source(), dumpContext, BoxSourceType.BOXTEMPLATE ); + } catch ( Throwable t ) { + throw new BoxRuntimeException( "Error executing dump template [" + dumpTemplate.path() + "]", t ); } finally { // Clean up the dumped objects dumped.remove( thisHashCode ); @@ -476,7 +483,7 @@ else if ( target instanceof Duration || target instanceof ZoneId ) { * * @return The compiled dump template */ - private static String getDumpTemplate( IBoxContext context, String dumpTemplateName ) { + private static DumpTemplate getDumpTemplate( IBoxContext context, String dumpTemplateName ) { String dumpTemplatePath = TEMPLATES_BASE_PATH + dumpTemplateName; // Bypass caching in debug mode for easier testing @@ -500,7 +507,7 @@ private static String getDumpTemplate( IBoxContext context, String dumpTemplateN * * @return The dump template */ - private static String computeDumpTemplate( String dumpTemplatePath, IBoxContext context ) { + private static DumpTemplate computeDumpTemplate( String dumpTemplatePath, IBoxContext context ) { Objects.requireNonNull( dumpTemplatePath, "dumpTemplatePath cannot be null" ); // Try by resource first @@ -525,8 +532,11 @@ private static String computeDumpTemplate( String dumpTemplatePath, IBoxContext // \\A is the beginning of the input boundary so it reads the entire file in one go. try ( Scanner s = new Scanner( dumpTemplate ).useDelimiter( "\\A" ) ) { - return s.hasNext() ? s.next() : ""; + return new DumpTemplate( dumpTemplatePath, s.hasNext() ? s.next() : "" ); } } + public record DumpTemplate( String path, String source ) { + } + } From 757b6c5562c5b17efc060d90c2ce83212cd9c6a2 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 20 Jan 2025 17:16:51 -0600 Subject: [PATCH 07/13] BL-960 --- .../TestCases/components/BoxTemplateTest.java | 26 ++++++++++++++++++- .../TestCases/components/CFTemplateTest.java | 22 ++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/test/java/TestCases/components/BoxTemplateTest.java b/src/test/java/TestCases/components/BoxTemplateTest.java index 3c57227ca..41415f0f8 100644 --- a/src/test/java/TestCases/components/BoxTemplateTest.java +++ b/src/test/java/TestCases/components/BoxTemplateTest.java @@ -247,7 +247,6 @@ public void testComponentIslandBufferOrder() { @DisplayName( "component script Island inception" ) @Test - @Disabled( "This can't work without re-working the lexers to 'count' the island blocks." ) public void testComponentScriptIslandInception() { instance.executeSource( """ @@ -269,6 +268,31 @@ public void testComponentScriptIslandInception() { assertThat( variables.get( result ) ).isEqualTo( "one two three four five six seven" ); } + @DisplayName( "component script Island inception 2" ) + @Test + @Disabled( "BL-960" ) + public void testComponentScriptIslandInception2() { + instance.executeSource( + """ + + + + result &= " two"; + collection = [1] + for( foo in collection ) { + ``` + + ``` + } + result &= " four" + + + + """, context, BoxSourceType.BOXTEMPLATE ); + + assertThat( variables.get( result ) ).isEqualTo( "one two three four five" ); + } + @Test public void testTryCatch1() { instance.executeSource( diff --git a/src/test/java/TestCases/components/CFTemplateTest.java b/src/test/java/TestCases/components/CFTemplateTest.java index aaa33a962..19a613201 100644 --- a/src/test/java/TestCases/components/CFTemplateTest.java +++ b/src/test/java/TestCases/components/CFTemplateTest.java @@ -248,6 +248,28 @@ public void testComponentScriptIslandInception() { assertThat( variables.get( result ) ).isEqualTo( "one two three four five six seven" ); } + @DisplayName( "component script Island inception 2" ) + @Test + public void testComponentScriptIslandInception2() { + instance.executeSource( + """ + + + result &= " two"; + collection = [1] + for( foo in collection ) { + ``` + + ``` + } + result &= " four" + + + """, context, BoxSourceType.CFTEMPLATE ); + + assertThat( variables.get( result ) ).isEqualTo( "one two three four five" ); + } + @Test public void testTryCatch1() { instance.executeSource( From 83b2fd93de77a780adc4375d7d4a3aa203f62ced Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 20 Jan 2025 17:18:11 -0600 Subject: [PATCH 08/13] BL-960 --- src/test/java/TestCases/components/CFTemplateTest.java | 1 + test.txt | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 test.txt diff --git a/src/test/java/TestCases/components/CFTemplateTest.java b/src/test/java/TestCases/components/CFTemplateTest.java index 19a613201..efee5a2e5 100644 --- a/src/test/java/TestCases/components/CFTemplateTest.java +++ b/src/test/java/TestCases/components/CFTemplateTest.java @@ -250,6 +250,7 @@ public void testComponentScriptIslandInception() { @DisplayName( "component script Island inception 2" ) @Test + @Disabled( "BL-960" ) public void testComponentScriptIslandInception2() { instance.executeSource( """ diff --git a/test.txt b/test.txt new file mode 100644 index 000000000..019c34f87 --- /dev/null +++ b/test.txt @@ -0,0 +1,2 @@ +__script__ +for( var i=0; i>10; i++ ) {} \ No newline at end of file From 0dc551c44b554edad90589a6994188651c77d6c9 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 20 Jan 2025 17:18:35 -0600 Subject: [PATCH 09/13] BL-960 --- .../TestCases/components/BoxTemplateTest.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/test/java/TestCases/components/BoxTemplateTest.java b/src/test/java/TestCases/components/BoxTemplateTest.java index 41415f0f8..ab1211b90 100644 --- a/src/test/java/TestCases/components/BoxTemplateTest.java +++ b/src/test/java/TestCases/components/BoxTemplateTest.java @@ -274,21 +274,19 @@ public void testComponentScriptIslandInception() { public void testComponentScriptIslandInception2() { instance.executeSource( """ - - - - result &= " two"; - collection = [1] - for( foo in collection ) { - ``` - - ``` - } - result &= " four" - - - - """, context, BoxSourceType.BOXTEMPLATE ); + + + result &= " two"; + collection = [1] + for( foo in collection ) { + ``` + + ``` + } + result &= " four" + + + """, context, BoxSourceType.BOXTEMPLATE ); assertThat( variables.get( result ) ).isEqualTo( "one two three four five" ); } From d6e6bee9624b90d620b6ba661f5a91a8788b50af Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 20 Jan 2025 22:53:07 -0600 Subject: [PATCH 10/13] BL-960 --- src/main/resources/dump/html/Array.bxm | 18 ++-- src/main/resources/dump/html/BoxClass.bxm | 24 +++-- src/main/resources/dump/html/Class.bxm | 102 +++++++++------------- src/main/resources/dump/html/Function.bxm | 68 +++++++-------- src/main/resources/dump/html/List.bxm | 20 ++--- src/main/resources/dump/html/Map.bxm | 21 ++--- src/main/resources/dump/html/Struct.bxm | 59 +++---------- src/main/resources/dump/html/XML.bxm | 10 +-- 8 files changed, 121 insertions(+), 201 deletions(-) diff --git a/src/main/resources/dump/html/Array.bxm b/src/main/resources/dump/html/Array.bxm index 942452c64..87b21b180 100644 --- a/src/main/resources/dump/html/Array.bxm +++ b/src/main/resources/dump/html/Array.bxm @@ -28,13 +28,11 @@ class="d-none" > - - for ( i = 1; i <= var.len(); i++ ) { - // Top limit only if > 0 - if( !isNull( top ) && i > top ) { - break; - } - ``` + + + + +
- ``` - } -
+ diff --git a/src/main/resources/dump/html/BoxClass.bxm b/src/main/resources/dump/html/BoxClass.bxm index 62ce8d0f8..9c3cce08b 100644 --- a/src/main/resources/dump/html/BoxClass.bxm +++ b/src/main/resources/dump/html/BoxClass.bxm @@ -116,20 +116,16 @@ - - for( thisAnnotation in annotations ) { - ``` - - - #encodeForHTML( thisAnnotation )# - - - #writeDump( annotations[ thisAnnotation ] )# - - - ``` - } - + + + + #encodeForHTML( thisAnnotation )# + + + #writeDump( annotations[ thisAnnotation ] )# + + + diff --git a/src/main/resources/dump/html/Class.bxm b/src/main/resources/dump/html/Class.bxm index 14c027da9..06893b28a 100644 --- a/src/main/resources/dump/html/Class.bxm +++ b/src/main/resources/dump/html/Class.bxm @@ -78,28 +78,24 @@ - - for( variables.field in fields ) { - ``` - - - #encodeForHTML( variables.field.getName() )# - - -
#encodeForHTML( variables.field.toString() )#
- - - - #encodeForHTML( variables.field.get( var ) )# - - --- Not Available --- - - - - - ``` - } -
+ + + + #encodeForHTML( variables.field.getName() )# + + +
#encodeForHTML( variables.field.toString() )#
+ + + + #encodeForHTML( variables.field.get( var ) )# + + --- Not Available --- + + + + +
@@ -130,18 +126,14 @@ - - for( variables.annotation in annotations ) { - ``` - - #variables.annotation.annotationType().toString()# - -
#encodeForHTML( variables.annotation.toString() )#
- - - ``` - } -
+ + + #variables.annotation.annotationType().toString()# + +
#encodeForHTML( variables.annotation.toString() )#
+ + +
@@ -171,17 +163,13 @@ - - for( variables.constructor in constructors ) { - ``` - - -
#encodeForHTML( variables.constructor.toString() )#
- - - ``` - } -
+ + + +
#encodeForHTML( variables.constructor.toString() )#
+ + +
@@ -214,20 +202,16 @@ NameSignature - - for( variables.method in methods ) { - ``` - - - #encodeForHTML( variables.method.getName() )# - - -
#encodeForHTML( variables.method.toString() )#
- - - ``` - } -
+ + + + #encodeForHTML( variables.method.getName() )# + + +
#encodeForHTML( variables.method.toString() )#
+ + +
diff --git a/src/main/resources/dump/html/Function.bxm b/src/main/resources/dump/html/Function.bxm index 00f48a620..d29054d9e 100644 --- a/src/main/resources/dump/html/Function.bxm +++ b/src/main/resources/dump/html/Function.bxm @@ -67,30 +67,26 @@ - - for( thisArg in args ) { - argHint = thisArg.documentation().hint ?: thisArg.annotations().hint ?: "" - ``` - - - #encodeForHTML( thisArg.required() )# - - - #encodeForHTML( thisArg.type() )# - - - #encodeForHTML( thisArg.name() )# - - - #writedump( var: thisArg.defaultValue(), top: isNull( top ) ? null : top - 1, expand: expand )# - - - #encodeForHTML( argHint )# - - - ``` - } - + + + + + #encodeForHTML( thisArg.required() )# + + + #encodeForHTML( thisArg.type() )# + + + #encodeForHTML( thisArg.name() )# + + + #writedump( var: thisArg.defaultValue(), top: isNull( top ) ? null : top - 1, expand: expand )# + + + #encodeForHTML( argHint )# + + + @@ -123,20 +119,16 @@ - - for( thisAnnotation in annotations ) { - ``` - - - #encodeForHTML( thisAnnotation )# - - - #writeDump( annotations[ thisAnnotation ] )# - - - ``` - } - + + + + #encodeForHTML( thisAnnotation )# + + + #writeDump( annotations[ thisAnnotation ] )# + + + diff --git a/src/main/resources/dump/html/List.bxm b/src/main/resources/dump/html/List.bxm index c965fd696..b59cfc5db 100644 --- a/src/main/resources/dump/html/List.bxm +++ b/src/main/resources/dump/html/List.bxm @@ -28,13 +28,11 @@ class="d-none" > - - for ( i = 0; i < var.size(); i++ ) { - // Top limit only if > 0 - if( !isNull( top ) && i >= top ) { - break; - } - ``` + + + + + - #i+1# + #i#
- +
- ``` - } -
+ diff --git a/src/main/resources/dump/html/Map.bxm b/src/main/resources/dump/html/Map.bxm index be3c19780..26ab44a6e 100644 --- a/src/main/resources/dump/html/Map.bxm +++ b/src/main/resources/dump/html/Map.bxm @@ -14,7 +14,7 @@ #label# - #var.getClass().getName()#: - #top#/#var.size()# items + #top#/#var.size()# item(s) @@ -22,21 +22,18 @@ #label# - #var.getClass().getName()#: - #top#/#var.size()# items + #top#/#var.size()# item(s) class="d-none" > - - index = 1; - for ( key in var ) { - // Top limit only if > 0 - if( !isNull( top ) && index++ > top ) { - break; - } - ``` + + + + + - ``` - } - + diff --git a/src/main/resources/dump/html/Struct.bxm b/src/main/resources/dump/html/Struct.bxm index e0db129f7..245a8dd97 100644 --- a/src/main/resources/dump/html/Struct.bxm +++ b/src/main/resources/dump/html/Struct.bxm @@ -4,39 +4,13 @@
- - - - - - - - - + + + + @@ -54,28 +28,21 @@ - class="d-none" > - - theCollection = var; - if( var instanceof 'CGIScope' ) { - theCollection = var.getDumpKeys(); - } - index = 1; - for ( key in theCollection ) { - if( !isNull( top ) && index++ > top ) { - break; - } - ``` + + + + + - ``` - } - +
open aria-expanded="true"aria-expanded="false" - > - - #label# - - #encodeForHTML( var.getName().getName().toUpperCase() )# Scope: - - #top#/#var.getDumpKeys().size()# - - #top#/#var.len()# - - - - - #label# - - #encodeForHTML( var.getName().getName().toUpperCase() )# Scope: - #top#/#var.len()# - - #label# - - Struct: + #dumpTitle# #top#/#var.len()# #label# - - Struct: + #dumpTitle# #top#/#var.len()#
diff --git a/src/main/resources/dump/html/XML.bxm b/src/main/resources/dump/html/XML.bxm index 6181a4690..b840b85f3 100644 --- a/src/main/resources/dump/html/XML.bxm +++ b/src/main/resources/dump/html/XML.bxm @@ -21,10 +21,8 @@ class="d-none" > - - theCollection = var.getDumpRepresentation(); - for ( key in theCollection ) { - ``` + + - ``` - } - + From aea98894cdc3cbf99dcdd893eb3d3c99dc345274 Mon Sep 17 00:00:00 2001 From: Jacob Beers Date: Tue, 21 Jan 2025 00:12:24 -0600 Subject: [PATCH 11/13] BL-960 Fix ASM compilation errors --- .../transformer/expression/BoxAssignmentTransformer.java | 6 +++--- .../transformer/expression/BoxIdentifierTransformer.java | 2 +- .../expression/BoxUnaryOperationTransformer.java | 2 +- .../transformer/statement/BoxScriptIslandTransformer.java | 6 ++---- .../transformer/statement/BoxTemplateIslandTransformer.java | 6 ++---- src/test/java/TestCases/components/BoxTemplateTest.java | 2 -- src/test/java/TestCases/components/CFTemplateTest.java | 1 - 7 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxAssignmentTransformer.java b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxAssignmentTransformer.java index 41a4d75a5..e90dddb54 100644 --- a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxAssignmentTransformer.java +++ b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxAssignmentTransformer.java @@ -266,7 +266,7 @@ public List transformEquals( BoxExpression left, List transformCompoundEquals( BoxAssignment assigment "getDefaultAssignmentScope", Type.getMethodDescriptor( Type.getType( IScope.class ) ), true ) ); - nodes.add( new LdcInsnNode( true ) ); + nodes.add( new LdcInsnNode( 1 ) ); nodes.add( new MethodInsnNode( Opcodes.INVOKEINTERFACE, Type.getInternalName( IBoxContext.class ), "scopeFindNearby", @@ -463,7 +463,7 @@ private List assignNullValue( BoxIdentifier name ) { "name", Type.getDescriptor( Key.class ) ) ); nodes.add( new InsnNode( Opcodes.ACONST_NULL ) ); - nodes.add( new LdcInsnNode( true ) ); + nodes.add( new LdcInsnNode( 1 ) ); nodes.add( new MethodInsnNode( Opcodes.INVOKEINTERFACE, Type.getInternalName( IBoxContext.class ), diff --git a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxIdentifierTransformer.java b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxIdentifierTransformer.java index ec7401af8..7bddc1787 100644 --- a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxIdentifierTransformer.java +++ b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxIdentifierTransformer.java @@ -63,7 +63,7 @@ public List transform( BoxNode node, TransformerContext contex } else { nodes.add( new InsnNode( Opcodes.ACONST_NULL ) ); } - nodes.add( new LdcInsnNode( false ) ); + nodes.add( new LdcInsnNode( 0 ) ); nodes.add( new MethodInsnNode( Opcodes.INVOKEINTERFACE, Type.getInternalName( IBoxContext.class ), "scopeFindNearby", diff --git a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxUnaryOperationTransformer.java b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxUnaryOperationTransformer.java index 505a3b90b..06605b402 100644 --- a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxUnaryOperationTransformer.java +++ b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/expression/BoxUnaryOperationTransformer.java @@ -83,7 +83,7 @@ public List transform( BoxNode node, TransformerContext contex nodes.addAll( transpiler.getCurrentMethodContextTracker().get().loadCurrentContext() ); nodes.addAll( transpiler.createKey( id.getName() ) ); nodes.add( new InsnNode( Opcodes.ACONST_NULL ) ); - nodes.add( new LdcInsnNode( true ) ); + nodes.add( new LdcInsnNode( 1 ) ); nodes.add( new MethodInsnNode( Opcodes.INVOKEINTERFACE, Type.getInternalName( IBoxContext.class ), "scopeFindNearby", diff --git a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxScriptIslandTransformer.java b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxScriptIslandTransformer.java index 406e6faf5..67bc42d28 100644 --- a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxScriptIslandTransformer.java +++ b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxScriptIslandTransformer.java @@ -28,7 +28,6 @@ import ortus.boxlang.compiler.asmboxpiler.transformer.ReturnValueContext; import ortus.boxlang.compiler.asmboxpiler.transformer.TransformerContext; import ortus.boxlang.compiler.ast.BoxNode; -import ortus.boxlang.compiler.ast.BoxStatement; import ortus.boxlang.compiler.ast.statement.BoxScriptIsland; public class BoxScriptIslandTransformer extends AbstractTransformer { @@ -42,9 +41,8 @@ public List transform( BoxNode node, TransformerContext contex BoxScriptIsland scriptIsland = ( BoxScriptIsland ) node; List nodes = new ArrayList<>(); - for ( BoxStatement statement : scriptIsland.getStatements() ) { - nodes.addAll( transpiler.transform( statement, context, returnContext ) ); - } + + nodes.addAll( AsmHelper.transformBodyExpressions( transpiler, scriptIsland.getStatements(), context, returnContext ) ); return AsmHelper.addLineNumberLabels( nodes, node ); } diff --git a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxTemplateIslandTransformer.java b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxTemplateIslandTransformer.java index 804416ebd..9322a9d83 100644 --- a/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxTemplateIslandTransformer.java +++ b/src/main/java/ortus/boxlang/compiler/asmboxpiler/transformer/statement/BoxTemplateIslandTransformer.java @@ -28,7 +28,6 @@ import ortus.boxlang.compiler.asmboxpiler.transformer.ReturnValueContext; import ortus.boxlang.compiler.asmboxpiler.transformer.TransformerContext; import ortus.boxlang.compiler.ast.BoxNode; -import ortus.boxlang.compiler.ast.BoxStatement; import ortus.boxlang.compiler.ast.statement.component.BoxTemplateIsland; public class BoxTemplateIslandTransformer extends AbstractTransformer { @@ -42,9 +41,8 @@ public List transform( BoxNode node, TransformerContext contex BoxTemplateIsland templateIsland = ( BoxTemplateIsland ) node; List nodes = new ArrayList<>(); - for ( BoxStatement statement : templateIsland.getStatements() ) { - nodes.addAll( transpiler.transform( statement, context, returnContext ) ); - } + + nodes.addAll( AsmHelper.transformBodyExpressions( transpiler, templateIsland.getStatements(), context, returnContext ) ); return AsmHelper.addLineNumberLabels( nodes, node ); } diff --git a/src/test/java/TestCases/components/BoxTemplateTest.java b/src/test/java/TestCases/components/BoxTemplateTest.java index ab1211b90..4d1f63e7c 100644 --- a/src/test/java/TestCases/components/BoxTemplateTest.java +++ b/src/test/java/TestCases/components/BoxTemplateTest.java @@ -25,7 +25,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -270,7 +269,6 @@ public void testComponentScriptIslandInception() { @DisplayName( "component script Island inception 2" ) @Test - @Disabled( "BL-960" ) public void testComponentScriptIslandInception2() { instance.executeSource( """ diff --git a/src/test/java/TestCases/components/CFTemplateTest.java b/src/test/java/TestCases/components/CFTemplateTest.java index efee5a2e5..19a613201 100644 --- a/src/test/java/TestCases/components/CFTemplateTest.java +++ b/src/test/java/TestCases/components/CFTemplateTest.java @@ -250,7 +250,6 @@ public void testComponentScriptIslandInception() { @DisplayName( "component script Island inception 2" ) @Test - @Disabled( "BL-960" ) public void testComponentScriptIslandInception2() { instance.executeSource( """ From a08b5b26038afab79353daf2b32ba6925b02c482 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 21 Jan 2025 13:23:33 +0100 Subject: [PATCH 12/13] BL-935 #resolve add http events: onHTTPRequest, onHTTPResponse --- .../boxlang/runtime/components/net/HTTP.java | 67 ++++++++++++++----- .../boxlang/runtime/events/BoxEvent.java | 7 ++ .../runtime/net/HTTPStatusReasons.java | 13 +++- .../boxlang/runtime/net/HttpManager.java | 6 +- .../ortus/boxlang/runtime/net/URIBuilder.java | 7 +- 5 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src/main/java/ortus/boxlang/runtime/components/net/HTTP.java b/src/main/java/ortus/boxlang/runtime/components/net/HTTP.java index e21a0ad69..de141c930 100644 --- a/src/main/java/ortus/boxlang/runtime/components/net/HTTP.java +++ b/src/main/java/ortus/boxlang/runtime/components/net/HTTP.java @@ -50,6 +50,7 @@ import ortus.boxlang.runtime.dynamic.casters.DoubleCaster; import ortus.boxlang.runtime.dynamic.casters.StringCaster; import ortus.boxlang.runtime.dynamic.casters.StructCaster; +import ortus.boxlang.runtime.events.BoxEvent; import ortus.boxlang.runtime.net.HTTPStatusReasons; import ortus.boxlang.runtime.net.HttpManager; import ortus.boxlang.runtime.net.HttpRequestMultipartBody; @@ -148,21 +149,25 @@ public HTTP() { * */ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBody body, IStruct executionState ) { + // Keeps track of the HTTPParams executionState.put( Key.HTTPParams, new Array() ); + // Process the component for HTTPParams BodyResult bodyResult = processBody( context, body ); + // IF there was a return statement inside our body, we early exit now if ( bodyResult.isEarlyExit() ) { return bodyResult; } - String variableName = StringCaster.cast( attributes.getOrDefault( Key.result, "bxhttp" ) ); + // Prepare invocation of the HTTP request + String variableName = attributes.getAsString( Key.result ); String theURL = attributes.getAsString( Key.URL ); - String method = StringCaster.cast( attributes.getOrDefault( Key.method, "GET" ) ).toUpperCase(); + String method = attributes.getAsString( Key.method ).toUpperCase(); Array params = executionState.getAsArray( Key.HTTPParams ); Struct HTTPResult = new Struct(); + URI targetURI = null; - URI uri = null; try { HttpRequest.Builder builder = HttpRequest.newBuilder(); URIBuilder uriBuilder = new URIBuilder( theURL ); @@ -170,6 +175,7 @@ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBod List formFields = new ArrayList<>(); List files = new ArrayList<>(); builder.header( "User-Agent", "BoxLang" ); + for ( Object p : params ) { IStruct param = StructCaster.cast( p ); String type = param.getAsString( Key.type ); @@ -247,24 +253,43 @@ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBod } builder.method( method, bodyPublisher ); - uri = uriBuilder.build(); - builder.uri( uri ); - HttpRequest request = builder.build(); - HttpClient client = HttpManager.getClient(); - CompletableFuture> inflightRequest = client.sendAsync( request, HttpResponse.BodyHandlers.ofString() ); + targetURI = uriBuilder.build(); + builder.uri( targetURI ); + HttpRequest targetHTTPRequest = builder.build(); + HttpClient client = HttpManager.getClient(); + + // Announce the HTTP request + interceptorService.announce( BoxEvent.ON_HTTP_REQUEST, Struct.of( + "httpClient", client, + "httpRequest", targetHTTPRequest, + "targetURI", targetURI, + "attributes", attributes + ) ); + + // Announce the HTTP request + CompletableFuture> inflightRequest = client.sendAsync( targetHTTPRequest, HttpResponse.BodyHandlers.ofString() ); CompletableFuture> winner = inflightRequest; if ( attributes.containsKey( Key.timeout ) ) { winner = inflightRequest.applyToEither( HttpManager.getTimeoutRequestAsync( attributes.getAsInteger( Key.timeout ) ), result -> result ); } - HttpResponse response = winner.get(); + HttpResponse response = winner.get(); - HttpHeaders httpHeaders = Optional.ofNullable( response.headers() ) + // Announce the HTTP RAW response + // Useful for debugging and pre-processing and timing, since the other events are after the response is processed + interceptorService.announce( BoxEvent.ON_HTTP_RAW_RESPONSE, Struct.of( + "response", response + ) ); + + // Start Processing Results + HttpHeaders httpHeaders = Optional + .ofNullable( response.headers() ) .orElse( HttpHeaders.of( Map.of(), ( a, b ) -> true ) ); - IStruct headers = transformToResponseHeaderStruct( - httpHeaders.map() ); - String httpVersionString = response.version() == HttpClient.Version.HTTP_1_1 ? "HTTP/1.1" : "HTTP/2"; - String statusCodeString = String.valueOf( response.statusCode() ); - String statusText = HTTPStatusReasons.getReasonForStatus( response.statusCode() ); + IStruct headers = transformToResponseHeaderStruct( + httpHeaders.map() + ); + String httpVersionString = response.version() == HttpClient.Version.HTTP_1_1 ? "HTTP/1.1" : "HTTP/2"; + String statusCodeString = String.valueOf( response.statusCode() ); + String statusText = HTTPStatusReasons.getReasonForStatus( response.statusCode() ); headers.put( Key.HTTP_Version, httpVersionString ); headers.put( Key.status_code, statusCodeString ); @@ -292,9 +317,14 @@ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBod } ); HTTPResult.put( Key.cookies, generateCookiesQuery( headers ) ); - // Set the result back into the page + // Set the result back into the page using the variable name ExpressionInterpreter.setVariable( context, variableName, HTTPResult ); + // Announce the HTTP response + interceptorService.announce( BoxEvent.ON_HTTP_RESPONSE, Struct.of( + "result", HTTPResult + ) ); + return DEFAULT_RETURN; } catch ( ExecutionException e ) { Throwable innerException = e.getCause(); @@ -306,8 +336,8 @@ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBod HTTPResult.put( Key.statusText, "Bad Gateway" ); HTTPResult.put( Key.status_text, "Bad Gateway" ); HTTPResult.put( Key.fileContent, "Connection Failure" ); - if ( uri != null ) { - HTTPResult.put( Key.errorDetail, String.format( "Unknown host: %s: Name or service not known.", uri.getHost() ) ); + if ( targetURI != null ) { + HTTPResult.put( Key.errorDetail, String.format( "Unknown host: %s: Name or service not known.", targetURI.getHost() ) ); } else { HTTPResult.put( Key.errorDetail, String.format( "Unknown host: %s: Name or service not known.", theURL ) ); } @@ -317,6 +347,7 @@ public BodyResult _invoke( IBoxContext context, IStruct attributes, ComponentBod } return DEFAULT_RETURN; } catch ( InterruptedException e ) { + Thread.currentThread().interrupt(); throw new BoxRuntimeException( "The request was interrupted", "InterruptedException", e ); } catch ( URISyntaxException | IOException e ) { throw new BoxRuntimeException( e.getMessage(), e ); diff --git a/src/main/java/ortus/boxlang/runtime/events/BoxEvent.java b/src/main/java/ortus/boxlang/runtime/events/BoxEvent.java index 067ffadc9..a7bcc9cd1 100644 --- a/src/main/java/ortus/boxlang/runtime/events/BoxEvent.java +++ b/src/main/java/ortus/boxlang/runtime/events/BoxEvent.java @@ -195,6 +195,13 @@ public enum BoxEvent { PRE_MODULE_UNLOAD( "preModuleUnload" ), POST_MODULE_UNLOAD( "postModuleUnload" ), + /** + * HTTP Events + */ + ON_HTTP_REQUEST( "onHTTPRequest" ), + ON_HTTP_RAW_RESPONSE( "onHTTPRawResponse" ), + ON_HTTP_RESPONSE( "onHTTPResponse" ), + /** * Module Service Events */ diff --git a/src/main/java/ortus/boxlang/runtime/net/HTTPStatusReasons.java b/src/main/java/ortus/boxlang/runtime/net/HTTPStatusReasons.java index 9372af0d7..18fc6ca31 100644 --- a/src/main/java/ortus/boxlang/runtime/net/HTTPStatusReasons.java +++ b/src/main/java/ortus/boxlang/runtime/net/HTTPStatusReasons.java @@ -17,10 +17,10 @@ */ package ortus.boxlang.runtime.net; -import java.util.Map; - import static java.util.Map.entry; +import java.util.Map; + public class HTTPStatusReasons { private static final String UNKNOWN_STATUS = "Unknown Status"; @@ -99,7 +99,14 @@ public class HTTPStatusReasons { entry( 511, "Network Authentication Required" ) ); + /** + * Returns the reason for the given status code. + * + * @param status The status code. + * + * @return The reason for the status code. + */ public static String getReasonForStatus( int status ) { return REASONS.getOrDefault( status, UNKNOWN_STATUS ); } -} \ No newline at end of file +} diff --git a/src/main/java/ortus/boxlang/runtime/net/HttpManager.java b/src/main/java/ortus/boxlang/runtime/net/HttpManager.java index 6fd0a412c..c31c66294 100644 --- a/src/main/java/ortus/boxlang/runtime/net/HttpManager.java +++ b/src/main/java/ortus/boxlang/runtime/net/HttpManager.java @@ -52,7 +52,11 @@ private HttpManager() { */ public static HttpClient getClient() { if ( instance == null ) { - instance = HttpClient.newHttpClient(); + synchronized ( HttpManager.class ) { + if ( instance == null ) { + instance = HttpClient.newHttpClient(); + } + } } return instance; } diff --git a/src/main/java/ortus/boxlang/runtime/net/URIBuilder.java b/src/main/java/ortus/boxlang/runtime/net/URIBuilder.java index 50d1b3b62..5633e728f 100644 --- a/src/main/java/ortus/boxlang/runtime/net/URIBuilder.java +++ b/src/main/java/ortus/boxlang/runtime/net/URIBuilder.java @@ -17,10 +17,6 @@ */ package ortus.boxlang.runtime.net; -import ortus.boxlang.runtime.net.NameValuePair; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.Charset; @@ -28,6 +24,9 @@ import java.util.List; import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class URIBuilder { private @Nullable String scheme; From 7b72b483243ab3c8245dbbf1c5f31bcf2fbaa6e7 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 21 Jan 2025 11:52:07 -0600 Subject: [PATCH 13/13] BL-961 --- src/main/resources/dump/html/Query.bxm | 2 +- .../runtime/components/system/DumpTest.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/resources/dump/html/Query.bxm b/src/main/resources/dump/html/Query.bxm index 1399fa5e9..ae84ba47b 100644 --- a/src/main/resources/dump/html/Query.bxm +++ b/src/main/resources/dump/html/Query.bxm @@ -33,7 +33,7 @@ - + #encodeForHTML( var[ column ] )# diff --git a/src/test/java/ortus/boxlang/runtime/components/system/DumpTest.java b/src/test/java/ortus/boxlang/runtime/components/system/DumpTest.java index aa6387c74..781d7bd78 100644 --- a/src/test/java/ortus/boxlang/runtime/components/system/DumpTest.java +++ b/src/test/java/ortus/boxlang/runtime/components/system/DumpTest.java @@ -76,6 +76,20 @@ public void testCanDumpTag() { assertThat( baos.toString() ).contains( "String" ); } + @DisplayName( "It can dump tag struct" ) + @Test + public void testCanDumpTagStruct() { + // @formatter:off + instance.executeSource( + """ + + """, + context, BoxSourceType.CFTEMPLATE ); + // @formatter:on + System.out.println( baos.toString() ); + assertThat( baos.toString() ).contains( "bar" ); + } + @DisplayName( "It can dump BL tag" ) @Test public void testCanDumpBLTag() {