You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hop.apache.org by ha...@apache.org on 2026/03/19 07:26:51 UTC

(hop) branch main updated: Issue 1874 (#6824)

This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new a6c41ebd0f Issue 1874 (#6824)
a6c41ebd0f is described below

commit a6c41ebd0fb613cbbbb84b4045a1fc208133cb4a
Author: Matt Casters <ma...@gmail.com>
AuthorDate: Thu Mar 19 08:26:46 2026 +0100

    Issue 1874 (#6824)
    
    * Issues #1874 (JavaScript XML cleanup, MDI test, warning fixes, removed "added classes", added script type injection option)
    
    * Issues #1874 (JavaScript XML cleanup, MDI test, warning fixes, removed "added classes", added script type injection option)
    
    * Issues #1874 (warning fixes)
    
    * Issues #1874 (warning fixes)
---
 integration-tests/mdi/0043-javascript-template.hpl |  74 ++
 integration-tests/mdi/0043-javascript-validate.hpl | 420 ++++++++++
 integration-tests/mdi/0043-javascript.hpl          | 426 ++++++++++
 .../mdi/datasets/golden-javascript-fields.csv      |   4 +
 .../mdi/datasets/golden-javascript-scripts.csv     |   4 +
 .../mdi/datasets/golden-javascript.csv             |   2 +
 integration-tests/mdi/files/javascript.xml         |  65 ++
 integration-tests/mdi/main-0043-javascript.hwf     | 113 +++
 integration-tests/mdi/main-0087-javascript.hwf     |  58 ++
 .../metadata/dataset/golden-javascript-fields.json |  56 ++
 .../dataset/golden-javascript-scripts.json         |  32 +
 .../mdi/metadata/dataset/golden-javascript.json    |  16 +
 .../unit-test/0043-javascript-validate UNIT.json   |  82 ++
 .../transforms/0087-javascript-basics.hpl          | 215 +++++
 .../datasets/golden-javascript-basic.csv           |  11 +
 .../transforms/main-0087-javascript.hwf            | 162 ++++
 .../metadata/dataset/golden-javascript-basic.json  |  48 ++
 .../unit-test/0087-javascript-basics UNIT.json     |  44 ++
 .../transforms/javascript/ScriptValues.java        | 391 +++++----
 .../javascript/ScriptValuesAddedFunctions.java     |   5 +-
 .../transforms/javascript/ScriptValuesData.java    |   4 +-
 .../transforms/javascript/ScriptValuesDialog.java  | 176 ++---
 .../transforms/javascript/ScriptValuesMeta.java    | 877 +++++++--------------
 .../transforms/javascript/ScriptValuesScript.java  |  88 +--
 .../javascript/messages/messages_en_US.properties  |   1 +
 .../javascript/ScriptValuesMetaInjectionTest.java  | 106 ---
 .../javascript/ScriptValuesMetaTest.java           | 251 ++----
 .../transforms/javascript/ScriptValuesTest.java    |  59 +-
 .../javascript/src/test/resources/javascript.xml   |  65 ++
 29 files changed, 2551 insertions(+), 1304 deletions(-)

diff --git a/integration-tests/mdi/0043-javascript-template.hpl b/integration-tests/mdi/0043-javascript-template.hpl
new file mode 100644
index 0000000000..374d386de0
--- /dev/null
+++ b/integration-tests/mdi/0043-javascript-template.hpl
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<pipeline>
+  <info>
+    <name>0043-javascript-template</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/03/18 15:31:56.005</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/03/18 15:31:56.005</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+  </order>
+  <transform>
+    <name>JavaScript</name>
+    <type>ScriptValueMod</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+</fields>
+    <jsScripts>
+      <jsScript>
+        <jsScript_name>Script 1</jsScript_name>
+        <jsScript_script>//Script here
+
+</jsScript_script>
+        <jsScript_type>0</jsScript_type>
+      </jsScript>
+    </jsScripts>
+    <optimizationLevel>9</optimizationLevel>
+    <attributes/>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/mdi/0043-javascript-validate.hpl b/integration-tests/mdi/0043-javascript-validate.hpl
new file mode 100644
index 0000000000..cb46027215
--- /dev/null
+++ b/integration-tests/mdi/0043-javascript-validate.hpl
@@ -0,0 +1,420 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<pipeline>
+  <info>
+    <name>0043-javascript-validate</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/03/18 17:22:17.510</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/03/18 17:22:17.510</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>/tmp/javascript.hpl</from>
+      <to>validate</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>/tmp/javascript.hpl scripts</from>
+      <to>validate scripts</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>/tmp/javascript.hpl fields</from>
+      <to>validate fields</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>/tmp/javascript.hpl</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <XmlField/>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <extensionFieldName/>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>optimizationLevel</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Integer</type>
+        <xPath>optimizationLevel</xPath>
+      </field>
+    </fields>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask/>
+      <include_subfolders>N</include_subfolders>
+      <name>${java.io.tmpdir}/javascript.hpl</name>
+    </file>
+    <hiddenFieldName/>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <include_field/>
+    <lastModificationTimeFieldName/>
+    <limit>0</limit>
+    <loopxpath>/pipeline/transform</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <pathFieldName/>
+    <prunePath/>
+    <readurl>N</readurl>
+    <rootUriNameFieldName/>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <shortFileFieldName/>
+    <sizeFieldName/>
+    <uriNameFieldName/>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>48</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>validate</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>384</xloc>
+      <yloc>48</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>/tmp/javascript.hpl scripts</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <XmlField/>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <extensionFieldName/>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>jsScript_type</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Integer</type>
+        <xPath>jsScript_type</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>jsScript_name</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>jsScript_name</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>jsScript_script</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>jsScript_script</xPath>
+      </field>
+    </fields>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask/>
+      <include_subfolders>N</include_subfolders>
+      <name>${java.io.tmpdir}/javascript.hpl</name>
+    </file>
+    <hiddenFieldName/>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <include_field/>
+    <lastModificationTimeFieldName/>
+    <limit>0</limit>
+    <loopxpath>/pipeline/transform/jsScripts/jsScript</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <pathFieldName/>
+    <prunePath/>
+    <readurl>N</readurl>
+    <rootUriNameFieldName/>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <shortFileFieldName/>
+    <sizeFieldName/>
+    <uriNameFieldName/>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>128</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>validate scripts</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>384</xloc>
+      <yloc>128</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>/tmp/javascript.hpl fields</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <XmlField/>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <extensionFieldName/>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>name</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>name</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>rename</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>rename</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>type</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>type</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>length</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Integer</type>
+        <xPath>length</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>precision</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Integer</type>
+        <xPath>precision</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>replace</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>replace</xPath>
+      </field>
+    </fields>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask/>
+      <include_subfolders>N</include_subfolders>
+      <name>${java.io.tmpdir}/javascript.hpl</name>
+    </file>
+    <hiddenFieldName/>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <include_field/>
+    <lastModificationTimeFieldName/>
+    <limit>0</limit>
+    <loopxpath>/pipeline/transform/fields/field</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <pathFieldName/>
+    <prunePath/>
+    <readurl>N</readurl>
+    <rootUriNameFieldName/>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <shortFileFieldName/>
+    <sizeFieldName/>
+    <uriNameFieldName/>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>208</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>validate fields</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>384</xloc>
+      <yloc>208</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/mdi/0043-javascript.hpl b/integration-tests/mdi/0043-javascript.hpl
new file mode 100644
index 0000000000..a2cb08b380
--- /dev/null
+++ b/integration-tests/mdi/0043-javascript.hpl
@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<pipeline>
+  <info>
+    <name>0043-javascript</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/03/18 17:15:02.536</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/03/18 17:15:02.536</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>files/javascript.xml</from>
+      <to>/tmp/0043-javascript-template.hpl</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>files/javascript.xml scripts</from>
+      <to>/tmp/0043-javascript-template.hpl</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>files/javascript.xml fields</from>
+      <to>/tmp/0043-javascript-template.hpl</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>/tmp/0043-javascript-template.hpl</name>
+    <type>MetaInject</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <filename>${PROJECT_HOME}/0043-javascript-template.hpl</filename>
+    <run_configuration>local</run_configuration>
+    <source_transform/>
+    <source_output_fields>    </source_output_fields>
+    <target_file>${java.io.tmpdir}/javascript.hpl</target_file>
+    <create_parent_folder>Y</create_parent_folder>
+    <no_execution>Y</no_execution>
+    <allow_empty_stream_on_execution>N</allow_empty_stream_on_execution>
+    <stream_source_transform/>
+    <stream_target_transform/>
+    <mappings>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>SCRIPT_NAME</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml scripts</source_transform>
+        <source_field>jsScript_name</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>SCRIPT_TYPE</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml scripts</source_transform>
+        <source_field>jsScript_type</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>FIELD_PRECISION</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml fields</source_transform>
+        <source_field>precision</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>SCRIPT</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml scripts</source_transform>
+        <source_field>jsScript_script</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>FIELD_RENAME_TO</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml fields</source_transform>
+        <source_field>rename</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>FIELD_TYPE</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml fields</source_transform>
+        <source_field>type</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>FIELD_LENGTH</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml fields</source_transform>
+        <source_field>length</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>FIELD_REPLACE</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml fields</source_transform>
+        <source_field>replace</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>FIELD_NAME</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <source_transform>files/javascript.xml fields</source_transform>
+        <source_field>name</source_field>
+      </mapping>
+      <mapping>
+        <target_transform_name>JavaScript</target_transform_name>
+        <target_attribute_key>OPTIMIZATION_LEVEL</target_attribute_key>
+        <target_detail>N</target_detail>
+        <source_transform>files/javascript.xml</source_transform>
+        <source_field>optimizationLevel</source_field>
+      </mapping>
+    </mappings>
+    <attributes/>
+    <GUI>
+      <xloc>416</xloc>
+      <yloc>48</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>files/javascript.xml</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>optimizationLevel</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>optimizationLevel</xPath>
+      </field>
+    </fields>
+    <file>
+      <file_required>N</file_required>
+      <include_subfolders>N</include_subfolders>
+      <name>${PROJECT_HOME}/files/javascript.xml</name>
+    </file>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <limit>0</limit>
+    <loopxpath>/transform</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <readurl>N</readurl>
+    <rownum>N</rownum>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>48</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>files/javascript.xml fields</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>name</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>name</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>rename</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>rename</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>type</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>type</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>length</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Integer</type>
+        <xPath>length</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>precision</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Integer</type>
+        <xPath>precision</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>replace</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>replace</xPath>
+      </field>
+    </fields>
+    <file>
+      <file_required>N</file_required>
+      <include_subfolders>N</include_subfolders>
+      <name>${PROJECT_HOME}/files/javascript.xml</name>
+    </file>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <limit>0</limit>
+    <loopxpath>/transform/fields/field</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <readurl>N</readurl>
+    <rownum>N</rownum>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>128</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>files/javascript.xml scripts</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>jsScript_type</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Integer</type>
+        <xPath>jsScript_type</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>jsScript_name</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>jsScript_name</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>jsScript_script</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>jsScript_script</xPath>
+      </field>
+    </fields>
+    <file>
+      <file_required>N</file_required>
+      <include_subfolders>N</include_subfolders>
+      <name>${PROJECT_HOME}/files/javascript.xml</name>
+    </file>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <limit>0</limit>
+    <loopxpath>/transform/jsScripts/jsScript</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <readurl>N</readurl>
+    <rownum>N</rownum>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>208</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/mdi/datasets/golden-javascript-fields.csv b/integration-tests/mdi/datasets/golden-javascript-fields.csv
new file mode 100644
index 0000000000..47ef304fe0
--- /dev/null
+++ b/integration-tests/mdi/datasets/golden-javascript-fields.csv
@@ -0,0 +1,4 @@
+name,rename,type,length,precision,replace
+f1,renamedF1,String,100,-1,Y
+f2,renamedF2,Integer,7,-1,Y
+f3,renamedF3,Number,9,2,Y
diff --git a/integration-tests/mdi/datasets/golden-javascript-scripts.csv b/integration-tests/mdi/datasets/golden-javascript-scripts.csv
new file mode 100644
index 0000000000..215e1d1c6e
--- /dev/null
+++ b/integration-tests/mdi/datasets/golden-javascript-scripts.csv
@@ -0,0 +1,4 @@
+jsScript_type,jsScript_name,jsScript_script
+1,startScript,startScript
+0,transformScript,transformScript
+2,endScript,endScript
diff --git a/integration-tests/mdi/datasets/golden-javascript.csv b/integration-tests/mdi/datasets/golden-javascript.csv
new file mode 100644
index 0000000000..28a22d82f2
--- /dev/null
+++ b/integration-tests/mdi/datasets/golden-javascript.csv
@@ -0,0 +1,2 @@
+optimizationLevel
+2
diff --git a/integration-tests/mdi/files/javascript.xml b/integration-tests/mdi/files/javascript.xml
new file mode 100644
index 0000000000..964c6d5e31
--- /dev/null
+++ b/integration-tests/mdi/files/javascript.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You 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.
+  ~
+  -->
+
+<transform>
+    <optimizationLevel>2</optimizationLevel>
+    <jsScripts>
+        <jsScript>
+            <jsScript_type>1</jsScript_type>
+            <jsScript_name>startScript</jsScript_name>
+            <jsScript_script>startScript</jsScript_script>
+        </jsScript>
+        <jsScript>
+            <jsScript_type>0</jsScript_type>
+            <jsScript_name>transformScript</jsScript_name>
+            <jsScript_script>transformScript</jsScript_script>
+        </jsScript>
+        <jsScript>
+            <jsScript_type>2</jsScript_type>
+            <jsScript_name>endScript</jsScript_name>
+            <jsScript_script>endScript</jsScript_script>
+        </jsScript>
+    </jsScripts>
+    <fields>
+        <field>
+            <name>f1</name>
+            <rename>renamedF1</rename>
+            <type>String</type>
+            <length>100</length>
+            <precision>-1</precision>
+            <replace>Y</replace>
+        </field>
+        <field>
+            <name>f2</name>
+            <rename>renamedF2</rename>
+            <type>Integer</type>
+            <length>7</length>
+            <precision>-1</precision>
+            <replace>Y</replace>
+        </field>
+        <field>
+            <name>f3</name>
+            <rename>renamedF3</rename>
+            <type>Number</type>
+            <length>9</length>
+            <precision>2</precision>
+            <replace>Y</replace>
+        </field>
+    </fields>
+</transform>
diff --git a/integration-tests/mdi/main-0043-javascript.hwf b/integration-tests/mdi/main-0043-javascript.hwf
new file mode 100644
index 0000000000..099298b6b0
--- /dev/null
+++ b/integration-tests/mdi/main-0043-javascript.hwf
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<workflow>
+  <name>main-0043-javascript</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <description/>
+  <extended_description/>
+  <workflow_version/>
+  <created_user>-</created_user>
+  <created_date>2026/03/18 15:31:43.347</created_date>
+  <modified_user>-</modified_user>
+  <modified_date>2026/03/18 15:31:43.347</modified_date>
+  <parameters>
+    </parameters>
+  <actions>
+    <action>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <hour>12</hour>
+      <intervalMinutes>60</intervalMinutes>
+      <intervalSeconds>0</intervalSeconds>
+      <minutes>0</minutes>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <weekDay>1</weekDay>
+      <parallel>N</parallel>
+      <xloc>80</xloc>
+      <yloc>64</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>0043-javascript</name>
+      <description/>
+      <type>PIPELINE</type>
+      <attributes/>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <clear_files>N</clear_files>
+      <clear_rows>N</clear_rows>
+      <create_parent_folder>N</create_parent_folder>
+      <exec_per_row>N</exec_per_row>
+      <filename>${PROJECT_HOME}/0043-javascript.hpl</filename>
+      <loglevel>Basic</loglevel>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <params_from_previous>N</params_from_previous>
+      <run_configuration>local</run_configuration>
+      <set_append_logfile>N</set_append_logfile>
+      <set_logfile>N</set_logfile>
+      <wait_until_finished>Y</wait_until_finished>
+      <parallel>N</parallel>
+      <xloc>256</xloc>
+      <yloc>64</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>0043-javascript-validate UNIT</name>
+      <description/>
+      <type>RunPipelineTests</type>
+      <attributes/>
+      <test_names>
+        <test_name>
+          <name>0043-javascript-validate UNIT</name>
+        </test_name>
+      </test_names>
+      <parallel>N</parallel>
+      <xloc>416</xloc>
+      <yloc>64</yloc>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+    <hop>
+      <from>Start</from>
+      <to>0043-javascript</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>Y</unconditional>
+    </hop>
+    <hop>
+      <from>0043-javascript</from>
+      <to>0043-javascript-validate UNIT</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+  </hops>
+  <notepads>
+  </notepads>
+  <attributes/>
+</workflow>
diff --git a/integration-tests/mdi/main-0087-javascript.hwf b/integration-tests/mdi/main-0087-javascript.hwf
new file mode 100644
index 0000000000..207028173a
--- /dev/null
+++ b/integration-tests/mdi/main-0087-javascript.hwf
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<workflow>
+  <name>main-0087-javascript</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <description/>
+  <extended_description/>
+  <workflow_version/>
+  <created_user>-</created_user>
+  <created_date>2026/03/18 19:32:06.360</created_date>
+  <modified_user>-</modified_user>
+  <modified_date>2026/03/18 19:32:06.360</modified_date>
+  <parameters>
+    </parameters>
+  <actions>
+    <action>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <hour>12</hour>
+      <intervalMinutes>60</intervalMinutes>
+      <intervalSeconds>0</intervalSeconds>
+      <minutes>0</minutes>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <weekDay>1</weekDay>
+      <parallel>N</parallel>
+      <xloc>50</xloc>
+      <yloc>50</yloc>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+  </hops>
+  <notepads>
+  </notepads>
+  <attributes/>
+</workflow>
diff --git a/integration-tests/mdi/metadata/dataset/golden-javascript-fields.json b/integration-tests/mdi/metadata/dataset/golden-javascript-fields.json
new file mode 100644
index 0000000000..7fbb698719
--- /dev/null
+++ b/integration-tests/mdi/metadata/dataset/golden-javascript-fields.json
@@ -0,0 +1,56 @@
+{
+  "base_filename": "golden-javascript-fields.csv",
+  "name": "golden-javascript-fields",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "name",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "rename",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "type",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "length",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "precision",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "replace",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git a/integration-tests/mdi/metadata/dataset/golden-javascript-scripts.json b/integration-tests/mdi/metadata/dataset/golden-javascript-scripts.json
new file mode 100644
index 0000000000..e8812dbe4e
--- /dev/null
+++ b/integration-tests/mdi/metadata/dataset/golden-javascript-scripts.json
@@ -0,0 +1,32 @@
+{
+  "base_filename": "golden-javascript-scripts.csv",
+  "name": "golden-javascript-scripts",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "jsScript_type",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "jsScript_name",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "jsScript_script",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git a/integration-tests/mdi/metadata/dataset/golden-javascript.json b/integration-tests/mdi/metadata/dataset/golden-javascript.json
new file mode 100644
index 0000000000..56bbc6291a
--- /dev/null
+++ b/integration-tests/mdi/metadata/dataset/golden-javascript.json
@@ -0,0 +1,16 @@
+{
+  "base_filename": "golden-javascript.csv",
+  "name": "golden-javascript",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "optimizationLevel",
+      "field_format": "####0;-####0"
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git a/integration-tests/mdi/metadata/unit-test/0043-javascript-validate UNIT.json b/integration-tests/mdi/metadata/unit-test/0043-javascript-validate UNIT.json
new file mode 100644
index 0000000000..be47231459
--- /dev/null
+++ b/integration-tests/mdi/metadata/unit-test/0043-javascript-validate UNIT.json	
@@ -0,0 +1,82 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "optimizationLevel",
+          "data_set_field": "optimizationLevel"
+        }
+      ],
+      "field_order": [
+        "optimizationLevel"
+      ],
+      "data_set_name": "golden-javascript",
+      "transform_name": "validate"
+    },
+    {
+      "field_mappings": [
+        {
+          "transform_field": "jsScript_type",
+          "data_set_field": "jsScript_type"
+        },
+        {
+          "transform_field": "jsScript_name",
+          "data_set_field": "jsScript_name"
+        },
+        {
+          "transform_field": "jsScript_script",
+          "data_set_field": "jsScript_script"
+        }
+      ],
+      "field_order": [
+        "jsScript_name"
+      ],
+      "data_set_name": "golden-javascript-scripts",
+      "transform_name": "validate scripts"
+    },
+    {
+      "field_mappings": [
+        {
+          "transform_field": "name",
+          "data_set_field": "name"
+        },
+        {
+          "transform_field": "rename",
+          "data_set_field": "rename"
+        },
+        {
+          "transform_field": "type",
+          "data_set_field": "type"
+        },
+        {
+          "transform_field": "length",
+          "data_set_field": "length"
+        },
+        {
+          "transform_field": "precision",
+          "data_set_field": "precision"
+        },
+        {
+          "transform_field": "replace",
+          "data_set_field": "replace"
+        }
+      ],
+      "field_order": [
+        "name"
+      ],
+      "data_set_name": "golden-javascript-fields",
+      "transform_name": "validate fields"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0043-javascript-validate UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0043-javascript-validate.hpl"
+}
\ No newline at end of file
diff --git a/integration-tests/transforms/0087-javascript-basics.hpl b/integration-tests/transforms/0087-javascript-basics.hpl
new file mode 100644
index 0000000000..af9a8e3746
--- /dev/null
+++ b/integration-tests/transforms/0087-javascript-basics.hpl
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<pipeline>
+  <info>
+    <name>0087-javascript-basics</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/03/18 19:32:21.153</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/03/18 19:32:21.153</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>10 rows</from>
+      <to>nr</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>nr</from>
+      <to>min,max,avg,sum</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>min,max,avg,sum</from>
+      <to>validate</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>10 rows</name>
+    <type>RowGenerator</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+</fields>
+    <interval_in_ms>5000</interval_in_ms>
+    <last_time_field>FiveSecondsAgo</last_time_field>
+    <limit>10</limit>
+    <never_ending>N</never_ending>
+    <row_time_field>now</row_time_field>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>min,max,avg,sum</name>
+    <type>ScriptValueMod</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <length>7</length>
+        <name>avg</name>
+        <precision>2</precision>
+        <rename>avg</rename>
+        <replace>N</replace>
+        <type>Number</type>
+      </field>
+      <field>
+        <length>7</length>
+        <name>min</name>
+        <precision>-1</precision>
+        <rename>min</rename>
+        <replace>N</replace>
+        <type>Integer</type>
+      </field>
+      <field>
+        <length>7</length>
+        <name>max</name>
+        <precision>-1</precision>
+        <rename>max</rename>
+        <replace>N</replace>
+        <type>Integer</type>
+      </field>
+      <field>
+        <length>7</length>
+        <name>cnt</name>
+        <precision>-1</precision>
+        <rename>cnt</rename>
+        <replace>N</replace>
+        <type>Integer</type>
+      </field>
+    </fields>
+    <jsScripts>
+      <jsScript>
+        <jsScript_name>startScript</jsScript_name>
+        <jsScript_script>
+var min = null;
+var max = null;
+var cnt=0;
+var sum=0;
+
+
+
+
+</jsScript_script>
+        <jsScript_type>1</jsScript_type>
+      </jsScript>
+      <jsScript>
+        <jsScript_name>transformScript</jsScript_name>
+        <jsScript_script>
+if (min==null || nr&lt;min) {
+  min = nr;
+} 
+if (max==null || nr>max) {
+  max = nr;
+}
+cnt++;
+sum+=nr;
+var avg = sum/cnt;</jsScript_script>
+        <jsScript_type>0</jsScript_type>
+      </jsScript>
+      <jsScript>
+        <jsScript_name>endScript</jsScript_name>
+        <jsScript_script>
+setVariable("TEST_VARIABLE", "testValue", "g");
+</jsScript_script>
+        <jsScript_type>2</jsScript_type>
+      </jsScript>
+    </jsScripts>
+    <optimizationLevel>9</optimizationLevel>
+    <attributes/>
+    <GUI>
+      <xloc>288</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>nr</name>
+    <type>Sequence</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <connection>h2</connection>
+    <increment_by>1</increment_by>
+    <max_value>999999999</max_value>
+    <seqname>SEQ_</seqname>
+    <start_at>1</start_at>
+    <use_counter>Y</use_counter>
+    <use_database>N</use_database>
+    <valuename>nr</valuename>
+    <attributes/>
+    <GUI>
+      <xloc>192</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>validate</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>432</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/transforms/datasets/golden-javascript-basic.csv b/integration-tests/transforms/datasets/golden-javascript-basic.csv
new file mode 100644
index 0000000000..2240891225
--- /dev/null
+++ b/integration-tests/transforms/datasets/golden-javascript-basic.csv
@@ -0,0 +1,11 @@
+nr,avg,min,max,cnt
+1,1.0,1,1,1
+2,1.5,1,2,2
+3,2.0,1,3,3
+4,2.5,1,4,4
+5,3.0,1,5,5
+6,3.5,1,6,6
+7,4.0,1,7,7
+8,4.5,1,8,8
+9,5.0,1,9,9
+10,5.5,1,10,10
diff --git a/integration-tests/transforms/main-0087-javascript.hwf b/integration-tests/transforms/main-0087-javascript.hwf
new file mode 100644
index 0000000000..17d6daada1
--- /dev/null
+++ b/integration-tests/transforms/main-0087-javascript.hwf
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<workflow>
+  <name>main-0087-javascript</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <description/>
+  <extended_description/>
+  <workflow_version/>
+  <created_user>-</created_user>
+  <created_date>2026/03/18 22:27:55.004</created_date>
+  <modified_user>-</modified_user>
+  <modified_date>2026/03/18 22:27:55.004</modified_date>
+  <parameters>
+    </parameters>
+  <actions>
+    <action>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <hour>12</hour>
+      <intervalMinutes>60</intervalMinutes>
+      <intervalSeconds>0</intervalSeconds>
+      <minutes>0</minutes>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <weekDay>1</weekDay>
+      <parallel>N</parallel>
+      <xloc>50</xloc>
+      <yloc>50</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>0087-javascript-basics UNIT</name>
+      <description/>
+      <type>RunPipelineTests</type>
+      <attributes/>
+      <test_names>
+        <test_name>
+          <name>0087-javascript-basics UNIT</name>
+        </test_name>
+      </test_names>
+      <parallel>N</parallel>
+      <xloc>208</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Simple evaluation</name>
+      <description/>
+      <type>SIMPLE_EVAL</type>
+      <attributes/>
+      <comparevalue>testValue</comparevalue>
+      <fieldtype>string</fieldtype>
+      <successbooleancondition>true</successbooleancondition>
+      <successcondition>equal</successcondition>
+      <successnumbercondition>equal</successnumbercondition>
+      <successwhenvarset>N</successwhenvarset>
+      <valuetype>variable</valuetype>
+      <variablename>TEST_VARIABLE</variablename>
+      <parallel>N</parallel>
+      <xloc>416</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Success</name>
+      <description/>
+      <type>SUCCESS</type>
+      <attributes/>
+      <parallel>N</parallel>
+      <xloc>544</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Fail</name>
+      <description/>
+      <type>ABORT</type>
+      <attributes/>
+      <always_log_rows>N</always_log_rows>
+      <message>End script not called</message>
+      <parallel>N</parallel>
+      <xloc>416</xloc>
+      <yloc>160</yloc>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+    <hop>
+      <from>Start</from>
+      <to>0087-javascript-basics UNIT</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>Y</unconditional>
+    </hop>
+    <hop>
+      <from>0087-javascript-basics UNIT</from>
+      <to>Simple evaluation</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+    <hop>
+      <from>Simple evaluation</from>
+      <to>Success</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+    <hop>
+      <from>Simple evaluation</from>
+      <to>Fail</to>
+      <enabled>Y</enabled>
+      <evaluation>N</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+  </hops>
+  <notepads>
+    <notepad>
+      <backgroundcolorblue>210</backgroundcolorblue>
+      <backgroundcolorgreen>136</backgroundcolorgreen>
+      <backgroundcolorred>15</backgroundcolorred>
+      <bordercolorblue>250</bordercolorblue>
+      <bordercolorgreen>231</bordercolorgreen>
+      <bordercolorred>200</bordercolorred>
+      <fontbold>N</fontbold>
+      <fontcolorblue>250</fontcolorblue>
+      <fontcolorgreen>231</fontcolorgreen>
+      <fontcolorred>200</fontcolorred>
+      <fontitalic>N</fontitalic>
+      <fontname>Noto Sans</fontname>
+      <fontsize>10</fontsize>
+      <height>20</height>
+      <xloc>32</xloc>
+      <yloc>112</yloc>
+      <note>The "End" script in the JavaScript transform sets a variable in the grand-parent workflow (this one).
+We check that the end script is called by checking the variable.</note>
+      <width>20</width>
+    </notepad>
+  </notepads>
+  <attributes/>
+</workflow>
diff --git a/integration-tests/transforms/metadata/dataset/golden-javascript-basic.json b/integration-tests/transforms/metadata/dataset/golden-javascript-basic.json
new file mode 100644
index 0000000000..4b8cdd551d
--- /dev/null
+++ b/integration-tests/transforms/metadata/dataset/golden-javascript-basic.json
@@ -0,0 +1,48 @@
+{
+  "base_filename": "golden-javascript-basic.csv",
+  "name": "golden-javascript-basic",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "nr",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": 7,
+      "field_type": 1,
+      "field_precision": 2,
+      "field_name": "avg",
+      "field_format": "####0.0#########;-####0.0#########"
+    },
+    {
+      "field_comment": "",
+      "field_length": 7,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "min",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": 7,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "max",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": 7,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "cnt",
+      "field_format": "####0;-####0"
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git a/integration-tests/transforms/metadata/unit-test/0087-javascript-basics UNIT.json b/integration-tests/transforms/metadata/unit-test/0087-javascript-basics UNIT.json
new file mode 100644
index 0000000000..afdac5d165
--- /dev/null
+++ b/integration-tests/transforms/metadata/unit-test/0087-javascript-basics UNIT.json	
@@ -0,0 +1,44 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "nr",
+          "data_set_field": "nr"
+        },
+        {
+          "transform_field": "avg",
+          "data_set_field": "avg"
+        },
+        {
+          "transform_field": "min",
+          "data_set_field": "min"
+        },
+        {
+          "transform_field": "max",
+          "data_set_field": "max"
+        },
+        {
+          "transform_field": "cnt",
+          "data_set_field": "cnt"
+        }
+      ],
+      "field_order": [
+        "nr"
+      ],
+      "data_set_name": "golden-javascript-basic",
+      "transform_name": "validate"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0087-javascript-basics UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0087-javascript-basics.hpl"
+}
\ No newline at end of file
diff --git a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValues.java b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValues.java
index f87b9717b9..8588ceba96 100644
--- a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValues.java
+++ b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValues.java
@@ -17,6 +17,10 @@
 
 package org.apache.hop.pipeline.transforms.javascript;
 
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopTransformException;
@@ -42,6 +46,8 @@ import org.mozilla.javascript.ScriptableObject;
  * Executes a JavaScript on the values in the input stream. Selected calculated values can then be
  * put on the output stream.
  */
+@Getter
+@Setter
 public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesData> {
   private static final Class<?> PKG = ScriptValuesMeta.class;
 
@@ -67,11 +73,9 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
 
   private boolean bRC = false;
 
-  private int iPipelineStat = CONTINUE_PIPELINE;
-
   private boolean bFirstRun = false;
 
-  private ScriptValuesScript[] jsScripts;
+  private final List<ScriptValuesScript> jsScripts;
 
   private String strTransformScript = "";
 
@@ -79,7 +83,7 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
 
   private String strEndScript = "";
 
-  public Script script;
+  private Script script;
 
   public ScriptValues(
       TransformMeta transformMeta,
@@ -89,6 +93,7 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
       PipelineMeta pipelineMeta,
       Pipeline pipeline) {
     super(transformMeta, meta, data, copyNr, pipelineMeta, pipeline);
+    jsScripts = new ArrayList<>();
   }
 
   private void determineUsedFields(IRowMeta row) {
@@ -97,8 +102,8 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
     // Perhaps we find values in comments, but we take no risk!
     //
     for (int i = 0; i < row.size(); i++) {
-      String valname = row.getValueMeta(i).getName().toUpperCase();
-      if (strTransformScript.toUpperCase().indexOf(valname) >= 0) {
+      String valueName = row.getValueMeta(i).getName().toUpperCase();
+      if (strTransformScript.toUpperCase().contains(valueName)) {
         nr++;
       }
     }
@@ -114,7 +119,7 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
       // Values are case-insensitive in JavaScript.
       //
       String valname = row.getValueMeta(i).getName();
-      if (strTransformScript.indexOf(valname) >= 0) {
+      if (strTransformScript.contains(valname)) {
         if (isDetailed()) {
           logDetailed(
               BaseMessages.getString(
@@ -134,7 +139,9 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
     }
   }
 
-  private boolean addValues(IRowMeta rowMeta, Object[] row) throws HopException {
+  @SuppressWarnings("deprecation")
+  private void addValuesToContext(IRowMeta rowMeta, Object[] row) throws HopException {
+    int iPipelineStat = CONTINUE_PIPELINE;
     if (first) {
       first = false;
 
@@ -149,25 +156,26 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
 
       // Get the indexes of the replaced fields...
       //
-      data.replaceIndex = new int[meta.getFieldname().length];
-      for (int i = 0; i < meta.getFieldname().length; i++) {
-        if (meta.getReplace()[i]) {
-          data.replaceIndex[i] = rowMeta.indexOfValue(meta.getFieldname()[i]);
+      data.replaceIndex = new int[meta.getScriptFields().size()];
+      for (int i = 0; i < meta.getScriptFields().size(); i++) {
+        ScriptValuesMeta.ScriptField field = meta.getScriptFields().get(i);
+        if (field.isReplace()) {
+          data.replaceIndex[i] = rowMeta.indexOfValue(field.getName());
           if (data.replaceIndex[i] < 0) {
-            if (Utils.isEmpty(meta.getFieldname()[i])) {
+            if (Utils.isEmpty(field.getName())) {
               throw new HopTransformException(
                   BaseMessages.getString(
                       PKG,
                       "ScriptValuesMetaMod.Exception.FieldToReplaceNotFound",
-                      meta.getFieldname()[i]));
+                      field.getName()));
             }
-            data.replaceIndex[i] = rowMeta.indexOfValue(meta.getRename()[i]);
+            data.replaceIndex[i] = rowMeta.indexOfValue(field.getRename());
             if (data.replaceIndex[i] < 0) {
               throw new HopTransformException(
                   BaseMessages.getString(
                       PKG,
                       "ScriptValuesMetaMod.Exception.FieldToReplaceNotFound",
-                      meta.getRename()[i]));
+                      field.getRename()));
             }
           }
         } else {
@@ -176,12 +184,12 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
       }
 
       // set the optimization level
-      data.cx = ContextFactory.getGlobal().enterContext();
+      data.context = ContextFactory.getGlobal().enterContext();
 
       try {
         String optimizationLevelAsString = resolve(meta.getOptimizationLevel());
         if (!Utils.isEmpty(Const.trim(optimizationLevelAsString))) {
-          data.cx.setOptimizationLevel(Integer.parseInt(optimizationLevelAsString.trim()));
+          data.context.setOptimizationLevel(Integer.parseInt(optimizationLevelAsString.trim()));
           if (isBasic()) {
             logBasic(
                 BaseMessages.getString(
@@ -190,7 +198,7 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
                     resolve(meta.getOptimizationLevel())));
           }
         } else {
-          data.cx.setOptimizationLevel(
+          data.context.setOptimizationLevel(
               Integer.parseInt(ScriptValuesMeta.OPTIMIZATION_LEVEL_DEFAULT));
           if (isBasic()) {
             logBasic(
@@ -210,112 +218,43 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
         throw new HopException(iae.getMessage());
       }
 
-      data.scope = data.cx.initStandardObjects(null, false);
+      data.scope = data.context.initStandardObjects(null, false);
 
       bFirstRun = true;
 
-      Scriptable jsvalue = Context.toObject(this, data.scope);
-      data.scope.put("_transform_", data.scope, jsvalue);
+      Scriptable jsTransform = Context.toObject(this, data.scope);
+      data.scope.put("_transform_", data.scope, jsTransform);
 
       // Adding the existing Scripts to the Context
-      for (int i = 0; i < meta.getNumberOfJSScripts(); i++) {
-        Scriptable jsR = Context.toObject(jsScripts[i].getScript(), data.scope);
-        data.scope.put(jsScripts[i].getScriptName(), data.scope, jsR);
+      for (int i = 0; i < meta.getJsScripts().size(); i++) {
+        Scriptable jsR = Context.toObject(jsScripts.get(i).getScript(), data.scope);
+        data.scope.put(jsScripts.get(i).getName(), data.scope, jsR);
       }
 
       // Adding the Name of the Pipeline to the Context
       data.scope.put("_PipelineName_", data.scope, getPipelineMeta().getName());
 
       try {
-        // add these now (they will be re-added later) to make compilation succeed
-        //
-
-        // Add the old style row object for compatibility reasons...
-        //
-        Scriptable jsrow = Context.toObject(row, data.scope);
-        data.scope.put("row", data.scope, jsrow);
-
         // Add the used fields...
         //
-        for (int i = 0; i < data.fieldsUsed.length; i++) {
-          IValueMeta valueMeta = rowMeta.getValueMeta(data.fieldsUsed[i]);
-          Object valueData = row[data.fieldsUsed[i]];
-
-          Object normalStorageValueData = valueMeta.convertToNormalStorageType(valueData);
-          Scriptable jsarg;
-          if (normalStorageValueData != null) {
-            jsarg = Context.toObject(normalStorageValueData, data.scope);
-          } else {
-            jsarg = null;
-          }
-          data.scope.put(valueMeta.getName(), data.scope, jsarg);
-        }
-
-        // also add the meta information for the whole row
-        //
-        Scriptable jsrowMeta = Context.toObject(rowMeta, data.scope);
-        data.scope.put("rowMeta", data.scope, jsrowMeta);
+        addFieldsToScope(rowMeta, row);
 
-        // Modification for Additional Script parsing
+        // Add the old style row object for compatibility reasons.
+        // also add the meta information for the whole row.
         //
-        try {
-          if (meta.getAddClasses() != null) {
-            for (int i = 0; i < meta.getAddClasses().length; i++) {
-              Object jsOut = Context.javaToJS(meta.getAddClasses()[i].getAddObject(), data.scope);
-              ScriptableObject.putProperty(data.scope, meta.getAddClasses()[i].getJSName(), jsOut);
-            }
-          }
-        } catch (Exception e) {
-          throw new HopValueException(
-              BaseMessages.getString(PKG, "ScriptValuesMod.Log.CouldNotAttachAdditionalScripts"),
-              e);
-        }
+        addRowAndRowMetaToScope(rowMeta, row);
 
         // Adding some default JavaScriptFunctions to the System
-        try {
-          Context.javaToJS(ScriptValuesAddedFunctions.class, data.scope);
-          ((ScriptableObject) data.scope)
-              .defineFunctionProperties(
-                  ScriptValuesAddedFunctions.jsFunctionList,
-                  ScriptValuesAddedFunctions.class,
-                  ScriptableObject.DONTENUM);
-        } catch (Exception ex) {
-          throw new HopValueException(
-              BaseMessages.getString(PKG, "ScriptValuesMod.Log.CouldNotAddDefaultFunctions"), ex);
-        }
+        addFunctionsToScope();
 
         // Adding some Constants to the JavaScript
-        try {
+        addConstantsToScope();
 
-          data.scope.put("SKIP_PIPELINE", data.scope, SKIP_PIPELINE);
-          data.scope.put("ABORT_PIPELINE", data.scope, ABORT_PIPELINE);
-          data.scope.put("ERROR_PIPELINE", data.scope, ERROR_PIPELINE);
-          data.scope.put("CONTINUE_PIPELINE", data.scope, CONTINUE_PIPELINE);
+        // Checking for StartScript
+        checkForStartScript();
 
-        } catch (Exception ex) {
-          throw new HopValueException(
-              BaseMessages.getString(PKG, "ScriptValuesMod.Log.CouldNotAddDefaultConstants"), ex);
-        }
-
-        try {
-          // Checking for StartScript
-          if (!Utils.isEmpty(strStartScript)) {
-            Script startScript = data.cx.compileString(strStartScript, "pipeline_Start", 1, null);
-            startScript.exec(data.cx, data.scope);
-            if (isDetailed()) {
-              logDetailed(("Start Script found!"));
-            }
-          } else {
-            if (isDetailed()) {
-              logDetailed(("No starting Script found!"));
-            }
-          }
-        } catch (Exception es) {
-          throw new HopValueException(
-              BaseMessages.getString(PKG, "ScriptValuesMod.Log.ErrorProcessingStartScript"), es);
-        }
         // Now Compile our Script
-        data.script = data.cx.compileString(strTransformScript, "script", 1, null);
+        data.script = data.context.compileString(strTransformScript, "script", 1, null);
       } catch (Exception e) {
         throw new HopValueException(
             BaseMessages.getString(PKG, "ScriptValuesMod.Log.CouldNotCompileJavascript"), e);
@@ -330,34 +269,11 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
     int outputIndex = rowMeta.size();
 
     try {
-      try {
-        Scriptable jsrow = Context.toObject(row, data.scope);
-        data.scope.put("row", data.scope, jsrow);
-
-        for (int i = 0; i < data.fieldsUsed.length; i++) {
-          IValueMeta valueMeta = rowMeta.getValueMeta(data.fieldsUsed[i]);
-          Object valueData = row[data.fieldsUsed[i]];
-
-          Object normalStorageValueData = valueMeta.convertToNormalStorageType(valueData);
-          Scriptable jsarg;
-          if (normalStorageValueData != null) {
-            jsarg = Context.toObject(normalStorageValueData, data.scope);
-          } else {
-            jsarg = null;
-          }
-          data.scope.put(valueMeta.getName(), data.scope, jsarg);
-        }
-
-        // also add the meta information for the hole row
-        Scriptable jsrowMeta = Context.toObject(rowMeta, data.scope);
-        data.scope.put("rowMeta", data.scope, jsrowMeta);
-      } catch (Exception e) {
-        throw new HopValueException(
-            BaseMessages.getString(PKG, "ScriptValuesMod.Log.UnexpectedeError"), e);
-      }
+      addFieldsToScope(rowMeta, row);
+      addRowAndRowMetaToScope(rowMeta, row);
 
       // Executing our Script
-      data.script.exec(data.cx, data.scope);
+      data.script.exec(data.context, data.scope, data.scope);
 
       if (bFirstRun) {
         bFirstRun = false;
@@ -379,14 +295,13 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
 
       if (bWithPipelineStat) {
         iPipelineStat = (int) Context.toNumber(data.scope.get("pipeline_Status", data.scope));
-      } else {
-        iPipelineStat = CONTINUE_PIPELINE;
       }
 
       if (iPipelineStat == CONTINUE_PIPELINE) {
         bRC = true;
-        for (int i = 0; i < meta.getFieldname().length; i++) {
-          Object result = data.scope.get(meta.getFieldname()[i], data.scope);
+        for (int i = 0; i < meta.getScriptFields().size(); i++) {
+          ScriptValuesMeta.ScriptField field = meta.getScriptFields().get(i);
+          Object result = data.scope.get(field.getName(), data.scope);
           Object valueData = getValueFromJScript(result, i);
           if (data.replaceIndex[i] < 0) {
             outputRow[outputIndex++] = valueData;
@@ -407,7 +322,7 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
             bRC = true;
             break;
           case ABORT_PIPELINE:
-            if (data.cx != null) {
+            if (data.context != null) {
               Context.exit();
             }
             stopAll();
@@ -415,7 +330,7 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
             bRC = false;
             break;
           case ERROR_PIPELINE:
-            if (data.cx != null) {
+            if (data.context != null) {
               Context.exit();
             }
             setErrors(1);
@@ -425,24 +340,88 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
           default:
             break;
         }
-
-        // TODO: kick this "ERROR handling" junk out now that we have solid error handling in place.
-        //
       }
     } catch (Exception e) {
       throw new HopValueException(
           BaseMessages.getString(PKG, "ScriptValuesMod.Log.JavascriptError"), e);
     }
-    return bRC;
+  }
+
+  private void addRowAndRowMetaToScope(IRowMeta rowMeta, Object[] row) {
+    Scriptable jsRow = Context.toObject(row, data.scope);
+    data.scope.put("row", data.scope, jsRow);
+    Scriptable jsRowMeta = Context.toObject(rowMeta, data.scope);
+    data.scope.put("rowMeta", data.scope, jsRowMeta);
+  }
+
+  private void checkForStartScript() throws HopValueException {
+    try {
+      if (!Utils.isEmpty(strStartScript)) {
+        Script startScript = data.context.compileString(strStartScript, "pipeline_Start", 1, null);
+        startScript.exec(data.context, data.scope, data.scope);
+        if (isDetailed()) {
+          logDetailed(("Start Script found!"));
+        }
+      } else {
+        if (isDetailed()) {
+          logDetailed(("No starting Script found!"));
+        }
+      }
+    } catch (Exception es) {
+      throw new HopValueException(
+          BaseMessages.getString(PKG, "ScriptValuesMod.Log.ErrorProcessingStartScript"), es);
+    }
+  }
+
+  private void addFieldsToScope(IRowMeta rowMeta, Object[] row) throws HopValueException {
+    for (int i = 0; i < data.fieldsUsed.length; i++) {
+      IValueMeta valueMeta = rowMeta.getValueMeta(data.fieldsUsed[i]);
+      Object valueData = row[data.fieldsUsed[i]];
+
+      Object normalStorageValueData = valueMeta.convertToNormalStorageType(valueData);
+      Scriptable jsarg;
+      if (normalStorageValueData != null) {
+        jsarg = Context.toObject(normalStorageValueData, data.scope);
+      } else {
+        jsarg = null;
+      }
+      data.scope.put(valueMeta.getName(), data.scope, jsarg);
+    }
+  }
+
+  private void addFunctionsToScope() throws HopValueException {
+    try {
+      Context.javaToJS(ScriptValuesAddedFunctions.class, data.scope);
+      ((ScriptableObject) data.scope)
+          .defineFunctionProperties(
+              ScriptValuesAddedFunctions.jsFunctionList,
+              ScriptValuesAddedFunctions.class,
+              ScriptableObject.DONTENUM);
+    } catch (Exception ex) {
+      throw new HopValueException(
+          BaseMessages.getString(PKG, "ScriptValuesMod.Log.CouldNotAddDefaultFunctions"), ex);
+    }
+  }
+
+  private void addConstantsToScope() throws HopValueException {
+    try {
+      data.scope.put("SKIP_PIPELINE", data.scope, SKIP_PIPELINE);
+      data.scope.put("ABORT_PIPELINE", data.scope, ABORT_PIPELINE);
+      data.scope.put("ERROR_PIPELINE", data.scope, ERROR_PIPELINE);
+      data.scope.put("CONTINUE_PIPELINE", data.scope, CONTINUE_PIPELINE);
+    } catch (Exception ex) {
+      throw new HopValueException(
+          BaseMessages.getString(PKG, "ScriptValuesMod.Log.CouldNotAddDefaultConstants"), ex);
+    }
   }
 
   public Object getValueFromJScript(Object result, int i) throws HopValueException {
-    String fieldName = meta.getFieldname()[i];
-    if (!Utils.isEmpty(fieldName)) {
+    ScriptValuesMeta.ScriptField field = meta.getScriptFields().get(i);
+    if (!Utils.isEmpty(field.getName())) {
       try {
         return (result == null)
             ? null
-            : JavaScriptUtils.convertFromJs(result, meta.getType()[i], fieldName);
+            : JavaScriptUtils.convertFromJs(result, field.getType(), field.getName());
       } catch (Exception e) {
         throw new HopValueException(
             BaseMessages.getString(PKG, "ScriptValuesMod.Log.JavascriptError"), e);
@@ -458,47 +437,10 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
 
   @Override
   public boolean processRow() throws HopException {
-
     Object[] r = getRow(); // Get row from input rowset & set row busy!
     if (r == null) {
       // Modification for Additional End Function
-      try {
-        if (data.cx != null) {
-          // Checking for EndScript
-          if (!Utils.isEmpty(strEndScript)) {
-            Script endScript = data.cx.compileString(strEndScript, "pipeline_End", 1, null);
-            endScript.exec(data.cx, data.scope);
-            if (isDetailed()) {
-              logDetailed(("End Script found!"));
-            }
-          } else {
-            if (isDetailed()) {
-              logDetailed(("No end Script found!"));
-            }
-          }
-        }
-      } catch (Exception e) {
-        logError(
-            BaseMessages.getString(PKG, "ScriptValuesMod.Log.UnexpectedeError")
-                + " : "
-                + e.toString());
-        logError(
-            BaseMessages.getString(PKG, "ScriptValuesMod.Log.ErrorStackTrace")
-                + Const.CR
-                + Const.getSimpleStackTrace(e)
-                + Const.CR
-                + Const.getStackTracker(e));
-        setErrors(1);
-        stopAll();
-      }
-
-      try {
-        if (data.cx != null) {
-          Context.exit();
-        }
-      } catch (Exception er) {
-        // Eat this error, it's typically : "Calling Context.exit without previous Context.enter"
-      }
+      processEndOfStream();
 
       setOutputDone();
       return false;
@@ -506,7 +448,7 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
 
     // Getting the Row, with the Pipeline Status
     try {
-      addValues(getInputRowMeta(), r);
+      addValuesToContext(getInputRowMeta(), r);
     } catch (HopValueException e) {
       String location = null;
       if (e.getCause() instanceof EvaluatorException evaluatorException) {
@@ -528,39 +470,78 @@ public class ScriptValues extends BaseTransform<ScriptValuesMeta, ScriptValuesDa
     return bRC;
   }
 
-  @Override
-  public boolean init() {
-
-    if (super.init()) {
-
-      // Add init code here.
-      // Get the actual Scripts from our MetaData
-      jsScripts = meta.getJSScripts();
-      for (ScriptValuesScript jsScript : jsScripts) {
-        switch (jsScript.getScriptType()) {
-          case ScriptValuesScript.TRANSFORM_SCRIPT:
-            strTransformScript = jsScript.getScript();
-            break;
-          case ScriptValuesScript.START_SCRIPT:
-            strStartScript = jsScript.getScript();
-            break;
-          case ScriptValuesScript.END_SCRIPT:
-            strEndScript = jsScript.getScript();
-            break;
-          default:
-            break;
+  private void processEndOfStream() {
+    try {
+      if (data.context != null) {
+        // Checking for EndScript
+        if (!Utils.isEmpty(strEndScript)) {
+          Script endScript = data.context.compileString(strEndScript, "pipeline_End", 1, null);
+          endScript.exec(data.context, data.scope, data.scope);
+          if (isDetailed()) {
+            logDetailed(("End Script found!"));
+          }
+        } else {
+          if (isDetailed()) {
+            logDetailed(("No end Script found!"));
+          }
         }
       }
+    } catch (Exception e) {
+      logError(
+          BaseMessages.getString(PKG, "ScriptValuesMod.Log.UnexpectedeError")
+              + " : "
+              + e.toString());
+      logError(
+          BaseMessages.getString(PKG, "ScriptValuesMod.Log.ErrorStackTrace")
+              + Const.CR
+              + Const.getSimpleStackTrace(e)
+              + Const.CR
+              + Const.getStackTracker(e));
+      setErrors(1);
+      stopAll();
+    }
 
-      return true;
+    try {
+      if (data.context != null) {
+        Context.exit();
+      }
+    } catch (Exception er) {
+      // Eat this error, it's typically : "Calling Context.exit without previous Context.enter"
+    }
+  }
+
+  @Override
+  public boolean init() {
+    if (!super.init()) {
+      return false;
+    }
+    // Add init code here.
+    // Get the actual Scripts from our MetaData
+    //
+    jsScripts.clear();
+    meta.getJsScripts().forEach(jsScript -> jsScripts.add(new ScriptValuesScript(jsScript)));
+    for (ScriptValuesScript jsScript : jsScripts) {
+      switch (jsScript.getType()) {
+        case ScriptValuesScript.TRANSFORM_SCRIPT:
+          strTransformScript = jsScript.getScript();
+          break;
+        case ScriptValuesScript.START_SCRIPT:
+          strStartScript = jsScript.getScript();
+          break;
+        case ScriptValuesScript.END_SCRIPT:
+          strEndScript = jsScript.getScript();
+          break;
+        default:
+          break;
+      }
     }
-    return false;
+    return true;
   }
 
   @Override
   public void dispose() {
     try {
-      if (data.cx != null) {
+      if (data.context != null) {
         Context.exit();
       }
     } catch (Exception er) {
diff --git a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesAddedFunctions.java b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesAddedFunctions.java
index 75d3c6e65f..30db19fe6a 100644
--- a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesAddedFunctions.java
+++ b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesAddedFunctions.java
@@ -92,7 +92,7 @@ public class ScriptValuesAddedFunctions extends ScriptableObject {
   public static final String CONST_THE_FIRST_ARGUMENT_MUST_BE_A_NUMBER =
       "The first Argument must be a Number.";
 
-  public static String[] jsFunctionList = {
+  protected static final String[] jsFunctionList = {
     "appendToFile",
     "getPipelineName",
     "writeToLog",
@@ -188,8 +188,7 @@ public class ScriptValuesAddedFunctions extends ScriptableObject {
   }
 
   // This is only used for reading, so no concurrency problems.
-  // todo: move in the real variables of the transform.
-
+  //
   // Functions to Add
   // date2num, num2date,
   // fisc_date, isNull
diff --git a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesData.java b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesData.java
index 0207f41c11..bff778fe43 100644
--- a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesData.java
+++ b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesData.java
@@ -26,7 +26,7 @@ import org.mozilla.javascript.Scriptable;
 
 @SuppressWarnings("java:S1104")
 public class ScriptValuesData extends BaseTransformData implements ITransformData {
-  public Context cx;
+  public Context context;
   public Scriptable scope;
   public Script script;
 
@@ -37,7 +37,7 @@ public class ScriptValuesData extends BaseTransformData implements ITransformDat
 
   public ScriptValuesData() {
     super();
-    cx = null;
+    context = null;
     fieldsUsed = null;
   }
 
diff --git a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesDialog.java b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesDialog.java
index 6cab057a0a..7677f2f98d 100644
--- a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesDialog.java
+++ b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesDialog.java
@@ -17,13 +17,13 @@
 
 package org.apache.hop.pipeline.transforms.javascript;
 
-import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Vector;
+import org.apache.commons.lang.StringUtils;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.Props;
 import org.apache.hop.core.exception.HopException;
@@ -71,7 +71,6 @@ import org.eclipse.swt.dnd.DragSourceAdapter;
 import org.eclipse.swt.dnd.DragSourceEvent;
 import org.eclipse.swt.dnd.TextTransfer;
 import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.FormAttachment;
@@ -122,8 +121,6 @@ public class ScriptValuesDialog extends BaseTransformDialog {
   public static final String CONST_FUNCTION = "Function";
   public static final String CONST_JS_FUNCTION = "jsFunction";
 
-  private ModifyListener lsMod;
-
   private TableView wFields;
 
   private Label wlPosition;
@@ -348,9 +345,9 @@ public class ScriptValuesDialog extends BaseTransformDialog {
     fdlFields.top = new FormAttachment(wSeparator, 0);
     wlFields.setLayoutData(fdlFields);
 
-    final int FieldsRows = input.getFieldname().length;
+    final int nrFields = input.getScriptFields().size();
 
-    ColumnInfo[] colinf =
+    ColumnInfo[] colInfos =
         new ColumnInfo[] {
           new ColumnInfo(
               BaseMessages.getString(PKG, "ScriptValuesDialogMod.ColumnInfo.Filename"),
@@ -383,8 +380,8 @@ public class ScriptValuesDialog extends BaseTransformDialog {
             variables,
             wBottom,
             SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI,
-            colinf,
-            FieldsRows,
+            colInfos,
+            nrFields,
             lsMod,
             props);
 
@@ -766,35 +763,36 @@ public class ScriptValuesDialog extends BaseTransformDialog {
       wOptimizationLevel.setText(ScriptValuesMeta.OPTIMIZATION_LEVEL_DEFAULT);
     }
 
-    for (int i = 0; i < input.getFieldname().length; i++) {
-      if (!Utils.isEmpty(input.getFieldname()[i])) {
+    for (int i = 0; i < input.getScriptFields().size(); i++) {
+      ScriptValuesMeta.ScriptField field = input.getScriptFields().get(i);
+      if (!Utils.isEmpty(field.getName())) {
         TableItem item = wFields.table.getItem(i);
-        item.setText(1, input.getFieldname()[i]);
-        if (input.getRename()[i] != null && !input.getFieldname()[i].equals(input.getRename()[i])) {
-          item.setText(2, input.getRename()[i]);
+        item.setText(1, field.getName());
+        if (field.getRename() != null && !field.getName().equals(field.getRename())) {
+          item.setText(2, field.getRename());
         }
-        item.setText(3, ValueMetaFactory.getValueMetaName(input.getType()[i]));
-        if (input.getLength()[i] >= 0) {
-          item.setText(4, "" + input.getLength()[i]);
+        item.setText(3, ValueMetaFactory.getValueMetaName(field.getType()));
+        if (field.getLength() >= 0) {
+          item.setText(4, "" + field.getLength());
         }
-        if (input.getPrecision()[i] >= 0) {
-          item.setText(5, "" + input.getPrecision()[i]);
+        if (field.getPrecision() >= 0) {
+          item.setText(5, "" + field.getPrecision());
         }
-        item.setText(6, input.getReplace()[i] ? YES_NO_COMBO[1] : YES_NO_COMBO[0]);
+        item.setText(6, field.isReplace() ? YES_NO_COMBO[1] : YES_NO_COMBO[0]);
       }
     }
 
-    ScriptValuesScript[] jsScripts = input.getJSScripts();
-    if (jsScripts.length > 0) {
+    List<ScriptValuesScript> jsScripts = input.getJsScripts();
+    if (!jsScripts.isEmpty()) {
       for (ScriptValuesScript jsScript : jsScripts) {
         if (jsScript.isTransformScript()) {
-          strActiveScript = jsScript.getScriptName();
+          strActiveScript = jsScript.getName();
         } else if (jsScript.isStartScript()) {
-          strActiveStartScript = jsScript.getScriptName();
+          strActiveStartScript = jsScript.getName();
         } else if (jsScript.isEndScript()) {
-          strActiveEndScript = jsScript.getScriptName();
+          strActiveEndScript = jsScript.getName();
         }
-        addCtab(jsScript.getScriptName(), jsScript.getScript(), ADD_DEFAULT);
+        addCtab(jsScript.getName(), jsScript.getScript(), ADD_DEFAULT);
       }
     } else {
       addCtab("", "", ADD_DEFAULT);
@@ -867,44 +865,43 @@ public class ScriptValuesDialog extends BaseTransformDialog {
 
   private void getInfo(ScriptValuesMeta meta) {
     meta.setOptimizationLevel(wOptimizationLevel.getText());
-    int nrFields = wFields.nrNonEmpty();
-    meta.allocate(nrFields);
-    for (int i = 0; i < nrFields; i++) {
-      TableItem item = wFields.getNonEmpty(i);
-      meta.getFieldname()[i] = item.getText(1);
-      meta.getRename()[i] = item.getText(2);
-      if (meta.getRename()[i] == null
-          || meta.getRename()[i].isEmpty()
-          || meta.getRename()[i].equalsIgnoreCase(meta.getFieldname()[i])) {
-        meta.getRename()[i] = meta.getFieldname()[i];
+
+    meta.getScriptFields().clear();
+    for (TableItem item : wFields.getNonEmptyItems()) {
+      ScriptValuesMeta.ScriptField field = new ScriptValuesMeta.ScriptField();
+      field.setName(item.getText(1));
+      field.setRename(item.getText(2));
+      if (StringUtils.isEmpty(field.getRename())
+          || field.getRename().equalsIgnoreCase(field.getName())) {
+        field.setRename(field.getName());
       }
-      meta.getType()[i] = ValueMetaFactory.getIdForValueMeta(item.getText(3));
-      String slen = item.getText(4);
-      String sprc = item.getText(5);
-      meta.getLength()[i] = Const.toInt(slen, -1);
-      meta.getPrecision()[i] = Const.toInt(sprc, -1);
-      meta.getReplace()[i] = YES_NO_COMBO[1].equalsIgnoreCase(item.getText(6));
+      field.setType(ValueMetaFactory.getIdForValueMeta(item.getText(3)));
+      String sLength = item.getText(4);
+      String sPrecision = item.getText(5);
+      field.setLength(Const.toInt(sLength, -1));
+      field.setPrecision(Const.toInt(sPrecision, -1));
+      field.setReplace(YES_NO_COMBO[1].equalsIgnoreCase(item.getText(6)));
+      meta.getScriptFields().add(field);
     }
 
     CTabItem[] cTabs = folder.getItems();
+    meta.getJsScripts().clear();
     if (cTabs.length > 0) {
-      ScriptValuesScript[] jsScripts = new ScriptValuesScript[cTabs.length];
       for (int i = 0; i < cTabs.length; i++) {
-        ScriptValuesScript jsScript =
-            new ScriptValuesScript(
-                ScriptValuesScript.NORMAL_SCRIPT,
-                cTabs[i].getText(),
-                getStyledTextComp(cTabs[i]).getText());
+        ScriptValuesScript jsScript = new ScriptValuesScript();
+        jsScript.setType(ScriptValuesScript.NORMAL_SCRIPT);
+        jsScript.setName(cTabs[i].getText());
+        jsScript.setScript(getStyledTextComp(cTabs[i]).getText());
+
         if (cTabs[i].getImage().equals(imageActiveScript)) {
-          jsScript.setScriptType(ScriptValuesScript.TRANSFORM_SCRIPT);
+          jsScript.setType(ScriptValuesScript.TRANSFORM_SCRIPT);
         } else if (cTabs[i].getImage().equals(imageActiveStartScript)) {
-          jsScript.setScriptType(ScriptValuesScript.START_SCRIPT);
+          jsScript.setType(ScriptValuesScript.START_SCRIPT);
         } else if (cTabs[i].getImage().equals(imageActiveEndScript)) {
-          jsScript.setScriptType(ScriptValuesScript.END_SCRIPT);
+          jsScript.setType(ScriptValuesScript.END_SCRIPT);
         }
-        jsScripts[i] = jsScript;
+        meta.getJsScripts().add(jsScript);
       }
-      meta.setJSScripts(jsScripts);
     }
   }
 
@@ -1133,6 +1130,7 @@ public class ScriptValuesDialog extends BaseTransformDialog {
     }
   }
 
+  @SuppressWarnings("deprecation")
   private boolean test(boolean getvars, boolean popup) {
     boolean retval = true;
     TextComposite wScript = getStyledTextComp();
@@ -1169,22 +1167,6 @@ public class ScriptValuesDialog extends BaseTransformDialog {
         Scriptable jsvalue = Context.toObject(dummyTransform, jsscope);
         jsscope.put("_transform_", jsscope, jsvalue);
 
-        // Modification for Additional Script parsing
-        try {
-          if (input.getAddClasses() != null) {
-            for (int i = 0; i < input.getAddClasses().length; i++) {
-              Object jsOut = Context.javaToJS(input.getAddClasses()[i].getAddObject(), jsscope);
-              ScriptableObject.putProperty(jsscope, input.getAddClasses()[i].getJSName(), jsOut);
-            }
-          }
-        } catch (Exception e) {
-          testException =
-              new HopException(
-                  BaseMessages.getString(
-                      PKG, "ScriptValuesDialogMod.CouldNotAddToContext", e.toString()));
-          retval = false;
-        }
-
         // Adding some default JavaScriptFunctions to the System
         try {
           Context.javaToJS(ScriptValuesAddedFunctions.class, jsscope);
@@ -1591,63 +1573,6 @@ public class ScriptValuesDialog extends BaseTransformDialog {
     if (wTreeClassesitem != null) {
       wTreeClassesitem.dispose();
     }
-    if (input.getAddClasses() != null) {
-      for (int i = 0; i < input.getAddClasses().length; i++) {
-        try {
-          Method[] methods = input.getAddClasses()[i].getAddClass().getMethods();
-          String strClassType = input.getAddClasses()[i].getAddClass().toString();
-          String strParams;
-          wTreeClassesitem = new TreeItem(wTree, SWT.NULL);
-          wTreeClassesitem.setText(input.getAddClasses()[i].getJSName());
-          for (Method method : methods) {
-            String strDeclaringClass = method.getDeclaringClass().toString();
-            if (strClassType.equals(strDeclaringClass)) {
-              TreeItem item2 = new TreeItem(wTreeClassesitem, SWT.NULL);
-              strParams = buildAddClassFunctionName(method);
-              item2.setText(method.getName() + "(" + strParams + ")");
-              String strData =
-                  input.getAddClasses()[i].getJSName()
-                      + "."
-                      + method.getName()
-                      + "("
-                      + strParams
-                      + ")";
-              item2.setData(strData);
-            }
-          }
-        } catch (Exception e) {
-          // Ignore errors
-        }
-      }
-    }
-  }
-
-  private String buildAddClassFunctionName(Method metForParams) {
-    StringBuilder sbRC = new StringBuilder();
-    String strRC = "";
-    Class<?>[] clsParamType = metForParams.getParameterTypes();
-    String strParam;
-
-    for (Class<?> aClass : clsParamType) {
-      strParam = aClass.getName();
-      if (!strParam.toLowerCase().contains("javascript")) {
-        if (strParam.toLowerCase().contains("object")) {
-          sbRC.append("var");
-          sbRC.append(", ");
-        } else if (strParam.equals("java.lang.String")) {
-          sbRC.append("String");
-          sbRC.append(", ");
-        } else {
-          sbRC.append(strParam);
-          sbRC.append(", ");
-        }
-      }
-    }
-    strRC = sbRC.toString();
-    if (!strRC.isEmpty()) {
-      strRC = strRC.substring(0, sbRC.length() - 2);
-    }
-    return strRC;
   }
 
   private void buildingFolderMenu() {
@@ -1916,6 +1841,7 @@ public class ScriptValuesDialog extends BaseTransformDialog {
   }
 
   // This could be useful for further improvements
+  @SuppressWarnings("deprecation")
   public static ScriptNode parseVariables(
       Context cx,
       Scriptable scope,
diff --git a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMeta.java b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMeta.java
index c4c13c2c6e..40ea0fd016 100644
--- a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMeta.java
+++ b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMeta.java
@@ -17,34 +17,26 @@
 
 package org.apache.hop.pipeline.transforms.javascript;
 
-import com.google.common.annotations.VisibleForTesting;
 import java.math.BigDecimal;
-import java.net.URL;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
-import java.util.Properties;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.hop.core.CheckResult;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.ICheckResult;
 import org.apache.hop.core.annotations.Transform;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopTransformException;
-import org.apache.hop.core.exception.HopXmlException;
-import org.apache.hop.core.injection.AfterInjection;
-import org.apache.hop.core.injection.DataTypeConverter;
-import org.apache.hop.core.injection.Injection;
-import org.apache.hop.core.injection.InjectionDeep;
-import org.apache.hop.core.injection.InjectionSupported;
-import org.apache.hop.core.injection.NullNumberConverter;
-import org.apache.hop.core.plugins.HopURLClassLoader;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.row.value.ValueMetaBase;
 import org.apache.hop.core.row.value.ValueMetaFactory;
 import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
-import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.metadata.api.HopMetadataProperty;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.pipeline.PipelineMeta;
 import org.apache.hop.pipeline.transform.BaseTransformMeta;
@@ -55,8 +47,6 @@ import org.mozilla.javascript.JavaScriptException;
 import org.mozilla.javascript.Script;
 import org.mozilla.javascript.Scriptable;
 import org.mozilla.javascript.ScriptableObject;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
 
 @Transform(
     id = "ScriptValueMod",
@@ -66,326 +56,109 @@ import org.w3c.dom.Node;
     categoryDescription = "i18n:org.apache.hop.pipeline.transform:BaseTransform.Category.Scripting",
     keywords = "i18n::ScriptValuesMeta.keyword",
     documentationUrl = "/pipeline/transforms/javascript.html")
-@InjectionSupported(
-    localizationPrefix = "ScriptValuesMod.Injection.",
-    groups = {"FIELDS", "SCRIPTS"})
+@Getter
+@Setter
 public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValuesData> {
   private static final Class<?> PKG = ScriptValuesMeta.class;
 
-  private static final String JSSCRIPT_TAG_TYPE = "jsScript_type";
-  private static final String JSSCRIPT_TAG_NAME = "jsScript_name";
-  private static final String JSSCRIPT_TAG_SCRIPT = "jsScript_script";
-
   public static final String OPTIMIZATION_LEVEL_DEFAULT = "9";
-  public static final String CONST_SPACES = "        ";
-
-  private ScriptValuesAddClasses[] additionalClasses;
-
-  @InjectionDeep private ScriptValuesScript[] jsScripts;
-
-  @Injection(name = "FIELD_NAME", group = "FIELDS")
-  private String[] fieldname;
-
-  @Injection(name = "FIELD_RENAME_TO", group = "FIELDS")
-  private String[] rename;
-
-  @Injection(
-      name = "FIELD_TYPE",
-      group = "FIELDS",
-      convertEmpty = true,
-      converter = DataTypeConverter.class)
-  private int[] type;
-
-  @Injection(
-      name = "FIELD_LENGTH",
-      group = "FIELDS",
-      convertEmpty = true,
-      converter = NullNumberConverter.class)
-  private int[] length;
-
-  @Injection(
-      name = "FIELD_PRECISION",
-      group = "FIELDS",
-      convertEmpty = true,
-      converter = NullNumberConverter.class)
-  private int[] precision;
-
-  @Injection(name = "FIELD_REPLACE", group = "FIELDS")
-  private boolean[] replace; // Replace the specified field.
-
-  @Injection(name = "OPTIMIZATION_LEVEL")
-  private String optimizationLevel;
-
-  public ScriptValuesMeta() {
-    super(); // allocate BaseTransformMeta
-    try {
-      parseXmlForAdditionalClasses();
-    } catch (Exception e) {
-      /* Ignore */
-    }
-  }
-
-  /**
-   * @return Returns the length.
-   */
-  public int[] getLength() {
-    return length;
-  }
-
-  /**
-   * @param length The length to set.
-   */
-  public void setLength(int[] length) {
-    this.length = length;
-  }
-
-  /**
-   * @return Returns the name.
-   */
-  public String[] getFieldname() {
-    return fieldname;
-  }
-
-  /**
-   * @param fieldname The name to set.
-   */
-  public void setFieldname(String[] fieldname) {
-    this.fieldname = fieldname;
-  }
-
-  /**
-   * @return Returns the precision.
-   */
-  public int[] getPrecision() {
-    return precision;
-  }
-
-  /**
-   * @param precision The precision to set.
-   */
-  public void setPrecision(int[] precision) {
-    this.precision = precision;
-  }
-
-  /**
-   * @return Returns the rename.
-   */
-  public String[] getRename() {
-    return rename;
-  }
-
-  /**
-   * @param rename The rename to set.
-   */
-  public void setRename(String[] rename) {
-    this.rename = rename;
-  }
-
-  /**
-   * @return Returns the type.
-   */
-  public int[] getType() {
-    return this.type;
-  }
-
-  @AfterInjection
-  public void afterInjection() {
-    // extend all fields related arrays to match the length of the fieldname array, as they may all
-    // be different
-    // sizes, after meta injection
-    extend(fieldname.length);
-  }
-
-  /**
-   * @param type The type to set.
-   */
-  public void setType(int[] type) {
-    this.type = type;
-  }
 
-  public int getNumberOfJSScripts() {
-    return jsScripts.length;
-  }
-
-  public String[] getJSScriptNames() {
-    String[] strJSNames = new String[jsScripts.length];
-    for (int i = 0; i < jsScripts.length; i++) {
-      strJSNames[i] = jsScripts[i].getScriptName();
+  @Getter
+  @Setter
+  public static class ScriptField {
+    @HopMetadataProperty(
+        key = "name",
+        injectionKey = "FIELD_NAME",
+        injectionKeyDescription = "ScriptValuesMod.Injection.FIELD_NAME")
+    private String name;
+
+    @HopMetadataProperty(
+        key = "rename",
+        injectionKey = "FIELD_RENAME_TO",
+        injectionKeyDescription = "ScriptValuesMod.Injection.FIELD_RENAME_TO")
+    private String rename;
+
+    @HopMetadataProperty(
+        key = "type",
+        intCodeConverter = ValueMetaBase.ValueTypeCodeConverter.class,
+        injectionKey = "FIELD_TYPE",
+        injectionKeyDescription = "ScriptValuesMod.Injection.FIELD_TYPE")
+    private int type;
+
+    @HopMetadataProperty(
+        key = "length",
+        injectionKey = "FIELD_LENGTH",
+        injectionKeyDescription = "ScriptValuesMod.Injection.FIELD_LENGTH")
+    private int length;
+
+    @HopMetadataProperty(
+        key = "precision",
+        injectionKey = "FIELD_PRECISION",
+        injectionKeyDescription = "ScriptValuesMod.Injection.FIELD_PRECISION")
+    private int precision;
+
+    @HopMetadataProperty(
+        key = "replace",
+        injectionKey = "FIELD_REPLACE",
+        injectionKeyDescription = "ScriptValuesMod.Injection.FIELD_REPLACE")
+    private boolean replace;
+
+    public ScriptField() {}
+
+    public ScriptField(ScriptField f) {
+      this.name = f.name;
+      this.rename = f.rename;
+      this.type = f.type;
+      this.length = f.length;
+      this.precision = f.precision;
+      this.replace = f.replace;
     }
-    return strJSNames;
   }
 
-  public ScriptValuesScript[] getJSScripts() {
-    return jsScripts;
-  }
-
-  public void setJSScripts(ScriptValuesScript[] jsScripts) {
-    this.jsScripts = jsScripts;
-  }
-
-  @Override
-  public void loadXml(Node transformNode, IHopMetadataProvider metadataProvider)
-      throws HopXmlException {
-    readData(transformNode);
-  }
-
-  public void allocate(int nrFields) {
-    fieldname = new String[nrFields];
-    rename = new String[nrFields];
-    type = new int[nrFields];
-    for (int i = 0; i < nrFields; i++) {
-      type[i] = -1;
-    }
-    length = new int[nrFields];
-    for (int i = 0; i < nrFields; i++) {
-      length[i] = -1;
-    }
-    precision = new int[nrFields];
-    for (int i = 0; i < nrFields; i++) {
-      precision[i] = -1;
-    }
-    replace = new boolean[nrFields];
-  }
-
-  /**
-   * Extends all field related arrays so that they are the same size.
-   *
-   * @param nrFields
-   */
-  @VisibleForTesting
-  void extend(int nrFields) {
-    fieldname = extend(fieldname, nrFields);
-    rename = extend(rename, nrFields);
-    type = extend(type, nrFields);
-    length = extend(length, nrFields);
-    precision = extend(precision, nrFields);
-    replace = extend(replace, nrFields);
-  }
+  @HopMetadataProperty(
+      key = "jsScript",
+      groupKey = "jsScripts",
+      injectionGroupKey = "SCRIPTS",
+      injectionGroupDescription = "ScriptValuesMod.Injection.SCRIPTS")
+  private List<ScriptValuesScript> jsScripts;
+
+  @HopMetadataProperty(
+      key = "field",
+      groupKey = "fields",
+      injectionGroupKey = "FIELDS",
+      injectionGroupDescription = "ScriptValuesMod.Injection.FIELDS")
+  private List<ScriptField> scriptFields;
+
+  @HopMetadataProperty(
+      key = "optimizationLevel",
+      injectionKey = "OPTIMIZATION_LEVEL",
+      injectionKeyDescription = "ScriptValuesMod.Injection.OPTIMIZATION_LEVEL")
+  private String optimizationLevel;
 
-  private String[] extend(final String[] array, final int nrFields) {
-    if (array == null) {
-      return new String[nrFields];
-    } else if (array.length < nrFields) {
-      return Arrays.copyOf(array, nrFields);
-    } else {
-      return array;
-    }
-  }
+  public ScriptValuesMeta() {
+    super();
+    jsScripts = new ArrayList<>();
+    scriptFields = new ArrayList<>();
+    optimizationLevel = OPTIMIZATION_LEVEL_DEFAULT;
 
-  private int[] extend(final int[] array, final int nrFields) {
-    if (array == null || array.length < nrFields) {
-      int originalLength = array == null ? 0 : array.length;
-      final int[] newArray = array == null ? new int[nrFields] : Arrays.copyOf(array, nrFields);
-      for (int i = originalLength; i < nrFields; i++) {
-        newArray[i] = -1;
-      }
-      return newArray;
-    } else {
-      return array;
-    }
+    ScriptValuesScript script = new ScriptValuesScript();
+    script.setType(ScriptValuesScript.TRANSFORM_SCRIPT);
+    script.setName(BaseMessages.getString(PKG, "ScriptValuesMod.Script1"));
+    script.setScript(
+        "//" + BaseMessages.getString(PKG, "ScriptValuesMod.ScriptHere") + Const.CR + Const.CR);
+    jsScripts.add(script);
   }
 
-  private boolean[] extend(final boolean[] array, final int nrFields) {
-    if (array == null) {
-      return new boolean[nrFields];
-    } else if (array.length < nrFields) {
-      return Arrays.copyOf(array, nrFields);
-    } else {
-      return array;
-    }
+  public ScriptValuesMeta(ScriptValuesMeta m) {
+    this();
+    this.optimizationLevel = m.optimizationLevel;
+    m.jsScripts.forEach(s -> this.jsScripts.add(new ScriptValuesScript(s)));
+    m.scriptFields.forEach(f -> scriptFields.add(new ScriptField(f)));
   }
 
   @Override
   public Object clone() {
-    ScriptValuesMeta retval = (ScriptValuesMeta) super.clone();
-
-    int nrFields = fieldname.length;
-
-    retval.allocate(nrFields);
-    System.arraycopy(fieldname, 0, retval.fieldname, 0, nrFields);
-    System.arraycopy(rename, 0, retval.rename, 0, nrFields);
-    System.arraycopy(type, 0, retval.type, 0, nrFields);
-    System.arraycopy(length, 0, retval.length, 0, nrFields);
-    System.arraycopy(precision, 0, retval.precision, 0, nrFields);
-    System.arraycopy(replace, 0, retval.replace, 0, nrFields);
-
-    return retval;
-  }
-
-  private void readData(Node transformNode) throws HopXmlException {
-    try {
-      String script = XmlHandler.getTagValue(transformNode, "script");
-      optimizationLevel = XmlHandler.getTagValue(transformNode, "optimizationLevel");
-
-      // When in compatibility mode, we load the script, not the other tabs...
-      //
-      if (!Utils.isEmpty(script)) {
-        jsScripts = new ScriptValuesScript[1];
-        jsScripts[0] =
-            new ScriptValuesScript(ScriptValuesScript.TRANSFORM_SCRIPT, "ScriptValue", script);
-      } else {
-        Node scripts = XmlHandler.getSubNode(transformNode, "jsScripts");
-        int nrscripts = XmlHandler.countNodes(scripts, "jsScript");
-        jsScripts = new ScriptValuesScript[nrscripts];
-        for (int i = 0; i < nrscripts; i++) {
-          Node fnode = XmlHandler.getSubNodeByNr(scripts, "jsScript", i);
-
-          jsScripts[i] =
-              new ScriptValuesScript(
-                  Integer.parseInt(XmlHandler.getTagValue(fnode, JSSCRIPT_TAG_TYPE)),
-                  XmlHandler.getTagValue(fnode, JSSCRIPT_TAG_NAME),
-                  XmlHandler.getTagValue(fnode, JSSCRIPT_TAG_SCRIPT));
-        }
-      }
-
-      Node fields = XmlHandler.getSubNode(transformNode, "fields");
-      int nrFields = XmlHandler.countNodes(fields, "field");
-
-      allocate(nrFields);
-
-      for (int i = 0; i < nrFields; i++) {
-        Node fnode = XmlHandler.getSubNodeByNr(fields, "field", i);
-
-        fieldname[i] = XmlHandler.getTagValue(fnode, "name");
-        rename[i] = XmlHandler.getTagValue(fnode, "rename");
-        type[i] = ValueMetaFactory.getIdForValueMeta(XmlHandler.getTagValue(fnode, "type"));
-
-        String slen = XmlHandler.getTagValue(fnode, "length");
-        String sprc = XmlHandler.getTagValue(fnode, "precision");
-        length[i] = Const.toInt(slen, -1);
-        precision[i] = Const.toInt(sprc, -1);
-        replace[i] = "Y".equalsIgnoreCase(XmlHandler.getTagValue(fnode, "replace"));
-      }
-    } catch (Exception e) {
-      throw new HopXmlException(
-          BaseMessages.getString(
-              PKG, "ScriptValuesMetaMod.Exception.UnableToLoadTransformMetaFromXML"),
-          e);
-    }
-  }
-
-  @Override
-  public void setDefault() {
-    jsScripts = new ScriptValuesScript[1];
-    jsScripts[0] =
-        new ScriptValuesScript(
-            ScriptValuesScript.TRANSFORM_SCRIPT,
-            BaseMessages.getString(PKG, "ScriptValuesMod.Script1"),
-            "//" + BaseMessages.getString(PKG, "ScriptValuesMod.ScriptHere") + Const.CR + Const.CR);
-
-    int nrFields = 0;
-    allocate(nrFields);
-
-    for (int i = 0; i < nrFields; i++) {
-      fieldname[i] = "newvalue";
-      rename[i] = "newvalue";
-      type[i] = IValueMeta.TYPE_NUMBER;
-      length[i] = -1;
-      precision[i] = -1;
-      replace[i] = false;
-    }
-
-    optimizationLevel = OPTIMIZATION_LEVEL_DEFAULT;
+    return new ScriptValuesMeta(this);
   }
 
   @Override
@@ -398,30 +171,34 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
       IHopMetadataProvider metadataProvider)
       throws HopTransformException {
     try {
-      for (int i = 0; i < fieldname.length; i++) {
-        if (!Utils.isEmpty(fieldname[i])) {
-          int valueIndex = -1;
+      for (ScriptField field : scriptFields) {
+        if (!Utils.isEmpty(field.getName())) {
+          int valueIndex;
           IValueMeta v;
-          if (replace[i]) {
-            valueIndex = row.indexOfValue(fieldname[i]);
+          if (field.isReplace()) {
+            valueIndex = row.indexOfValue(field.getName());
             if (valueIndex < 0) {
               // The field was not found using the "name" field
-              if (Utils.isEmpty(rename[i])) {
+              if (Utils.isEmpty(field.getRename())) {
                 // There is no "rename" field to try; Therefore we cannot find the
                 // field to replace
                 throw new HopTransformException(
                     BaseMessages.getString(
-                        PKG, "ScriptValuesMetaMod.Exception.FieldToReplaceNotFound", fieldname[i]));
+                        PKG,
+                        "ScriptValuesMetaMod.Exception.FieldToReplaceNotFound",
+                        field.getName()));
               } else {
                 // Lookup the field to replace using the "rename" field
-                valueIndex = row.indexOfValue(rename[i]);
+                valueIndex = row.indexOfValue(field.getRename());
                 if (valueIndex < 0) {
                   // The field was not found using the "rename" field"; Therefore
                   // we cannot find the field to replace
                   //
                   throw new HopTransformException(
                       BaseMessages.getString(
-                          PKG, "ScriptValuesMetaMod.Exception.FieldToReplaceNotFound", rename[i]));
+                          PKG,
+                          "ScriptValuesMetaMod.Exception.FieldToReplaceNotFound",
+                          field.getRename()));
                 }
               }
             }
@@ -429,19 +206,19 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
             // Change the data type to match what's specified...
             //
             IValueMeta source = row.getValueMeta(valueIndex);
-            v = ValueMetaFactory.cloneValueMeta(source, type[i]);
+            v = ValueMetaFactory.cloneValueMeta(source, field.getType());
             row.setValueMeta(valueIndex, v);
           } else {
-            if (!Utils.isEmpty(rename[i])) {
-              v = ValueMetaFactory.createValueMeta(rename[i], type[i]);
+            if (!Utils.isEmpty(field.getRename())) {
+              v = ValueMetaFactory.createValueMeta(field.getRename(), field.getType());
             } else {
-              v = ValueMetaFactory.createValueMeta(fieldname[i], type[i]);
+              v = ValueMetaFactory.createValueMeta(field.getName(), field.getType());
             }
           }
-          v.setLength(length[i]);
-          v.setPrecision(precision[i]);
+          v.setLength(field.getLength());
+          v.setPrecision(field.getPrecision());
           v.setOrigin(originTransformName);
-          if (!replace[i]) {
+          if (!field.isReplace()) {
             row.addValueMeta(v);
           }
         }
@@ -451,46 +228,7 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
     }
   }
 
-  @Override
-  public String getXml() {
-    StringBuilder retval = new StringBuilder(300);
-
-    retval.append("    ").append(XmlHandler.addTagValue("optimizationLevel", optimizationLevel));
-
-    retval.append("    <jsScripts>");
-    for (ScriptValuesScript jsScript : jsScripts) {
-      retval.append("      <jsScript>");
-      retval
-          .append(CONST_SPACES)
-          .append(XmlHandler.addTagValue(JSSCRIPT_TAG_TYPE, jsScript.getScriptType()));
-      retval
-          .append(CONST_SPACES)
-          .append(XmlHandler.addTagValue(JSSCRIPT_TAG_NAME, jsScript.getScriptName()));
-      retval
-          .append(CONST_SPACES)
-          .append(XmlHandler.addTagValue(JSSCRIPT_TAG_SCRIPT, jsScript.getScript()));
-      retval.append("      </jsScript>");
-    }
-    retval.append("    </jsScripts>");
-
-    retval.append("    <fields>");
-    for (int i = 0; i < fieldname.length; i++) {
-      retval.append("      <field>");
-      retval.append(CONST_SPACES).append(XmlHandler.addTagValue("name", fieldname[i]));
-      retval.append(CONST_SPACES).append(XmlHandler.addTagValue("rename", rename[i]));
-      retval
-          .append(CONST_SPACES)
-          .append(XmlHandler.addTagValue("type", ValueMetaFactory.getValueMetaName(type[i])));
-      retval.append(CONST_SPACES).append(XmlHandler.addTagValue("length", length[i]));
-      retval.append(CONST_SPACES).append(XmlHandler.addTagValue("precision", precision[i]));
-      retval.append(CONST_SPACES).append(XmlHandler.addTagValue("replace", replace[i]));
-      retval.append("      </field>");
-    }
-    retval.append("    </fields>");
-
-    return retval.toString();
-  }
-
+  @SuppressWarnings("deprecation")
   @Override
   public void check(
       List<ICheckResult> remarks,
@@ -502,18 +240,16 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
       IRowMeta info,
       IVariables variables,
       IHopMetadataProvider metadataProvider) {
-    boolean errorFound = false;
     String errorMessage = "";
     CheckResult cr;
 
-    Context jscx;
-    Scriptable jsscope;
-    Script jsscript;
+    Context jsContext;
+    ScriptableObject jsScope;
 
-    jscx = ContextFactory.getGlobal().enterContext();
-    jsscope = jscx.initStandardObjects(null, false);
+    jsContext = ContextFactory.getGlobal().enterContext();
+    jsScope = jsContext.initStandardObjects(null, false);
     try {
-      jscx.setOptimizationLevel(Integer.parseInt(variables.resolve(optimizationLevel)));
+      jsContext.setOptimizationLevel(Integer.parseInt(variables.resolve(optimizationLevel)));
     } catch (NumberFormatException nfe) {
       errorMessage =
           "Error with optimization level.  Could not convert the value of "
@@ -534,15 +270,15 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
     String strActiveEndScript = "";
 
     // Building the Scripts
-    if (jsScripts.length > 0) {
+    if (!jsScripts.isEmpty()) {
       for (ScriptValuesScript jsScript : jsScripts) {
         if (jsScript.isTransformScript()) {
           strActiveScript = jsScript.getScript();
         } else if (jsScript.isStartScript()) {
-          strActiveStartScriptName = jsScript.getScriptName();
+          strActiveStartScriptName = jsScript.getName();
           strActiveStartScript = jsScript.getScript();
         } else if (jsScript.isEndScript()) {
-          strActiveEndScriptName = jsScript.getScriptName();
+          strActiveEndScriptName = jsScript.getName();
           strActiveEndScript = jsScript.getScript();
         }
       }
@@ -560,47 +296,32 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
       remarks.add(cr);
 
       // Adding the existing Scripts to the Context
-      for (int i = 0; i < getNumberOfJSScripts(); i++) {
-        Scriptable jsR = Context.toObject(jsScripts[i].getScript(), jsscope);
-        jsscope.put(jsScripts[i].getScriptName(), jsscope, jsR);
-      }
-
-      // Modification for Additional Script parsing
-      try {
-        if (getAddClasses() != null) {
-          for (int i = 0; i < getAddClasses().length; i++) {
-            Object jsOut = Context.javaToJS(getAddClasses()[i].getAddObject(), jsscope);
-            ScriptableObject.putProperty(jsscope, getAddClasses()[i].getJSName(), jsOut);
-          }
-        }
-      } catch (Exception e) {
-        errorMessage = ("Couldn't add JavaClasses to Context! Error:");
-        cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
-        remarks.add(cr);
+      for (ScriptValuesScript jsScript : jsScripts) {
+        Scriptable jsR = Context.toObject(jsScript.getScript(), jsScope);
+        jsScope.put(jsScript.getName(), jsScope, jsR);
       }
 
       // Adding some default JavaScriptFunctions to the System
       try {
-        Context.javaToJS(ScriptValuesAddedFunctions.class, jsscope);
-        ((ScriptableObject) jsscope)
-            .defineFunctionProperties(
-                ScriptValuesAddedFunctions.jsFunctionList,
-                ScriptValuesAddedFunctions.class,
-                ScriptableObject.DONTENUM);
+        Context.javaToJS(ScriptValuesAddedFunctions.class, jsScope);
+        jsScope.defineFunctionProperties(
+            ScriptValuesAddedFunctions.jsFunctionList,
+            ScriptValuesAddedFunctions.class,
+            ScriptableObject.DONTENUM);
       } catch (Exception ex) {
-        errorMessage = "Couldn't add Default Functions! Error:" + Const.CR + ex.toString();
+        errorMessage = "Couldn't add Default Functions! Error:" + Const.CR + ex;
         cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
         remarks.add(cr);
       }
 
       // Adding some Constants to the JavaScript
       try {
-        jsscope.put("SKIP_PIPELINE", jsscope, ScriptValues.SKIP_PIPELINE);
-        jsscope.put("ABORT_PIPELINE", jsscope, ScriptValues.ABORT_PIPELINE);
-        jsscope.put("ERROR_PIPELINE", jsscope, ScriptValues.ERROR_PIPELINE);
-        jsscope.put("CONTINUE_PIPELINE", jsscope, ScriptValues.CONTINUE_PIPELINE);
+        jsScope.put("SKIP_PIPELINE", jsScope, ScriptValues.SKIP_PIPELINE);
+        jsScope.put("ABORT_PIPELINE", jsScope, ScriptValues.ABORT_PIPELINE);
+        jsScope.put("ERROR_PIPELINE", jsScope, ScriptValues.ERROR_PIPELINE);
+        jsScope.put("CONTINUE_PIPELINE", jsScope, ScriptValues.CONTINUE_PIPELINE);
       } catch (Exception ex) {
-        errorMessage = "Couldn't add Pipeline Constants! Error:" + Const.CR + ex.toString();
+        errorMessage = "Couldn't add Pipeline Constants! Error:" + Const.CR + ex;
         cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
         remarks.add(cr);
       }
@@ -608,12 +329,12 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
       try {
         ScriptValuesDummy dummyTransform =
             new ScriptValuesDummy(prev, pipelineMeta.getTransformFields(variables, transformMeta));
-        Scriptable jsvalue = Context.toObject(dummyTransform, jsscope);
-        jsscope.put("_transform_", jsscope, jsvalue);
+        Scriptable jsvalue = Context.toObject(dummyTransform, jsScope);
+        jsScope.put("_transform_", jsScope, jsvalue);
 
         Object[] row = new Object[prev.size()];
-        Scriptable jsRowMeta = Context.toObject(prev, jsscope);
-        jsscope.put("rowMeta", jsscope, jsRowMeta);
+        Scriptable jsRowMeta = Context.toObject(prev, jsScope);
+        jsScope.put("rowMeta", jsScope, jsRowMeta);
         for (int i = 0; i < prev.size(); i++) {
           IValueMeta valueMeta = prev.getValueMeta(i);
           Object valueData = null;
@@ -648,114 +369,29 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
           }
 
           row[i] = valueData;
-
-          Scriptable jsarg = Context.toObject(valueData, jsscope);
-          jsscope.put(valueMeta.getName(), jsscope, jsarg);
+          if (valueData != null) {
+            Scriptable jsArgument = Context.toObject(valueData, jsScope);
+            jsScope.put(valueMeta.getName(), jsScope, jsArgument);
+          }
         }
-        Scriptable jsRow = Context.toObject(row, jsscope);
-        jsscope.put("row", jsscope, jsRow);
+        Scriptable jsRow = Context.toObject(row, jsScope);
+        jsScope.put("row", jsScope, jsRow);
       } catch (Exception ev) {
-        errorMessage = "Couldn't add Input fields to Script! Error:" + Const.CR + ev.toString();
+        errorMessage = "Couldn't add Input fields to Script! Error:" + Const.CR + ev;
         cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
         remarks.add(cr);
       }
 
-      try {
-        // Checking for StartScript
-        if (!Utils.isEmpty(strActiveStartScript)) {
-          /* Object startScript = */ jscx.evaluateString(
-              jsscope, strActiveStartScript, "pipeline_Start", 1, null);
-          errorMessage = "Found Start Script. " + strActiveStartScriptName + " Processing OK";
-          cr = new CheckResult(ICheckResult.TYPE_RESULT_OK, errorMessage, transformMeta);
-          remarks.add(cr);
-        }
-      } catch (Exception e) {
-        errorMessage = "Couldn't process Start Script! Error:" + Const.CR + e.toString();
-        cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
-        remarks.add(cr);
-      }
-
-      try {
-        jsscript = jscx.compileString(strActiveScript, "script", 1, null);
-
-        cr =
-            new CheckResult(
-                ICheckResult.TYPE_RESULT_OK,
-                BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.ScriptCompiledOK"),
-                transformMeta);
-        remarks.add(cr);
-
-        try {
-
-          jsscript.exec(jscx, jsscope);
-
-          cr =
-              new CheckResult(
-                  ICheckResult.TYPE_RESULT_OK,
-                  BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.ScriptCompiledOK2"),
-                  transformMeta);
-          remarks.add(cr);
-
-          if (fieldname.length > 0) {
-            StringBuilder message =
-                new StringBuilder(
-                    BaseMessages.getString(
-                            PKG,
-                            "ScriptValuesMetaMod.CheckResult.FailedToGetValues",
-                            String.valueOf(fieldname.length))
-                        + Const.CR
-                        + Const.CR);
-
-            if (errorFound) {
-              cr =
-                  new CheckResult(
-                      ICheckResult.TYPE_RESULT_ERROR, message.toString(), transformMeta);
-            } else {
-              cr = new CheckResult(ICheckResult.TYPE_RESULT_OK, message.toString(), transformMeta);
-            }
-            remarks.add(cr);
-          }
-        } catch (JavaScriptException jse) {
-          Context.exit();
-          errorMessage =
-              BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.CouldNotExecuteScript")
-                  + Const.CR
-                  + jse.toString();
-          cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
-          remarks.add(cr);
-        } catch (Exception e) {
-          Context.exit();
-          errorMessage =
-              BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.CouldNotExecuteScript2")
-                  + Const.CR
-                  + e.toString();
-          cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
-          remarks.add(cr);
-        }
-
-        // Checking End Script
-        try {
-          if (!Utils.isEmpty(strActiveEndScript)) {
-            /* Object endScript = */ jscx.evaluateString(
-                jsscope, strActiveEndScript, "pipeline_End", 1, null);
-            errorMessage = "Found End Script. " + strActiveEndScriptName + " Processing OK";
-            cr = new CheckResult(ICheckResult.TYPE_RESULT_OK, errorMessage, transformMeta);
-            remarks.add(cr);
-          }
-        } catch (Exception e) {
-          errorMessage = "Couldn't process End Script! Error:" + Const.CR + e.toString();
-          cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
-          remarks.add(cr);
-        }
-      } catch (Exception e) {
-        Context.exit();
-        errorMessage =
-            BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.CouldNotCompileScript")
-                + Const.CR
-                + e.toString();
-        cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
-        remarks.add(cr);
-      }
+      checkStartScript(
+          transformMeta,
+          jsContext,
+          jsScope,
+          strActiveStartScript,
+          strActiveStartScriptName,
+          remarks);
+      checkTransformScript(transformMeta, jsContext, jsScope, strActiveStartScript, remarks);
+      checkEndScript(
+          transformMeta, jsContext, jsScope, strActiveEndScript, strActiveEndScriptName, remarks);
     } else {
       Context.exit();
       errorMessage =
@@ -783,100 +419,147 @@ public class ScriptValuesMeta extends BaseTransformMeta<ScriptValues, ScriptValu
     }
   }
 
-  public String getFunctionFromScript(String strFunction, String strScript) {
-    String sRC = "";
-    int iStartPos = strScript.indexOf(strFunction);
-    if (iStartPos > 0) {
-      iStartPos = strScript.indexOf('{', iStartPos);
-      int iCounter = 1;
-      while (iCounter != 0) {
-        if (strScript.charAt(iStartPos++) == '{') {
-          iCounter++;
-        } else if (strScript.charAt(iStartPos++) == '}') {
-          iCounter--;
-        }
-        sRC = sRC + strScript.charAt(iStartPos);
-      }
+  private void checkTransformScript(
+      TransformMeta transformMeta,
+      Context jsContext,
+      ScriptableObject jsScope,
+      String strActiveScript,
+      List<ICheckResult> remarks) {
+    try {
+      Script jsscript = jsContext.compileString(strActiveScript, "script", 1, null);
+      CheckResult cr =
+          new CheckResult(
+              ICheckResult.TYPE_RESULT_OK,
+              BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.ScriptCompiledOK"),
+              transformMeta);
+      remarks.add(cr);
+
+      checkTransformScriptExecution(transformMeta, jsContext, jsScope, remarks, jsscript);
+    } catch (Exception e) {
+      Context.exit();
+      String errorMessage =
+          BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.CouldNotCompileScript")
+              + Const.CR
+              + e;
+      CheckResult cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
+      remarks.add(cr);
     }
-    return sRC;
   }
 
-  // This is for Additional Classloading
-  public void parseXmlForAdditionalClasses() throws HopException {
+  private void checkTransformScriptExecution(
+      TransformMeta transformMeta,
+      Context jsContext,
+      ScriptableObject jsScope,
+      List<ICheckResult> remarks,
+      Script jsscript) {
+    CheckResult cr;
     try {
-      Properties sysprops = System.getProperties();
-      String strActPath = sysprops.getProperty("user.dir");
-      Document dom =
-          XmlHandler.loadXmlFile(strActPath + "/plugins/transforms/ScriptValues_mod/plugin.xml");
-      Node transformNode = dom.getDocumentElement();
-      Node libraries = XmlHandler.getSubNode(transformNode, "js_libraries");
-      int nbOfLibs = XmlHandler.countNodes(libraries, "js_lib");
-      additionalClasses = new ScriptValuesAddClasses[nbOfLibs];
-      for (int i = 0; i < nbOfLibs; i++) {
-        Node fnode = XmlHandler.getSubNodeByNr(libraries, "js_lib", i);
-        String strJarName = XmlHandler.getTagAttribute(fnode, "name");
-        String strClassName = XmlHandler.getTagAttribute(fnode, "classname");
-        String strJSName = XmlHandler.getTagAttribute(fnode, "js_name");
-
-        Class<?> addClass =
-            LoadAdditionalClass(
-                strActPath + "/plugins/transforms/ScriptValues_mod/" + strJarName, strClassName);
-        Object addObject = addClass.newInstance();
-        additionalClasses[i] = new ScriptValuesAddClasses(addClass, addObject, strJSName);
+      jsscript.exec(jsContext, jsScope, jsScope);
+      cr =
+          new CheckResult(
+              ICheckResult.TYPE_RESULT_OK,
+              BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.ScriptCompiledOK2"),
+              transformMeta);
+      remarks.add(cr);
+
+      if (!scriptFields.isEmpty()) {
+        String message =
+            BaseMessages.getString(
+                    PKG,
+                    "ScriptValuesMetaMod.CheckResult.FailedToGetValues",
+                    String.valueOf(scriptFields.size()))
+                + Const.CR
+                + Const.CR;
+
+        cr = new CheckResult(ICheckResult.TYPE_RESULT_OK, message, transformMeta);
+        remarks.add(cr);
       }
+    } catch (JavaScriptException jse) {
+      Context.exit();
+      String errorMessage =
+          BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.CouldNotExecuteScript")
+              + Const.CR
+              + jse;
+      cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
+      remarks.add(cr);
     } catch (Exception e) {
-      throw new HopException(
-          BaseMessages.getString(
-              PKG, "ScriptValuesMetaMod.Exception.UnableToParseXMLforAdditionalClasses"),
-          e);
+      Context.exit();
+      String errorMessage =
+          BaseMessages.getString(PKG, "ScriptValuesMetaMod.CheckResult.CouldNotExecuteScript2")
+              + Const.CR
+              + e;
+      cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
+      remarks.add(cr);
     }
   }
 
-  private static Class<?> LoadAdditionalClass(String strJar, String strClassName)
-      throws HopException {
+  private void checkStartScript(
+      TransformMeta transformMeta,
+      Context jsContext,
+      ScriptableObject jsScope,
+      String strActiveStartScript,
+      String strActiveStartScriptName,
+      List<ICheckResult> remarks) {
     try {
-      Thread t = Thread.currentThread();
-      ClassLoader cl = t.getContextClassLoader();
-      URL u = new URL("jar:file:" + strJar + "!/");
-      // We never know what else the script wants to load with the class loader, so lets not close
-      // it just like that.
-      HopURLClassLoader kl = new HopURLClassLoader(new URL[] {u}, cl);
-      return kl.loadClass(strClassName);
+      // Checking for StartScript
+      if (!Utils.isEmpty(strActiveStartScript)) {
+        jsContext.evaluateString(jsScope, strActiveStartScript, "pipeline_Start", 1, null);
+        String errorMessage = "Found Start Script. " + strActiveStartScriptName + " Processing OK";
+        CheckResult cr = new CheckResult(ICheckResult.TYPE_RESULT_OK, errorMessage, transformMeta);
+        remarks.add(cr);
+      }
     } catch (Exception e) {
-      throw new HopException(
-          BaseMessages.getString(PKG, "ScriptValuesMetaMod.Exception.UnableToLoadAdditionalClass"),
-          e);
+      String errorMessage = "Couldn't process Start Script! Error:" + Const.CR + e;
+      CheckResult cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
+      remarks.add(cr);
     }
   }
 
-  public ScriptValuesAddClasses[] getAddClasses() {
-    return additionalClasses;
-  }
-
-  @Override
-  public boolean supportsErrorHandling() {
-    return true;
-  }
-
-  /**
-   * @return the replace
-   */
-  public boolean[] getReplace() {
-    return replace;
-  }
-
-  /**
-   * @param replace the replace to set
-   */
-  public void setReplace(boolean[] replace) {
-    this.replace = replace;
+  /** Checking End Script */
+  private void checkEndScript(
+      TransformMeta transformMeta,
+      Context jsContext,
+      ScriptableObject jsScope,
+      String strActiveEndScript,
+      String strActiveEndScriptName,
+      List<ICheckResult> remarks) {
+    try {
+      if (!Utils.isEmpty(strActiveEndScript)) {
+        jsContext.evaluateString(jsScope, strActiveEndScript, "pipeline_End", 1, null);
+        String errorMessage = "Found End Script. " + strActiveEndScriptName + " Processing OK";
+        CheckResult cr = new CheckResult(ICheckResult.TYPE_RESULT_OK, errorMessage, transformMeta);
+        remarks.add(cr);
+      }
+    } catch (Exception e) {
+      String errorMessage = "Couldn't process End Script! Error:" + Const.CR + e;
+      CheckResult cr = new CheckResult(ICheckResult.TYPE_RESULT_ERROR, errorMessage, transformMeta);
+      remarks.add(cr);
+    }
   }
 
-  public void setOptimizationLevel(String optimizationLevel) {
-    this.optimizationLevel = optimizationLevel;
+  public String getFunctionFromScript(String strFunction, String strScript) {
+    StringBuilder sRC = new StringBuilder();
+    int iStartPos = strScript.indexOf(strFunction);
+    if (iStartPos > 0) {
+      iStartPos = strScript.indexOf('{', iStartPos);
+      int iCounter = 1;
+      while (iCounter != 0) {
+        if (strScript.charAt(iStartPos++) == '{') {
+          iCounter++;
+        } else if (strScript.charAt(iStartPos++) == '}') {
+          iCounter--;
+        }
+        sRC.append(strScript.charAt(iStartPos));
+      }
+    }
+    return sRC.toString();
   }
 
-  public String getOptimizationLevel() {
-    return this.optimizationLevel;
+  public String[] getJSScriptNames() {
+    String[] strJSNames = new String[jsScripts.size()];
+    for (int i = 0; i < jsScripts.size(); i++) {
+      strJSNames[i] = jsScripts.get(i).getName();
+    }
+    return strJSNames;
   }
 }
diff --git a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesScript.java b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesScript.java
index d90c7cf69b..00ccad1171 100644
--- a/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesScript.java
+++ b/plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesScript.java
@@ -17,87 +17,65 @@
 
 package org.apache.hop.pipeline.transforms.javascript;
 
-import org.apache.hop.core.injection.Injection;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.hop.metadata.api.HopMetadataProperty;
 
+@Getter
+@Setter
 public class ScriptValuesScript {
-
   public static final int NORMAL_SCRIPT = -1;
   public static final int TRANSFORM_SCRIPT = 0;
   public static final int START_SCRIPT = 1;
   public static final int END_SCRIPT = 2;
 
-  private int iScriptType;
-  private boolean bScriptActive;
+  @HopMetadataProperty(
+      key = "jsScript_type",
+      injectionKey = "SCRIPT_TYPE",
+      injectionKeyDescription = "ScriptValuesMod.Injection.SCRIPT_TYPE")
+  private int type;
 
-  @Injection(name = "SCRIPT_NAME", group = "SCRIPTS")
-  private String sScriptName;
+  @HopMetadataProperty(
+      key = "jsScript_name",
+      injectionKey = "SCRIPT_NAME",
+      injectionKeyDescription = "ScriptValuesMod.Injection.SCRIPT_NAME")
+  private String name;
 
-  @Injection(name = "SCRIPT", group = "SCRIPTS")
-  private String sScript;
+  @HopMetadataProperty(
+      key = "jsScript_script",
+      injectionKey = "SCRIPT",
+      injectionKeyDescription = "ScriptValuesMod.Injection.SCRIPT")
+  private String script;
 
   public ScriptValuesScript() {}
 
-  public ScriptValuesScript(int iScriptType, String sScriptName, String sScript) {
+  public ScriptValuesScript(ScriptValuesScript s) {
     super();
-    this.iScriptType = iScriptType;
-    this.sScriptName = sScriptName;
-    this.sScript = sScript;
-    bScriptActive = true;
-  }
-
-  public int getScriptType() {
-    return iScriptType;
-  }
-
-  public void setScriptType(int iScriptType) {
-    this.iScriptType = iScriptType;
-  }
-
-  public String getScript() {
-    return this.sScript;
+    this.type = s.type;
+    this.name = s.name;
+    this.script = s.script;
   }
 
-  public void setScript(String sScript) {
-    this.sScript = sScript;
-  }
-
-  public String getScriptName() {
-    return sScriptName;
-  }
-
-  public void setScriptName(String sScriptName) {
-    this.sScriptName = sScriptName;
+  public ScriptValuesScript(int type, String name, String script) {
+    this();
+    this.type = type;
+    this.name = name;
+    this.script = script;
   }
 
   public boolean isTransformScript() {
-    if (this.bScriptActive && this.iScriptType == TRANSFORM_SCRIPT) {
-      return true;
-    } else {
-      return false;
-    }
+    return this.type == TRANSFORM_SCRIPT;
   }
 
   public boolean isStartScript() {
-    if (this.bScriptActive && this.iScriptType == START_SCRIPT) {
-      return true;
-    } else {
-      return false;
-    }
+    return this.type == START_SCRIPT;
   }
 
   public boolean isEndScript() {
-    if (this.bScriptActive && this.iScriptType == END_SCRIPT) {
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  public boolean isActive() {
-    return bScriptActive;
+    return this.type == END_SCRIPT;
   }
 
   public String toString() {
-    return String.format("ScriptValuesScript: (%d, %s, %s)", iScriptType, sScriptName, sScript);
+    return String.format("ScriptValuesScript: (%d, %s, %s)", type, name, script);
   }
 }
diff --git a/plugins/transforms/javascript/src/main/resources/org/apache/hop/pipeline/transforms/javascript/messages/messages_en_US.properties b/plugins/transforms/javascript/src/main/resources/org/apache/hop/pipeline/transforms/javascript/messages/messages_en_US.properties
index 366eb43e36..34c0d78773 100644
--- a/plugins/transforms/javascript/src/main/resources/org/apache/hop/pipeline/transforms/javascript/messages/messages_en_US.properties
+++ b/plugins/transforms/javascript/src/main/resources/org/apache/hop/pipeline/transforms/javascript/messages/messages_en_US.properties
@@ -96,6 +96,7 @@ ScriptValuesMod.Injection.FIELD_TYPE=The field type.
 ScriptValuesMod.Injection.FIELDS=The output fields to write to.
 ScriptValuesMod.Injection.OPTIMIZATION_LEVEL=Specify the level of optimization.
 ScriptValuesMod.Injection.SCRIPT=The java script statement.
+ScriptValuesMod.Injection.SCRIPT_TYPE=The type of script: -1=normal, 0=transform, 1=start, 2=end
 ScriptValuesMod.Injection.SCRIPT_NAME=The name of the script.
 ScriptValuesMod.Injection.SCRIPTS=The java scripts.
 ScriptValuesMod.Log.CouldNotAddDefaultConstants=Could not add default constants to the project.
diff --git a/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMetaInjectionTest.java b/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMetaInjectionTest.java
deleted file mode 100644
index 180acd651c..0000000000
--- a/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMetaInjectionTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.hop.pipeline.transforms.javascript;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.apache.hop.core.injection.BaseMetadataInjectionTestJunit5;
-import org.apache.hop.core.row.IValueMeta;
-import org.apache.hop.core.row.value.ValueMetaInteger;
-import org.apache.hop.core.row.value.ValueMetaNumber;
-import org.apache.hop.core.row.value.ValueMetaString;
-import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class ScriptValuesMetaInjectionTest extends BaseMetadataInjectionTestJunit5<ScriptValuesMeta> {
-
-  @RegisterExtension
-  static RestoreHopEngineEnvironmentExtension env = new RestoreHopEngineEnvironmentExtension();
-
-  @BeforeEach
-  void setup() throws Exception {
-    setup(new ScriptValuesMeta());
-  }
-
-  @Test
-  void test() throws Exception {
-    check("OPTIMIZATION_LEVEL", () -> meta.getOptimizationLevel());
-    check("FIELD_NAME", () -> meta.getFieldname()[0]);
-    check("FIELD_RENAME_TO", () -> meta.getRename()[0]);
-    check("FIELD_REPLACE", () -> meta.getReplace()[0]);
-    check("SCRIPT_NAME", () -> meta.getJSScripts()[0].getScriptName());
-    check("SCRIPT", () -> meta.getJSScripts()[0].getScript());
-
-    // field type requires special handling, since it's stored as an array of ints, but injected as
-    // strings
-    skipPropertyTest("FIELD_TYPE");
-    IValueMeta mftt = new ValueMetaString("f");
-    injector.setProperty(meta, "FIELD_TYPE", setValue(mftt, "String"), "f");
-    assertEquals(IValueMeta.TYPE_STRING, meta.getType()[0]);
-    // reset the types array, so we can set it again
-    meta.setType(new int[] {});
-    injector.setProperty(meta, "FIELD_TYPE", setValue(mftt, "Integer"), "f");
-    assertEquals(IValueMeta.TYPE_INTEGER, meta.getType()[0]);
-
-    // length and precision fields also need special handing, to ensure that we get -1 when the
-    // injected string value
-    // is empty or null
-    skipPropertyTest("FIELD_LENGTH");
-    injector.setProperty(meta, "FIELD_LENGTH", setValue(new ValueMetaString(""), ""), "");
-    assertEquals(-1, meta.getLength()[0]);
-    injector.setProperty(meta, "FIELD_LENGTH", setValue(new ValueMetaString(" "), " "), " ");
-    assertEquals(-1, meta.getLength()[0]);
-    injector.setProperty(meta, "FIELD_LENGTH", setValue(new ValueMetaString(null), null), null);
-    assertEquals(-1, meta.getLength()[0]);
-    injector.setProperty(meta, "FIELD_LENGTH", setValue(new ValueMetaString("5"), "5"), "5");
-    assertEquals(5, meta.getLength()[0]);
-    injector.setProperty(meta, "FIELD_LENGTH", setValue(new ValueMetaInteger("5"), 5L), "5");
-    assertEquals(5, meta.getLength()[0]);
-    injector.setProperty(
-        meta, "FIELD_LENGTH", setValue(new ValueMetaInteger("5"), (Long) null), "5");
-    assertEquals(-1, meta.getLength()[0]);
-    injector.setProperty(meta, "FIELD_LENGTH", setValue(new ValueMetaNumber("5"), 5.0), "5");
-    assertEquals(5, meta.getLength()[0]);
-    injector.setProperty(
-        meta, "FIELD_LENGTH", setValue(new ValueMetaInteger("5"), (Double) null), "5");
-    assertEquals(-1, meta.getLength()[0]);
-
-    skipPropertyTest("FIELD_PRECISION");
-    injector.setProperty(meta, "FIELD_PRECISION", setValue(new ValueMetaString(""), ""), "");
-    assertEquals(-1, meta.getPrecision()[0]);
-    injector.setProperty(meta, "FIELD_PRECISION", setValue(new ValueMetaString(" "), " "), " ");
-    assertEquals(-1, meta.getPrecision()[0]);
-    injector.setProperty(meta, "FIELD_PRECISION", setValue(new ValueMetaString(null), null), null);
-    assertEquals(-1, meta.getPrecision()[0]);
-    injector.setProperty(meta, "FIELD_PRECISION", setValue(new ValueMetaString("5"), "5"), "5");
-    assertEquals(5, meta.getPrecision()[0]);
-    injector.setProperty(meta, "FIELD_PRECISION", setValue(new ValueMetaInteger("5"), 5L), "5");
-    assertEquals(5, meta.getPrecision()[0]);
-    injector.setProperty(
-        meta, "FIELD_PRECISION", setValue(new ValueMetaInteger("5"), (Long) null), "5");
-    assertEquals(-1, meta.getPrecision()[0]);
-    injector.setProperty(meta, "FIELD_PRECISION", setValue(new ValueMetaNumber("5"), 5.0), "5");
-    assertEquals(5, meta.getPrecision()[0]);
-    injector.setProperty(
-        meta, "FIELD_PRECISION", setValue(new ValueMetaInteger("5"), (Double) null), "5");
-    assertEquals(-1, meta.getPrecision()[0]);
-  }
-}
diff --git a/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMetaTest.java b/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMetaTest.java
index dec109a92d..018d10a9ec 100644
--- a/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMetaTest.java
+++ b/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesMetaTest.java
@@ -17,195 +17,80 @@
 package org.apache.hop.pipeline.transforms.javascript;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.UUID;
-import org.apache.hop.core.HopEnvironment;
+import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.plugins.PluginRegistry;
-import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
-import org.apache.hop.pipeline.transform.ITransformMeta;
-import org.apache.hop.pipeline.transforms.loadsave.LoadSaveTester;
-import org.apache.hop.pipeline.transforms.loadsave.initializer.IInitializer;
-import org.apache.hop.pipeline.transforms.loadsave.validator.ArrayLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.BooleanLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.IntLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.PrimitiveBooleanArrayLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.PrimitiveIntArrayLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.StringLoadSaveValidator;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.hop.core.row.value.ValueMetaDate;
+import org.apache.hop.core.row.value.ValueMetaInteger;
+import org.apache.hop.core.row.value.ValueMetaNumber;
+import org.apache.hop.core.row.value.ValueMetaPlugin;
+import org.apache.hop.core.row.value.ValueMetaPluginType;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.pipeline.transform.TransformSerializationTestUtil;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
-class ScriptValuesMetaTest implements IInitializer<ITransformMeta> {
-  @RegisterExtension
-  static RestoreHopEngineEnvironmentExtension env = new RestoreHopEngineEnvironmentExtension();
-
-  LoadSaveTester loadSaveTester;
-  Class<ScriptValuesMeta> testMetaClass = ScriptValuesMeta.class;
-
-  @BeforeEach
-  void setUpLoadSave() throws Exception {
-    HopEnvironment.init();
-    PluginRegistry.init();
-    List<String> attributes =
-        Arrays.asList(
-            "fieldname",
-            "rename",
-            "type",
-            "length",
-            "precision",
-            "replace",
-            "jsScripts",
-            "optimizationLevel");
-
-    Map<String, String> getterMap =
-        new HashMap<>() {
-          {
-            put("fieldname", "getFieldname");
-            put("rename", "getRename");
-            put("type", "getType");
-            put("length", "getLength");
-            put("precision", "getPrecision");
-            put("replace", "getReplace");
-            //        put( "compatible", "isCompatible" );
-            put("optimizationLevel", "getOptimizationLevel");
-            put("jsScripts", "getJSScripts");
-          }
-        };
-    Map<String, String> setterMap =
-        new HashMap<>() {
-          {
-            put("fieldname", "setFieldname");
-            put("rename", "setRename");
-            put("type", "setType");
-            put("length", "setLength");
-            put("precision", "setPrecision");
-            put("replace", "setReplace");
-            //        put( "compatible", "setCompatible" );
-            put("optimizationLevel", "setOptimizationLevel");
-            put("jsScripts", "setJSScripts");
-          }
-        };
-    IFieldLoadSaveValidator<String[]> stringArrayLoadSaveValidator =
-        new ArrayLoadSaveValidator<>(new StringLoadSaveValidator(), 5);
-
-    IFieldLoadSaveValidator<ScriptValuesScript[]> svsArrayLoadSaveValidator =
-        new ArrayLoadSaveValidator<>(new ScriptValuesScriptLoadSaveValidator(), 5);
-
-    Map<String, IFieldLoadSaveValidator<?>> attrValidatorMap = new HashMap<>();
-    attrValidatorMap.put("fieldname", stringArrayLoadSaveValidator);
-    attrValidatorMap.put("rename", stringArrayLoadSaveValidator);
-    attrValidatorMap.put(
-        "type", new PrimitiveIntArrayLoadSaveValidator(new IntLoadSaveValidator(9), 5));
-    attrValidatorMap.put(
-        "length", new PrimitiveIntArrayLoadSaveValidator(new IntLoadSaveValidator(100), 5));
-    attrValidatorMap.put(
-        "precision", new PrimitiveIntArrayLoadSaveValidator(new IntLoadSaveValidator(6), 5));
-    attrValidatorMap.put(
-        "replace", new PrimitiveBooleanArrayLoadSaveValidator(new BooleanLoadSaveValidator(), 5));
-    attrValidatorMap.put("jsScripts", svsArrayLoadSaveValidator);
-
-    Map<String, IFieldLoadSaveValidator<?>> typeValidatorMap = new HashMap<>();
-
-    loadSaveTester =
-        new LoadSaveTester(
-            testMetaClass,
-            attributes,
-            getterMap,
-            setterMap,
-            attrValidatorMap,
-            typeValidatorMap,
-            this);
-  }
-
-  // Call the allocate method on the LoadSaveTester meta class
-  @Override
-  public void modify(ITransformMeta someMeta) {
-    if (someMeta instanceof ScriptValuesMeta) {
-      ((ScriptValuesMeta) someMeta).allocate(5);
-    }
-  }
-
-  public class ScriptValuesScriptLoadSaveValidator
-      implements IFieldLoadSaveValidator<ScriptValuesScript> {
-    final Random rand = new Random();
-
-    @Override
-    public ScriptValuesScript getTestObject() {
-      int scriptType = rand.nextInt(4);
-      if (scriptType == 3) {
-        scriptType = -1;
-      }
-      return new ScriptValuesScript(
-          scriptType, UUID.randomUUID().toString(), UUID.randomUUID().toString());
-    }
-
-    @Override
-    public boolean validateTestObject(ScriptValuesScript testObject, Object actual) {
-      if (!(actual instanceof ScriptValuesScript)) {
-        return false;
-      }
-      return (actual.toString().equals(testObject.toString()));
-    }
+class ScriptValuesMetaTest {
+  @BeforeAll
+  static void beforeAll() throws HopException {
+    PluginRegistry registry = PluginRegistry.getInstance();
+    registry.registerPluginClass(
+        ValueMetaString.class.getName(), ValueMetaPluginType.class, ValueMetaPlugin.class);
+    registry.registerPluginClass(
+        ValueMetaInteger.class.getName(), ValueMetaPluginType.class, ValueMetaPlugin.class);
+    registry.registerPluginClass(
+        ValueMetaNumber.class.getName(), ValueMetaPluginType.class, ValueMetaPlugin.class);
+    registry.registerPluginClass(
+        ValueMetaDate.class.getName(), ValueMetaPluginType.class, ValueMetaPlugin.class);
   }
 
   @Test
-  void testExtend() {
-    ScriptValuesMeta meta = new ScriptValuesMeta();
-    int size = 1;
-    meta.extend(size);
-
-    assertEquals(size, meta.getFieldname().length);
-    assertNull(meta.getFieldname()[0]);
-    assertEquals(size, meta.getRename().length);
-    assertNull(meta.getRename()[0]);
-    assertEquals(size, meta.getType().length);
-    assertEquals(-1, meta.getType()[0]);
-    assertEquals(size, meta.getLength().length);
-    assertEquals(-1, meta.getLength()[0]);
-    assertEquals(size, meta.getPrecision().length);
-    assertEquals(-1, meta.getPrecision()[0]);
-    assertEquals(size, meta.getReplace().length);
-    assertFalse(meta.getReplace()[0]);
-
-    meta = new ScriptValuesMeta();
-
-    meta.extend(3);
-    validateExtended(meta);
-  }
-
-  private void validateExtended(final ScriptValuesMeta meta) {
-
-    assertEquals(3, meta.getFieldname().length);
-    //    assertEquals("Field 1", meta.getFieldname()[0]);
-    //    assertEquals("Field 2", meta.getFieldname()[1]);
-    //    assertEquals("Field 3", meta.getFieldname()[2]);
-    //    assertEquals(3, meta.getRename().length);
-    //    assertEquals("Field 1 - new", meta.getRename()[0]);
-    //    assertNull(meta.getRename()[1]);
-    //    assertNull(meta.getRename()[2]);
-    //    assertEquals(3, meta.getType().length);
-    //    assertEquals(IValueMeta.TYPE_STRING, meta.getType()[0]);
-    //    assertEquals(IValueMeta.TYPE_INTEGER, meta.getType()[1]);
-    //    assertEquals(IValueMeta.TYPE_NUMBER, meta.getType()[2]);
-    //    assertEquals(3, meta.getLength().length);
-    //    assertEquals(-1, meta.getLength()[0]);
-    //    assertEquals(-1, meta.getLength()[1]);
-    //    assertEquals(-1, meta.getLength()[2]);
-    //    assertEquals(3, meta.getPrecision().length);
-    //    assertEquals(-1, meta.getPrecision()[0]);
-    //    assertEquals(-1, meta.getPrecision()[1]);
-    //    assertEquals(-1, meta.getPrecision()[2]);
-    //    assertEquals(3, meta.getReplace().length);
-    //    assertFalse(meta.getReplace()[0]);
-    //    assertFalse(meta.getReplace()[1]);
-    //    assertFalse(meta.getReplace()[2]);
+  void testXmlRoundTrip() throws Exception {
+    // Test XML->Meta->XML->Meta
+    ScriptValuesMeta meta =
+        TransformSerializationTestUtil.testSerialization("/javascript.xml", ScriptValuesMeta.class);
+
+    // See if after all that we still have the correct data
+    //
+    assertEquals("2", meta.getOptimizationLevel());
+
+    // The scripts
+    assertEquals(3, meta.getJsScripts().size());
+    ScriptValuesScript s = meta.getJsScripts().getFirst();
+    assertEquals("startScript", s.getName());
+    assertEquals("startScript", s.getScript());
+    assertEquals(1, s.getType());
+    s = meta.getJsScripts().get(1);
+    assertEquals("transformScript", s.getName());
+    assertEquals("transformScript", s.getScript());
+    assertEquals(0, s.getType());
+    s = meta.getJsScripts().getLast();
+    assertEquals("endScript", s.getName());
+    assertEquals("endScript", s.getScript());
+    assertEquals(2, s.getType());
+
+    // The fields
+    assertEquals(3, meta.getScriptFields().size());
+    ScriptValuesMeta.ScriptField f = meta.getScriptFields().getFirst();
+    assertEquals("f1", f.getName());
+    assertEquals("renamedF1", f.getRename());
+    assertEquals(100, f.getLength());
+    assertEquals(-1, f.getPrecision());
+    assertTrue(f.isReplace());
+
+    f = meta.getScriptFields().get(1);
+    assertEquals("f2", f.getName());
+    assertEquals("renamedF2", f.getRename());
+    assertEquals(7, f.getLength());
+    assertEquals(-1, f.getPrecision());
+    assertTrue(f.isReplace());
+
+    f = meta.getScriptFields().getLast();
+    assertEquals("f3", f.getName());
+    assertEquals("renamedF3", f.getRename());
+    assertEquals(9, f.getLength());
+    assertEquals(2, f.getPrecision());
+    assertTrue(f.isReplace());
   }
 }
diff --git a/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesTest.java b/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesTest.java
index 1f0b0228b2..f19186eed1 100644
--- a/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesTest.java
+++ b/plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesTest.java
@@ -58,20 +58,24 @@ class ScriptValuesTest {
     doReturn(new Object[] {BigDecimal.ONE, BigDecimal.ONE}).when(transform).getRow();
 
     ScriptValuesMeta meta = new ScriptValuesMeta();
-    meta.allocate(2);
-    meta.setFieldname(new String[] {"value_int", "value_double"});
-    meta.setType(new int[] {IValueMeta.TYPE_BIGNUMBER, IValueMeta.TYPE_BIGNUMBER});
-    meta.setReplace(new boolean[] {true, true});
-
-    meta.setJSScripts(
-        new ScriptValuesScript[] {
-          new ScriptValuesScript(
-              ScriptValuesScript.TRANSFORM_SCRIPT,
-              "script",
-              "value_int = 10.00;\nvalue_double = 10.50")
-        });
-
-    ScriptValuesData data = new ScriptValuesData();
+    ScriptValuesMeta.ScriptField f1 = new ScriptValuesMeta.ScriptField();
+    f1.setName("value_int");
+    f1.setType(IValueMeta.TYPE_BIGNUMBER);
+    f1.setReplace(true);
+    meta.getScriptFields().add(f1);
+    ScriptValuesMeta.ScriptField f2 = new ScriptValuesMeta.ScriptField();
+    f2.setName("value_double");
+    f2.setType(IValueMeta.TYPE_BIGNUMBER);
+    f2.setReplace(true);
+    meta.getScriptFields().add(f2);
+
+    meta.getJsScripts()
+        .add(
+            new ScriptValuesScript(
+                ScriptValuesScript.TRANSFORM_SCRIPT,
+                "script",
+                "value_int = 10.00;\nvalue_double = 10.50"));
+
     transform.init();
 
     Object[] expectedRow = {BigDecimal.TEN, new BigDecimal("10.5")};
@@ -94,20 +98,19 @@ class ScriptValuesTest {
     doReturn(new Object[] {""}).when(transform).getRow();
 
     ScriptValuesMeta meta = new ScriptValuesMeta();
-    meta.allocate(1);
-    meta.setFieldname(new String[] {"str"});
-    meta.setType(new int[] {IValueMeta.TYPE_STRING});
-    meta.setReplace(new boolean[] {true});
-
-    meta.setJSScripts(
-        new ScriptValuesScript[] {
-          new ScriptValuesScript(
-              ScriptValuesScript.TRANSFORM_SCRIPT,
-              "script",
-              "setVariable('temp', 'pass', 'r');\nstr = getVariable('temp', 'fail');")
-        });
-
-    ScriptValuesData data = new ScriptValuesData();
+    ScriptValuesMeta.ScriptField f1 = new ScriptValuesMeta.ScriptField();
+    f1.setName("str");
+    f1.setType(IValueMeta.TYPE_STRING);
+    f1.setReplace(true);
+    meta.getScriptFields().add(f1);
+
+    meta.getJsScripts()
+        .add(
+            new ScriptValuesScript(
+                ScriptValuesScript.TRANSFORM_SCRIPT,
+                "script",
+                "setVariable('temp', 'pass', 'r');\nstr = getVariable('temp', 'fail');"));
+
     transform.init();
 
     Object[] expectedRow = {"pass"};
diff --git a/plugins/transforms/javascript/src/test/resources/javascript.xml b/plugins/transforms/javascript/src/test/resources/javascript.xml
new file mode 100644
index 0000000000..964c6d5e31
--- /dev/null
+++ b/plugins/transforms/javascript/src/test/resources/javascript.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You 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.
+  ~
+  -->
+
+<transform>
+    <optimizationLevel>2</optimizationLevel>
+    <jsScripts>
+        <jsScript>
+            <jsScript_type>1</jsScript_type>
+            <jsScript_name>startScript</jsScript_name>
+            <jsScript_script>startScript</jsScript_script>
+        </jsScript>
+        <jsScript>
+            <jsScript_type>0</jsScript_type>
+            <jsScript_name>transformScript</jsScript_name>
+            <jsScript_script>transformScript</jsScript_script>
+        </jsScript>
+        <jsScript>
+            <jsScript_type>2</jsScript_type>
+            <jsScript_name>endScript</jsScript_name>
+            <jsScript_script>endScript</jsScript_script>
+        </jsScript>
+    </jsScripts>
+    <fields>
+        <field>
+            <name>f1</name>
+            <rename>renamedF1</rename>
+            <type>String</type>
+            <length>100</length>
+            <precision>-1</precision>
+            <replace>Y</replace>
+        </field>
+        <field>
+            <name>f2</name>
+            <rename>renamedF2</rename>
+            <type>Integer</type>
+            <length>7</length>
+            <precision>-1</precision>
+            <replace>Y</replace>
+        </field>
+        <field>
+            <name>f3</name>
+            <rename>renamedF3</rename>
+            <type>Number</type>
+            <length>9</length>
+            <precision>2</precision>
+            <replace>Y</replace>
+        </field>
+    </fields>
+</transform>